File Coverage

blib/lib/ARSObject.pm
Criterion Covered Total %
statement 42 2181 1.9
branch 0 2498 0.0
condition 0 1836 0.0
subroutine 14 136 10.2
pod 78 104 75.0
total 134 6755 1.9


"
line stmt bran cond sub pod time code
1             #!perl -w
2             #
3             # High level interface above ARS module
4             #
5             # Andrew V Makarow, 2010-03-02, K)
6             #
7             #
8             # 2010-03-24 detached
9             # 2010-03-02 started inside a script
10             #
11             package ARSObject;
12 1     1   61665 use vars qw($VERSION @ISA $AUTOLOAD $CGI::Carp::CUSTOM_MSG);
  1         3  
  1         223  
13 1     1   897 use UNIVERSAL;
  1         13  
  1         4  
14 1     1   38 use strict;
  1         3  
  1         32  
15 1     1   5 use POSIX qw(:fcntl_h);
  1         2  
  1         10  
16            
17             $VERSION = '0.57';
18            
19             my $fretry =8;
20            
21             1;
22            
23             sub new { # New ARS object
24             # (-param=>value,...) -> ARS object
25 0     0 1   my $c=shift;
26             my $s ={'' => ''
27             ,-ctrl => undef # ARS control struct from ars_Login()
28             ,-srv => undef # Server name
29             ,-usr => undef # User name
30             ,-pswd => undef # Password string
31             ,-lang => '' # Language
32             ,-schema => undef # Schemas to use: [form,...]
33             ,-vfbase => # Var files base
34 0 0         (do{ my $v =$^O eq 'MSWin32' ? scalar(Win32::GetFullPathName($0)) : $0;
  0            
35 0 0         $v =~/^(.+?)\.[^\\\/]*$/ ? "$1-" : "$v-"
36             })
37             #,-storable =>undef # Use Storable module for cache files?
38             ,-schgen => 1 # 1 - use vfname('meta') for '-meta', generate it from ARS if not exists.
39             # 2 - renewable 'meta' smartly
40             # 3 - renew meta always
41             # [schema,...] - list to renew
42             ,-schfdo => 0 # Include display only fields into schema (AR_FIELD_OPTION_DISPLAY)
43             ,-meta => {} # Forms metadata from ARS:
44             # {formName}->{-fields}->{fieldName}=>{}
45             # {formName}->{-fldids}->{fieldId}=>{}
46             # Additional parameters may be:
47             # ,'fieldLbl' =>label
48             # ,'fieldLbll'=>label localised
49             # ,'fieldLblc'=>label catenation/comment
50             # ,'fieldLbv' =>labels of values
51             # ,'fieldLbvl'=>labels of values localised
52             # ,'indexUnique'
53             # ,'strOut'|'strIn'=>sub(self,form,{field},$_=val){}
54             #,-meta-min # Used in 'arsmetamin' operation
55             #,-meta-sql # 'arsmetasql': {tableName}->{-cols}->{sqlName}=>{fieldName, sqlName,...}
56             # {tableName}->{-fields}->{fieldName}=>sqlName
57             # {tableName}->{-ids}->{fieldId}=>sqlName
58             # {-forms}->{formName}->{tableName}
59             # also: -sqlname, -sqlntbl, -sqlncol, -sqlninc
60             # -sqlschema
61             ,-metax => # Exclude field schema parameters from '-meta'
62             ['displayInstanceList','permissions']
63             ,-metaid => {} # Commonly used fields with common names and value translation
64             ,-metadn => {} # {fieldId | fieldName =>
65             # {fieldName=>'name',FieldId=>id
66             # ,strIn=>sub(self,form,{field},$_=val){}
67             # ,strOut=>sub(self,form,{field},$_=val){}
68             # },...}
69             ,-maxRetrieve => 0 # ARS::ars_GetListEntry(maxRetrieve)
70             ,-entryNo => undef # Logical number of entry inserted
71             ,-strFields => 1 # Translate fields data using 'strIn'/'strOut'/'-meta'?
72             # 1 - 'enumLimits', 2 - 'fieldLbvl' before 'enumLimits'
73             ,-cmd =>'' # Command running, for err messages, script local $s->{-cmd}
74             ,-die =>undef # Error die/warn, 'Carp' or 'CGI::Carp...'
75             # ,-diemsg => undef #
76             ,-warn=>undef # , see set() and connect() below
77             # ,-warnmsg => undef #
78             ,-cpcon=>undef # Translation to console codepage sub{}(self, args) -> translated
79             ,-echo=>0 # Echo printout switch
80             ,-dbi=>undef # DBI object, by dbiconnect()
81             ,-dbiconnect =>undef #
82             ,-cgi=>undef # CGI object, by cgi()
83             ,-smtp=>undef
84             ,-smtphost=>undef
85             #,-fpl=>[] # CGI Form Presenter fields list
86             #,-fphc=>{} # CGI fields cache
87             #,-fphd=>{} # DB fields cache
88             #,-fpbv=>[] # buffer values
89             #,-fpbn=>'' # buffer name == record common name
90             };
91 0           bless $s,$c;
92 0           set($s, @_);
93 0 0         $s->{-storable} =eval('use Storable; 1') if !exists($s->{-storable});
94 0           $s
95             }
96            
97            
98             sub AUTOLOAD { # Use self->arsXXX() syntax for ars_XXX(ctrl,...) calls
99 0     0     my $m =substr($AUTOLOAD, rindex($AUTOLOAD, '::')+2);
100 0 0         return(&{$_[0]->{-die}}($_[0]->efmt("Called name without 'ars'", $_[0]->{-cmd}, undef, 'AUTOLOAD',$m)))
  0            
101             if $m !~/^ars/;
102 0 0         $m =~s/^ars/ars_/
103             if $m !~/^ars_/;
104 0 0         $m =~s/^ars/ARS::ars/
105             if $m !~/^ARS::/;
106 1     1   1473 no strict;
  1         2  
  1         2672  
107 0           &$m($_[0]->{-ctrl}, @_[1..$#_])
108             }
109            
110            
111             sub DESTROY {
112 0     0     my $s =shift;
113 0           $s->{-die} =undef;
114 0           $s->{-warn}=undef;
115 0 0         $s->{-ctrl} && eval{ars_Logoff($s->{-ctrl})};
  0            
116 0           $s->{-ctrl}=undef;
117 0 0         $s->{-dbi} && eval{$s->{-dbi}->disconnect()};
  0            
118 0           $s->{-dbi} =undef;
119 0           $s->{-cgi} =undef;
120 0           $s->{-diemsg} =undef;
121 0           $s->{-warnmsg} =undef;
122             }
123            
124            
125             sub set { # Set/Get parameters
126             # () -> (parameters)
127             # (-param) -> value
128             # (-param => value,...) -> self
129 0 0   0 1   return(keys(%{$_[0]})) if scalar(@_) ==1;
  0            
130 0 0         return($_[0]->{$_[1]}) if scalar(@_) ==2;
131 0           my ($s,%a) =@_;
132 0           foreach my $k (keys %a) {
133 0           $s->{$k} =$a{$k}
134             }
135 0 0         if ($a{-die}) {
    0          
136 0 0         if ($a{-die} =~/^Carp/) {
    0          
    0          
137 0           eval('use ' .$a{-die} .';');
138 0           $s->{-die} =\&Carp::confess;
139 0           $s->{-warn}=\&Carp::carp;
140             }
141             elsif ($a{-die} =~/^CGI::Carp/) {
142 0           eval('use ' .$a{-die} .';');
143 0           $s->{-die} =\&CGI::Carp::confess;
144 0           $s->{-warn}=\&CGI::Carp::carp;
145 0 0         if ($s->{-diemsg}) {
146 0           my $dm =$s->{-diemsg};
147 0 0   0     CGI::Carp::set_message(sub{&$dm(@_); $s->disconnect() if $s;})
  0            
148 0           }
149             }
150             elsif ($a{-die} =~/^CGI::Die/) {
151 0           eval('use Carp;');
152 0           $s->{-die} =\&Carp::confess;
153 0           $s->{-warn}=\&Carp::carp;
154 0           my $sigdie =$SIG{__DIE__};
155             $SIG{__DIE__} =sub{
156 0 0   0     return if ineval();
157 0 0 0       if ($s && $s->{-diemsg}) {
158 0           &{$s->{-diemsg}}(@_)
  0            
159             }
160             else {
161 0 0 0       print $s->{-cgi}->header(-content=>'text/html'
    0 0        
162             ,($ENV{SERVER_SOFTWARE}||'') =~/IIS/ ? (-nph=>1) : ()
163             )
164             , "

Error:

"
165             , $s->{-cgi}->escapeHTML($_[0])
166             , "
\n"
167             if $s && $s->{-cgi}
168             }
169 0 0         $s->DESTROY() if $s;
170 0           $s =undef;
171             # $SIG{__DIE__} =$sigdie;
172             # &$sigdie(@_) if ref($sigdie) eq 'CODE';
173             # CORE::die($_[0]);
174 0           };
175             $SIG{__WARN__} =sub{
176 0 0 0 0     return if !$^W ||ineval();
177 0 0 0       if ($s && $s->{-warnmsg}) {
178 0           &{$s->{-warnmsg}}(@_)
  0            
179             }
180             else {
181 0 0 0       print '
Warnig: '
182             , $s->{-cgi}->escapeHTML($_[0])
183             , "
\n"
184             if $s && $s->{-cgi}
185             }
186             # CORE::warn($_[0]);
187 0 0         } if $^W;
188             }
189             }
190             elsif ($a{-vfbase}) {
191 0 0         if ($a{-vfbase} !~/[\\\/]/) {
192 0 0         my $v =$^O eq 'MSWin32' ? scalar(Win32::GetFullPathName($0)) : $0;
193 0 0         $s->{-vfbase} =$v =~/^(.+?[\\\/])[^\\\/]+$/ ? $1 .$a{-vfbase} : $a{-vfbase};
194             }
195             }
196             $s
197 0           }
198            
199            
200             sub ineval { # is inside eval{}?
201             # for PerlEx and mod_perl
202             # see CGI::Carp::ineval comments and errors
203 0 0 0 0 0   return $^S if !($ENV{GATEWAY_INTERFACE}
      0        
204             && ($ENV{GATEWAY_INTERFACE} =~/PerlEx/))
205             && !$ENV{MOD_PERL};
206 0           my ($i, @a) =(1);
207 0           while (@a =caller($i)) {
208 0 0         return(0) if $a[0] =~/^(?:PerlEx::|Apache::Perl|Apache::Registry|Apache::ROOT)/i;
209 0 0         return(1) if $a[3] eq '(eval)';
210 0           $i +=1;
211             }
212             $^S
213 0           }
214            
215             # error message form ??? use ???
216             # (err/var, command, operation, function, args)
217             sub efmt {
218 0     0 0   efmt1(@_)
219             }
220            
221             sub efmt0 {
222 0     0 0   my ($s, $e, $c, $o, $f, @a) =@_;
223 0           cpcon($s
224             ,join(': '
225             ,($c ? $c : ())
226 0 0 0       ,($f ? $f .'(' .join(',', map {$s->dsquot($_)} @a) .')' : ())
    0 0        
    0          
    0          
227             ,($o ? $o : ())
228             )
229             .($e && ($e eq '$!') && $^E ? (' -> ' .$! .' / ' .$^E) : ( ' -> ' .($e || 'unknown error')))
230             )
231             }
232            
233             sub efmt1 {
234 0     0 0   my ($s, $e, $c, $o, $f, @a) =@_;
235 0           cpcon($s
236             ,join(' # '
237             ,($e && ($e eq '$!') && $^E ? ($! .' / ' .$^E) : ($e || 'unknown error'))
238             ,($o ? $o : ())
239 0 0 0       ,($f ? $f .'(' .join(',', map {$s->dsquot($_)} @a) .')' : ())
    0 0        
    0          
    0          
240             ,($c ? $c : ())
241             )
242             )
243             }
244            
245            
246             sub strquot { # Quote and Escape string enclosing in ''
247 0     0 1   my $v =$_[1]; # (string) -> escaped
248 0 0         return('undef') if !defined($v);
249 0           $v =~s/([\\'])/\\$1/g;
250 0           $v =~s/([\x00-\x1f])/sprintf("\\x%02x",ord($1))/eg;
  0            
251 0 0         $v =~/^\d+$/ ? $v : ('\'' .$v .'\'');
252             }
253            
254            
255             sub strquot2 { # Quote and Escape string enclosing in ""
256 0     0 1   my $v =$_[1]; # (string) -> escaped
257 0 0         return('undef') if !defined($v);
258 0           $v =~s/([\\"])/\\$1/g;
259 0           $v =~s/([\x00-\x1f])/sprintf("\\x%02x",ord($1))/eg;
  0            
260 0 0         $v =~/^\d+$/ ? $v : ('"' .$v .'"');
261             }
262            
263            
264             sub arsquot { # Quote string for ARS
265 0 0   0 1   return('NULL') if !defined($_[1]);
266 0           my $v =$_[1];
267 0           $v =~s/"/""/g;
268 0 0         $v =~/^\d+$/ ? $v : ('"' .$v .'"');
269             }
270            
271            
272             sub dsquot { # Quote data structure
273 0           $#_ <2 # (self, ?'=>', data struct)
274             ? dsquot($_[0],'=> ',$_[1])
275             : !ref($_[2]) # (, hash delim, value) -> stringified
276             ? strquot($_[0],$_[2])
277             : ref($_[2]) eq 'ARRAY'
278 0           ? '[' .join(', ', map {dsquot(@_[0..1],$_)
279 0           } @{$_[2]}) .']'
280             : ref($_[2]) eq 'HASH'
281 0           ? '{' .join(', ', map {$_ .$_[1] .dsquot(@_[0..1],$_[2]->{$_})
282 0 0   0 1   } sort keys %{$_[2]}) .'}'
    0          
    0          
    0          
283             : strquot($_[0],$_[2])
284             }
285            
286            
287             sub dsquot1 { # Quote data structure, defined elements only
288 0 0         $#_ <2 # (self, ?'=>', data struct)
289             ? dsquot1($_[0],'=> ',$_[1])
290             : !ref($_[2]) # (, hash delim, value) -> stringified
291             ? strquot($_[0],$_[2])
292             : ref($_[2]) eq 'ARRAY'
293 0           ? '[' .join(', ', map {defined($_) ? dsquot1(@_[0..1],$_) : ()
294 0 0         } @{$_[2]}) .']'
295             : ref($_[2]) eq 'HASH'
296 0           ? '{' .join(', ', map {defined($_[2]->{$_}) ? $_ .$_[1] .dsquot1(@_[0..1],$_[2]->{$_}) : ()
297 0 0   0 1   } sort keys %{$_[2]}) .'}'
    0          
    0          
    0          
298             : strquot($_[0],$_[2])
299             }
300            
301            
302             sub dsdump { # Data structure dump to string
303 0     0 1   my ($s, $d) =@_; # (data structure) -> dump string
304 0           eval('use Data::Dumper');
305 0           my $o =Data::Dumper->new([$d]);
306 0           $o->Indent(1);
307 0           $o->Deepcopy(1);
308 0           $o->Dump();
309             }
310            
311            
312             sub dsparse { # Data structure dump string to perl structure
313 0     0 1   my ($s, $d) =@_; # (string) -> data structure
314 0 0         eval('use Safe; 1')
315             && Safe->new()->reval($d)
316             }
317            
318            
319             sub dscmp { # Compare data structures
320 0     0 1   my($s, $ds1, $ds2) =@_;
321 0 0 0       return(1) if (defined($ds1) && !defined($ds2)) ||(defined($ds2) && !defined($ds1));
      0        
      0        
322 0 0 0       return(0) if !defined($ds1) && !defined($ds2);
323 0 0 0       return(1) if (ref($ds1) ||'') ne (ref($ds2) ||'');
      0        
324 0 0         return($ds1 cmp $ds2) if !ref($ds1);
325 0 0         return(dsquot($s,$ds1) cmp dsquot($s,$ds2)) if ref($ds1) eq 'ARRAY';
326 0 0         return(dsquot($s,$ds1) cmp dsquot($s,$ds2)) if ref($ds1) eq 'HASH';
327 0           $ds1 cmp $ds2
328             }
329            
330            
331             sub dsunique { # Unique list
332 0 0   0 1   my %h =(map {defined($_) ? ($_ => 1) : ()} @_[1..$#_]);
  0            
333 1     1   1012 use locale;
  1         226  
  1         5  
334 0           sort keys %h
335             }
336            
337            
338            
339             sub dsmerge { # Merge arrays or hashes
340 0     0 1   my $r;
341 0 0         if (ref($_[1]) eq 'ARRAY') {
    0          
342 0           $r =[];
343 0           for (my $i=1; $i <=$#_; $i++) {
344 0           for (my $j=0; $j <=$#{$_[$i]}; $j++) {
  0            
345 0           $r->[$j] =$_[$i]->[$j]
346             }
347             }
348             }
349             elsif (ref($_[1]) eq 'HASH') {
350 0           $r ={};
351 0           for (my $i=1; $i <=$#_; $i++) {
352 0           foreach my $k (keys %{$_[$i]}) {
  0            
353 0           $r->{$k} =$_[$i]->{$k}
354             }
355             }
356             }
357             $r
358 0           }
359            
360            
361             sub strtime { # Stringify Time
362 0     0 1   my $s =shift;
363 0 0 0       if (scalar(@_) && !defined($_[0])) {
364 0 0         &{$s->{-warn}}('Not defined time in strtime()') if $^W;
  0            
365             return(undef)
366 0           }
367 0 0 0       my $msk =(scalar(@_) ==0) || ($_[0] =~/^\d+$/i) ? 'yyyy-mm-dd hh:mm:ss' : shift;
368 0 0         my @tme =(scalar(@_) ==0) ? localtime(time) : scalar(@_) ==1 ? localtime($_[0]) : @_;
    0          
369 0           $msk =~s/yyyy/%Y/;
370 0           $msk =~s/yy/%y/;
371 0           $msk =~s/mm/%m/;
372 0           $msk =~s/mm/%M/i;
373 0           $msk =~s/dd/%d/;
374 0           $msk =~s/hh/%H/;
375 0           $msk =~s/hh/%h/i;
376 0           $msk =~s/ss/%S/;
377             #eval('use POSIX');
378 0           my $r =POSIX::strftime($msk, @tme);
379             # &{$s->{-warn}}("Not defined strtime('$msk'," .join(',', map {defined($_) ? $_ : 'undef'} @tme) .")")
380             # if !defined($r);
381 0           $r
382             }
383            
384            
385             sub timestr { # Time from String
386 0     0 1   my $s =shift;
387 0 0 0       if (scalar(@_) && !defined($_[0])) {
388 0 0         &{$s->{-warn}}('Not defined time in timestr()') if $^W;
  0            
389             return(undef)
390 0           }
391 0 0 0       my $msk =(scalar(@_) <2) || !$_[1] ? 'yyyy-mm-dd hh:mm:ss' : shift;
392 0           my $ts =$_[0];
393 0           my %th;
394 0           while ($msk =~/(yyyy|yy|mm|dd|hh|MM|ss)/) {
395 0           my $m=$1; $msk =$';
  0            
396 0 0         last if !($ts =~/(\d+)/);
397 0           my $d =$1; $ts =$';
  0            
398 0 0 0       $d -=1900 if $m eq 'yyyy' ||$m eq '%Y';
399 0           $m =chop($m);
400 0 0 0       $m ='M' if $m eq 'm' && $th{$m};
401 0 0         $m =lc($m) if $m ne 'M';
402 0           $th{$m}=$d;
403             }
404             #eval('use POSIX');
405 0   0       my $r =POSIX::mktime($th{'s'}||0,$th{'M'}||0,$th{'h'}||0,$th{'d'}||0,($th{'m'}||1)-1,$th{'y'}||0,0,0,(localtime(time))[8]);
      0        
      0        
      0        
      0        
      0        
406             # &{$s->{-warn}}("Not defined timestr('$_[0]')")
407             # if !defined($r);
408 0           $r
409             }
410            
411            
412             sub timeadd { # Adjust time to years, months, days,...
413 0     0 1   my $s =$_[0];
414 0 0         if (!defined($_[1])) {
415 0 0         &{$s->{-warn}}('Not defined time in timeadd()') if $^W;
  0            
416             return(undef)
417 0           }
418 0           my @t =localtime($_[1]);
419 0           my $i =5;
420 0   0       foreach my $a (@_[2..$#_]) {$t[$i] += ($a||0); $i--}
  0            
  0            
421             #eval('use POSIX');
422 0           POSIX::mktime(@t[0..5],0,0,$t[8])
423             }
424            
425            
426             sub charset {
427 0 0 0 0 0   $_[0]->{-charset} && ($_[0]->{-charset} =~/^\d/)
      0        
428             ? 'windows-' .$_[0]->{-charset}
429             : ($_[0]->{-charset} || ($_[0]->{-cgi} && $_[0]->{-cgi}->charset())
430             || eval('!${^ENCODING}') && eval('use POSIX; POSIX::setlocale(POSIX::LC_CTYPE)=~/\\.([^.]+)$/ ? "cp$1" : "cp1252"'))
431             }
432            
433            
434             sub cptran { # Translate strings between codepages
435 0     0 1   my ($s,$f,$t,@s) =@_; # (from, to, string,...) -> string,...
436 0 0 0       if (($] >=5.008) && eval("use Encode; 1")) {
437 0 0         map {$_= /oem|866/i ? 'cp866'
  0 0          
    0          
    0          
438             : /ansi|1251/i ? 'cp1251'
439             : /koi/i ? 'koi8-r'
440             : /8859-5/i ? 'iso-8859-5'
441             : $_
442             } $f, $t;
443 0 0 0       map {Encode::is_utf8($_)
  0 0          
444             ? ($_ =Encode::encode($t, $_, 0))
445             : Encode::from_to($_, $f, $t, 0)
446             if defined($_) && ($_ ne '')
447             } @s;
448             }
449             else {
450 0           foreach my $v ($f, $t) { # See also utf8enc, utf8dec
451 0 0         if ($v =~/oem|866/i) {$v ='€‚ƒ„…ð†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™œ›šžŸ ¡¢£¤¥ñ¦§¨©ª«¬­®¯àáâãäåæçèéìëêíîï'}
  0 0          
  0 0          
    0          
452 0           elsif ($v =~/ansi|1251/i) {$v ='ÀÁÂÃÄŨÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÜÛÚÝÞßàáâãäå¸æçèéêëìíîïðñòóôõö÷øùüûúýþÿ'}
453 0           elsif ($v =~/koi/i) {$v ='áâ÷çäå³öúéêëìíîïðòóôõæèãþûýøùÿüàñÁÂ×ÇÄÅ£ÖÚÉÊËÌÍÎÏÐÒÓÔÕÆÈÃÞÛÝØÙßÜÀÑ'}
454             elsif ($v =~/8859-5/i) {$v ='°±²³´µ¡¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÌËÊÍÎÏÐÑÒÓÔÕñÖ×ØÙÚÛÜÝÞßàáâãäåæçèéìëêíîï'}
455             }
456 0 0         map {eval("~tr/$f/$t/") if defined($_)} @s;
  0            
457             }
458 0 0         @s >1 ? @s : $s[0];
459             }
460            
461            
462             sub cpcon { # Translate to console codepage
463 0           $_[0] && $_[0]->{-cpcon}
464 0 0 0 0 1   ? &{$_[0]->{-cpcon}}(@_)
    0          
465             : $#_ <2
466             ? $_[1]
467             : (@_[1..$#_])
468             }
469            
470            
471             sub sfpath { # self file path
472             # () -> script's dir
473             # (subpath) -> dir/subpath
474 0 0   0 0   my $p =$0 =~/[\\\/]/ ? $0 : $^O eq 'MSWin32' ? Win32::GetFullPathName($0) : '';
    0          
475 0 0         $_[1]
    0          
    0          
476             ? (($p =~/^(.+?[\\\/])[^\\\/]+$/ ? $1 : '') .$_[1])
477             : ($p =~/^(.+?)[\\\/][^\\\/]+$/ ? $1 : '')
478             }
479            
480            
481            
482             sub fopen { # Open file
483 0     0 1   my $s =shift; # ('-b',filename) -> success
484 0 0         my $o =$_[0] =~/^-(?:\w[\w\d+-]*)*$/ ? shift : '-';
485 0 0         my $f =$_[0]; $f ='<' .$f if $f !~/^[<>]/;
  0            
486 0           eval('use IO::File');
487 0   0       my $h =IO::File->new($f) || return(&{$s->{-die}}($s->efmt('$!',undef,'cannot open file','fopen',$f)));
488 0 0 0       $h->binmode() if $h && ($o =~/b/);
489 0           $h
490             }
491            
492            
493             sub fdirls { # Directory listing
494 0     0 1   my $s =shift; # ('-',pathname, ?filter sub{}(self, path, $_=entry), ? []) -> (list) || [list]
495 0 0         my $o =$_[0] =~/^-(?:\w[\w\d+-]*)*$/ ? shift : '-';
496 0           my ($f, $cf, $cs) =@_;
497 0 0         local *FILE; opendir(FILE, $f) || return(&{$s->{-die}}($s->efmt('$!',undef,'cannot open dir','fdirls',$f)));
  0            
  0            
498 0           local $_;
499 0           my ($r, @r);
500 0 0         if ($cs) {
501 0           while (defined($r =readdir(FILE))) {
502 0 0 0       push @$cs, $r if !$cf ||&$cf($s,$f,$_ =$r)
503             }
504 0           closedir(FILE);
505 0           return $cs;
506             }
507             else {
508 0           while (defined($r =readdir(FILE))) {
509 0 0 0       push @r, $r if !$cf ||&$cf($s,$f,$_ =$r)
510             }
511 0           closedir(FILE);
512 0           return @r;
513             }
514             }
515            
516            
517             sub fstore { # Store file
518 0     0 1   my $s =shift; # ('-b',filename, strings) -> success
519 0 0         my $o =$_[0] =~/^-(?:\w[\w\d+-]*)*$/ ? shift : '-';
520 0 0         my $f =$_[0]; $f ='>' .$f if $f !~/^[<>]/;
  0            
521 0 0         print "fstore('$f')\n" if $s->{-echo};
522             # local $SIG{'TERM'} ='IGNORE';
523             # local $SIG{'INT'} ='IGNORE';
524             # local $SIG{'BREAK'}='IGNORE';
525 0           my $r;
526 0           local *FILE;
527 0           for (my $i =0; $i <$fretry; $i++) {
528 0           $r =open(FILE, $f);
529 0 0         last if $r;
530             }
531 0 0         return(&{$s->{-die}}($s->efmt('$!',undef,'cannot open file','fstore',$f)))
  0            
532             if !$r;
533 0 0         if ($o =~/b/) {
534 0           binmode(FILE);
535 0           $r =defined(syswrite(FILE,$_[1]))
536             }
537             else {
538 0           $r =print FILE join("\n",@_[1..$#_])
539             }
540 0           close(FILE);
541 0 0         $r || &{$s->{-die}}($s->efmt('$!',undef,'Cannot write file','fstore',$f))
  0            
542             }
543            
544            
545             sub fload { # Load file
546 0     0 1   my $s =shift; # ('-b',filename) -> content
547 0 0         my $o =$_[0] =~/^-(?:\w[\w\d+-]*)*$/ ? shift : '-';
548 0           my($f,$f0) =($_[0],$_[0]);
549 0 0         if ($f =~/^[<>]+/) {$f0 =$'}
  0            
  0            
550             else {$f ='<' .$f}
551 0 0         print "fload('$f')\n" if $s->{-echo};
552 0           local *FILE;
553 0           my $r;
554 0           for (my $i =0; $i <$fretry; $i++) {
555 0           $r =open(FILE, $f);
556 0 0         last if $r;
557             }
558 0 0         return(&{$s->{-die}}($s->efmt('$!',undef,'Cannot open file','fload',$f)))
  0            
559             if !$r;
560 0           my $b =undef;
561 0 0         binmode(FILE) if $o =~/b/;
562 0           $r =read(FILE,$b,-s $f0);
563 0           close(FILE);
564 0 0         defined($r) ? $b : &{$s->{-die}}($s->efmt('$!',undef,'Cannot read file','fload',$f))
  0            
565             }
566            
567            
568             sub vfname { # Name of variables file
569             # (varname|-slot) -> pathname
570 0 0   0 1   return($_[0]->{-vfbase}) if !$_[1];
571 0           my $v =$_[1]; $v =~s/[\s.,:;|\/\\?*+()<>\]\["']/_/g;
  0            
572 0 0 0       $_[0]->{-vfbase} .($v =~/^-(.+)/ ? ($1 .($_[2] ||'.var')) : ($v .($_[2] ||'.var')))
      0        
573             }
574            
575            
576             sub vfstore { # Store variables file
577             # (varname, {data}) -> success
578             # (-slot) -> success
579 0     0 1   my($s,$n,$d)=@_;
580 0 0 0       $d =$s->{$n} if !$d && ($n =~/^-/);
581 0           my $f =$s->vfname($n, '.new');
582 0           my $r;
583 0 0 0       if (($n =~/^-/) && exists($s->{"${n}-storable"}) ? $s->{"${n}-storable"} : $s->{-storable}) {
    0          
584 0   0       for (my $i =0; ($i <$fretry) && eval("use Storable; 1"); $i++) {
585 0           $r =Storable::store($d, $f);
586 0 0         last if $r;
587             }
588 0 0         return(&{$s->{-die}}($s->efmt('$!',$s->{-cmd},undef,'Storable::store',$f)))
  0            
589             if !$r;
590             }
591             else {
592 0           $r =$s->fstore('-', $f, $s->dsdump($d));
593             }
594 0 0         if ($r) {
595 0           my $rr =0;
596 0           for (my $i =0; $i <$fretry; $i++) {
597 0           $rr =rename($f, $s->vfname($n));
598 0 0         last if $rr
599             }
600 0 0         return(&{$s->{-die}}($s->efmt('$!',$s->{-cmd},undef,'rename',$f,'*.var')))
  0            
601             if !$rr
602             }
603             $r
604 0           }
605            
606            
607             sub vfload { # Load variables file
608             # (varname|-slot, ?{use default} | load default, ?renew | renew seconds) -> {data}
609 0     0 1   my($s,$f,$d,$nn) =@_; # -slot-calc, -slot-store
610 0 0         my $k =($f =~/^-/ ? $f : undef);
611 0           $f =$s->vfname($f);
612 0 0 0       if ($nn && $nn >1) {
613 0           my @st =stat($f);
614 0 0 0       $nn =0 if $st[9] && (time() -$st[9] <$nn);
615             }
616 0 0 0       if ($d && ($nn || !-f $f)) {
    0 0        
617 0 0         if (ref($d)) {
    0          
    0          
    0          
    0          
618 0 0         $s->vfstore($k, $d =ref($d) eq 'CODE' ? &$d($s,$k) : $d);
619 0 0         $s->{$k} =$d if $k;
620             }
621             elsif (!$k) {
622             }
623             elsif (ref($s->{"$k-calc"}) eq 'CODE') {
624 0           my $cc =$s->{"$k-calc"};
625 0           local $s->{"$k-calc"} =undef;
626 0           $s->{$k} =$d =&$cc($s,$k);
627             }
628             elsif (ref($s->{"$k-store"}) eq 'CODE') {
629 0           $s->vfstore($k, $s->{$k} =$d =&{$s->{"$k-store"}}($s,$k))
  0            
630             }
631             elsif (ref($s->{$k}) eq 'CODE') {
632 0           $s->vfstore($k, $s->{$k} =$d =&{$s->{$k}}($s,$k))
  0            
633             }
634 0           return($d)
635             }
636             elsif (ref($s->{"$k-calc"}) eq 'CODE') {
637 0           my $cc =$s->{"$k-calc"};
638 0           local $s->{"$k-calc"} =undef;
639 0           $s->{$k} =$d =&$cc($s,$k);
640 0           return($d);
641             }
642 0           my $r;
643 0           if (0) {
644             $r =($k && exists($s->{"${k}-storable"}) ? $s->{"${k}-storable"} : $s->{-storable})
645             ? eval("use Storable; 1")
646             && Storable::retrieve($f)
647             || return(&{$s->{-die}}($s->efmt('$!',$s->{-cmd},undef,'Storable::retrieve',$f)))
648             : ((eval{do($f)}) || return(&{$s->{-die}}($s->efmt($@,$s->{-cmd},undef,'do',$f))));
649             }
650             else {
651 0           local *FILE;
652 0           for (my $i =0; $i <$fretry; $i++) {
653 0           $r =open(FILE, "<$f");
654 0 0         last if $r;
655             }
656 0 0         return(&{$s->{-die}}($s->efmt('$!',undef,'Cannot open file','vfload',$f)))
  0            
657             if !$r;
658 0           binmode(FILE);
659 0           my $v;
660 0           sysread(FILE,$v,64,0)
661 0 0         ||return(&{$s->{-die}}($s->efmt('$!',$s->{-cmd},undef,'sysread',$f)));
662             $r =($v
663             ? $v !~/^\$VAR1\s*=/
664             : ($k && exists($s->{"${k}-storable"}) ? $s->{"${k}-storable"} : $s->{-storable}))
665             ? ((seek(FILE,0,0) ||1)
666             && eval("use Storable; 1")
667             && Storable::fd_retrieve(\*FILE)
668             || return(&{$s->{-die}}($s->efmt('$!',$s->{-cmd},undef,'Storable::retrieve',$f))))
669             : ((eval{close(FILE); 1}) &&
670 0 0 0       do($f) || return(&{$s->{-die}}($s->efmt($@,$s->{-cmd},undef,'do',$f)))
    0 0        
    0 0        
671             );
672 0           eval{close(FILE)};
  0            
673             }
674 0 0         $s->{$k} =$r if $k;
675 0           $r
676             }
677            
678            
679            
680             sub vfrenew { # Renew variables file
681 0     0 1   my($s,$f,$nn) =@_; # (-slot, ?period seconds) -> vfload
682 0 0         return(1) if $f !~/^-/;
683 0   0       vfload($s,$f,1,$nn ||1);
684             }
685            
686            
687            
688             sub vfclear { # Clear vfdata() and vfhash()
689 0     0 1   my($s,$f) =@_; # (-slot, ?period seconds) -> vfload
690 0 0         return(1) if $f !~/^-/;
691 0           delete($s->{$f});
692 0           foreach my $k (keys %$s) {
693 0 0         next if $k !~/^\Q$f\E[\/].+/;
694 0           delete $s->{$k};
695             }
696 0           1;
697             }
698            
699            
700             sub vfdata { # Access to array data from variables file
701             # automatically load using vfload().
702             # (-slot) -> [array]
703             # (-slot, filter sub{}(self, -slot, index, $_=value)) -> [array]
704 0 0 0 0 1   vfload($_[0], $_[1], 1) if !$_[0]->{$_[1]} || (ref($_[0]->{$_[1]}) eq 'CODE');
705 0 0         if ($_[2]) {
706 0 0         if (ref($_[2]) eq 'CODE') {
707 0           local $_;
708 0 0         local $_[0]->{-cmd} =($_[0]->{-cmd} ? $_[0]->{-cmd} .': ' : '')
709             ."vfdata('$_[1]', sub{})";
710 0           my ($rr, $v);
711 0 0         if (ref($_[0]->{$_[1]}) eq 'ARRAY') {
    0          
712 0           $rr =[];
713 0           for(my $i=0; $i<=$#{$_[0]->{$_[1]}}; $i++) {
  0            
714 0 0 0       if (!defined(eval{$v =&{$_[2]}($_[0], $_[1], $i, $_ =$_[0]->{$_[1]}->[$i])}) && $@) {
  0 0          
  0            
715 0 0         last if $@ =~/^last[\r\n]*$/;
716 0 0         next if $@ =~/^next[\r\n]*$/;
717 0           return(&{$_[0]->{-die}}($_[0]->efmt($@,$_[0]->{-cmd})));
  0            
718             }
719             elsif ($v) {
720 0           push @$rr, $_[0]->{$_[1]}->[$i]
721             }
722             }
723             }
724             elsif (ref($_[0]->{$_[1]}) eq 'HASH') {
725 0           $rr ={};
726 0           foreach my $i (keys %{$_[0]->{$_[1]}}) {
  0            
727 0 0 0       if (!defined(eval{$v =&{$_[2]}($_[0], $_[1], $i, $_ =$_[0]->{$_[1]}->{$i})}) && $@) {
  0 0          
  0            
728 0 0         last if $@ =~/^last[\r\n]*$/;
729 0 0         next if $@ =~/^next[\r\n]*$/;
730 0           return(&{$_[0]->{-die}}($_[0]->efmt($@,$_[0]->{-cmd})));
  0            
731             }
732             elsif ($v) {
733 0           $rr->{$i} =$_[0]->{$_[1]}->{$i}
734             }
735             }
736             }
737 0           return($rr)
738             }
739             else {
740 0           return($_[0]->{$_[1]}->[$_[2]])
741             }
742             }
743 0           $_[0]->{$_[1]}
744             }
745            
746            
747             sub vfhash { # Access to hash of array data from variables file
748             # automatically formed in memory using vfdata().
749             # (-slot, key name) -> {hash from vfdata()}
750             # (-slot, key name => key value) -> {key=>value,...}
751             # (-slot, key name => key value => elem name ) -> elem value
752             # (-slot, key name => filter sub{}(self, -slot, key, $_ = value)) -> {key=>value,...}
753 0     0 1   my($s, $f, $k, $v, $e) =@_;
754 0 0         return(&{$s->{-die}}($s->efmt('Key name needed',undef,undef,'vfhash',$f))) if !$k;
  0            
755 0 0 0       $s->vfload($f, 1) if !$s->{$f} ||(ref($s->{$f}) eq 'CODE');
756 0           my $kk ="$f/$k";
757 0 0         if (!$s->{$kk}) {
758 0           $s->{$kk} ={};
759 0 0         if (ref($s->{$f}) eq 'ARRAY') {
760 0           for(my $i=0; $i<=$#{$s->{$f}}; $i++) {
  0            
761 0 0         $s->{$kk}->{$s->{$f}->[$i]->{$k}} =$s->{$f}->[$i]
762             if defined($s->{$f}->[$i]->{$k})
763             }
764             }
765             else {
766 0           foreach my $kh (keys %{$s->{$f}}) {
  0            
767 0 0         $s->{$kk}->{$s->{$f}->{$kh}->{$k}} =$s->{$f}->{$kh}
768             if defined($s->{$f}->{$kh}->{$k})
769             }
770             }
771             }
772 0 0         if (ref($v) eq 'CODE') {
773 0           my ($rh, $t) =({});
774 0           local $_;
775 0 0         local $_[0]->{-cmd} =($_[0]->{-cmd} ? $_[0]->{-cmd} .': ' : '')
776             ."vfhash('$f', '$k', sub{})";
777 0           foreach my $ke (keys %{$s->{$kk}}) {
  0            
778 0 0 0       if (!defined(eval{$t =&$v($s, $f, $k, $_ =$s->{$kk}->{$ke})}) && $@) {
  0 0          
779 0 0         last if $@ =~/^last[\r\n]*$/;
780 0 0         next if $@ =~/^next[\r\n]*$/;
781 0           return(&{$s->{-die}}($s->efmt($@,$s->{-cmd})));
  0            
782             }
783             elsif ($t) {
784 0           $rh->{$ke} =$s->{$kk}->{$ke};
785             }
786             }
787 0           return($rh)
788             }
789 0 0         !defined($v)
    0          
    0          
    0          
790             ? $s->{$kk}
791             : !defined($s->{$kk})
792             ? $s->{$kk}
793             : !ref($s->{$kk}->{$v})
794             ? $s->{$kk}->{$v}
795             : defined($e)
796             ? $s->{$kk}->{$v}->{$e}
797             : $s->{$kk}->{$v}
798             }
799            
800            
801            
802             sub vfdistinct {# Distinct values from vfdata() field.
803             # (-slot, key name) -> [keys %{vfhash(...)}]
804             # (-slot, key name => filter sub{}(self, -slot, key, $_ = value)) -> [keys %{vfhash(...)}]
805 0     0 1   my($s, $f, $k, $v) =@_;
806 0           my(%rh, $t);
807 0           local $_;
808 0 0         local $_[0]->{-cmd} =($_[0]->{-cmd} ? $_[0]->{-cmd} .': ' : '')
809             ."vfdistinct('$f', '$k', sub{})";
810 0 0 0       $s->vfload($f, 1) if !$s->{$f} ||(ref($s->{$f}) eq 'CODE');
811 0 0         if (ref($s->{$f}) eq 'ARRAY') {
812 0           for(my $i=0; $i<=$#{$s->{$f}}; $i++) {
  0            
813 0 0 0       if (!defined($s->{$f}->[$i]->{$k})) {
  0 0 0        
    0 0        
814             }
815             elsif ($v && !defined(eval{$t =&$v($s, $f, $k, $_ =$s->{$f}->[$i])}) && $@) {
816 0 0         last if $@ =~/^last[\r\n]*$/;
817 0 0         next if $@ =~/^next[\r\n]*$/;
818 0           return(&{$s->{-die}}($s->efmt($@,$s->{-cmd})));
  0            
819             }
820             elsif (!$v ||$t) {
821 0           $rh{$s->{$f}->[$i]->{$k}} =1
822             }
823             }
824             }
825             else {
826 0           foreach my $kh (keys %{$s->{$f}}) {
  0            
827 0 0 0       if (!defined($s->{$f}->{$kh}->{$k})) {
  0 0 0        
    0 0        
828             }
829             elsif ($v && !defined(eval{$t =&$v($s, $f, $k, $_ =$s->{$k}->{$kh})}) && $@) {
830 0 0         last if $@ =~/^last[\r\n]*$/;
831 0 0         next if $@ =~/^next[\r\n]*$/;
832 0           return(&{$s->{-die}}($s->efmt($@,$s->{-cmd})));
  0            
833             }
834             elsif (!$v ||$t) {
835 0           $rh{$s->{$f}->{$kh}->{$k}} =1
836             }
837             }
838             }
839 1     1   6532 use locale;
  1         2  
  1         8  
840 0           return([sort {$a cmp $b} keys %rh])
  0            
841             }
842            
843            
844            
845             sub connect { # Connect to ARS server
846 0     0 1   eval('use ARS'); # (-param=>value,...) -> self
847 0           my $s =shift; # -srv, -usr, -pswd, -lang
848 0           $s->set(@_);
849 0 0         $s->set(-die=>'Carp') if !$s->{-die};
850 0           local $s->{-cmd} ="connect()";
851 0 0         return($s) if $s->{-ctrl};
852 0 0         print $s->cpcon("connect()\n") if $s->{-echo};
853 0 0 0       return($s) if $s->{-ctrl} && ARS::ars_VerifyUser($s->{-ctrl});
854             $s->{-ctrl} =ARS::ars_Login(
855             $s->{-srv}, $s->{-usr}, $s->{-pswd}, $s->{-lang}
856             , '' # , join('-', ($ENV{COMPUTERNAME} ||$ENV{HOSTNAME} ||eval('use Sys::Hostname;hostname') ||'localhost'), getlogin() || $> || '', $$, $^T, time())
857             , 0, 0)
858 0   0       || return(&{$s->{-die}}($s->efmt($ARS::ars_errstr,$s->{-cmd},undef,'ars_Login', map {$_=>$s->{$_}} qw(-srv -usr -lang))));
859 0 0         $s->{-ctrl} && ARS::ars_SetSessionConfiguration($s->{-ctrl}, &ARS::AR_SESS_OVERRIDE_PREV_IP, 1);
860 0           $s->arsmeta();
861 0           $s
862             }
863            
864            
865             sub disconnect { # Disconnect data servers
866 0     0 0   my $s =shift;
867 0 0         $s->{-ctrl} && eval{ars_Logoff($s->{-ctrl})};
  0            
868 0           $s->{-ctrl}=undef;
869 0 0         $s->{-dbi} && eval{$s->{-dbi}->disconnect()};
  0            
870 0           $s->{-dbi} =undef;
871             }
872            
873            
874             sub arsmeta { # Load/refresh ARS metadata
875 0     0 1   my $s =shift; # -srv, -usr, -pswd, -lang
876 0           $s->set(@_);
877 0 0         local $s->{-cmd} =($s->{-cmd} ? $s->{-cmd} .': ' : '')
    0          
878             .($s->{-schgen} ? "dumper('" .$s->vfname('meta') ."')" : 'arsmeta()');
879 0 0 0       if (ref($s->{-schgen})
    0 0        
      0        
880             || ($s->{-schgen} && ($s->{-schgen} >1))
881             || (!-e $s->vfname('-meta'))
882             ) {
883             #
884             # Data types:
885             # 'integer','real','char','enum','time','decimal'
886             # 'diary','attach','currency'
887             # 'trim','control','table','column','page','page_holder'
888             #
889 0           my ($vfs, $vfu);
890 0           local $s->{-schgen} =$s->{-schgen};
891 0 0 0       if (ref($s->{-schgen}) && (-e $s->vfname('-meta'))) {
    0 0        
892 0           $s->vfload('-meta');
893             }
894             elsif (($s->{-schgen} >1) && (-e $s->vfname('-meta'))) {
895 0           $s->vfload('-meta');
896 0 0 0       $vfs =$s->{-schgen} >2
897             ? 0
898             : ([stat $s->vfname('-meta')]->[9] ||0);
899             }
900             else {
901 0           $s->{-meta} ={};
902             }
903 0 0         foreach my $f (ref($s->{-schgen}) ? @{$s->{-schgen}} : @{$s->{-schema}}){
  0            
  0            
904 0           my $fa =ARS::ars_GetSchema($s->{-ctrl}, $f);
905 0 0         !$fa && return(&{$s->{-die}}($s->efmt($ARS::ars_errstr,$s->{-cmd},undef,'ars_GetSchema',$f)));
  0            
906 0 0 0       if ($vfs && $s->{-meta}->{$f}) {
907             #print $s->strtime($fa->{timestamp}),'/',$s->strtime($vfs), "\n", $s->cpcon($s->dsdump($fa)), "\n"; exit(0);
908 0 0 0       next if $s->{-meta}->{$f} && $s->{-meta}->{$f}->{timestamp}
    0 0        
      0        
909             ? (($s->{-meta}->{$f}->{timestamp}||0) >=($fa->{timestamp}||0))
910             && ($vfs >=($fa->{timestamp}||0))
911             : $vfs >=($fa->{timestamp}||0 +60*60);
912             }
913 0           $vfu =1;
914 0           $s->{-meta}->{$f} ={}; # {} || $fa
915 0           $s->{-meta}->{$f}->{-fields} ={};
916 0           $s->{-meta}->{$f}->{timestamp} =$fa->{timestamp};
917             # $s->{-meta}->{$f}->{indexList} =$fa->{indexList};
918             # $s->{-meta}->{$f}->{getListFields} =$fa->{getListFields};
919             # $s->{-meta}->{$f}->{sortList} =$fa->{sortList};
920 0   0       my ($cyr, $vli, $vll) =1 && $s->{-lang} && ($s->{-lang} =~/^(?:ru)/i);
921 0 0 0       if (!$cyr && $s->{-lang}) {
922 0           my $vlc;
923 0 0         my $ull =$s->{-lang} =~/^([A-Za-z]+)/ ? $1 : $s->{-lang};
924 0 0         my $ulc =$s->{-lang} =~/^([A-Za-z_]+)/ ? $1 : $s->{-lang};
925 0           my $i =0;
926 0           foreach my $vi (ars_GetListVUI($s->{-ctrl}, $f, 0)) {
927 0           my $vw =ars_GetVUI($s->{-ctrl}, $f, $vi);
928             # language[_territory[.codeset]][@modifier]
929             # en_US.ISO8859-15@euro
930 0 0 0       $vli =$i if !defined($vli) && !$vw->{locale};
931 0 0 0       $vlc =$i if !defined($vlc) && $vw->{locale} && ($vw->{locale} =~/^\Q$ulc\E/);
      0        
932 0 0 0       $vll =$i if !defined($vll) && $vw->{locale} && ($vw->{locale} =~/^\Q$ull\E/);
      0        
933 0 0 0       last if defined($vli) && defined($vlc) && defined($vll);
      0        
934 0           $i++
935             }
936 0 0         $vll =$vlc if defined($vlc);
937             }
938 0           my $ix ={map {$_->{unique}
939 0 0 0       && (scalar(@{$_->{fieldIds}}) ==1)
940             ? ($_->{fieldIds}->[0] => 1)
941 0           : ()} @{$fa->{indexList}}};
942 0           my %ff =ARS::ars_GetFieldTable($s->{-ctrl}, $f);
943 0 0         !%ff && return(&{$s->{-die}}($s->efmt($ARS::ars_errstr,$s->{-cmd},undef,'ars_GetFieldTable',$f)));
  0            
944 0           foreach my $ff (sort keys %ff) {
945             my $fm =ARS::ars_GetField($s->{-ctrl},$f,$ff{$ff})
946 0   0       || return(&{$s->{-die}}($s->efmt($ARS::ars_errstr,$s->{-cmd},undef,'ars_GetField',$f,$ff)));
947             # 'fieldId', 'fieldName', 'dataType'
948 0 0 0       next if !$fm->{dataType}
949             || ($fm->{dataType} =~/^(trim|control|table|column|page)/);
950 0 0 0       next if !$s->{-schfdo} && $fm->{option} && ($fm->{option} == 4); # AR_FIELD_OPTION_DISPLAY
      0        
951 0           $s->{-meta}->{$f}->{-fields}->{$ff} =$fm;
952 0 0 0       $s->{-meta}->{$f}->{-fields}->{$ff}->{indexUnique} =$fm->{fieldId}
953             if $ix->{$fm->{fieldId}}
954             || ($fm->{fieldId} eq '1'); # || '179'?
955 0 0         if ($fm->{displayInstanceList}->{dInstanceList}
956             ) {
957             # foreach my $i (defined($vli) || defined($vll) ? (map {defined($_) ? $_ : ()} $vli, $vll) : (0..$#{$fm->{displayInstanceList}->{dInstanceList}})) {
958 0           for (my $i =0; $i <=$#{$fm->{displayInstanceList}->{dInstanceList}}; $i++) {
  0            
959 0 0         next if !$fm->{displayInstanceList}->{dInstanceList}->[$i]->{props};
960 0           for(my $j =0; $j <=$#{$fm->{displayInstanceList}->{dInstanceList}->[$i]->{props}}; $j++) {
  0            
961 0           my $prp =$fm->{displayInstanceList}->{dInstanceList}->[$i]->{props}->[$j]->{prop};
962 0 0         if ($prp ==20) {
    0          
963             # $i == vui id
964             # prop == 20 == AR_DPROP_LABEL
965 0           my $v =$fm->{displayInstanceList}->{dInstanceList}->[$i]->{props}->[$j]->{value};
966 0 0 0       $fm->{fieldLbl} =$v
      0        
967             if 1
968             && !$fm->{fieldLbl}
969             && ((defined($vli)
970             && ($i == $vli))
971             || ($v =~/^[\s\d*\\=-]*[A-Za-z]/));
972 0 0 0       $fm->{fieldLbll} =$v
      0        
973             if 1
974             && !$fm->{fieldLbll}
975             && ((defined($vll)
976             && ($i == $vll))
977             || ($cyr && ($v !~/^[\s\d*\\=-]*[A-Za-z]/)));
978 0 0 0       $fm->{fieldLblc} =($fm->{fieldLblc} ? $fm->{fieldLblc} .'; ' : '')
    0 0        
      0        
979             ."[$i] $v"
980             if !$cyr
981             && !defined($vll)
982             && ($fm->{fieldLblc}||'') !~/\Q$v\E/;
983             }
984             elsif ($prp ==230) {
985             # $i == vui id
986             # prop == 230 == AR_DPROP_ENUM_LABELS
987             # 6\0\Proposed\1\Enabled\2\Offline\3\Obsolete\4\Archive\5\Delete
988             # next if $fm->{fieldLbv} && (!$cyr ||$fm->{fieldLbvl});
989 0           my $v =$fm->{displayInstanceList}->{dInstanceList}->[$i]->{props}->[$j]->{value};
990 0 0         $v=$v =~/^\d+(\\\d+\\.+)/ ? $1 : $v;
991 0           $fm->{fieldLbv} =$v
992             if 0
993             && !$fm->{fieldLbv}
994             && ((defined($vli)
995             && ($i == $vli))
996             || ($v =~/^[\s\d*\\=-]*[A-Za-z]/));
997 0 0 0       $fm->{fieldLbvl} =$v
      0        
998             if 1
999             && !$fm->{fieldLbvl}
1000             && ((defined($vll)
1001             && ($i == $vll))
1002             || ($cyr && ($v !~/^[\s\d*\\=-]*[A-Za-z]/)));
1003             }
1004             }
1005             }
1006             }
1007 0 0         if ($s->{-metax}) {
1008 0           foreach my $e (@{$s->{-metax}}) {
  0            
1009 0           delete $fm->{$e};
1010             }
1011             }
1012             }
1013             }
1014 0 0         if (!$s->{-schgen}) {
1015             }
1016             else {
1017 0 0         $vfu && $s->vfstore('-meta')
1018             }
1019             # print $s->cpcon($s->dsdump($s->{-meta})), "\n"; exit(0);
1020             }
1021             elsif (-e $s->vfname('meta')) {
1022 0           $s->vfload('-meta');
1023             # print $s->cpcon($s->dsdump($s->{-meta})), "\n"; exit(0);
1024             }
1025             else {
1026 0           $s->{-meta} ={};
1027 0           return(&{$s->{-die}}($s->efmt('No metadata',$s->{-cmd})))
  0            
1028             }
1029 0 0         $s->arsmetaix() if $s->{-meta};
1030             }
1031            
1032            
1033             sub arsmetaix { # Index ARS metadata
1034 0     0 0   my $s =shift;
1035 0 0         if ($s->{-meta}) {
1036 0           foreach my $f (keys %{$s->{-meta}}){
  0            
1037 0 0         next if $f =~/^-/;
1038 0 0         $s->{-meta}->{$f}->{-fldids} ={}
1039             if !$s->{-meta}->{$f}->{-fldids};
1040 0           foreach my $ff (keys %{$s->{-meta}->{$f}->{-fields}}) {
  0            
1041 0           $s->{-meta}->{$f}->{-fldids}->{$s->{-meta}->{$f}->{-fields}->{$ff}->{fieldId}}
1042             =$s->{-meta}->{$f}->{-fields}->{$ff}
1043             }
1044             }
1045 0 0         if (ref($s->{-metadn})) {
1046 0           foreach my $dn (keys %{$s->{-metadn}}) {
  0            
1047 0 0         $s->{-metadn}->{$dn} ={fieldName=>$dn, fieldId=>$s->{-metadn}->{$dn}}
1048             if !ref($s->{-metadn}->{$dn});
1049 0 0         $s->{-metadn}->{$dn}->{fieldName} =$dn
1050             if !$s->{-metadn}->{$dn}->{fieldName};
1051 0 0 0       $s->{-metaid}->{$s->{-metadn}->{$dn}->{fieldId}} =$s->{-metadn}->{$dn}
1052             if $s->{-metadn}->{$dn}->{fieldId}
1053             && !$s->{-metaid}->{$s->{-metadn}->{$dn}->{fieldId}};
1054             }
1055             }
1056 0 0         if (ref($s->{-metaid})) {
1057 0           foreach my $id (keys %{$s->{-metaid}}) {
  0            
1058 0 0         $s->{-metaid}->{$id} ={fieldId=>$id, fieldName=>$s->{-metaid}->{$id}}
1059             if !ref($s->{-metaid}->{$id});
1060 0           $s->{-metaid}->{$id}->{fieldId} =$id;
1061 0 0 0       $s->{-metadn}->{$s->{-metaid}->{$id}->{fieldName}} =$s->{-metaid}->{$id}
1062             if $s->{-metaid}->{$id}->{fieldName}
1063             && !$s->{-metadn}->{$s->{-metaid}->{$id}->{fieldName}};
1064             }
1065             }
1066             # print $s->cpcon($s->dsdump($s->{-metaid})), "\n"; exit(0);
1067             }
1068             }
1069            
1070            
1071             sub arsmetamin { # Minimal ARS metadata ('-meta-min' varfile)
1072 0     0 1   my $s =shift; # refresh after 'arsmeta'/'connect'
1073 0           $s->set(@_); # load instead of 'arsmeta'/'connect'
1074 0 0         local $s->{-cmd} =($s->{-cmd} ? $s->{-cmd} .': ' : '')
    0          
1075             .($s->{-schgen} ? "dumper('" .$s->vfname('meta-min') ."')" : 'arsmetamin()');
1076 0 0 0       if (ref($s->{-schgen})
      0        
      0        
      0        
1077             || !$s->{-schgen}
1078             || ($s->{-schgen} && ($s->{-schgen} >1))
1079             || (!-e $s->vfname('-meta-min'))
1080             ) {
1081 0 0 0       $s->arsmeta() if !$s->{-meta} ||!scalar(%{$s->{-meta}});
  0            
1082 0   0       my $fvs =[stat $s->vfname('-meta-min')]->[9] ||0;
1083 0 0 0       $fvs =0 if ($s->{-schgen} && (ref($s->{-schgen}) || ($s->{-schgen} >2)));
      0        
1084 0 0 0       $fvs =0 if $fvs && ($fvs <([stat $s->vfname('-meta')]->[9]||0));
      0        
1085 0 0 0       $fvs =0 if $fvs && ($fvs <([stat ($^O eq 'MSWin32' ? scalar(Win32::GetFullPathName($0)) : $0)]->[9]||0));
      0        
1086 0 0         if (!$fvs) {
1087 0           $s->{'-meta-min'} ={};
1088 0           foreach my $f (keys %{$s->{-meta}}) {
  0            
1089 0           foreach my $ff (keys %{$s->{-meta}->{$f}->{-fields}}) {
  0            
1090 0           my $e =$s->{-meta}->{$f}->{-fields}->{$ff};
1091 0 0 0       next if (!$e->{dataType}
      0        
      0        
1092             || ($e->{dataType} ne 'time'))
1093             && (!$e->{'limit'}
1094             || !$e->{'limit'}->{'enumLimits'}
1095             || !($e->{'limit'}->{'enumLimits'}->{'regularList'} ||$e->{'limit'}->{'enumLimits'}->{'customList'}));
1096 0 0         $s->{'-meta-min'}->{$f} ={} if !$s->{'-meta-min'}->{$f};
1097 0 0         $s->{'-meta-min'}->{$f}->{-fields} ={} if !$s->{'-meta-min'}->{$f}->{-fields};
1098 0           $e ={%$e};
1099 0           delete @$e{'owner','lastChanged', 'timestamp'};
1100 0           $s->{'-meta-min'}->{$f}->{-fields}->{$ff} ={%$e};
1101             }
1102             }
1103 0 0 0       $s->vfstore('-meta-min') if $s->{-schgen} && ($s->{-schgen} eq '1' ? !-e $s->vfname('-meta-min') : 1);
    0          
1104             };
1105             };
1106             # print do($s->vfname('-meta-min'))||0,' ', $@||'', $s->vfname('-meta-min'),' ', "\n";
1107 0 0 0       $s->vfload('-meta-min') if !$s->{'-meta-min'} && $s->{-schgen};
1108 0 0 0       if (!$s->{-meta} ||!scalar(%{$s->{-meta}})) {
1109 0           $s->{-meta} =$s->{'-meta-min'};
1110 0           $s->arsmetaix();
1111             }
1112             else {
1113 0           foreach my $f (keys %{$s->{'-meta-min'}}) {
  0            
1114 0 0         next if $s->{-meta}->{$f};
1115 0           my $fs =$s->{'-meta-min'}->{$f};
1116 0 0         $s->{-meta}->{$f} ={}
1117             if !$s->{-meta}->{$f};
1118 0           foreach my $ff (keys %{$fs->{-fields}}) {
  0            
1119 0 0         $s->{-meta}->{$f}->{-fields}->{$ff} ={}
1120             if !$s->{-meta}->{$f}->{-fields}->{$ff};
1121 0           eval {@{$s->{-meta}->{$f}->{-fields}->{$ff}}{keys %{$fs->{-fields}->{$ff}}}
  0            
  0            
  0            
1122 0           =values %{$fs->{-fields}->{$ff}}};
1123             }
1124             }
1125             $s->arsmetaix()
1126 0           }
1127 0           delete $s->{'-meta-min'};
1128 0           $s;
1129             }
1130            
1131            
1132             sub arsmetasql { # SQL ARS metadata ('-meta-sql' varfile)
1133 0     0 1   my $s =shift; # refresh after 'arsmeta'/'connect'
1134 0           $s->set(@_); # !!! 'enum' texts
1135 0 0         local $s->{-cmd} =($s->{-cmd} ? $s->{-cmd} .': ' : '')
    0          
1136             .($s->{-schgen} ? "dumper('" .$s->vfname('meta-sql') ."')" : 'arsmetasql()');
1137 0 0 0       if (ref($s->{-schgen})
      0        
      0        
      0        
1138             || !$s->{-schgen}
1139             || ($s->{-schgen} && ($s->{-schgen} >1))
1140             || (!-e $s->vfname('-meta-sql'))
1141             ) {
1142 0 0 0       $s->arsmeta() if !$s->{-meta} ||!scalar(%{$s->{-meta}});
  0            
1143 0   0       my $fvs =[stat $s->vfname('-meta-sql')]->[9] ||0;
1144 0 0 0       $fvs =0 if ($s->{-schgen} && (ref($s->{-schgen}) || ($s->{-schgen} >2)));
      0        
1145 0 0 0       $fvs =0 if $fvs && ($fvs <([stat $s->vfname('-meta')]->[9]||0));
      0        
1146 0 0 0       $fvs =0 if $fvs && ($fvs <([stat ($^O eq 'MSWin32' ? scalar(Win32::GetFullPathName($0)) : $0)]->[9]||0));
      0        
1147 0 0         if (!$fvs) {
1148 0 0 0       $s->vfload('-meta-sql') if $s->{-schgen} && -e $s->vfname('-meta-sql');
1149 0 0         $s->{'-meta-sql'} ={} if !$s->{'-meta-sql'};
1150 0 0         foreach my $f ($s->{-schema} ? @{$s->{-schema}} : sort keys %{$s->{-meta}}) {
  0            
  0            
1151 0           $s->sqlname($f);
1152 0           foreach my $ff (sort keys %{$s->{-meta}->{$f}->{-fields}}) {
  0            
1153 0           $s->sqlname($f,$ff,1);
1154 0 0         if ($s->{-meta}->{$f}->{-fields}->{$ff}->{dataType} eq 'enum') {
1155             # $s->sqlname($f,'_str_' .$ff,1);
1156             # $s->{'-meta-sql'}->{$s->sqlname($f)}->{-cols}->{$s->sqlname($f,'_str_' .$ff)}->{TYPE_NAME} ='varchar';
1157             }
1158             }
1159 0           foreach my $ff ('_arsobject_insert', '_arsobject_update', '_arsobject_delete') {
1160 0           $s->sqlname($f,$ff,1);
1161 0           $s->{'-meta-sql'}->{$s->sqlname($f)}->{-cols}->{$s->sqlname($f,$ff)}->{TYPE_NAME} ='int';
1162             }
1163             }
1164 0 0 0       $s->vfstore('-meta-sql') if $s->{-schgen} && ($s->{-schgen} eq '1' ? !-e $s->vfname('-meta-sql') : 1);
    0          
1165             };
1166             };
1167             # print do($s->vfname('-meta-sql'))||0,' ', $@||'', $s->vfname('-meta-sql'),' ', "\n";
1168 0 0 0       $s->vfload('-meta-sql') if !$s->{'-meta-sql'} && $s->{-schgen};
1169 0           $s;
1170             }
1171            
1172            
1173            
1174             sub sqlnesc { # SQL name escaping, default for '-sqlname', '-sqlntbl', '-sqlncol'
1175 0     0 0   my $v =lc($_[1]); # (self, name) -> escaped
1176 0           $v =~s/[^a-zA-Z0-9_]/_/g;
1177 0 0         $v =substr($v,0,64) if length($v) >64;
1178 0           $v
1179             }
1180            
1181            
1182             sub sqlninc { # SQL name incrementing, default for '-sqlninc'
1183 0     0 0   my $v =$_[1]; # (self, name) -> incremented
1184 0           my ($n, $nn);
1185 0           if (0) {
1186             ($n, $nn) =$v =~/^(.+?)_([1-9]+)$/ ? ($1, '_' .($2 +1)) : ($v, '_1');
1187             }
1188             else {
1189 0 0         ($n, $nn) =$v =~/^(.+?)_([A-Z]+)$/ ? ($1, $2) : ($v, '');
1190 0 0         $nn ='_' .(!$nn ? 'A' : substr($nn,-1,1) eq 'Z' ? $nn .'A' : (substr($nn,0,-1) .chr(ord(substr($nn,-1,1)) +1)));
    0          
1191             }
1192 0           $v =$n .$nn;
1193 0 0         length($v) >64 ? substr($n, 0, 64 -length($nn)) .$nn : $v
1194             }
1195            
1196            
1197             sub sqlname { # SQL name from ARS name
1198             # (formName, ?fieldName, ?force update meta) -> SQL name
1199             # -sqlname, -sqlntbl, -sqlncol, -sqlninc
1200 0     0 1   my($s,$f,$ff,$fu) =@_;
1201             return(undef)
1202 0 0         if !$f;
1203 0 0 0       return($s->{'-meta-sql'}->{-forms}->{$f})
      0        
      0        
      0        
1204             if !$ff && !$fu
1205             && $s->{'-meta-sql'}
1206             && $s->{'-meta-sql'}->{-forms}
1207             && $s->{'-meta-sql'}->{-forms}->{$f};
1208 0 0 0       return($s->{'-meta-sql'}->{$s->{'-meta-sql'}->{-forms}->{$f}}->{-fields}->{$ff})
      0        
      0        
      0        
      0        
      0        
1209             if $ff && !$fu
1210             && $s->{'-meta-sql'}
1211             && $s->{'-meta-sql'}->{-forms}
1212             && $s->{'-meta-sql'}->{-forms}->{$f}
1213             && $s->{'-meta-sql'}->{$s->{'-meta-sql'}->{-forms}->{$f}}->{-fields}
1214             && $s->{'-meta-sql'}->{$s->{'-meta-sql'}->{-forms}->{$f}}->{-fields}->{$ff};
1215 0   0       my $ffh =$ff && $s->{-meta} && $s->{-meta}->{$f} && $s->{-meta}->{$f}->{-fields} && $s->{-meta}->{$f}->{-fields}->{$ff};
1216 0 0 0       return($s->{'-meta-sql'}->{$s->{'-meta-sql'}->{-forms}->{$f}}->{-fields}->{$s->{'-meta-sql'}->{$s->{'-meta-sql'}->{-forms}->{$f}}->{-ids}->{$ffh->{fieldId}}})
      0        
      0        
      0        
      0        
      0        
      0        
      0        
1217             if $ff && !$fu && $ffh && $ffh->{fieldId}
1218             && $s->{'-meta-sql'}
1219             && $s->{'-meta-sql'}->{-forms}
1220             && $s->{'-meta-sql'}->{-forms}->{$f}
1221             && $s->{'-meta-sql'}->{$s->{'-meta-sql'}->{-forms}->{$f}}->{-ids}
1222             && $s->{'-meta-sql'}->{$s->{'-meta-sql'}->{-forms}->{$f}}->{-ids}->{$ffh->{fieldId}};
1223 0           my $tn =!$f
1224             ? $f
1225             : $s->{-sqlntbl}
1226 0           ? &{$s->{-sqlntbl}($s, $f)}
1227             : $s->{-sqlname}
1228 0 0         ? &{$s->{-sqlname}($s, $f)}
    0          
    0          
1229             : sqlnesc($s, $f);
1230 0 0 0       return($tn) if !$f ||!$tn;
1231 0 0         $s->{'-meta-sql'} ={} if !$s->{'-meta-sql'};
1232 0 0         $s->{'-meta-sql'}->{-forms} ={} if !$s->{'-meta-sql'}->{-forms};
1233 0   0       while ($s->{'-meta-sql'}->{$tn} && ($s->{'-meta-sql'}->{$tn}->{formName} ne $f)) {
1234 0 0         $tn =$s->{-sqlninc} ? &{$s->{-sqlninc}}($s, $tn) : sqlninc($s, $tn);
  0            
1235             }
1236 0 0         if (!$s->{'-meta-sql'}->{$tn}) {
    0          
1237 0           $s->{'-meta-sql'}->{$tn} ={formName=>$f, -cols=>{}, -fields=>{}, -ids=>{}, timestamp=>time()};
1238 0           $s->{'-meta-sql'}->{-forms}->{$f} =$tn;
1239             }
1240             elsif ($fu) {
1241 0           $s->{'-meta-sql'}->{$tn}->{formName} =$f;
1242 0           $s->{'-meta-sql'}->{-forms}->{$f} =$tn;
1243             }
1244 0 0         return($tn) if !$ff;
1245 0           my $tc =!$ff
1246             ? $ff
1247             : $ffh && $ffh->{fieldId}
1248             && $s->{'-meta-sql'}->{$tn}
1249             && $s->{'-meta-sql'}->{$tn}->{-ids} && $s->{'-meta-sql'}->{$tn}->{-ids}->{$ffh->{fieldId}}
1250             ? $s->{'-meta-sql'}->{$tn}->{-ids}->{$ffh->{fieldId}}
1251             : $s->{-sqlncol}
1252 0           ? &{$s->{-sqlncol}($s, $ff)}
1253             : $s->{-sqlname}
1254 0 0 0       ? &{$s->{-sqlname}($s, $ff)}
    0          
    0          
    0          
1255             : sqlnesc($s, $ff);
1256 0 0         return($tc) if !$tc;
1257 0   0       while ($s->{'-meta-sql'}->{$tn}->{-cols}->{$tc} && ($s->{'-meta-sql'}->{$tn}->{-cols}->{$tc}->{fieldName} ne $ff)) {
1258 0 0         $tc =$s->{-sqlninc} ? &{$s->{-sqlninc}}($s, $tc) : sqlninc($s, $tc);
  0            
1259             }
1260 0 0 0       if ($fu ||!$s->{'-meta-sql'}->{$tn}->{-cols}->{$tc}) {
1261 0           my $flh =$s->{-meta}->{$f}->{-fields}->{$ff}->{limit};
1262 0 0 0       my $tch ={COLUMN_NAME => $tc
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1263             , 'fieldName'=>$ff
1264             , 'dataType' => $ffh->{dataType}
1265             , 'timestamp'=>$s->{'-meta-sql'}->{$tn}->{-cols}->{$tc}
1266             && $s->{'-meta-sql'}->{$tn}->{-cols}->{$tc}->{'timestamp'}
1267             || time()
1268             , $ffh && $ffh->{fieldId}
1269             ? ('fieldId' => $ffh->{fieldId})
1270             : ()
1271             , !$ffh ||!$ffh->{dataType}
1272             ? ()
1273             : $ffh->{dataType} eq 'integer'
1274             ? (TYPE_NAME => 'int')
1275             : $ffh->{dataType} eq 'real'
1276             ? (TYPE_NAME => 'float')
1277             : $ffh->{dataType} eq 'decimal'
1278             ? (TYPE_NAME => $ffh->{dataType}
1279             , $flh
1280             ? ($flh->{precision} ? (DECIMAL_DIGITS => $flh->{precision}) : ()
1281             ,$flh->{rangeHigh} ? (COLUMN_SIZE => length($flh->{rangeHigh})) : ()
1282             )
1283             : ()
1284             )
1285             : $ffh->{dataType} eq 'char'
1286             && (!$flh || !$flh->{maxLength} || ($flh->{maxLength} >255))
1287             ? (TYPE_NAME => 'text')
1288             : 0 && ($ffh->{dataType} eq 'char') && $ffh->{indexUnique}
1289             ? (TYPE_NAME => 'char'
1290             , $flh && $flh->{maxLength}
1291             ? (COLUMN_SIZE => $flh->{maxLength})
1292             : ()
1293             )
1294             : $ffh->{dataType} eq 'char'
1295             ? (TYPE_NAME=>'varchar' # $ffh->{dataType}
1296             , $flh && $flh->{maxLength}
1297             ? (COLUMN_SIZE => $flh->{maxLength})
1298             : ()
1299             )
1300             : $ffh->{dataType} eq 'diary'
1301             ? (TYPE_NAME => 'text')
1302             : $ffh->{dataType} eq 'time'
1303             ? (TYPE_NAME => 'datetime' # !'int'
1304             #,COLUMN_SIZE=>19,DECIMAL_DIGITS=>0
1305             )
1306             : $ffh->{dataType} eq 'enum'
1307             ? (TYPE_NAME => 'int')
1308             : ()
1309             , $ffh && $ffh->{fieldId}
1310             && (($ffh->{fieldId} =~/^(?:1)$/) || $ffh->{indexUnique})
1311             ? (IS_PK => $ffh->{fieldId})
1312             : ()
1313             , $ffh && $ffh->{fieldMap}
1314             && $ffh->{fieldMap}->{fieldType}
1315             && ($ffh->{fieldMap}->{fieldType} ==2)
1316             && $ffh->{fieldMap}->{join}
1317             && (($ffh->{fieldMap}->{join}->{schemaIndex}||0) !=0)
1318             ? (IS_JOINED => ($ffh->{fieldMap}->{join}->{realId} || 1))
1319             : ()
1320             , !$ffh ||!$ffh->{option}
1321             ? ()
1322             : $ffh->{option} ==1
1323             ? ()
1324             : $ffh->{option} ==2
1325             ? (NULLABLE => 1)
1326             : $ffh->{option} ==4
1327             ? (DISPLAY_ONLY => 1)
1328             : ()
1329             , $ffh && $ffh->{fieldId} && ($ffh->{fieldId} ==6)
1330             ? (IS_TIMESTAMP => 1)
1331             : ()
1332             };
1333 0           $s->{'-meta-sql'}->{$tn}->{-cols}->{$tc} =$tch;
1334 0           $s->{'-meta-sql'}->{$tn}->{-fields}->{$ff} =$tc;
1335 0 0         $s->{'-meta-sql'}->{$tn}->{-ids}->{$ffh->{fieldId}} =$tc
1336             if $ffh->{fieldId};
1337             }
1338             $tc
1339 0           }
1340            
1341            
1342             sub ars_errstr {# Last ARS error
1343 0     0 1   $ARS::ars_errstr
1344             }
1345            
1346            
1347            
1348             sub schema { # Schema by form name
1349             # (schema) -> {schema descr}
1350             # () -> {schemaName=>{descr}}
1351 0 0   0 1   $_[1]
    0          
1352             ? $_[0]->{-meta}->{ref($_[1]) ? $_[1]->{schemaName} : $_[1]}
1353             : $_[0]->{-meta};
1354             }
1355            
1356            
1357             sub schfld { # Schema of field
1358             # (schema, field) -> {field descr}
1359             # ({schemaName=>name, fieldName=>name}) -> {field descr}
1360             # (schema) -> {field=>descr}
1361 0 0   0 1   ref($_[1])
    0          
1362             ? $_[0]->{-meta}->{$_[1]->{schemaName}}->{-fields}->{$_[1]->{fieldName}}
1363             : $_[2]
1364             ? $_[0]->{-meta}->{$_[1]}->{-fields}->{$_[2]}
1365             : $_[0]->{-meta}->{$_[1]}->{-fields}
1366             }
1367            
1368            
1369             sub schid { # Schema info by field id
1370             # (schema, fieldId) -> {fieldName=>'name', FieldId=>id}
1371             # () -> rearranged self
1372 0           $_[0]->{-metaid}->{$_[2]}
1373             || $_[0]->{-meta}->{$_[1]}->{-fldids}->{$_[2]}
1374 0 0 0 0 1   || &{$_[0]->{-die}}($_[0]->efmt('Field not found',$_[0]->{-cmd},undef,'schid',$_[1],$_[2]))
1375             }
1376            
1377            
1378             sub schdn { # Schema info by field distiguished name
1379             # (schema, fieldName) -> {fieldName=>'name', FieldId=>id}
1380 0           (($_[2] =~/^\d+$/)
1381             && ($_[0]->{-metaid}->{$_[2]}
1382             || $_[0]->{-meta}->{$_[1]}->{-fldids}->{$_[2]}))
1383             || $_[0]->{-metadn}->{$_[2]}
1384             || $_[0]->{-meta}->{$_[1]}->{-fields}->{$_[2]}
1385 0 0 0 0 1   || &{$_[0]->{-die}}($_[0]->efmt('Field not found',$_[0]->{-cmd},undef,'schdn',$_[1],$_[2]))
      0        
      0        
      0        
1386             }
1387            
1388            
1389             sub schdi { # Schema info by field Id
1390             # (schema, fieldId) -> {fieldName=>'name', FieldId=>id} || undef
1391 0 0   0 0   $_[0]->{-metaid}->{$_[2]}
1392             || $_[0]->{-meta}->{$_[1]}->{-fldids}->{$_[2]}
1393             }
1394            
1395            
1396             sub schlbls { # Enum field {values => labels}
1397             # (schema, fieldId) -> {value=>label,...}
1398 0     0 1   my($s,$f,$ff) =@_;
1399 0 0 0       $ff =ref($ff) ? $ff
    0          
    0          
1400             : !$s->{-meta} || !$s->{-meta}->{$f} ? return(undef)
1401             : $ff =~/^\d+$/ ? $s->{-meta}->{$f}->{-fldids}->{$ff}
1402             : $s->{-meta}->{$f}->{-fields}->{$ff};
1403 0 0 0       if ($ff && !$ff->{-hashOut} && ($ff->{dataType} eq 'enum')) {
      0        
1404 0 0         my $et =ref($ff->{'limit'}->{'enumLimits'}) eq 'ARRAY'
    0          
    0          
1405             ? $ff->{'limit'}->{'enumLimits'}
1406             : exists $ff->{'limit'}->{'enumLimits'}->{'regularList'}
1407             ? $ff->{'limit'}->{'enumLimits'}->{'regularList'}
1408             : exists $ff->{'limit'}->{'enumLimits'}->{'customList'}
1409             ? $ff->{'limit'}->{'enumLimits'}->{'customList'}
1410             : undef;
1411 0 0 0       if (!$et) {}
    0          
    0          
1412             elsif (!ref($et->[0])) {
1413 0           $ff->{-hashOut} ={map {($_ => $et->[$_])} (0..$#$et)}
  0            
1414             }
1415             elsif ((ref($et->[0]) eq 'HASH') && defined($et->[0]->{itemNumber})) {
1416 0           $ff->{-hashOut} ={map {($et->[$_]->{itemNumber} => $et->[$_]->{itemName})} (0..$#$et)}
  0            
1417             }
1418             }
1419 0 0         $ff && $ff->{-hashOut}
1420             }
1421            
1422            
1423            
1424             sub schlblsl { # Enum field {values => labels localised}
1425             # (schema, fieldId) -> {value=>localised label,...}
1426 0     0 1   my($s,$f,$ff) =@_;
1427 0 0 0       $ff =ref($ff) ? $ff
    0          
    0          
1428             : !$s->{-meta} || !$s->{-meta}->{$f} ? return(undef)
1429             : $ff =~/^\d+$/ ? $s->{-meta}->{$f}->{-fldids}->{$ff}
1430             : $s->{-meta}->{$f}->{-fields}->{$ff};
1431 0 0         $ff->{fieldLbvl} ? {split /\\+/, substr($ff->{fieldLbvl},1)} : schlbls($s,$f,$ff)
1432             }
1433            
1434            
1435            
1436             sub schvals { # Enum field [values]
1437             # (schema, fieldId) -> [value,...]
1438 0     0 1   my($s,$f,$ff) =@_;
1439 0 0 0       $ff =ref($ff) ? $ff
    0          
    0          
1440             : !$s->{-meta} || !$s->{-meta}->{$f} ? return(undef)
1441             : $ff =~/^\d+$/ ? $s->{-meta}->{$f}->{-fldids}->{$ff}
1442             : $s->{-meta}->{$f}->{-fields}->{$ff};
1443 0 0 0       if ($ff && !$ff->{-listVals} && ($ff->{dataType} eq 'enum')) {
      0        
1444 0 0         my $et =ref($ff->{'limit'}->{'enumLimits'}) eq 'ARRAY'
    0          
    0          
1445             ? $ff->{'limit'}->{'enumLimits'}
1446             : exists $ff->{'limit'}->{'enumLimits'}->{'regularList'}
1447             ? $ff->{'limit'}->{'enumLimits'}->{'regularList'}
1448             : exists $ff->{'limit'}->{'enumLimits'}->{'customList'}
1449             ? $ff->{'limit'}->{'enumLimits'}->{'customList'}
1450             : undef;
1451 0 0 0       if (!$et) {}
    0          
    0          
1452             elsif (!ref($et->[0])) {
1453 0           $ff->{-listVals} =[0..$#$et]
1454             }
1455             elsif ((ref($et->[0]) eq 'HASH') && defined($et->[0]->{itemNumber})) {
1456 0           $ff->{-listVals} =[map {$et->[$_]->{itemNumber}} (0..$#$et)]
  0            
1457             }
1458             }
1459 0 0         $ff && $ff->{-listVals}
1460             }
1461            
1462            
1463            
1464             sub strOut { # Convert field value for output, using '-meta'
1465             # (schema, fieldId, fieldValue) -> fieldValue
1466 0     0 1   my($s,$f,$ff,$v) =@_;
1467 0 0         $ff =ref($ff) ? $ff : $ff =~/^\d+$/ ? $s->{-meta}->{$f}->{-fldids}->{$ff} : $s->{-meta}->{$f}->{-fields}->{$ff};
    0          
1468 0 0 0       if (!defined($v) ||!$ff ||!$s->{-strFields}) {
    0 0        
    0 0        
    0          
    0          
1469             }
1470             elsif ($ff->{fieldLbvl} && ($s->{-strFields} ==2) && ($ff->{fieldLbvl} =~/\\\Q$v\E\\([^\\]+)/)) {
1471 0           $v =$1
1472             }
1473             elsif ($ff->{-hashOut}) {
1474 0 0         if (exists($ff->{-hashOut}->{$v})) {
1475 0           $v =$ff->{-hashOut}->{$v}
1476             }
1477             else {
1478             # return(&{$s->{-die}}($s->efmt('Could not transate value',$s->{-cmd},undef,'strOut',$f,$ff->{fieldName},$v)))
1479             }
1480             }
1481             elsif ($ff->{dataType} eq 'enum') {
1482 0           schlbls(@_);
1483 0 0         $v =strOut(@_) if $ff->{-hashOut};
1484             }
1485             elsif ($ff->{dataType} eq 'time') {
1486 0           $v =strtime($s,$v)
1487             }
1488             $v
1489 0           }
1490            
1491            
1492             sub strIn { # Convert input field value to internal, using '-meta'
1493             # (schema, fieldId, fieldValue) -> fieldValue
1494 0     0 1   my($s,$f,$ff,$v) =@_;
1495 0 0         $ff =ref($ff) ? $ff : $ff =~/^\d+$/ ? $s->{-meta}->{$f}->{-fldids}->{$ff} : $s->{-meta}->{$f}->{-fields}->{$ff};
    0          
1496 0 0 0       if (!defined($v) ||!$ff ||!$s->{-strFields}) {
    0 0        
    0          
    0          
    0          
    0          
1497             }
1498             elsif ($v =~/^\d+$/) {
1499             }
1500             elsif ($ff->{fieldLbvl} && ($ff->{fieldLbvl} =~/\\(\d+)\\\Q$v\E(?:\\|$)/)) {
1501             # && ($s->{-strFields} ==2)
1502 0           $v =$1
1503             }
1504             elsif ($ff->{-hashIn}) {
1505 0 0         if (exists($ff->{-hashIn}->{$v})) {
1506 0           $v =$ff->{-hashIn}->{$v};
1507             }
1508             else {
1509 0           return(&{$s->{-die}}($s->efmt('Could not transate value',$s->{-cmd},undef,'strIn',$f,$ff->{fieldName},$v)))
  0            
1510             }
1511             }
1512             elsif ($ff->{dataType} eq 'enum') {
1513 0 0         my $et = ref($ff->{'limit'}->{'enumLimits'}) eq 'ARRAY'
    0          
    0          
1514             ? $ff->{'limit'}->{'enumLimits'}
1515             : exists $ff->{'limit'}->{'enumLimits'}->{'regularList'}
1516             ? $ff->{'limit'}->{'enumLimits'}->{'regularList'}
1517             : exists $ff->{'limit'}->{'enumLimits'}->{'customList'}
1518             ? $ff->{'limit'}->{'enumLimits'}->{'customList'}
1519             : undef;
1520 0 0 0       if (!$et) {}
    0          
    0          
1521             elsif (!ref($et->[0])) {
1522 0           $ff->{-hashIn} ={map {($et->[$_] => $_)} (0..$#$et)};
  0            
1523 0           $v =strIn(@_);
1524             }
1525             elsif ((ref($et->[0]) eq 'HASH') && defined($et->[0]->{itemNumber})) {
1526 0           $ff->{-hashIn} ={map {($et->[$_]->{itemName} => $et->[$_]->{itemNumber})} (0..$#$et)};
  0            
1527 0           $v =strIn(@_);
1528             }
1529             else {
1530 0           $et =undef
1531             }
1532 0 0 0       return(&{$s->{-die}}($s->efmt('Could not transate value',$s->{-cmd},undef,'strIn',$f,$ff->{fieldName},$v)))
  0            
1533             if $et && ($v !~/^\d+$/);
1534             }
1535             elsif ($ff->{dataType} eq 'time') {
1536 0           $v =timestr($s,$v);
1537             }
1538             $v
1539 0           }
1540            
1541            
1542             sub lsflds { # List fields from '-meta'
1543             # (additional field options)
1544 0     0 1   my ($s, @a) =@_;
1545 0 0         @a =('fieldLblc') if !@a;
1546 0           unshift @a, 'fieldName', 'fieldId', 'dataType', 'option', 'createMode';
1547 0           map { my $f =$_;
  0            
1548 0           $f =~/^-/
1549             ? ()
1550 0           : map { my $ff =$s->{-meta}->{$f}->{-fields}->{$_};
1551 0 0         join("\t", $f
1552             #, $ff->{option} && ($ff->{option} == 4) ? 'ro' : ()
1553 0           , (map { $_ eq 'fieldLblc'
1554             ? join('; '
1555 0 0         , map {$ff->{$_} ? $ff->{$_} : ()
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1556             } $ff->{$_} ? ('fieldLblc') : ('fieldLbl', 'fieldLbll'), 'fieldLbv', 'fieldLbvl', 'helpText')
1557             : !defined($ff->{$_})
1558             ? ''
1559             : $_ eq 'option'
1560             ? (!$ff->{$_} ? '' : $ff->{$_} == 4 ? 'r' : $ff->{$_} == 2 ? 'o' : $ff->{$_} == 1 ? 'm' : '')
1561             : $ff->{$_}
1562             } @a[0..$#a]))
1563 0 0         } sort keys %{$s->{-meta}->{$f}->{-fields}}
1564 0           } sort keys %{$s->{-meta}}
1565             }
1566            
1567            
1568             sub query { # ars_GetListEntry / ars_LoadQualifier
1569             # (-clause=>val) -> list
1570             # (...-for=>sub{}) -> self
1571             # Field Ids translated using -metadn/-metaid
1572             # -from ||-form ||-schema => schema name
1573             # -where || -query ||-qual => search condition
1574             # Syntax:
1575             # 'fieldId' || 'fieldName' - fields
1576             # "string value" - strings
1577             # digits - numeric value, number of seconds as date value
1578             # strIn(form, fieldName, value) - to encode value for '-where'
1579             #
1580             # -fields => [{fieldId=>1, columnWidth=>9, separator=>"\t"},...
1581             # ,[{fieldName=>name, width=>9},...
1582             # ,[{field=>name|id, width=>9},...] # 128 bytes limit strings
1583             # ||-fields => [fieldId | fieldName,...] # using ars_GetListEntryWithFields()
1584             # ||-fields => '*' | 1 | '*-$', -xfields=>sub{} || [fieldName| fieldId,...]
1585             # ||-fetch => '*' | 1 | [fieldId|fieldName,...] # using ars_GetEntry() for each record
1586             # -order ||-sort => [fieldId, (1||2),...] # 1 - asc, 2 - desc
1587             # [..., fieldName, field=>'desc', field=>'asc',...]
1588             # -limit ||-max => maxRetrieve
1589             # -first ||-start => firstRetrieve
1590             # -for ||-foreach => sub(self, form, id|string, ?{record}){die "last\n", die "next\n"} -> self
1591             # ?-echo=>1
1592             #
1593             # ars_GetListEntry(ctrl, schema, qualifier, maxRetrieve=0, firstRetrieve=0,...)
1594             # ..., getListFields, sortList,...
1595             # ars_LoadQualifier(ctrl, schema, qualifier string)
1596             #
1597             # Using the advanced search bar:
1598             # 'Currency Field.VALUE' 'Currency Field' = $NULL$
1599             # ??? BookValue=> {conversionDate=> 1090544110, currencyCode=> 'USD', funcList=> [{currencyCode=> 'USD', value=> '0.00'}, {currencyCode=> 'EUR', value=> ''}, {currencyCode=> 'GBP', value=> ''}, {currencyCode=> 'JPY', value=> ''}, {currencyCode=> 'CAD', value=> ''}], value=> '0.00'}
1600             # 'Status History.Fixed.TIME' < "07/01/99"
1601             # 'Create date' > "10:00:00"
1602             #
1603 0     0 1   my $s =shift;
1604 0           my %a =@_;
1605 0   0       my $f =$a{-schema} ||$a{-form} ||$a{-from};
1606 0   0       my $c =$a{-for} ||$a{-foreach};
1607            
1608 0 0 0       if ($a{-fields} && !ref($a{-fields})) {
1609 0           my $q ='trim|control|table|column|page';
1610 0 0         $q .= '|currency|attach' if $a{-fields} =~/^-\$/;
1611 0 0         $q .= '|attach' if $a{-fields} =~/^-f/;
1612 0           $a{-fields} =
1613 0           [map { my $ff =$s->{-meta}->{$f}->{-fields}->{$_};
1614             !$ff->{dataType} || !$ff->{fieldId}
1615             || ($ff->{dataType} =~/^($q)/)
1616             || ($ff->{fieldId} eq '15') # 'Status-History'
1617             # ars_GetListEntryWithFields() -> [ERROR] (ORA-00904: "C15": invalid identifier) (ARERR #552)
1618 0 0 0       || (!$a{-xfields} ? 0 : ref($a{-xfields}) eq 'CODE' ? &{$a{-xfields}}($s, $ff) : grep {($_ eq $ff->{fieldId}) || ($_ eq $ff->{fieldName})} @{$a{-xfields}})
1619             ? ()
1620             : ($ff->{fieldId})
1621 0           } sort keys %{$s->{-meta}->{$f}->{-fields}}]
1622             }
1623            
1624 0 0 0       $a{-fetch} =1 if $a{-fields} && !ref($a{-fields});
1625 0 0         delete $a{-fields} if $a{-fetch};
1626            
1627 0 0         local $s->{-cmd} ="query(" .join(', ',map {!defined($a{$_}) ? () : ref($a{$_}) ? "$_=>" .dsquot($s,$a{$_}) : ("$_=>" .strquot($s,$a{$_}))
  0 0          
1628             } qw(-schema -form -from -fields -fetch -qual -query -where -sort -order -limit -max -maxRetrieve -first -start))
1629             .")";
1630            
1631 0 0         my $fl = ref($a{-fetch})
1632 0 0 0       ? [map {/^\d+$/ ? $_ : schdn($s,$f,$_)->{fieldId}} @{$a{-fetch}}]
  0 0 0        
      0        
1633             : $a{-fields} && ref($a{-fields}->[0])
1634 0           ? [map {ref($_)
1635             ? {fieldId=>$_->{fieldId} ||schdn($s,$f, $_->{fieldName} ||$_->{field})->{fieldId}
1636             , separator=>$_->{separator} ||"\t"
1637             , columnWidth=>$_->{columnWidth} ||$_->{width} ||10
1638             }
1639             : {fieldId=>/^\d+$/ ? $_ : schdn($s,$f,$_)->{fieldId}
1640             , separator=>"\t"
1641             , columnWidth=>10
1642             }
1643 0 0         } @{$a{-fields}}]
1644             : $a{-fields}
1645 0 0 0       ? [map {/^\d+$/ ? $_ : schdn($s,$f,$_)->{fieldId}} @{$a{-fields}}]
  0 0          
    0          
1646             : [];
1647 0           my @fs;
1648 0   0       {my ($v, $x, @r) =($a{-sort} ||$a{-order});
  0            
1649 0           @fs = $v
1650 0 0         ? (map {if (!$x) {$x =$_; @r=()}
  0 0          
  0 0          
  0 0          
1651 0 0         elsif(/^(desc|2)$/) {@r =($x=~/^\d+$/ ? $x : schdn($s,$f,$x)->{fieldId}, 2); $x =undef}
  0            
1652 0 0         else {@r=($x =~/^\d+$/ ? $x : schdn($s,$f,$x)->{fieldId},1); $x=undef if /^(asc|1)$/}
1653 0           @r} @$v)
1654             : ();
1655 0 0         push @fs, $x =~/^\d+$/ ? $x : schdn($s,$f,$x)->{fieldId}, 1
    0          
1656             if $x}
1657 0   0       my $q =$s->_qsubst('',$a{-qual} ||$a{-query} ||$a{-where}, $f);
1658             $s->{-cmd} .=": subst(-from=>'$f'"
1659             .(@$fl ? ',-fields=>' .join(', ', map {ref($_) ? "'" .$_->{fieldId} ."'(" .$_->{columnWidth} .")" : "'$_'"
1660             } @$fl) : '')
1661             .($q ? ",-where=>$q" : '')
1662 0           .(@fs ? ',-order=>' .join(', ', map {"'$_'"} @fs) : '')
1663             .")"
1664             if 0;
1665 0           $q =ARS::ars_LoadQualifier($s->{-ctrl}, $f, $q);
1666 0 0         return(&{$s->{-die}}($s->efmt($ARS::ars_errstr,$s->{-cmd})))
  0            
1667             if !$q;
1668 0           $s->{-cmd} .=": qual". $s->dsquot(ARS::ars_perl_qualifier($s->{-ctrl}, $q))
1669             if 0;
1670            
1671 0 0         print $s->cpcon(join(";\n", split /\):\s/, $s->{-cmd})), "\n"
    0          
1672             if exists($a{-echo}) ? $a{-echo} : $s->{-echo};
1673            
1674 0 0 0       if ($c && $a{-fields} && !ref($a{-fields}->[0])) {
    0 0        
    0 0        
1675 0           my $id;
1676 0           local $_;
1677 0   0       foreach my $e (ARS::ars_GetListEntryWithFields($s->{-ctrl}, $f, $q
      0        
1678             , $a{-limit} ||$a{-max} ||$s->{-maxRetrieve} ||0
1679             , $a{-first} ||$a{-start} ||0
1680             , $fl
1681             , @fs)) {
1682 0 0 0       if (!ref($e)) {
  0 0          
1683 0           $_ =$id =$e
1684             }
1685             elsif (!defined(eval{&$c($s, $f, $_ =$id, entryOut($s, $f, $e))}) && $@) {
1686 0 0         last if $@ =~/^last[\r\n]*$/;
1687 0 0         next if $@ =~/^next[\r\n]*$/;
1688 0           return(&{$s->{-die}}($s->efmt($@,$s->{-cmd},'eval(-for)')));
  0            
1689             }
1690             }
1691 0 0 0       return(&{$s->{-die}}($s->efmt($ARS::ars_errstr,$s->{-cmd},'undef','ars_GetListEntryWithFields')))
  0            
1692             if !defined($id) && $ARS::ars_errstr;
1693 0           return($s);
1694             }
1695             elsif ($c) {
1696 0           my $i =undef;
1697 0           local $_ ='';
1698 0   0       foreach my $e (ARS::ars_GetListEntry($s->{-ctrl}, $f, $q
      0        
1699             , $a{-limit} ||$a{-max} ||$s->{-maxRetrieve} ||0
1700             , $a{-first} ||$a{-start} ||0
1701             , $fl
1702             , @fs)) {
1703 0 0         if ($i) {
1704 0           $i =0;
1705 0 0         $_ =$_ .($fl->[0]->{separator}) .$e
1706             if $a{-fields};
1707             }
1708             else {
1709 0           $i =1;
1710 0           $_ =$e;
1711             next
1712 0           }
1713 0 0 0       if (!defined(eval{&$c($s, $f, $_
  0 0          
    0          
1714             , $a{-fetch}
1715             ? $s->entry(-from=>$f, -id=>$_
1716             , ref($a{-fetch}) ? (-fields => $a{-fetch}) : ())
1717             : ())}) && $@) {
1718 0 0         last if $@ =~/^last[\r\n]*$/;
1719 0 0         next if $@ =~/^next[\r\n]*$/;
1720 0           return(&{$s->{-die}}($s->efmt($@,$s->{-cmd},'eval(-for)')));
  0            
1721             }
1722             }
1723 0 0 0       return(&{$s->{-die}}($s->efmt($ARS::ars_errstr,$s->{-cmd},undef,'ars_GetListEntry')))
  0            
1724             if !defined($i) && $ARS::ars_errstr;
1725 0           return($s)
1726             }
1727             elsif ($a{-fields} && !ref($a{-fields}->[0])) {
1728 0   0       my @r =ARS::ars_GetListEntryWithFields($s->{-ctrl}, $f, $q
      0        
1729             , $a{-limit} ||$a{-max} ||$s->{-maxRetrieve} ||0
1730             , $a{-first} ||$a{-start} ||0
1731             , $fl
1732             , @fs);
1733 0 0         if (@r) {
1734 0           my @rr;
1735 0           for (my $i =0; $i <$#r; $i +=2) {
1736 0           push @rr, entryOut($s, $f, $r[$i+1])
1737             }
1738 0           return(@rr)
1739             }
1740 0 0         return(&{$s->{-die}}($s->efmt($ARS::ars_errstr,$s->{-cmd},undef,'ars_GetListEntryWithFields')))
  0            
1741             if $ARS::ars_errstr;
1742 0           return(())
1743             }
1744             else {
1745 0   0       my @r =ARS::ars_GetListEntry($s->{-ctrl}, $f, $q
      0        
1746             , $a{-limit} ||$a{-max} ||$s->{-maxRetrieve} ||0
1747             , $a{-first} ||$a{-start} ||0
1748             , $fl
1749             , @fs);
1750 0 0         if (@r) {
1751 0           my @rr;
1752 0 0         if ($a{-fields}) {
    0          
1753 0           for (my $i =0; $i <$#r; $i +=2) {
1754 0           push @rr, $r[$i]
1755             .($fl->[0]->{separator})
1756             . $r[$i+1]
1757             }
1758             }
1759             elsif ($a{-fetch}) {
1760 0           for (my $i =0; $i <$#r; $i +=2) {
1761 0 0         push @rr
1762             , $s->entry(-from=>$f, -id=>$r[$i]
1763             , ref($a{-fetch}) ? (-fields=>$a{-fetch}) : ())
1764             }
1765             }
1766             else {
1767 0           for (my $i =0; $i <$#r; $i +=2) { push @rr, $r[$i] }
  0            
1768             }
1769 0           return(@rr)
1770             }
1771 0 0         return(&{$s->{-die}}($s->efmt($ARS::ars_errstr,$s->{-cmd},undef,'ars_GetListEntry')))
  0            
1772             if $ARS::ars_errstr;
1773 0           return(())
1774             }
1775             }
1776            
1777            
1778             sub _qsubst { # query condition string substitutions
1779             # (''|char, expr string, form) -> translated
1780 0     0     my ($s, $c, $q, $f) =@_;
1781 0 0 0       return($q) if !defined($q) ||($q eq '');
1782 0           my $r ='';
1783 0 0         if (!$c) {
    0          
    0          
    0          
1784 0           while ($q =~/^(.*?)(['"]|#[\w]+[\w\d]+\()(.*)/) {
1785 0           $r .=$1;
1786 0           $q =$3;
1787 0 0         if (!defined($q)) {
    0          
1788 0           $q =''
1789             }
1790             elsif (substr($2,0,1) eq "'") {
1791 0 0         if ($q =~/^([^']+)'(.*)/) {
1792 0           $q =$2;
1793 0           my $n =$1;
1794 0 0         $r .="'" .($n =~/^\d+$/ ? $n : schdn($s,$f,$n)->{fieldId}) ."'";
1795             }
1796             else {
1797 0           $r .="'"
1798             }
1799             }
1800             else {
1801 0           $r .=_qsubst($s, $2, $q, $f)
1802             }
1803             }
1804 0 0         $r .=$q if defined($q);
1805             }
1806             elsif ($c eq '(') {
1807 0           $r =$c;
1808 0           while ($q =~/^(.*?)([()'"])(.*)/) {
1809 0           $q =$3;
1810 0           $r .=$1;
1811 0 0         if ($2 eq ')') {$r .=$2; last}
  0            
  0            
  0            
1812             else {$r .=_qsubst($s, $2, $q, $f)}
1813             }
1814 0           $_[2] =$q;
1815             }
1816             elsif ($c =~/['"]/) {
1817 0           my $cq =$s->strquot($c);
1818 0           $cq =substr($cq,1,-1);
1819 0           $r =$c;
1820 0           while ($q =~/^(.*?)(\Q$c\E|\Q$cq\E)(.*)/) {
1821 0           $q =$3;
1822 0           $r .=$1 .$2;
1823 0 0         last if $2 eq $c;
1824             }
1825 0           $_[2] =$q;
1826             }
1827             elsif ($c eq ',') {
1828 0           my @r;
1829 0           while ($q =~/^(.*?)(['"(]|\Q$c\E)(.*)/i) {
1830 0           $q =$3;
1831 0           $r .=$1;
1832 0 0         if ($2 eq $c) {
1833 0 0         push @r, ($r =~/^\s*(.*?)\s*$/ ? $1 : $r);
1834 0           $r ='';
1835             }
1836             else {
1837 0           $r .=_qsubst($s, $2, $q, $f);
1838             }
1839             }
1840 0           $r .=$q;
1841 0 0         push @r, ($r =~/^\s*(.*?)\s*$/ ? $1 : $r) if $r ne '';
    0          
1842 0           return(@r)
1843             }
1844             else {
1845 0           $r =$c .$q
1846             }
1847 0           $r
1848             }
1849            
1850            
1851             sub entry { # ars_GetEntry
1852             # (-from=>form, -id=>entryId, ?-for=>{}, ?-fields=>[internalId,...])
1853             # -> {fieldName => value}
1854             # # Field Ids translated using -schdn/-schid
1855             # -from ||-form ||-schema => schema name
1856             # -id => entryId
1857             # -fields => [internalId, fieldName,...]
1858             # -for => {} # steady hash to store each entry fetched
1859             # ?-echo=>1
1860             #
1861             # ars_GetEntry(ctrl,schema,entry_id,...) -> (internalId => value,...)
1862             # no ars_GetEntryBLOB(ctrl,schema,entry_id,field_id,locType,locFile)
1863             # no ars_EncodeDiary(diaryEntryHash1, ... diaryEntryHashN)
1864             # encoded 'Status-History'
1865             # decoded 'diary'
1866             #
1867 0     0 1   my ($s, %a) =@_;
1868 0   0       my $f =$a{-schema} ||$a{-form} ||$a{-from};
1869 0 0 0       print $s->cpcon("entry(-form=>'$f',-id=>'$a{-id}')\n")
1870             if $s->{-echo} || $a{-echo};
1871 0 0         my %r =ARS::ars_GetEntry($s->{-ctrl},$f,$a{-id}
1872             ,$a{-fields}
1873 0 0         ? (map {/^\d+$/ ? $_ : schdn($s, $f, $_)->{fieldId}} @{$a{-fields}})
  0            
1874             : ()
1875             );
1876 0 0         if (%r) {
1877 0   0       my $rr =$a{-for} ||{};
1878 0 0         undef(@{$rr}{keys %$rr}) if %$rr;
  0            
1879             # @{$rr}{map {schid($s,$f,$_)->{fieldName}} keys %r} =values %r;
1880             # return($rr);
1881 0           local $_;
1882 0 0         local $s->{-cmd} =($s->{-cmd} ? $s->{-cmd} .': ' : '') ."entry(-form=>'$f',-id=>'$a{-id}')";
1883 0           foreach my $id (keys %r) {
1884 0           my $ff =schdi($s,$f,$id);
1885 0 0         if ($ff) {
1886 0           $rr->{$ff->{fieldName}}
1887             = !$s->{-strFields}
1888             ? $r{$id}
1889             : $ff->{strOut}
1890 0 0         ? &{$ff->{strOut}}($s,$f,$ff,$_=$r{$id})
    0          
1891             : strOut($s,$f,$id,$r{$id})
1892             }
1893             else {
1894 0           $rr->{$id} =$r{$id}
1895             }
1896             }
1897 0           return($rr)
1898             }
1899 0           return($ARS::ars_errstr
1900 0 0         ? &{$s->{-die}}($s->efmt($ARS::ars_errstr,$s->{-cmd},undef,'entry',-form=>$f,-id=>$a{-id}))
1901             : {})
1902             }
1903            
1904            
1905             sub entryOut { # Format entry hash ref for output
1906             # (schema, entry, ?sample) -> entry
1907 0     0 0   my ($s, $f, $r, $rr) =@_;
1908 0 0         if ($rr) {
1909 0 0         undef(@{$rr}{keys %$rr}) if %$rr;
  0            
1910             }
1911             else {
1912 0           $rr ={}
1913             }
1914 0           local $_;
1915 0           foreach my $id (keys %$r) {
1916 0           my $ff =schdi($s,$f,$id);
1917 0           my $v =$r->{$id};
1918 0 0         if ($ff) {
1919 0           $rr->{$ff->{fieldName}}
1920             = !$s->{-strFields}
1921             ? $r->{$id}
1922             : $ff->{strOut}
1923 0 0         ? &{$ff->{strOut}}($s,$f,$ff,$_=$v)
    0          
1924             : strOut($s,$f,$id,$v);
1925             }
1926             else {
1927 0           $rr->{$id} =$r->{$id}
1928             }
1929             }
1930             $rr
1931 0           }
1932            
1933            
1934             sub entryDif { # Diff hash refs
1935             # ({old}, {new}, exclude empty) -> {to update}
1936 0     0 1   my($s, $ds1, $ds2, $ee) =@_;
1937 0 0 0       return(undef) if (ref($ds1) ||'') ne (ref($ds2) ||'');
      0        
1938 0 0 0       return(undef) if (ref($ds1) ||'') ne 'HASH';
1939 0           my ($r, $rr) =({});
1940 0           foreach my $k (keys %$ds2) {
1941 0 0 0       next if !defined($ds1->{$k}) && !defined($ds2->{$k});
1942 0 0 0       next if (ref($ds1->{$k}) && ref($ds2->{$k}))
      0        
1943             && !dscmp($s,$ds1,$ds2);
1944 0 0 0       next if (defined($ds1->{$k}) && defined($ds2->{$k}))
      0        
1945             && ($ds1->{$k} eq $ds2->{$k});
1946 0 0 0       next if $ee && (!defined($ds2->{$k}) ||($ds2->{$k} eq ''))
      0        
      0        
      0        
1947             && (!defined($ds1->{$k}) ||($ds1->{$k} eq ''));
1948 0           $r->{$k} =$ds2->{$k}; $rr =1;
  0            
1949             }
1950 0 0         $rr ? $r : undef
1951             }
1952            
1953            
1954             sub entryNew { # New {field => value}
1955             # (-form=>form, field=>value,...) -> {field=>value,...}
1956             # ?'Incident Number'=>1 for 'HPD:Help Desk'
1957 0     0 1   my ($s, %a) =@_;
1958 0   0       my $f =$a{-schema} ||$a{-form} ||$a{-into} ||$a{-for};
1959 0           delete @a{qw(-schema -form -from -into -for)};
1960 0           local $_;
1961 0 0         local $s->{-cmd} =($s->{-cmd} ? $s->{-cmd} .': ' : '') ."entryNew(-form=>'$f',"
    0          
1962 0 0         .join(',', map {!defined($a{$_})
1963             ? "$_=>undef"
1964             : ref($a{$_})
1965             ? ("$_=>" .dsquot($s, $a{$_}))
1966             : ("$_=>" .strquot($s, $a{$_}))
1967             } sort keys %a)
1968             .')';
1969 0           foreach my $k (%{$s->{-meta}->{$f}->{-fields}}) {
  0            
1970 0           my $ff =$s->{-meta}->{$f}->{-fields}->{$k};
1971 0 0 0       next if !$ff
      0        
      0        
      0        
1972             || exists($a{$k})
1973             || ((!defined($ff->{defaultVal}) || ref($ff->{defaultVal}))
1974             && !$s->{-metaid}->{$ff->{fieldId}}->{defaultVal});
1975 0 0         $a{$k} =defined($s->{-metaid}->{$ff->{fieldId}}->{defaultVal})
1976             ? $s->{-metaid}->{$ff->{fieldId}}->{defaultVal}
1977             : $ff->{defaultVal};
1978 0           $a{$k} =$s->{-metaid}->{$ff->{fieldId}}->{strOut}
1979 0 0         ? &{$s->{-metaid}->{$ff->{fieldId}}->{strOut}}($s,$f,$s->{-metaid}->{$ff->{fieldId}},$_=$a{$k})
    0          
1980             : strOut($s, $f, $ff->{fieldId},$_=$a{$k})
1981             if $s->{-strFields};
1982             }
1983 0 0         if ($f eq 'HPD:Help Desk') {
1984 0 0 0       if ($a{'Incident Number'} && (length($a{'Incident Number'}) ==1)) {
    0 0        
1985 0           $a{'Incident Number'} =$s->entryIns(-form=>'HPD:CFG Ticket Num Generator', 'DataTags'=>'za')
1986             }
1987             elsif (defined($a{'Incident Number'}) && !$a{'Incident Number'}) {
1988 0           delete $a{'Incident Number'}
1989             }
1990             }
1991 0           \%a
1992             }
1993            
1994            
1995             sub entryIns { # ars_CreateEntry
1996             # (-form=>form, field=>value) -> id
1997             # ?-echo=>1
1998             # ?'Incident Number'=>1 for 'HPD:Help Desk'
1999 0     0 1   my ($s, %a) =@_;
2000 0   0       my $f =$a{-schema} ||$a{-form} ||$a{-into};
2001 0           my $r;
2002 0 0         print $s->cpcon("entryIns(-form=>'$f')\n")
    0          
2003             if exists($a{-echo}) ? $a{-echo} : $s->{-echo};
2004 0           delete @a{qw(-schema -form -from -into -echo)};
2005 0           local $_;
2006 0 0         local $s->{-cmd} =($s->{-cmd} ? $s->{-cmd} .': ' : '') ."entryIns(-form=>'$f',"
    0          
2007 0 0         .join(',', map {!defined($a{$_})
2008             ? "$_=>undef"
2009             : ref($a{$_})
2010             ? ("$_=>" .dsquot($s, $a{$_}))
2011             : ("$_=>" .strquot($s, $a{$_}))
2012             } sort keys %a)
2013             .')';
2014 0           %a = map { my ($k, $v) =($_, $a{$_});
  0            
2015 0 0         if ($k !~/^\d+$/) {
2016 0           my $ff =schdn($s,$f,$k);
2017 0           $k =$ff->{fieldId};
2018 0           $v =$ff->{strIn}
2019 0 0         ? &{$ff->{strIn}}($s,$f,$ff,$_=$v)
    0          
2020             : strIn($s,$f,$k,$v)
2021             if $s->{-strFields};
2022             }
2023 0           ($k => $v)
2024             } keys %a;
2025 0           delete $s->{-entryNo};
2026 0 0         if ($f eq 'HPD:Help Desk') {
2027 0           my $ii=schdn($s,$f,'Incident Number')->{fieldId};
2028 0 0         $a{$ii} =$s->entryIns(-form=>'HPD:CFG Ticket Num Generator', 'DataTags'=>'za')
2029             if length($a{$ii}) <2;
2030 0           $s->{-entryNo} =$a{$ii};
2031 0           $r =ARS::ars_CreateEntry($s->{-ctrl}, $f, %a)
2032             }
2033             else {
2034 0           $r =$s->{-entryNo} =ARS::ars_CreateEntry($s->{-ctrl}, $f, %a)
2035             }
2036 0 0         if (!$r) {
2037 0           my $t =$s->efmt($ARS::ars_errstr,$s->{-cmd});
2038 0 0 0       return(&{$s->{-die}}($t)) if !$r && $ARS::ars_errstr;
  0            
2039             # warn($t) if !$r && !$ARS::ars_errstr;
2040             }
2041 0 0         $r ||$s
2042             }
2043            
2044            
2045             sub entryUpd { # ars_SetEntry(ctrl,schema,entry_id,getTime,...)
2046             # (-form=>form, -id=>entryId, field=>value) -> id
2047             # ?-echo=>1
2048             #
2049             # ??? ARMergeEntry()/ars_MergeEntry(ctrl, schema, mergeType, ...)
2050             # ??? ars_EncodeDiary(diaryEntryHash1, ... diaryEntryHashN)
2051             #
2052 0     0 1   my ($s, %a) =@_;
2053 0   0       my $f =$a{-schema} ||$a{-form} ||$a{-into};
2054 0           my $id=$a{-id};
2055 0 0         print $s->cpcon("entryUpd(-form=>'$f',-id=>'$id')\n")
    0          
2056             if exists($a{-echo}) ? $a{-echo} : $s->{-echo};
2057 0           delete @a{qw(-schema -form -from -into -id -echo)};
2058 0           local $_;
2059 0 0         local $s->{-cmd} =($s->{-cmd} ? $s->{-cmd} .': ' : '')
    0          
2060             ."entryUpd(-form=>'$f',-id=>'$id',"
2061 0 0         .join(',', map {!defined($a{$_})
2062             ? "$_=>undef"
2063             : ref($a{$_})
2064             ? ("$_=>" .dsquot($s, $a{$_}))
2065             : ("$_=>" .strquot($s, $a{$_}))
2066             } sort keys %a)
2067             .')';
2068 0           %a = map { my ($k, $v) =($_, $a{$_});
  0            
2069 0 0         if ($k !~/^\d+$/) {
2070 0           my $ff =schdn($s,$f,$k);
2071 0           $k =$ff->{fieldId};
2072 0           $v =$ff->{strIn}
2073 0 0         ? &{$ff->{strIn}}($s,$f,$ff,$_=$v)
    0          
2074             : strIn($s,$f,$k,$v)
2075             if $s->{-strFields}
2076             }
2077 0           ($k => $v)
2078             } keys %a;
2079 0           my $r =ARS::ars_SetEntry($s->{-ctrl}, $f, $id, 0, %a);
2080 0 0 0       return(&{$s->{-die}}($s->efmt($ARS::ars_errstr, $s->{-cmd})))
  0            
2081             if !$r && $ARS::ars_errstr;
2082 0           $id
2083             }
2084            
2085            
2086             sub entryDel { # ars_DeleteEntry
2087             # (-form=>form, -id=>entryId) -> id
2088             # ?-echo=>1
2089 0     0 1   my ($s, %a) =@_;
2090 0   0       my $f =$a{-schema} ||$a{-form} ||$a{-from} ||$a{-into};
2091 0           my $id=$a{-id};
2092 0 0         print $s->cpcon("entryDel(-form=>'$f',-id=>'$id')\n")
    0          
2093             if exists($a{-echo}) ? $a{-echo} : $s->{-echo};
2094 0           delete @a{qw(-schema -form -from -into -id -echo)};
2095 0           my $r =ARS::ars_DeleteEntry($s->{-ctrl}, $f, $id);
2096 0 0 0       return(&{$s->{-die}}($s->efmt($ARS::ars_errstr
  0            
2097             ,"entryDel(-form=>'$f',-id=>'$id')")))
2098             if !$r && $ARS::ars_errstr;
2099 0           $id
2100             }
2101            
2102            
2103             sub entryBLOB { # BLOB field retrieve/update
2104             # (-form=>form, -id=>entryId, -field=>fieldId|fieldName
2105             # ,?-set=>data
2106             # ,?-file=>filePath, ?-set=>boolean
2107 0     0 1   my ($s, %a) =@_;
2108 0   0       my $f =$a{-schema} ||$a{-form} ||$a{-from} ||$a{-into};
2109 0 0         my $eu =!$a{-file} ? exists($a{-set}) : exists($a{-set}) ? $a{-set} : $a{-into};
    0          
2110 0 0         if ($eu) {
2111 0 0         return($s->entryUpd(-form=>$f, -id=>$a{-id}
    0          
2112             , exists($a{-echo}) ? (-echo=>$a{-echo}) : ()
2113             , $a{-field}
2114             , {$a{-file}
2115             ? ('file'=>$a{-file}, 'size'=> -s $a{-file})
2116             : ('buffer'=>$a{-set}, 'size'=> length($a{-set}))
2117             }))
2118             }
2119             else {
2120 0 0         my $r =ARS::ars_GetEntryBLOB($s->{-ctrl}, $f, $a{-id}
    0          
2121             ,$a{-field} =~/^\d+$/ ? $a{-field} : schdn($s,$f,$a{-field})->{fieldId}
2122             ,$a{-file} ? (ARS::AR_LOC_FILENAME(), $a{-file}) : (ARS::AR_LOC_BUFFER()));
2123 0 0 0       return(&{$s->{-die}}($s->efmt($ARS::ars_errstr
  0            
2124             ,"entryBLOB(-form=>'$f',-id=>'" .$a{-id} ."',-field=>" .$a{-field} ."')")))
2125             if !defined($r) && $ARS::ars_errstr;
2126 0 0         return(!$a{-file} ? $r : $r ? $a{-id} : $r)
    0          
2127             }
2128             }
2129            
2130            
2131             sub dbi { # DBI connection object
2132 0 0   0 1   return($_[0]->{-dbi}) if $_[0]->{-dbi};
2133 0           dbiconnect(@_)
2134             }
2135            
2136            
2137             sub dbiconnect {# DBI connect to any database
2138             # (-dbiconnect=>[]) -> dbi object
2139 0     0 1   set(@_);
2140 0 0         set($_[0],-die=>'Carp') if !$_[0]->{-die};
2141 0 0         print $_[0]->cpcon("dbiconnect()\n")
2142             if $_[0]->{-echo};
2143 0 0         eval('use DBI; 1') ||return(&{$_[0]->{-die}}($_[0]->efmt('No DBI')));
  0            
2144             $_[0]->{-dbi} =DBI->connect(ref($_[0]->{-dbiconnect}) ? @{$_[0]->{-dbiconnect}} : $_[0]->{-dbiconnect})
2145 0   0       || &{$_[0]->{-die}}($_[0]->efmt(DBI->errstr,undef,undef,'dbiconnect') ."\n");
2146             }
2147            
2148            
2149             sub dbiquery { # DBI query
2150             # (dbi query args) -> dbi cursor object
2151             # (-echo=>1,...)
2152 0     0 1   my($s, @q) =@_;
2153 0   0       my(%a); while ($#q && ($q[0] =~/^-/)) {$a{$q[0]} =$q[1]; shift @q; shift @q};
  0            
  0            
  0            
  0            
2154 0 0         print $s->cpcon("dbiquery($q[0])\n")
    0          
2155             if exists($a{-echo}) ? $a{-echo} : $s->{-echo};
2156             my $op =$s->{-dbi}->prepare(@q)
2157 0   0       || return(&{$s->{-die}}($s->efmt($s->{-dbi}->errstr, undef, undef, 'dbiprepair',@q)));
2158 0           $op->execute()
2159 0 0         || return(&{$s->{-die}}($s->efmt($s->{-dbi}->errstr, undef, undef, 'dbiexecute',@q)));
2160 0           $op;
2161             }
2162            
2163            
2164             sub dbido { # DBI do
2165             # (dbi do args) -> dbi cursor object
2166             # (-echo=>1,...)
2167 0     0 1   my($s, @q) =@_;
2168 0   0       my(%a); while ($#q && ($q[0] =~/^-/)) {$a{$q[0]} =$q[1]; shift @q; shift @q};
  0            
  0            
  0            
  0            
2169 0 0         print $s->cpcon("dbiquery($q[0])\n")
    0          
2170             if exists($a{-echo}) ? $a{-echo} : $s->{-echo};
2171 0           $s->{-dbi}->do(@q)
2172 0 0         || &{$s->{-die}}($s->efmt($s->{-dbi}->errstr, undef, undef, 'dbido',@q));
2173             }
2174            
2175            
2176             sub dbierrstr { # Last DBI error
2177 0     0 1   $_[0]->{-dbi}->errstr
2178             }
2179            
2180            
2181             sub dbitables { # DBI tables array
2182 0     0 0   my ($s, $sch, $tbl) =@_;
2183 0   0       my @t =$s->dbi()->tables('',$sch||$s->{-sqlschema}||'', $tbl||'%');
      0        
2184 0 0 0       if (!scalar(@t)
      0        
2185             && (((ref($s->{-dbiconnect}) ? $s->{-dbiconnect}->[0] : $s->{-dbiconnect})||'') =~/^dbi:ADO:/i)) {
2186 0   0       $sch =$sch||$s->{-sqlschema};
2187 0 0         @t =$sch
2188 0 0         ? (map {$_ =~/\."*\Q$sch\E"*\./i ? ($_) : ()} $s->dbi()->tables())
2189             : $s->dbi()->tables();
2190             }
2191             @t
2192 0           }
2193            
2194            
2195             sub dbicols { # DBI table columns
2196 0     0 0   my ($s, $sch, $tbl) =@_;
2197             # my $st =$s->dbiquery('SHOW COLUMNS FROM ' .($sch ? $sch .'.' : '') .$tbl);
2198 0   0       my $st =$s->dbi()->column_info('',$sch||$s->{-sqlschema}||'', $tbl||'','%');
      0        
2199 0           @{$st->fetchall_arrayref({})}
  0            
2200             }
2201            
2202            
2203             sub dbitypespc { # DBI column type spec
2204 0     0 0   my ($s, $d) =@_;
2205 0 0         ($d->{'TYPE_NAME'} ||'unknown')
2206             .($d->{'COLUMN_SIZE'}
2207 0 0 0       ? ' (' .join(',', map {defined($d->{$_}) ? $d->{$_} : ()
2208             } 'COLUMN_SIZE', 'DECIMAL_DIGITS') .')'
2209             : '')
2210            
2211             }
2212            
2213             sub dbidsmetasync { # DBI datastore - sync meta with 'arsmetasql'
2214 0     0 1   my ($s, %arg) =@_; # (-echo)
2215 0 0         return(undef) if !$s->{'-meta-sql'};
2216 0 0         my $dbt ={map {!$_
  0 0          
2217             ? ()
2218             : $_ =~/\."*([^."]+)"*$/
2219             ? (lc($1) => 1)
2220             : (lc($_) => 1)
2221             } $s->dbitables()};
2222 0           foreach my $tbl (sort keys %{$s->{'-meta-sql'}}) {
  0            
2223 0           my @sql;
2224 0 0         if ($tbl =~/^-/) {
    0          
2225             next
2226 0           }
2227             elsif (!$dbt->{$tbl}) {
2228 0 0 0       push @sql, 'CREATE TABLE ' .join('.', map {defined($_) ? $_ : ()} $s->{-sqlschema}, $tbl)
  0 0          
    0          
    0          
2229             ." (\n"
2230             .join("\n, "
2231 0           , map { $s->{'-meta-sql'}->{$tbl}->{-cols}->{$_}->{'TYPE_NAME'}
2232             ? '"' .$_ .'" ' .$s->dbitypespc($s->{'-meta-sql'}->{$tbl}->{-cols}->{$_})
2233             .(($s->{'-meta-sql'}->{$tbl}->{-cols}->{$_}->{fieldId}||'') eq '1'
2234             ? " PRIMARY KEY"
2235             : $s->{'-meta-sql'}->{$tbl}->{-cols}->{$_}->{IS_PK}
2236             ? " UNIQUE"
2237             : '')
2238             : ()
2239 0           } sort keys %{$s->{'-meta-sql'}->{$tbl}->{-cols}})
2240             .')'
2241             }
2242             else {
2243 0 0 0       my $dbc ={map {
2244 0           !$_ ||!$_->{COLUMN_NAME}
2245             ? ()
2246             : (lc($_->{COLUMN_NAME}) => $_)
2247             } $s->dbicols('',$tbl)};
2248 0 0         if (scalar(%$dbc)) {
2249 0           my (@altc, @addc);
2250 0           foreach my $col (sort keys %{$s->{'-meta-sql'}->{$tbl}->{-cols}}) {
  0            
2251 0           my $cl =lc($col);
2252 0           my $cm =$s->{'-meta-sql'}->{$tbl}->{-cols}->{$col};
2253 0 0         next if !$cm->{'TYPE_NAME'};
2254 0 0 0       if (!$dbc->{$cl}) {
    0 0        
    0          
2255 0           push @addc, '"' .$col .'" ' .$s->dbitypespc($cm)
2256             }
2257             elsif (($dbc->{$cl}->{'TYPE_NAME'} ne $cm->{'TYPE_NAME'})
2258             || ($cm->{'TYPE_NAME'} ne 'datetime'
2259             ? (($dbc->{$cl}->{'COLUMN_SIZE'}||0) < ($cm->{'COLUMN_SIZE'}||0))
2260             || (($dbc->{$cl}->{'DECIMAL_DIGITS'}||0) ne ($cm->{'DECIMAL_DIGITS'}||0))
2261             : 0 )
2262             ) {
2263 0           push @altc, '"' .$col .'" ' .$s->dbitypespc($cm)
2264             }
2265             else {
2266 0 0 0       $cm->{COLUMN_SIZE_DB} =$dbc->{$cl}->{'COLUMN_SIZE'}
      0        
2267             if ($cm->{COLUMN_SIZE_DB}||0) ne ($dbc->{$cl}->{'COLUMN_SIZE'}||0);
2268 0 0 0       $cm->{DECIMAL_DIGITS_DB} =$dbc->{$cl}->{'DECIMAL_DIGITS'}
      0        
2269             if ($cm->{DECIMAL_DIGITS_DB}||0) ne ($dbc->{$cl}->{'DECIMAL_DIGITS'}||0);
2270             }
2271             }
2272 0           foreach my $r (@addc) {
2273 0 0         push @sql
2274             ,'ALTER TABLE '
2275 0           .join('.', map {defined($_) ? $_ : ()} $s->{-sqlschema}, $tbl)
2276             .' ADD ' .$r;
2277             }
2278 0           foreach my $r (@altc) {
2279 0 0         push @sql
2280             ,'ALTER TABLE '
2281 0           .join('.', map {defined($_) ? $_ : ()} $s->{-sqlschema}, $tbl)
2282             .' ALTER COLUMN ' .$r;
2283             }
2284             }
2285             }
2286 0           foreach my $r (@sql) {
2287 0 0         print "$r;\n" if exists($arg{-echo}) ? $arg{-echo} : $s->{-echo};
    0          
2288 0           $s->dbi()->do($r)
2289 0 0         || &{$s->{-die}}($s->efmt($s->{-dbi}->errstr,$r,undef,'dbidsmetasync'));
2290             }
2291             }
2292 0           $s;
2293             }
2294            
2295            
2296             sub dbidsrpl { # DBI datastore - load data from ARS
2297 0     0 1   my ($s, %arg) =@_;
2298 0 0 0       $arg{-form} =$arg{-from} ||$arg{-schema} if !$arg{-form};
2299 0 0 0       $arg{-query} =$arg{-where} ||$arg{-qual} if !$arg{-query};
2300 0 0         $arg{-filter}=undef if !$arg{-filter};
2301 0 0         $arg{-lim_rf}=300 if !$arg{-lim_rf};
2302 0 0         $arg{-lim_or}=40 if !$arg{-lim_or};
2303 0 0         $arg{-fields}='*' if !$arg{-fields};
2304             # $arg{-echo}=0;
2305             # $arg{-ckpush}=1; # check db pushes into ARS (_arsobject_insert, _arsobject_update, _arsobject_delete)
2306             # $arg{-ckdel}=0; # check ARS deletes into db
2307             # $arg{-ckupd}=1; # check ARS updates into db
2308             # $arg{-sleep}=0;
2309             # $arg{-pk}=undef;
2310             # $arg{-timestamp}=undef; # field name || 0
2311             # $arg{-unused}=undef;
2312             # $arg{-master}
2313             # $arg{-master_pk}
2314             # $arg{-master_fk}
2315             # $arg{-master_ts}
2316 0           my $tbl =$s->sqlname($arg{-form});
2317 0 0         my $tbc =join('.', map {defined($_) ? $_ : ()} $s->{-sqlschema}, $tbl);
  0            
2318 0           my ($fpk, $fid, $fts, @flds);
2319 0           my ($ci, $cu, $cd) =(0, 0, 0);
2320 0           { my $flds =$s->{'-meta-sql'}->{$tbl}->{-cols};
  0            
2321 0 0         $fpk = $flds->{$arg{-pk}} if $arg{-pk};
2322 0 0         $fts = $flds->{$arg{-timestamp}} if $arg{-timestamp};
2323 0           foreach my $fn (sort keys %$flds) {
2324 0 0 0       next if !$flds->{$fn}->{fieldName} || !$flds->{$fn}->{COLUMN_NAME}
      0        
2325             || !$flds->{$fn}->{TYPE_NAME};
2326 0 0 0       $fpk =$flds->{$fn} if !$fpk && $flds->{$fn}->{IS_PK}
      0        
2327             && ($flds->{$fn}->{IS_PK} eq '1');
2328 0 0 0       $fid =$flds->{$fn} if !$fid && $flds->{$fn}->{IS_PK}
      0        
2329             && ($flds->{$fn}->{IS_PK} eq '1');
2330 0 0 0       $fts =$flds->{$fn} if !$fts && $flds->{$fn}->{IS_TIMESTAMP};
2331 0           push @flds, $flds->{$fn};
2332             }
2333 0 0         !$fpk && &{$s->{-die}}($s->efmt('PK not found','',undef,'dbidsrpl',$arg{-form}));
  0            
2334 0 0 0       $fts =undef if defined($arg{-timestamp}) && !$arg{-timestamp};
2335             # !$fts && &{$s->{-die}}($s->efmt('Timestamp not found','',undef,'dbidsrpl',$arg{-form}));
2336             }
2337 0 0         $s->dbi() if !$s->{-dbi};
2338 0 0         local $s->{-dbi}->{LongReadLen} =$s->{-dbi}->{LongReadLen} <= 1024 ? 4*64*1024 : $s->{-dbi}->{LongReadLen};
2339 0   0       my $vts =$fts && $s->dbiquery('SELECT max(' .$fts->{COLUMN_NAME} .') FROM ' .$tbc)->fetchrow_arrayref();
2340 0   0       $vts =$vts && $vts->[0];
2341 0           my $cts =0;
2342 0 0         if ($vts) {
2343 0           my $sql ='SELECT count(*) FROM ' .$tbc .' WHERE ' .$s->{-dbi}->quote_identifier($fts->{COLUMN_NAME}) .'=' .$s->{-dbi}->quote($vts);
2344 0           $cts =$s->dbiquery($sql)->fetchrow_arrayref();
2345 0   0       $cts =$cts && $cts->[0] ||0;
2346 0 0         print "$sql --> $cts;\n" if exists($arg{-echo}) ? $arg{-echo} : $s->{-echo};
    0          
2347 0 0         if (!$cts) {
    0          
    0          
2348             }
2349             elsif (0 && ($cts > $arg{-lim_rf})) {
2350             $cts -=1;
2351             }
2352             elsif ($cts >= $arg{-lim_rf} *2) {
2353 0           $cts -=$arg{-lim_rf};
2354 0           $arg{-lim_rf} *=2;
2355             }
2356             elsif ($cts >= $arg{-lim_rf}) {
2357 0           $arg{-lim_rf} +=$cts;
2358 0           $cts =0;
2359             }
2360             else {
2361 0           $cts =0;
2362             }
2363 0 0         $vts =$s->timestr($vts) if $vts =~/\s/;
2364 0 0         $vts =$s->timestr($vts) if $vts =~/^(.+)\.0+$/;
2365             }
2366 0 0 0       if ($s->{'-meta-sql'}->{$tbl}->{-cols}->{_arsobject_insert}
      0        
2367             && (!exists($arg{-ckpush}) ||$arg{-ckpush})) {
2368 0           local $s->{-strFields} =0;
2369 0           my $sql ='SELECT * FROM ' .$tbc
2370             .' WHERE _arsobject_insert=1 OR _arsobject_update=1 OR _arsobject_delete=1'
2371             .' ORDER BY ' .$s->{-dbi}->quote_identifier($fpk->{COLUMN_NAME}) .' asc';
2372 0 0         print "$sql;\n" if exists($arg{-echo}) ? $arg{-echo} : $s->{-echo};
    0          
2373 0           my $dbq =$s->dbiquery($sql);
2374 0           my ($rd, @rq) =({});
2375 0   0       while (($rd && ($rd =$dbq->fetchrow_hashref())) ||scalar(@rq)) {
      0        
2376 0 0         if ($rd) {
2377 0           push @rq, $rd;
2378 0 0         next if scalar(@rq) <$arg{-lim_or};
2379             }
2380             else {
2381 0 0         next if !scalar(@rq)
2382             }
2383 0 0 0       my $arq =join(' OR '
2384 0           , map { $_->{$fpk->{COLUMN_NAME}}
2385             && ($_->{_arsobject_update} ||$_->{_arsobject_delete})
2386             ? "'" .$fpk->{fieldName} ."'=" .$s->arsquot($_->{$fpk->{COLUMN_NAME}})
2387             : () } @rq);
2388 0           my %ars =$arq
2389 0 0         ? map { ($_->{$fpk->{fieldName}} => $_)
    0          
2390             } $s->query(-form=>$arg{-form}
2391             ,-fields=>$arg{-fields}
2392             ,-echo=>$arg{-echo}
2393             ,-query=>join(' AND '
2394             , $arg{-query} ? '(' .$arg{-query} .')' : ()
2395             , "($arq)"))
2396             : ();
2397 0           foreach my $rd (@rq) {
2398 0           my $ra =$ars{$rd->{$fpk->{COLUMN_NAME}}};
2399 0           my $rw ={};
2400 0           foreach my $f (@flds) {
2401 0 0 0       next if !$f->{fieldName} || !$f->{COLUMN_NAME} || !$f->{TYPE_NAME}
      0        
      0        
      0        
      0        
      0        
2402             || !exists($rd->{$f->{COLUMN_NAME}})
2403             || !$f->{fieldId}
2404             || $f->{IS_JOINED} ||$f->{DISPLAY_ONLY}
2405             || $f->{IS_PK}
2406             || (($f->{fieldId}||'') =~/^(1|2|3|5|6|15|179)$/);
2407 0 0 0       $rd->{$f->{COLUMN_NAME}} =$1
      0        
2408             if defined($rd->{$f->{COLUMN_NAME}})
2409             && ($f->{TYPE_NAME} =~/^(?:datetime|float)$/)
2410             && ($rd->{$f->{COLUMN_NAME}}=~/^(.+)\.0+$/);
2411 0 0 0       $rd->{$f->{COLUMN_NAME}} =defined($ra->{$f->{fieldName}}) && ($ra->{$f->{fieldName}} =~/\.(\d+)$/)
    0 0        
    0 0        
2412             ? sprintf('%.' .length($1) .'f', $rd->{$f->{COLUMN_NAME}})
2413             : $rd->{$f->{COLUMN_NAME}} =~/^(.+)\.0+$/
2414             ? $1
2415             : $rd->{$f->{COLUMN_NAME}}
2416             if $ra
2417             && ($f->{TYPE_NAME} eq 'float')
2418             && defined($rd->{$f->{COLUMN_NAME}});
2419 0 0         $rw->{$f->{fieldName}} =!defined($rd->{$f->{COLUMN_NAME}})
    0          
2420             ? $rd->{$f->{COLUMN_NAME}}
2421             : $f->{TYPE_NAME} eq 'datetime'
2422             ? timestr($s, $rd->{$f->{COLUMN_NAME}})
2423             : $rd->{$f->{COLUMN_NAME}};
2424             }
2425 0 0         if ($rd->{_arsobject_delete}) {
    0          
    0          
2426 0           $rd->{_arsobject_insert} =$rd->{_arsobject_update} =undef;
2427 0           next if $arg{-filter}
2428 0 0 0       && !&{$arg{-filter}}($s,\%arg,$s->{'-meta-sql'}->{$tbl},$rw,$rd);
2429 0   0       sleep($arg{-sleep} ||0);
2430 0           $cd++;
2431 0           $s->entryDel(-form=>$arg{-form}, -echo=>$arg{-echo}
2432             ,-id=>$rd->{$fid->{COLUMN_NAME}});
2433             }
2434             elsif ($rd->{_arsobject_update}) {
2435 0           $rd->{_arsobject_insert} =$rd->{_arsobject_delete} =undef;
2436 0           next if $arg{-filter}
2437 0 0 0       && !&{$arg{-filter}}($s,\%arg,$s->{'-meta-sql'}->{$tbl},$rw,$rd);
2438 0 0 0       $rw ={map { !defined($rw->{$_}) && !defined($ra->{$_})
  0 0 0        
    0          
    0          
2439             ? ()
2440             : !defined($rw->{$_}) ||!defined($ra->{$_})
2441             ? ($_ => $rw->{$_})
2442             : $rw->{$_} ne $ra->{$_}
2443             ? ($_ => $rw->{$_})
2444             : ()
2445             } keys %$rw}
2446             if $ra;
2447 0 0         if (scalar(%$rw)) {
2448 0   0       sleep($arg{-sleep} ||0);
2449 0           $cu++;
2450 0           $s->entryUpd(-form=>$arg{-form}, -echo=>$arg{-echo}
2451             ,-id=>$rd->{$fid->{COLUMN_NAME}}
2452             , %$rw);
2453             }
2454             }
2455             elsif ($rd->{_arsobject_insert}) {
2456 0           $rd->{_arsobject_update} =$rd->{_arsobject_delete} =undef;
2457 0           next if $arg{-filter}
2458 0 0 0       && !&{$arg{-filter}}($s,\%arg,$s->{'-meta-sql'}->{$tbl},$rw,$rd);
2459 0   0       sleep($arg{-sleep} ||0);
2460 0           $ci++;
2461 0 0         $s->entryIns(-form=>$arg{-form}, -echo=>$arg{-echo}
2462 0           , map {defined($rw->{$_}) ? ($_ => $rw->{$_}) : ()} keys %$rw);
2463             }
2464 0 0         my $sql = $rd->{_arsobject_insert} || $rd->{_arsobject_delete}
2465             ? ('DELETE FROM ' .$tbc
2466             .' WHERE ' .$s->{-dbi}->quote_identifier($fpk->{COLUMN_NAME}) .' =' .$s->{-dbi}->quote($rd->{$fpk->{COLUMN_NAME}}))
2467             : ('UPDATE ' .$tbc .' SET '
2468 0 0 0       .join(', ', map { !exists($rd->{$_})
2469             ? ()
2470             : ($s->{-dbi}->quote_identifier($_) .' =NULL')
2471             } '_arsobject_insert','_arsobject_update', '_arsobject_delete')
2472             .' WHERE ' .$s->{-dbi}->quote_identifier($fpk->{COLUMN_NAME}) .' =' .$s->{-dbi}->quote($rd->{$fpk->{COLUMN_NAME}}));
2473 0 0         print "$sql;\n" if exists($arg{-echo}) ? $arg{-echo} : $s->{-echo};
    0          
2474 0           $s->{-dbi}->do($sql)
2475 0 0         || &{$s->{-die}}($s->efmt($s->{-dbi}->errstr,$sql,undef,'dbidsrpl',$arg{-form}));
2476             }
2477 0           @rq =();
2478             }
2479             }
2480 0 0         if ($arg{-ckdel}) {
2481 0           my $cnl ='';
2482 0           my $dbr =[];
2483 0           while ($dbr) {
2484 0 0         my $sql ='SELECT ' .$s->{-dbi}->quote_identifier($fpk->{COLUMN_NAME})
2485             .' FROM ' .$tbc
2486             .($cnl ||$s->{'-meta-sql'}->{$tbl}->{-cols}->{_arsobject_insert}
2487 0 0 0       ? ' WHERE ' .join(' AND ', map {$_ ? "($_)" : ()
    0          
    0          
2488             } ($s->{'-meta-sql'}->{$tbl}->{-cols}->{_arsobject_insert} ? '_arsobject_insert IS NULL OR _arsobject_insert=0' : '')
2489             , ($cnl ? $s->{-dbi}->quote_identifier($fpk->{COLUMN_NAME}) .'<=' .$s->{-dbi}->quote($cnl) : ''))
2490             : '')
2491             .' ORDER BY 1 desc';
2492 0 0         print "$sql;\n" if exists($arg{-echo}) ? $arg{-echo} : $s->{-echo};
    0          
2493 0           my $dbq =$s->dbiquery($sql);
2494 0           my @cnd;
2495             my @rms;
2496 0   0       while (($dbr && ($dbr =$dbq->fetchrow_arrayref())) ||scalar(@cnd)) {
      0        
2497 0 0         if ($dbr) {
2498 0 0         push @cnd, $dbr->[0] =~/^([^\s]+)/i ? $1 : $dbr->[0];
2499             }
2500 0 0         if ($dbr ? scalar(@cnd) >=$arg{-lim_or} : scalar(@cnd)) {
    0          
2501 0           my %ars =map { ($_->{$fpk->{fieldName}} => 1)
  0            
2502             } $s->query(-form=>$arg{-form}
2503             ,-fields=>[$fpk->{fieldName}]
2504             ,-echo=>$arg{-echo}
2505             ,-query=>join(' AND '
2506             , $arg{-query} ? '(' .$arg{-query} .')' : ()
2507 0 0         , '(' .join(' OR ', map {"'" .$fpk->{fieldName} ."'=" .$s->arsquot($_)
2508             } @cnd) .')')
2509             );
2510 0           my @del =map { $ars{$_}
2511             ? ()
2512 0 0 0       : !$arg{-filter} || &{$arg{-filter}}($s,\%arg,$s->{'-meta-sql'}->{$tbl},undef,$_)
    0          
2513             ? $_
2514             : ()
2515             } @cnd;
2516 0 0         if (scalar(@del)) {
2517 0           $cnl =$del[$#del];
2518 0           $sql ="DELETE FROM $tbc WHERE "
2519 0           .join(' OR ', map {$s->{-dbi}->quote_identifier($fpk->{COLUMN_NAME}) .'=' .$s->{-dbi}->quote($_)
2520             } @del);
2521 0           push @rms, $sql;
2522 0           $cd +=scalar(@del);
2523             }
2524 0           @cnd =();
2525 0   0       sleep($arg{-sleep} ||0);
2526 0 0         if (scalar(@del)) {
2527 0           $dbq->finish();
2528 0           last;
2529             }
2530             }
2531             }
2532 0           foreach $sql (@rms) {
2533 0 0         print "$sql;\n" if exists($arg{-echo}) ? $arg{-echo} : $s->{-echo};
    0          
2534 0           $@ ='Unknown error';
2535 0           $s->{-dbi}->do($sql)
2536 0 0         || &{$s->{-die}}($s->efmt($s->{-dbi}->errstr,$sql,undef,'dbidsrpl',$arg{-form}));
2537             }
2538             }
2539             }
2540 0 0 0       if (!exists($arg{-ckupd}) || $arg{-ckupd}) {
2541 0           my $sqlm=0;
2542 0           local $s->{-strFields} =0;
2543 0           my $fpksql ='SELECT * FROM ' .$tbc .' WHERE ' .$fpk->{COLUMN_NAME} .'=';
2544 0           my $lm;
2545 0 0 0       if ($arg{-master} && $arg{-master_fk} && $fts) {
      0        
2546 0           my $mtb =$s->sqlname($arg{-master});
2547 0   0       my $mts =$arg{-master_ts} && ($s->{'-meta-sql'}->{$mtb}->{-fields}->{$arg{-master_ts}} ||$arg{-master_ts});
2548 0   0       my $mpk =$arg{-master_pk} && ($s->{'-meta-sql'}->{$mtb}->{-fields}->{$arg{-master_pk}} ||$arg{-master_pk});
2549 0   0       my $mfk =$arg{-master_fk} && ($s->{'-meta-sql'}->{$tbl}->{-fields}->{$arg{-master_fk}} ||$arg{-master_fk});
2550 0 0 0       if (!$mts ||!$mpk) {
2551 0           my $flds =$s->{'-meta-sql'}->{$tbl}->{-cols};
2552 0           foreach my $fn (sort keys %$flds) {
2553 0 0 0       $mts =$fn if !$mts && $flds->{$fn}->{IS_TIMESTAMP};
2554 0 0 0       $mpk =$fn if !$mpk && $flds->{$fn}->{IS_PK}
      0        
2555             && ($flds->{$fn}->{IS_PK} eq '1');
2556 0 0 0       last if $mts && $mpk;
2557             }
2558             }
2559 0 0         my $sql ='SELECT max(d.' .$s->{-dbi}->quote_identifier($fts->{COLUMN_NAME}) .')'
2560             .', max(m.' .$s->{-dbi}->quote_identifier($mts) .')'
2561             .' FROM '
2562 0           .join('.', map {defined($_) ? $_ : ()} $s->{-sqlschema}, $mtb)
2563             ." m, $tbc d"
2564             .' WHERE m.' .$s->{-dbi}->quote_identifier($mpk)
2565             .'=d.' .$s->{-dbi}->quote_identifier($mfk);
2566 0           my $mtv = $s->dbiquery($sql)->fetchrow_arrayref();
2567 0 0         print "$sql --> " .($mtv ? join(', ', map {$s->{-dbi}->quote(defined($_) ? $_ : 'undef')} @$mtv) : "'undef'") .";\n"
  0 0          
    0          
    0          
2568             if exists($arg{-echo}) ? $arg{-echo} : $s->{-echo};
2569 0 0 0       $mtv =!$mtv ||!$mtv->[0] ||!$mtv->[1]
    0          
2570             ? ''
2571             : $mtv->[0] lt $mtv->[1]
2572             ? $mtv->[0]
2573             : $mtv->[1];
2574 0 0         $sql ='SELECT count(*) FROM '
2575 0           .join('.', map {defined($_) ? $_ : ()} $s->{-sqlschema}, $mtb)
2576             .' WHERE '
2577             .$s->{-dbi}->quote_identifier($mts) .'=' .$s->{-dbi}->quote($mtv);
2578 0           my $mtc =$s->dbiquery($sql)->fetchrow_arrayref();
2579 0   0       $mtc =$mtc && $mtc->[0] ||0;
2580 0 0         my $mpv =$mtc >=($arg{-lim_rf} -$arg{-lim_rf} *0.1)
2581             ? $s->dbiquery('SELECT max(m.' .$s->{-dbi}->quote_identifier($mpk) .'), count(*)'
2582             .' FROM '
2583 0 0         .join('.', map {defined($_) ? $_ : ()} $s->{-sqlschema}, $mtb)
2584             ." m, $tbc d"
2585             .' WHERE m.' .$s->{-dbi}->quote_identifier($mpk)
2586             .'=d.' .$s->{-dbi}->quote_identifier($mfk)
2587             .' AND m.' .$s->{-dbi}->quote_identifier($mts) .'=' .$s->{-dbi}->quote($mtv)
2588             )->fetchrow_arrayref()
2589             : '';
2590 0   0       $mpv =$mpv && $mpv->[0] ||'';
2591 0 0 0       print "$sql --> $mtc;\n"
    0          
2592             if $mpv && (exists($arg{-echo}) ? $arg{-echo} : $s->{-echo});
2593 0 0         $sql ='SELECT ' .$s->{-dbi}->quote_identifier($mpk)
2594             .' FROM '
2595 0 0         .join('.', map {defined($_) ? $_ : ()} $s->{-sqlschema}, $mtb)
    0          
2596             .($mtv
2597             ? ' WHERE ' .$s->{-dbi}->quote_identifier($mts)
2598             .'>=' .$s->{-dbi}->quote($mtv)
2599             .($mpv
2600             ? ' AND ' .$s->{-dbi}->quote_identifier($mpk)
2601             .'>=' .$s->{-dbi}->quote($mpv)
2602             : '')
2603             : '')
2604             .' ORDER BY ' .$s->{-dbi}->quote_identifier($mts) .' ASC '
2605             .', ' .$s->{-dbi}->quote_identifier($mpk) .' ASC ';
2606 0 0         print "$sql;\n" if exists($arg{-echo}) ? $arg{-echo} : $s->{-echo};
    0          
2607 0           $lm =$s->{-dbi}->selectcol_arrayref($sql,{'MaxRows'=>$arg{-lim_rf}});
2608 0 0 0       return(&{$s->{-die}}($s->efmt($s->{-dbi}->errstr, undef, undef, 'selectcol_arrayref',$sql)))
  0            
2609             if !$lm && $s->{-dbi}->errstr;
2610             # print $s->dsquot($lm),"\n";
2611             # die('TEST')
2612             # -form=>'HPD:HelpDesk_AuditLogSystem'
2613             # ,-master=>'HPD:Help Desk', -master_pk=>'Entry ID',-master_fk=>'Original Request ID', -master_ts=>'Last Modified Date'
2614             }
2615 0           my ($rw, $rd) =({});
2616 0           my ($cs, $cw) =($cts,0);
2617 0 0         while ($lm ? scalar(@$lm) : 1) {
2618 0           $cw++;
2619 0 0 0       foreach my $r ($s->query(-form=>$arg{-form}
  0 0 0        
    0          
2620             ,-fields=>$arg{-fields}
2621             ,-echo=>$arg{-echo}
2622             ,$lm
2623             ? (-query=>join(' AND '
2624             , $arg{-query} ? '(' .$arg{-query} .')' : ()
2625             , '(' .join(' OR '
2626             , map {"'" .($s->{'-meta-sql'}->{$tbl}->{-cols}->{$arg{-master_fk}} && $s->{'-meta-sql'}->{$tbl}->{-cols}->{$arg{-master_fk}}->{fieldName} || $arg{-master_fk})
2627             ."'=\"$_\""
2628             } splice @$lm, 0, $arg{-lim_or}) .')'))
2629             : (-query=>join(' AND ', map {$_ ? "($_)" : ()
2630             } $arg{-query}, $fts && $vts ? "'" .$fts->{fieldName} ."'>=" .$vts : ()
2631             ) ||'1=1'
2632             ,-limit=>$arg{-lim_rf}
2633             ,-start=>$cs)
2634             ,-order=>$fts
2635             ? [$fts->{fieldName} => 'asc', $fpk->{fieldName} => 'asc']
2636             : [$fpk->{fieldName} => 'asc']
2637             )) {
2638 0           $cs++;
2639 0 0         next if !$r->{$fpk->{fieldName}};
2640 0           my $sql ='';
2641 0           $rd =$s->dbiquery($fpksql .$s->{-dbi}->quote($r->{$fpk->{fieldName}}))->fetchrow_hashref();
2642 0           my $ru;
2643 0           foreach my $f (@flds) {
2644 0 0 0       next if !$f->{fieldName} || !$f->{COLUMN_NAME} || !$f->{TYPE_NAME}
      0        
      0        
2645             || !exists($r->{$f->{fieldName}});
2646 0 0 0       $rw->{$f->{fieldName}} =!defined($r->{$f->{fieldName}})
    0 0        
    0          
2647             ? $r->{$f->{fieldName}}
2648             : $f->{TYPE_NAME} eq 'datetime'
2649             ? strtime($s, $r->{$f->{fieldName}})
2650             : ($f->{dataType} =~/^(?:char)$/) && $f->{COLUMN_SIZE}
2651             ? substr($r->{$f->{fieldName}}, 0, $f->{COLUMN_SIZE_DB} ||$f->{COLUMN_SIZE})
2652             : $r->{$f->{fieldName}};
2653 0 0 0       $rd->{$f->{COLUMN_NAME}} =$1
      0        
      0        
2654             if $rd
2655             && defined($rd->{$f->{COLUMN_NAME}})
2656             && ($f->{TYPE_NAME} =~/^(?:datetime|float)$/)
2657             && ($rd->{$f->{COLUMN_NAME}}=~/^(.+)\.0+$/);
2658 0 0 0       $rd->{$f->{COLUMN_NAME}} =defined($rw->{$f->{fieldName}}) && ($rw->{$f->{fieldName}} =~/\.(\d+)$/)
    0 0        
    0 0        
2659             ? sprintf('%.' .length($1) .'f', $rd->{$f->{COLUMN_NAME}})
2660             : $rd->{$f->{COLUMN_NAME}} =~/^(.+)\.0+$/
2661             ? $1
2662             : $rd->{$f->{COLUMN_NAME}}
2663             if $rd
2664             && defined($rd->{$f->{COLUMN_NAME}})
2665             && ($f->{TYPE_NAME} eq 'float');
2666 0 0 0       $rd->{$f->{COLUMN_NAME}} =substr($rd->{$f->{COLUMN_NAME}}, 0, $f->{COLUMN_SIZE_DB} ||$f->{COLUMN_SIZE})
      0        
      0        
      0        
2667             if $rd
2668             && defined($rd->{$f->{COLUMN_NAME}})
2669             && ($f->{dataType} =~/^(?:char)$/) && $f->{COLUMN_SIZE};
2670 0 0 0       $ru =1 if $rd
    0 0        
2671             && (defined($rd->{$f->{COLUMN_NAME}})
2672             ? !defined($rw->{$f->{fieldName}})
2673             || ($rd->{$f->{COLUMN_NAME}} ne $rw->{$f->{fieldName}})
2674             : defined($rw->{$f->{fieldName}}));
2675             }
2676 0 0         if (!$rd) {
    0          
2677 0           next if $arg{-filter}
2678 0 0 0       && !&{$arg{-filter}}($s,\%arg,$s->{'-meta-sql'}->{$tbl},$rw,$rd);
2679 0 0 0       $sql ='INSERT INTO ' .$tbc .' ('
2680             .join(', '
2681 0 0 0       , map { !exists($rw->{$_->{fieldName}})
2682             || !defined($rw->{$_->{fieldName}})
2683             ? ()
2684             : $s->{-dbi}->quote_identifier($_->{COLUMN_NAME})
2685             } @flds)
2686             .') VALUES ('
2687             .join(', '
2688 0           , map { !exists($rw->{$_->{fieldName}})
2689             || !defined($rw->{$_->{fieldName}})
2690             ? ()
2691             : $s->{-dbi}->quote($rw->{$_->{fieldName}})
2692             } @flds)
2693             .')';
2694 0           $ci++;
2695             }
2696             elsif ($ru) {
2697 0 0 0       next if (!exists($arg{-ckpush}) ||$arg{-ckpush})
      0        
      0        
2698             && ($rd->{'_arsobject_insert'}
2699             || $rd->{'_arsobject_update'}
2700             || $rd->{'_arsobject_delete'});
2701 0           next if $arg{-filter}
2702 0 0 0       && !&{$arg{-filter}}($s,\%arg,$s->{'-meta-sql'}->{$tbl},$rw,$rd);
2703 0 0         $sql ='UPDATE ' .$tbc .' SET '
    0          
2704             .join(', '
2705             ,(exists($arg{-ckpush}) && !$arg{-ckpush}
2706             && $s->{'-meta-sql'}->{$tbl}->{-cols}->{_arsobject_insert}
2707             ? '_arsobject_insert=NULL, _arsobject_update=NULL, _arsobject_delete=NULL'
2708             : ())
2709 0 0 0       , map { !exists($rw->{$_->{fieldName}})
2710             ? ()
2711             : ($s->{-dbi}->quote_identifier($_->{COLUMN_NAME}) .' ='
2712             .(!defined($rw->{$_->{fieldName}})
2713             ? 'NULL'
2714             : $s->{-dbi}->quote($rw->{$_->{fieldName}})
2715             ))
2716             } @flds)
2717             .' WHERE ' .$s->{-dbi}->quote_identifier($fpk->{COLUMN_NAME}) .' =' .$s->{-dbi}->quote($rw->{$fpk->{fieldName}});
2718 0           $cu++
2719             }
2720 0 0         if ($sql) {
2721             # local $s->{-dbi}->{LongTruncOk} =1;
2722 0 0         print "$sql;\n" if exists($arg{-echo}) ? $arg{-echo} : $s->{-echo};
    0          
2723 0           $s->{-dbi}->do($sql)
2724 0 0         || &{$s->{-die}}($s->efmt($s->{-dbi}->errstr,$sql,undef,'dbidsrpl',$arg{-form}));
2725             }
2726             }
2727 0 0 0       if (!$fts && ($cs == $cw *$arg{-lim_rf})) {
    0          
2728 0   0       sleep($arg{-sleep} ||0);
2729 0           next;
2730             }
2731             elsif ($lm) {
2732 0   0       sleep($arg{-sleep} ||0);
2733 0           next;
2734             }
2735 0           last;
2736             }
2737 0 0 0       if ($arg{-unused} && ($fts ? $vts : 1)) {
    0          
2738 0 0 0       my $sql ='DELETE FROM ' .$tbc .' WHERE '
      0        
2739             .dbidsqq($s
2740             , $vts && $fts ? '(' .$fts->{COLUMN_NAME} .'<' .$s->{-dbi}->quote($s->strtime($vts||0)) .') AND (' .$arg{-unused} .')' : $arg{-unused}
2741             , $s->{'-meta-sql'}->{$tbl});
2742 0 0         print "$sql;\n" if exists($arg{-echo}) ? $arg{-echo} : $s->{-echo};
    0          
2743             my $n= $s->{-dbi}->do($sql)
2744 0   0       || &{$s->{-die}}($s->efmt($s->{-dbi}->errstr,$sql,undef,'dbidsrpl',$arg{-form}));
2745 0           $cd +=$n;
2746             }
2747             }
2748 0 0 0       join(', ', map {$_ ? $_ : ()} $ci && "new $ci", $cu && "upd $cu", $cd && "del $cd")
  0 0 0        
      0        
2749             ||'up-to-date'
2750             }
2751            
2752            
2753             sub dbidsquery { # DBI datastore - query data alike ARS
2754 0     0 1   my ($s, %arg) =@_;
2755             # -form => ARS form || -from => sql table name
2756             # -fields=> ARS fields || -select=>sql select list
2757             # -query=> ARS query || -where => sql where
2758             # -order =>
2759             # -filter=> undef
2760             # -undefs=>1
2761             # -strFields=>1|0
2762 0           my $m =$s->{'-meta-sql'}->{$s->sqlname($arg{-form})};
2763 0   0       my $sql =join(' ', 'SELECT'
2764             ,(ref($arg{-fields})
2765 0           ? join(', ', map {$s->{-dbi}->quote_identifier($m->{-fields}->{$_} || $m->{-ids}->{$_} || $_)
2766 0 0         } @{$arg{-fields}})
2767             : $arg{-fields} && ($arg{-fields} ne '*')
2768             ? dbidsqq($s, $arg{-fields}, $m)
2769             : ($arg{-fields} ||$arg{-select} ||'*')
2770             )
2771             ,'FROM'
2772             ,($arg{-from}
2773             ? $arg{-from}
2774             : join('.', map {defined($_) ? $_ : ()} $s->{-sqlschema}, $s->sqlname($arg{-form})))
2775             ,($arg{-where}
2776             ? 'WHERE ' .$arg{-where}
2777             : $arg{-query}
2778             ? 'WHERE ' .dbidsqq($s, $arg{-query}, $m)
2779             : '')
2780             ,(ref($arg{-order})
2781             ? 'ORDER BY '
2782 0 0 0       .(do{ my $r ='';
  0 0 0        
    0          
    0          
    0          
    0          
    0          
2783 0           my $i =0;
2784 0           foreach my $e (@{$arg{-order}}) {
  0            
2785 0 0 0       $r .= $i && ($e =~/^(asc|1)$/)
    0 0        
    0 0        
2786             ? ' asc'
2787             : $i && ($e =~/^(desc|2)$/)
2788             ? ' desc'
2789             : (($r ? ',' : '')
2790             .$s->{-dbi}->quote_identifier($m->{-fields}->{$e} || $m->{-ids}->{$e} || $e)
2791             );
2792 0           $i =!$i;
2793             }
2794 0           $r})
2795             : $arg{-order}
2796             ? ('ORDER BY ' .$arg{-order})
2797             : '')
2798             );
2799 0 0         print "$sql;\n" if exists($arg{-echo}) ? $arg{-echo} : $s->{-echo};
    0          
2800 0 0         local $s->{-dbi}->{LongReadLen} =$s->{-dbi}->{LongReadLen} <= 1024 ? 4*64*1024 : $s->{-dbi}->{LongReadLen};
2801 0           my $h =$s->dbiquery($sql);
2802 0   0       my $xu=exists($arg{-undefs}) && !$arg{-undefs};
2803 0   0       my $yc=$arg{-select} ||ref($arg{-fields})
2804             || ($arg{-fields} && ($arg{-fields} eq '*'));
2805 0 0         my $ys=defined($arg{-strFields}) ? $arg{-strFields} : $s->{-strFields};
2806 0 0         local $s->{-strFields} =defined($arg{-strFields}) ? $arg{-strFields} : $s->{-strFields};
2807 0           my ($r, $r1, @r);
2808 0           while ($r =$h->fetchrow_hashref()) {
2809 0 0 0       $r1 ={map { $xu && !defined($r->{$_})
  0 0 0        
    0 0        
    0 0        
    0          
    0          
2810             ? ()
2811             : $m->{-cols}->{$_} && $m->{-cols}->{$_}->{fieldName} && $m->{-cols}->{$_}->{fieldId}
2812             ? ($m->{-cols}->{$_}->{fieldName}
2813             =>
2814             (!defined($r->{$_})
2815             ? $r->{$_}
2816             : $ys && ($m->{-cols}->{$_}->{dataType} eq 'enum')
2817             ? $s->strOut($arg{-form}, $m->{-cols}->{$_}->{fieldId}, $r->{$_})
2818             : ($m->{-cols}->{$_}->{TYPE_NAME} =~/^(?:datetime|float)$/) && ($r->{$_} =~/^(.+)\.0+$/)
2819             ? $1
2820             : $r->{$_}))
2821             : $yc
2822             ? ($_ => $r->{$_})
2823             : ()
2824             } keys %$r};
2825 0 0 0       next if $arg{-filter} && !&{$arg{-filter}}($s,$r1);
  0            
2826 0           push @r, $r1;
2827             }
2828             @r
2829 0           }
2830            
2831            
2832             sub dbidsqq { # DBI datastore - quote/parse condition to SQL names
2833 0     0 0   my ($s,$sf,$mh) =@_; # (self, query string, default sql metadata)
2834 0           if (0) {
2835             my $q =substr($s->{-dbi}->quote_identifier(' '),0,1);
2836             $sf =~s/$q([^$q]+)$q\.$q([^$q]+)$q/!$s->{'-meta-sql'}->{-forms}->{$1} ? "?1$q$1${q}.$q$2$q" : $s->{'-meta-sql'}->{$s->{'-meta-sql'}->{-forms}->{$1}}->{-fields}->{$2} ? $s->{-dbi}->quote_identifier($s->{'-meta-sql'}->{-forms}->{$1}) .'.' .$s->{-dbi}->quote_identifier($s->{'-meta-sql'}->{$s->{'-meta-sql'}->{-forms}->{$1}}->{-fields}->{$2}) : $s->{'-meta-sql'}->{$s->{'-meta-sql'}->{-forms}->{$1}}->{-ids}->{$2} ? $s->{-dbi}->quote_identifier($s->{'-meta-sql'}->{-forms}->{$1}) .'.' .$s->{-dbi}->quote_identifier($s->{'-meta-sql'}->{$s->{'-meta-sql'}->{-forms}->{$1}}->{-ids}->{$2}) : "?2$q$1${q}.$q$2$q"/ge;
2837             $sf =~s/$q([^$q]+)$q/$s->{'-meta-sql'}->{-forms}->{$1} ? ($s->{-sqlschema} ? $s->{-dbi}->quote_identifier($s->{-sqlschema}) .'.' : '') .$s->{-dbi}->quote_identifier($s->{'-meta-sql'}->{-forms}->{$1}) : $mh->{-fields}->{$1} ? $s->{-dbi}->quote_identifier($mh->{-fields}->{$1}) : $mh->{-ids}->{$1} ? $s->{-dbi}->quote_identifier($mh->{-ids}->{$1}) : "$q$1$q"/ge;
2838             return($sf);
2839             }
2840 0 0         my $qs =$s->{-dbi}->quote('w') =~/^([^w]+)w/ ? $1 : "'";
2841 0 0         my $qi =$s->{-dbi}->quote_identifier('w') =~/^([^w]+)w/ ? $1 : '"';
2842 0 0         my $qsq=$s->{-dbi}->quote("'w") =~/^([^w]+)w/ ? $1 : "''";
2843 0 0         my $qiq=$s->{-dbi}->quote_identifier('"w') =~/^([^w]+)w/ ? $1 : '""';
2844 0           my $qit=$qi .'.' .$qi;
2845 0           my $sr ='';
2846 0           my $m =undef;
2847 0           while ($sf =~/^(.*?)(\Q$qs\E|\Q$qi\E)(.*)/) {
2848 0 0         if ($2 eq $qi) {
    0          
2849 0           $sr .=$1 .$2;
2850 0           $sf =$3;
2851 0           my ($st,$sn) =('','');
2852 0           while (1) {
2853 0 0         if (!($sf =~/^(.*?)(\Q$qiq\E|\Q$qit\E|\Q$qi\E)(.*)/)) {
    0          
    0          
2854 0 0         return($sr .($st ? $st .$qit : '') .$sn .$sf)
2855             }
2856             elsif ($2 eq $qiq) {
2857 0           $sn .=$1 .$2;
2858 0           $sf =$3;
2859             next
2860 0           }
2861             elsif ($2 eq $qit) {
2862 0           $st =$sn .$1;
2863 0           $sn ='';
2864 0           $sf =$3;
2865             next
2866 0           }
2867             else {
2868 0           $sn .=$1;
2869 0           $sf =$3;
2870 0   0       $st =$st && $s->{'-meta-sql'}->{-forms}->{$st} || $st;
2871 0 0 0       $sn =$st && $s->{'-meta-sql'}->{$st}
      0        
      0        
2872             ? ($s->{'-meta-sql'}->{$st}->{-fields}->{$sn}
2873             || $s->{'-meta-sql'}->{$st}->{-ids}->{$sn}
2874             || $sn)
2875             : ($mh->{-fields}->{$sn}
2876             || $mh->{-ids}->{$sn}
2877             || ($s->{'-meta-sql'}->{-forms}->{$sn}
2878             && (($s->{-sqlschema} ? $s->{-sqlschema} .$qit : '')
2879             .$s->{'-meta-sql'}->{-forms}->{$sn}))
2880             || $sn);
2881 0 0         $sr .=($st ? $st .$qit : '') .$sn .$qi;
2882             last
2883 0           }
2884             }
2885             }
2886             elsif ($2 eq $qs) {
2887 0           $sr .=$1 .$2;
2888 0           $sf =$3;
2889 0           while (1) {
2890 0 0         if (!($sf =~/^(.*?)(\Q$qsq\E|\Q$qs\E)(.*)/)) {
    0          
2891 0           return($sr .$sf)
2892             }
2893             elsif ($2 eq $qsq) {
2894 0           $sr .=$1 .$2;
2895 0           $sf =$3;
2896             next
2897 0           }
2898             else {
2899 0           $sr .=$1 .$2;
2900 0           $sf =$3;
2901             last
2902 0           }
2903             }
2904             }
2905             }
2906 0           $sr .$sf
2907             }
2908            
2909            
2910            
2911             sub cgi { # CGI object
2912 0 0   0 1   return($_[0]->{-cgi}) if $_[0]->{-cgi};
2913 0           cgiconnect(@_)
2914             }
2915            
2916            
2917             sub cgiconnect {# Connect CGI
2918 0     0 1   my $s =shift;
2919 1     1   22126 no warnings;
  1         3  
  1         1004  
2920 0           local $^W =0;
2921 0   0       $ENV{HTTP_USER_AGENT} =$ENV{HTTP_USER_AGENT}||'';
2922 0 0 0       $ENV{PERLXS} ='PerlIS' if !$ENV{PERLXS} && ($^O eq 'MSWin32') && $0 =~/[\\\/]perlis\.dll$/i;
      0        
2923 0           eval('use CGI; 1')
2924 0 0         ||return(&{$s->{-die}}($s->efmt('No CGI')));
2925             $s->{-cgi} =$CGI::Q =$CGI::Q =eval{CGI->new(@_)}
2926             ||return($s->{-die}
2927 0   0       ? &{$s->{-die}}($s->efmt($@, undef, undef, 'cgi'))
2928             : CORE::die($s->efmt($@, undef, undef, 'cgi')));
2929 0 0         $s->set(-die=>'CGI::Carp fatalsToBrowser') if !$s->{-die};
2930 0 0         return(&{$s->{-die}}($s->efmt($s->{-cgi}->{'.cgi_error'}, undef, undef, 'cgi')))
  0            
2931             if $s->{-cgi}->{'.cgi_error'};
2932 0           if (1) { # parse parameters
2933             # __C_ change(d),
2934             # __O_ open, __L_ listbox choise, __S_ set, __X_ close
2935             # __P_ previous value
2936             # __B_ button for javascript
2937 0           foreach my $p ($s->{-cgi}->param) {
2938 0 0         if ($p =~/^(.+?)__S_$/) {
    0          
2939 0           $s->{-cgi}->param($1, $s->{-cgi}->param("$1__L_"));
2940 0           $s->{-cgi}->param("$1__C_", 1);
2941 0           $s->{-cgi}->delete("$1__L_");
2942             }
2943             elsif ($p =~/^(.+?)__X_$/) {
2944 0 0         if (defined($s->{-cgi}->param("$1__P_"))) {
2945 0           $s->{-cgi}->param($1, $s->{-cgi}->param("$1__P_"));
2946             }
2947             else {
2948 0           $s->{-cgi}->delete($1);
2949             }
2950 0           $s->{-cgi}->delete("$1__L_");
2951             }
2952             }
2953 0           foreach my $p ($s->{-cgi}->param) {
2954 0 0         if ($p =~/^(.+?)__L_$/) {
2955             # $s->{-cgi}->param($1, $s->{-cgi}->param("$1__L_"));
2956             # $s->{-cgi}->param("$1__C_", 1);
2957 0           $s->{-cgi}->delete("$1__L_");
2958             }
2959             }
2960             }
2961 0           $s->{-cgi}
2962             }
2963            
2964            
2965             sub cgipar { # CGI parameter
2966 0     0 1   $_[0]->{-cgi}->param(@_[1..$#_])
2967             }
2968            
2969            
2970             sub cgiurl { # CGI script URL
2971 0     0 0   local $^W =0; # $ENV{PATH_INFO}
2972 0 0         if ($#_ >0) {
2973 0   0       my $v =($_[0]->{-cgi}||$_[0]->cgi)->url(@_[1..$#_]);
2974 0 0 0       if ($v) {}
    0 0        
    0 0        
    0          
    0          
2975             elsif (!($ENV{PERLXS} ||(($ENV{GATEWAY_INTERFACE}||'') =~/PerlEx/))) {}
2976             elsif (($#_ >2) ||(($#_ ==2) && !$_[2])) {}
2977             elsif ($_[1] eq '-relative') {
2978 0           $v =$ENV{SCRIPT_NAME};
2979 0 0         $v =$1 if $v =~/[\\\/]([^\\\/]+)$/;
2980             }
2981             elsif ($_[1] eq '-absolute') {
2982 0           $v =$ENV{SCRIPT_NAME}
2983             }
2984 0           return($v)
2985             }
2986             else {
2987             # MSDN: "GetServerVariable (ISAPI Extensions)"
2988             # ms-help://MS.MSDNQTR.v90.en/wcecomm5/html/wce50lrfGetServerVariableISAPIExtensions.htm
2989             # http:// $ENV{HTTP_HOST} : $ENV{SERVER_PORT} / ($ENV{PATH_INFO} | $ENV{SCRIPT_NAME})
2990             # + $ENV{QUERY_STRING}
2991 0   0       my $v =($_[0]->{-cgi}||$_[0]->cgi)->url();
2992 0 0 0       if ($ENV{PERLXS} ||(($ENV{GATEWAY_INTERFACE}||'') =~/PerlEx/)) {
      0        
2993 0 0 0       $v .= (($v =~/\/$/) ||($ENV{SCRIPT_NAME} =~/^\//) ? '' : '/')
    0 0        
2994             .$ENV{SCRIPT_NAME}
2995             if ($v !~/\w\/\w/) && $ENV{SCRIPT_NAME};
2996             }
2997 0           return($v)
2998             }
2999             }
3000            
3001            
3002             sub cgitext { # CGI textarea field
3003 0     0 1   $_[0]->{-cgi}->textarea(@_[1..$#_])
3004             # -default=>$v, -override=>1
3005             }
3006            
3007            
3008             sub cgistring { # CGI string field
3009 0     0 1   $_[0]->{-cgi}->textfield(@_[1..$#_])
3010             }
3011            
3012            
3013             sub cgiselect { # CGI selection field composition
3014             # -onchange=>1 reloads form
3015 0     0 1   my ($s, %a) =@_;
3016 0   0       my $cs =$a{-onchange} && (length($a{-onchange}) ==1);
3017 1         6 ($cs
3018             ? ''
3019             : '')
3020             .$s->{-cgi}->popup_menu(%a
3021             , $a{-labels} && !$a{-values}
3022 1 0 0 1   7 ? (-values => do{use locale; [sort {$a{-labels}->{$a} cmp $a{-labels}->{$b}} keys %{$a{-labels}}]})
  1 0 0     2  
  0 0          
  0 0          
  0            
  0            
3023             : ()
3024             , $cs
3025             ? (-onchange => '{window.document.forms[0].' .$a{-name} .'__C_.value="1"; window.document.forms[0].submit(); return(false)}')
3026             : ()
3027             )
3028             .( $cs && ($a{-onchange}=~/^\d/) && $s->{-cgi}->param($a{-name} .'__C_')
3029             ? ''
3030             : '')
3031             }
3032            
3033            
3034             sub cgiddlb { # CGI drop-down listbox field composition
3035             # -strict=> - disable text edit, be alike cgiselect
3036 0     0 1   my ($s, %a) =@_;
3037 0           $s->cgi();
3038 0           my $n =$a{-name};
3039 0           my $nl="${n}__L_";
3040 0 0   0     my $av=sub{ return($a{-values}) if $a{-values};
3041 1     1   196 use locale;
  1         3  
  1         17  
3042 0 0         $a{-values} =[
    0          
3043             $a{-labels0}
3044 0           ? sort {(defined($a{-labels0}->{$a}) ? $a{-labels0}->{$a} : '')
3045             cmp (defined($a{-labels0}->{$b}) ? $a{-labels0}->{$b} : '')
3046 0 0         } keys %{$a{-labels0}}
    0          
3047             : ()
3048 0           , (sort {(defined($a{-labels}->{$a}) ? $a{-labels}->{$a} : '')
3049             cmp (defined($a{-labels}->{$b}) ? $a{-labels}->{$b} : '')
3050 0 0         } keys %{$a{-labels}})
    0          
3051             , $a{-labels1}
3052 0           ? sort {(defined($a{-labels1}->{$a}) ? $a{-labels1}->{$a} : '')
3053             cmp (defined($a{-labels1}->{$b}) ? $a{-labels1}->{$b} : '')
3054 0 0         } keys %{$a{-labels1}}
    0          
3055             : ()
3056             ];
3057 0           foreach my $e ('-labels0','-labels1') {
3058 0 0         next if !$a{$e};
3059 0           foreach my $k (keys %{$a{$e}}) {
  0            
3060 0           $a{-labels}->{$k} =$a{$e}->{$k}
3061             }
3062             }
3063             $a{-values}
3064 0           };
  0            
3065 0 0         my $ac=$a{-class} ? ' class="' .$a{-class} .'"' : '';
3066 0 0         my $as=$a{-style} ? ' style="' .$a{-style} .'"' : '';
3067 0   0       my $aw=$a{-size} ||80;
3068 0 0 0       my $v =!defined($s->{-cgi}->param($n)) ||$a{-override}
3069             ? $a{-default}
3070             : $s->{-cgi}->param($n);
3071             $v =&$av()->[0]
3072 0 0 0       if $a{-strict} && (!defined($v) || !grep /^\Q$v\E$/, @{&$av()});
      0        
3073 0 0         $s->{-cgi}->param($n, defined($v) ? $v : '');
3074 0 0         my $ek =$s->{-cgi}->user_agent('MSIE') ? 'window.event.keyCode' : 'event.which';
3075             my $fs =sub{
3076 0 0 0 0     '{var k;'
    0 0        
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3077             ."var l=window.document.forms[0].$nl;"
3078             ."if(l.style.display=='none'){"
3079             .($_[0] eq '4' ? '' : 'return(true)') .'}else{'
3080             .(!$_[0] # onkeypess - input
3081             ? "if (String.fromCharCode($ek) ==\"\\r\") {${n}__S_.focus(); ${n}__S_.click(); return(true)}; k=window.document.forms[0].$n.value +String.fromCharCode($ek);"
3082             : $_[0] eq '1' # onkeypess - list -> input (first char)
3083             ? "if (String.fromCharCode($ek) ==\"\\r\") {${n}__S_.focus(); ${n}__S_.click(); return(true)}; window.document.forms[0].$n.focus(); k=window.document.forms[0].$n.value =String.fromCharCode($ek); "
3084             : $_[0] eq '2' # onkeypess - list -> prompt (selected char)
3085             # ? "k=prompt('Enter search string',String.fromCharCode($ek));"
3086             ? "if (String.fromCharCode($ek) ==\"\\r\") {${n}__S_.focus(); ${n}__S_.click(); return(true)}; k =String.fromCharCode($ek); for (var i=0; i
3087             : $_[0] eq '3' # button - '..'
3088             ? "k=prompt('Enter search substring',''); $nl.focus();"
3089             : $_[0] eq '4' # onload - document
3090             ? "k=window.document.forms[0].$n.value; window.document.forms[0].$nl.focus();"
3091             : ''
3092             )
3093             .'if(k){'
3094             .'k=k.toLowerCase();'
3095             .'for (var i=0; i
3096             .($_[0] eq '4'
3097             ? 'if (l.options.item(i).value.toLowerCase() ==k){'
3098             : $s->{-cgi}->user_agent('MSIE')
3099             ? "if (l.options.item(i).innerText !='' ? l.options.item(i).innerText.toLowerCase().indexOf(k)"
3100             .($_[0] eq '3' ?'>=' :'==') .'0 : l.options.item(i).value.toLowerCase().indexOf(k)'
3101             .($_[0] eq '3' ?'>=' :'==') .'0){'
3102             : "if (l.options.item(i).text !='' ? l.options.item(i).text.toLowerCase().indexOf(k)"
3103             .($_[0] eq '3' ?'>=' :'==') .'0 : l.options.item(i).value.toLowerCase().indexOf(k)'
3104             .($_[0] eq '3' ?'>=' :'==') .'0){')
3105             .'l.selectedIndex =i; break;};}};'
3106             .($_[0] && ($_[0] ne '4')
3107             ? 'return(false);'
3108             : $_[0] && ($_[0] eq '2')
3109             ? 'return(false);'
3110             : '')
3111 0           .'}}'};
3112            
3113 0 0 0       ($s->{-cgi}->param("${n}__O_")
    0 0        
3114             ? "
\n"
3115             : '')
3116 0 0         .$s->{-cgi}->textfield((map {defined($_) && defined($a{$_})
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3117             ? ($_ => $a{$_})
3118             : $a{-textfield} && $a{-textfield}->{$_} && !$s->{-cgi}->param("${n}__O_")
3119             ? ($_ => $a{-textfield}->{$_})
3120             : ()
3121             } qw(-name -title -class -style -size -maxlength))
3122             , -default=>$v
3123             , -override=>1
3124             , ($a{-strict} && !$s->{-cgi}->param("${n}__O_")
3125             ? (-readonly=>1) # ,-hidefocus=>0, -disabled=>0
3126             : ())
3127             )
3128             .($s->{-cgi}->param("${n}__O_")
3129             ? (""
3130             ."{-cgi}->escapeHTML($v) : '') ."\"$ac$as />\n"
3131             ."
\n"
3132             ."
3133             ."$ac$as"
3134             ." ondblclick=\"{${n}__S_.focus(); ${n}__S_.click(); return(true)}\""
3135             ." onkeypress=\"" .($s->{-cgi}->user_agent('MSIE') ? &$fs(1) : &$fs(2))
3136             ."\">\n"
3137 0           .join('',map {'
3138             .((defined($v) ? $v : '') eq (defined($_) ? $_ : '') ? ' selected' : '')
3139             .' value="' .$s->{-cgi}->escapeHTML(defined($_) ? $_ : '') .'">'
3140             .$s->{-cgi}->escapeHTML(
3141             !defined($_)
3142             ? ''
3143             : !$a{-labels}
3144             ? (length($_) > $aw ? substr($_,0,$aw) .'...' : $_)
3145             : defined($a{-labels}->{$_})
3146             ? (length($a{-labels}->{$_}) > $aw ? substr($a{-labels}->{$_},0,$aw) .'...' : $a{-labels}->{$_})
3147             : '') ."\n"
3148 0 0 0       } @{&$av()})
    0 0        
    0          
    0          
    0          
    0          
3149             ."\n"
3150             .""
3151             .$s->{-cgi}->button(-value=>'...', -title=>'find', -onClick=>&$fs(3))
3152             .""
3153             ."\n"
3154             .""
3155             )
3156             : (""
3157             .($s->{-cgi}->param("${n}__C_") ||$s->{-cgi}->param("${n}__X_")
3158             ? ""
3159             : ''
3160             ))
3161             )
3162             }
3163            
3164            
3165             sub cgiesc { # escape strings to html
3166 0     0 1   $_[0]->{-cgi}->escapeHTML(@_[1..$#_])
3167             }
3168            
3169            
3170             sub cgitfrm { # table form layot
3171             # -form =>{form attrs}, -table=>{table attrs}, -tr=>{tr attrs}, -td=>{}, -th=>{}
3172 0     0 1   my ($s, %a) =$_[0];
3173 0           my $i =1;
3174 0           while (ref($_[$i]) ne 'ARRAY') {$a{$_[$i]} =$_[$i+1]; $i +=2};
  0            
  0            
3175 0           $s->cgi->start_form(-method=>'POST',-action=>'', $a{-form} ? %{$a{-form}} : ())
  0            
3176             # ,-name=>'test'
3177             .$s->{-cgi}->table($a{-table} ? $a{-table} : (), "\n"
3178             .join(''
3179 0 0         , map { my $r =$_;
    0          
3180 0 0 0       $s->{-cgi}->Tr($a{-tr} ? $a{-tr} : (), "\n"
      0        
3181             .join(''
3182 0 0         , map { ($_ =~/^
3183             ? $s->{-cgi}->td($a{-td} || {-align=>'left', -valign=>'top'}, $_)
3184             : $s->{-cgi}->th($a{-th} || $a{-td} || {-align=>'left', -valign=>'top'}, $_)
3185             ) ."\n"
3186             } @$r)
3187             ) ."\n"
3188             } @_[$i..$#_])) ."\n"
3189             .$s->cgi->end_form()
3190             }
3191            
3192            
3193             sub smtpconnect {# Connect SMTP
3194 0     0 1   set(@_); # (-smtphost) -> self->{-smtp}
3195 0 0         set($_[0],-die=>'Carp') if !$_[0]->{-die};
3196 0           my $s =shift;
3197 1     1   1694 no warnings;
  1         2  
  1         6670  
3198 0           local $^W =0;
3199 0 0         eval('use Net::SMTP; 1') ||return(&{$s->{-die}}($@, $s->efmt('Net::SMTP')));
  0            
3200 0           $s->{-smtp} =eval {
3201 0           local $^W=undef;
3202 0           eval("use Net::SMTP");
3203 0 0         $s->{-smtphost}
3204             ? Net::SMTP->new($s->{-smtphost})
3205             : CORE::die($s->efmt('SMTP host name required'))
3206             };
3207 0 0 0       return(&{$s->{-die}}("SMTP host '" .($s->{-smtphost}||'') ."': $@\n"))
  0   0        
3208             if !$s->{-smtp} ||$@;
3209 0           $s->{-smtp}
3210             }
3211            
3212            
3213             sub smtp { # SMTP connection object
3214 0 0   0 1   return($_[0]->{-smtp}) if $_[0]->{-smtp};
3215 0           smtpconnect(@_)
3216             }
3217            
3218            
3219             sub smtpsend { # SMTP mail msg send
3220             # -from||-sender, -to||-recipient,
3221             # -data|| -subject + (-text || -html)
3222 0     0 1   my ($s, %a) =@_;
3223 0 0         return(&{$s->{-die}}("SMTP host not defined"))
  0            
3224             if !$s->{-smtphost};
3225 0     0     local $s->{-smtpdomain} =$s->{-smtpdomain}
3226 0   0       || ($s->{-smtphost} && $s->smtp(sub{$_[1]->domain()}))
3227             || 'nothing.net';
3228 0   0       $a{-from} =$a{-from} ||$a{-sender} ||$ENV{REMOTE_USER} ||$ENV{USERNAME};
3229 0 0         $a{-from} =&{$a{-from}}($s,\%a) if ref($a{-from}) eq 'CODE';
  0            
3230 0 0         $a{-to} =&{$a{-to}}($s,\%a) if ref($a{-to}) eq 'CODE';
  0            
3231 0 0 0       $a{-to} =[grep {$_} split /\s*[,;]\s*/, ($a{-to} =~/^\s*(.*)\s*$/ ? $1 : $a{-to})]
  0 0 0        
3232             if $a{-to} && !ref($a{-to}) && ($a{-to} =~/[,;]/);
3233 0   0       $a{-sender} =$a{-sender} ||$a{-from};
3234 0   0       $a{-recipient} =$a{-recipient} ||$a{-to};
3235 0 0         $a{-recipient} =&{$a{-recipient}}($s,\%a) if ref($a{-recipient}) eq 'CODE';
  0            
3236 0 0 0       $a{-recipient} =[grep {$_} split /\s*[,;]\s*/, ($a{-recipient} =~/^\s*(.*)\s*$/ ? $1 : $a{-recipient})]
  0 0 0        
3237             if $a{-recipient} && ref($a{-recipient}) && ($a{-recipient} =~/[,;]/);
3238 0 0         return(&{$s->{-die}}("SMTP e-mail recipients not defined"))
  0            
3239             if !$a{-recipient};
3240 0 0         if (!defined($a{-data})) {
3241 0   0       my $koi =(($a{-charset}||$s->charset()||'') =~/1251/);
3242 0           $a{-subject} = ref($a{-subject}) eq 'CODE'
3243 0 0 0       ? &{$a{-subject}}($s,\%a)
    0          
3244             : 'ARSObject'
3245             if ref($a{-subject}) ||!defined($a{-subject});
3246 0           $a{-data} ='';
3247 0 0         $a{-data} .='From: ' .($koi ? $s->cptran('ansi','koi',$a{-from})
3248             : $a{-from})
3249             ."\cM\cJ";
3250 0 0         $a{-data} .='Subject: '
3251             .($koi
3252             ? $s->cptran('ansi','koi',$a{-subject})
3253             : $a{-subject}) ."\cM\cJ";
3254 0           $a{-data} .='To: '
3255             .($koi
3256 0           ? $s->cptran('ansi','koi', ref($a{-to}) ? join(', ',@{$a{-to}}) : $a{-to})
3257 0 0         : (ref($a{-to}) ? join(', ',@{$a{-to}}) : $a{-to}))
    0          
    0          
    0          
3258             ."\cM\cJ"
3259             if $a{-to};
3260 0           foreach my $k (keys %a) {
3261 0 0         next if $k =~/^-(data|subject|html|text|from|to|sender|recipient)$/;
3262 0 0         next if !defined($a{$k});
3263 0 0         my $n =$k =~/^-(.+)/ ? ucfirst($1) .':' : $k;
3264 0           $a{-data} .=$n .' ' .$a{$k} ."\cM\cJ";
3265             }
3266 0           $a{-data} .="MIME-Version: 1.0\cM\cJ";
3267 0 0 0       $a{-data} .='Content-type: ' .($a{-html} ? 'text/html' : 'text/plain')
3268             .'; charset=' .($a{-charset}||$s->charset())
3269             ."\cM\cJ";
3270 0   0       $a{-data} .='Content-Transfer-Encoding: ' .($a{-encoding} ||'8bit') ."\cM\cJ";
3271 0           $a{-data} .="\cM\cJ";
3272 0   0       $a{-data} .=$a{-html} ||$a{-text} ||'';
3273             }
3274 0           local $^W=undef;
3275 0           $s->smtp->mail($a{-sender} =~/<\s*([^<>]+)\s*>/ ? $1 : $a{-sender})
3276 0 0 0       ||return(&{$s->{-die}}("SMTP sender \'" .$a{-sender} ."' -> " .($s->smtp->message()||'?')));
    0          
3277 0 0         $s->smtp->to(ref($a{-recipient})
    0          
3278 0           ? (map { !$_ ? () : /<\s*([^<>]+)\s*>/ ? $1 : $_ } @{$a{-recipient}})
  0            
3279             : $a{-recipient}, {'SkipBad'=>1}) # , {'SkipBad'=>1}
3280 0 0         || return(&{$s->{-die}}("SMTP recipient \'"
    0          
3281 0 0 0       .(ref($a{-recipient}) ? join(', ', (map { !$_ ? () : /<\s*([^<>]+)\s*>/ ? $1 : $_ } @{$a{-recipient}})) : $a{-recipient}) ."' -> " .($s->smtp->message()||'?')));
  0 0          
    0          
3282 0           $s->smtp->data($a{-data})
3283 0 0 0       ||return(&{$s->{-die}}("SMTP data '" .$a{-data} ."' -> " .($s->smtp->message()||'?')));
3284             my $r =$s->smtp->dataend()
3285 0   0       ||return(&{$s->{-die}}("SMTP dataend -> " .($s->smtp->message()||'?')));
3286 0 0         $r ||1;
3287             }
3288            
3289            
3290             sub soon { # Periodical execution of this script
3291             # (minutes ||sub{}, ?log file, ?run command, ?soon command)
3292             # minutes: undef - clear sched, run once || sub{} -> number
3293             # log file: empty || full file name || var file name
3294             # run command: empty || 'command line' || [command line] || sub{}
3295             # soon command: empty || 'command line' || [command line] || []
3296             # empty run command - only soon command will be scheduled
3297             # empty soon command - sleep(minutes*60) will be used
3298             # !defined(minutes) - soon command will be deleted from schedule
3299             # and run command will be executed once
3300             # [soon command,... [arg,...],...] - schedule cleaning hint:
3301             # join(' ',@{[soon,...arg]}) used to clean schedule
3302             # join('', @{[arg,...]}) used in soon command
3303 0     0 1   my ($s, $mm, $lf, $cr, $cs) =@_;
3304 0 0 0       $lf =$s->vfname($lf) if $lf && ($lf !~/[\\\/]/);
3305 0           my $wl;
3306 0 0         if (ref($cs) ? scalar(@$cs) : $cs) {
    0          
3307 0 0         return(&{$s->{-die}}("MSWin32 required for `at` in soon()\n"))
  0            
3308             if $^O ne 'MSWin32';
3309 0 0 0       if (defined($mm) && ($^O eq 'MSWin32') && eval('use Win32::Event; 1')) {
      0        
3310             # MSDN: 'CreateEvent', 'Kernel Object Namespaces'
3311 0           my $q =_sooncl($s, $cs, 1);
3312 0           my $n =$q;
3313 0           $n =~s/[\\]/!/g;
3314 0           $n ="Global\\$n";
3315             # sleep(60);
3316 0           $wl =Win32::Event->new(0,0,$n);
3317             # $s->fstore(">>$lf", $s->strtime() ."\t$$\tWin32::Event->new(0,0,$n) -> " .join(', ', $wl &&1 ||0, $^E ? ($^E +0) .".'$^E'" : ()) ."\n")
3318             # if $lf;
3319 0 0 0       if ($wl && $^E && ($^E ==183)) {
      0        
3320 0           print "Already '$q', done.\n";
3321 0 0         $s->fstore(">>$lf", "\n" .$s->strtime() ."\t$$\tAlready '$q', done.\n")
3322             if $lf;
3323 0           return(0);
3324             }
3325             }
3326 0 0         _sooncln($s, $mm, $lf, $wl ? '' : $cr, $cs, 1);
3327             }
3328 0           my $r =1;
3329 0           while (1) {
3330 0 0         if (!$cr) {
    0          
3331             }
3332             elsif (ref($cr) eq 'CODE') {
3333 0           local *OLDOUT;
3334 0           local *OLDERR;
3335 0 0         if ($lf) {
3336 0 0         eval{fileno(STDOUT) && open(OLDOUT, '>&STDOUT')};
  0            
3337 0 0         eval{fileno(STDERR) && open(OLDERR, '>&STDERR')};
  0            
3338 0           open(STDOUT, ">>$lf");
3339 0           open(STDERR, ">>$lf");
3340             }
3341 0           $r =&$cr(@_);
3342 0 0         if ($lf) {
3343 0 0 0       eval{fileno(OLDOUT) && close(STDOUT) && open(STDOUT, '>&OLDOUT')};
  0            
3344 0 0 0       eval{fileno(OLDERR) && close(STDERR) && open(STDERR, '>&OLDERR')};
  0            
3345             }
3346             }
3347             else {
3348 0           my $cmd =$cr;
3349 0 0         if (ref($cr) eq 'ARRAY') {
3350 0 0 0       $cr->[0] =Win32::GetFullPathName($cr->[0])
3351             if ($^O eq 'MSWin32') && ($cr->[0] !~/[\\\/]/);
3352 0 0         $cr->[0] = $cr->[0]=~/^(.+?)[^\\\/]+$/ ? $1 .'perl.exe' : $cr->[0]
    0          
3353             if $cr->[0] =~/\.dll$/i;
3354 0           $cmd =join(' ', @$cr);
3355             }
3356 0 0         if ($lf) {
3357 0           $cmd ="$cmd >>$lf 2>>\&1";
3358 0 0         print(($cs ? '' : "\n") ."$cmd\n");
3359 0 0         $s->fstore(">>$lf", ($cs ? '' : "\n") .$s->strtime() ."\t$$\t$cmd\n");
3360 0 0         if (system($cmd) <0) {
3361 0           $r =0;
3362 0           print("Error $!\n");
3363 0           $s->fstore(">>$lf", $s->strtime() ."\t$$\t$!\n");
3364             }
3365             }
3366             else {
3367 0 0         print(($cs ? '' : "\n") ."$cmd\n");
3368 0 0         if (system(ref($cr) ? @$cr : $cr) <0) {
    0          
3369 0           $r =0;
3370 0           print("Error $!\n");
3371             }
3372             }
3373             }
3374 0 0 0       last if $cs || !defined($mm);
3375 0 0         my $mmm =ref($mm) eq 'CODE' ? &$mm($s) : $mm;
3376 0           print "sleep(", $mmm *60, ")...\n";
3377 0 0         $s->fstore(">>$lf", $s->strtime() ."\t$$\tsleep(" .($mmm*60) .")...\n")
3378             if $lf;
3379 0           sleep($mmm *60);
3380             }
3381 0 0 0       if (defined($mm) && (ref($cs) ? scalar(@$cs) : $cs)) {
    0          
3382 0 0         _sooncln($s, $mm, $lf, $cr, $cs, 0) if !$wl;
3383 0 0         my $t1 =$s->strtime($s->timeadd(
3384             sprintf('%.0f', time()/60) *60
3385             , 0,0,0,0
3386             , ref($mm) eq 'CODE' ? &$mm($s) : $mm
3387             ));
3388 0 0         $t1 =$1 if $t1 =~/\s([^\s]+)/;
3389 0           my $cmd ="at $t1 /interactive " ._sooncl($s, $cs);
3390 0           print("$cmd\n");
3391 0 0         $s->fstore(">>$lf", $s->strtime() ."\t$$\t$cmd\n")
3392             if $lf;
3393 0 0         if (system($cmd) <0) {
3394 0           print("Error $!\n");
3395 0 0         $s->fstore(">>$lf", $s->strtime() ."\t$$\t$!\n")
3396             if $lf;
3397             }
3398             }
3399             $r
3400 0           }
3401            
3402            
3403            
3404             sub _sooncl { # soon() command line former
3405 0     0     my ($s, $cs, $q) =@_;
3406 0           my $nc;
3407 0           my $qry =$cs;
3408 0 0         if (ref($cs)) {
3409 0 0         return(&{$s->{-die}}("MSWin32 required for `at` in soon()\n"))
  0            
3410             if $^O ne 'MSWin32';
3411 0 0 0       $cs->[0] =Win32::GetFullPathName($cs->[0])
3412             if ($^O eq 'MSWin32') && ($cs->[0] !~/[\\\/]/);
3413 0 0         $cs->[0] = $cs->[0]=~/^(.+?)[^\\\/]+$/ ? $1 .'perl.exe' : $cs->[0]
    0          
3414             if $cs->[0] =~/\.dll$/i;
3415 0 0         $qry =$q ? join(' ', map { $nc
  0 0          
3416             ? ()
3417             : !defined($_)
3418             ? '""'
3419             : ref($_)
3420 0 0         ? (do{$nc =$_->[0]})
    0          
    0          
3421             : $_
3422             } @$cs)
3423 0 0         : join(' ', map {!defined($_) ? '""' : ref($_) ? join('', @$_) : $_
3424             } @$cs);
3425             }
3426             $qry
3427 0           }
3428            
3429            
3430             sub _sooncln { # soon() cleaner
3431 0     0     my ($s, $mm, $lf, $cr, $cs, $strt) =@_;
3432 0 0 0       $lf =$s->vfname($lf) if $lf && ($lf !~/[\\\/]/);
3433 0 0         if (ref($cs) ? scalar(@$cs) : $cs) {
    0          
3434 0           my $nc;
3435 0           my $qry =_sooncl($s, $cs, 1);
3436 0 0 0       print "Starting '$qry'...\n" if $strt && defined($mm);
3437 0 0 0       $s->fstore(">>$lf", "\n" .$s->strtime() ."\t$$\tStarting '$qry'...\n")
      0        
3438             if $strt && $lf && defined($mm);
3439 0 0 0       sleep(int(rand(20))) if $strt && defined($mm) && $cr;
      0        
3440 0           foreach my $l (`at`) {
3441 0 0         next if $nc
    0          
3442             ? $l !~/\Q$qry\E/i
3443             : $l !~/\Q$qry\E[\w\d\s]*[\r\n]*$/i;
3444 0 0         next if $l !~/(\d+)/;
3445 0           my $v =$1;
3446 0           my $cmd ="at $v /d";
3447 0           print("$cmd # $l\n");
3448 0 0         $s->fstore(">>$lf", $s->strtime() ."\t$$\t$cmd # $l\n")
3449             if $lf;
3450 0           system($cmd);
3451             }
3452             }
3453             1
3454 0           }
3455            
3456            
3457             sub cfpinit { # Field Player: init data structures
3458 0     0 0   my ($s) =@_; # (self) -> self
3459 0           $s->{-fphc} ={};
3460 0           $s->{-fphd} ={};
3461 0           my $dh ={};
3462 0           my $dp =undef;
3463 0           my $ah ={};
3464 0           my $ak;
3465 0           my $bf =undef;
3466 0           foreach my $f (@{$s->{-fpl}}) {
  0            
3467 0 0 0       if (ref($f) && $f->{-key} && $f->{-namecgi}) {
      0        
3468 0           $ak =$f->{-namecgi};
3469             last
3470 0           }
3471             }
3472 0           foreach my $f (@{$s->{-fpl}}) {
  0            
3473 0 0         if (ref($f) ne 'HASH') {
3474 0 0         if (!defined($dp)) {
    0          
3475 0   0       $dp =$f ||'-unknown';
3476             }
3477             elsif (!defined($f)) {
3478 0           delete $dh->{$dp};
3479 0 0         delete $dh->{-record} if $dp eq '-formdb';
3480 0           $dp =undef;
3481             }
3482             else {
3483 0           $dh->{$dp} =$f;
3484 0 0         delete $dh->{-record} if $dp eq '-formdb';
3485 0           $dp =undef;
3486             }
3487             }
3488             else {
3489 0           @$f{keys %$dh} =values %$dh;
3490 0 0 0       if ($f->{-metadb} && $f->{-formdb} && $s->{-meta} && $s->{-meta}->{$f->{-formdb}}) {
      0        
      0        
3491 0           my $fm =$f->{-metadb};
3492             $fm = ($fm =~/^\d+$/
3493             ? $s->{-meta}->{$f->{-formdb}}->{-fldids}->{$fm}
3494             : $s->{-meta}->{$f->{-formdb}}->{-fields}->{$fm})
3495 0   0       || &{$s->{-die}}($s->efmt('Field not found',$s->{-cmd},undef,'cfpinit',$f->{-formdb},$f->{-metadb}));
3496 0 0         $f->{-name} =$fm->{fieldName} if !$f->{-name};
3497 0 0         $f->{-namelbl}=$fm->{fieldLbll} if !exists($f->{-namelbl});
3498 0 0 0       $f->{-values} =schvals($s, $f->{-formdb}, $fm)
      0        
3499             if !($f->{-values} ||$f->{-labels})
3500             && schvals($s, $f->{-formdb}, $fm);
3501 0 0 0       $f->{-labels} =schlblsl($s, $f->{-formdb}, $fm)
3502             if !$f->{-labels}
3503             && schlbls($s, $f->{-formdb}, $fm);
3504 0 0 0       $f->{-value} =$fm->{defaultVal}
3505             if !exists($f->{-value})
3506             && exists($fm->{defaultVal});
3507             }
3508 0 0         if (!$f->{-namecgi}) {
3509 0           $f->{-namecgi} =$f->{-name};
3510 0 0         $f->{-namecgi} =~s/[\s-]/_/g
3511             if $f->{-namecgi};
3512             }
3513 0 0         if (!$f->{-namedb}) {
3514 0           $f->{-namedb} =$f->{-name};
3515             }
3516 0 0         $s->{-fphc}->{$f->{-namecgi}} =$f if $f->{-namecgi};
3517 0 0         $s->{-fphd}->{$f->{-namedb}} =$f if $f->{-namedb};
3518 0 0 0       $f->{-namecmt} =$f->{-namelbl} ||$f->{-namecgi} ||$f->{-namedb} ||$f->{-name} if !$f->{-namecmt};
3519            
3520 0 0 0       $f->{-values} =schvals($s, $f->{-formdb}, $f->{-namedb})
      0        
      0        
      0        
3521             if $f->{-namedb} && $f->{-formdb}
3522             && !($f->{-values} ||$f->{-labels})
3523             && schvals($s, $f->{-formdb}, $f->{-namedb});
3524            
3525 0 0 0       $f->{-labels} =$s->{-strFields} && ($s->{-strFields} ==2)
    0 0        
      0        
      0        
3526             ? schlblsl($s, $f->{-formdb}, $f->{-namedb})
3527             : schlbls($s, $f->{-formdb}, $f->{-namedb})
3528             if $f->{-namedb} && $f->{-formdb}
3529             && !$f->{-labels}
3530             && schlbls($s, $f->{-formdb}, $f->{-namedb});
3531            
3532 0 0         if ((ref($f->{-labels}) eq 'HASH')) {
3533 0           foreach my $k (keys %{$f->{-labels}}) {
  0            
3534 0 0         last if !ref($f->{-labels}->{$k});
3535 0 0         $f->{-changelb} ={} if !$f->{-changelb};
3536 0 0         my $n =defined($f->{-labels}->{$k}->{-label})
    0          
3537             ? $f->{-labels}->{$k}->{-label}
3538             : defined($f->{-labels}->{$k}->{-name})
3539             ? $f->{-labels}->{$k}->{-name}
3540             : '';
3541 0           $f->{-changelb}->{$k} =$f->{-labels}->{$k};
3542 0           $f->{-labels}->{$k} =$n;
3543             }
3544             }
3545 0 0         if ((ref($f->{-values}) eq 'ARRAY')) {
3546 0           for (my $i =0; $i <=$#{$f->{-values}}; $i++) {
  0            
3547 0 0         last if !ref($f->{-values}->[$i]);
3548 0 0         $f->{-changelb} ={} if !$f->{-changelb};
3549 0 0         my $n =defined($f->{-values}->[$i]->{-name})
    0          
3550             ? $f->{-values}->[$i]->{-name}
3551             : defined($f->{-values}->[$i]->{-label})
3552             ? $f->{-values}->[$i]->{-label}
3553             : '';
3554 0           $f->{-changelb}->{$n} =$f->{-values}->[$i];
3555 0           $f->{-values}->[$i] =$n;
3556             }
3557             }
3558            
3559 0 0 0       if ($f->{-change} ||$f->{-changelb}) {
3560 0           $f->{-onchange} =1
3561             }
3562            
3563 0 0 0       if (exists($f->{-computed}) && !($f->{-readonly} ||$f->{-disabled})) {
      0        
3564 0           $f->{-disabled} =1
3565             }
3566            
3567 0 0 0       if (!$f->{-namecgi} || !$f->{-action}) {
    0 0        
    0          
3568             }
3569             elsif (!$ah->{$f->{-namecgi}}) {
3570 0           $ah->{$f->{-namecgi}} =$f
3571             }
3572             elsif (ref($f->{-action}) ||($f->{-action} =~/^../)) {
3573             }
3574             else {
3575 0 0 0       $f->{-used} =$ah->{$f->{-namecgi}}->{-used}
3576             if !exists($f->{-used})
3577             && exists($ah->{$f->{-namecgi}}->{-used});
3578 0 0 0       $f->{-unused} =$ah->{$f->{-namecgi}}->{-unused}
3579             if !exists($f->{-unused})
3580             && exists($ah->{$f->{-namecgi}}->{-unused});
3581 0 0         $ah->{$f->{-namecgi}}->{-widget} =undef
3582             if !exists($ah->{$f->{-namecgi}}->{-widget});
3583             }
3584 0 0 0       if (exists($f->{-used}) ||exists($f->{-unused})) {
    0 0        
      0        
      0        
      0        
3585             }
3586             elsif ($ak && ($f->{-action}||$f->{-preact})
3587             && (($f->{-action}||$f->{-preact}) =~/^(?:entryUpd|entryDel|entry|vfentry|vfhash)$/)) {
3588 0     0     $f->{-used} =sub{$_[0]->cgipar($ak)}
3589 0           }
3590             else {
3591 0           $f->{-used} =1
3592             }
3593 0 0 0       $f->{-widget} =undef
3594             if $f->{-preact} && !exists($f->{-widget});
3595 0 0 0       $bf =1
3596             if $f->{-action} && ($f->{-action} =~/^\d$/);
3597             }
3598             }
3599 0 0         if (!$bf) {
3600 0           my @bl;
3601 0           foreach my $f (@{$s->{-fpl}}) {
  0            
3602 0 0         next if ref($f) ne 'HASH';
3603 0 0 0       next if !$f->{-namecgi} || !$f->{-action};
3604 0           $f->{-widget} =undef;
3605 0 0 0       next if exists($f->{-computed}) || exists($f->{-value})
      0        
3606             || !$ah->{$f->{-namecgi}};
3607 0           push @bl, {%$f, -action=>1};
3608 0           delete $bl[$#bl]->{-widget};
3609 0           delete $ah->{$f->{-namecgi}};
3610             }
3611 0           push @{$s->{-fpl}}, @bl;
  0            
3612             }
3613             $s
3614 0           }
3615            
3616            
3617             sub cfpused { # Field Player: field should be used?
3618             # (self, field) -> yes?
3619 0     0 0   my ($s, $f) =@_;
3620 0 0 0       return(map {ref($_) && cfpused($s, $_) ? $_ : ()} @{$s->{-fpl}})
  0 0          
  0            
3621             if !$f;
3622 0 0 0       $f =$s->{-fphc}->{$f} ||$s->{-fphd}->{$f}
3623             if !ref($f);
3624             !ref($f) || (ref($f) ne 'HASH')
3625             ? 0
3626             : ( !exists($f->{-used})
3627             ? 1
3628             : !$f->{-used}
3629             ? 0
3630             : (ref($f->{-used}) eq 'CODE')
3631             ? &{$f->{-used}}($s, $f)
3632             : (ref($f->{-used}) eq 'ARRAY')
3633             ? !scalar(grep {my $v =cfpused($s, $_) && cfpvv($s, $_);
3634             !defined($v) || ($v eq '')} @{$f->{-used}})
3635             : !ref($f->{-used}) && ($f->{-used} !~/^\d/)
3636             ? (do{ my $v =cfpused($s, $f->{-used}) && cfpvv($s, $f->{-used});
3637             defined($v) && ($v ne '')})
3638             : ($f->{-used} && 1)
3639             )
3640             && ( !exists($f->{-unused})
3641             ? 1
3642             : !$f->{-unused}
3643             ? 1
3644             : (ref($f->{-unused}) eq 'CODE')
3645             ? !&{$f->{-unused}}($s, $f)
3646             : (ref($f->{-unused}) eq 'ARRAY')
3647             ? scalar(grep {my $v =cfpused($s, $_) && cfpvv($s, $_);
3648             !defined($v) || ($v eq '')} @{$f->{-unused}})
3649             : !ref($f->{-unused}) && ($f->{-unused} !~/^\d/)
3650 0 0 0       ? !(do{ my $v =cfpused($s, $f->{-unused}) && cfpvv($s, $f->{-unused});
      0        
3651             defined($v) && ($v ne '')})
3652             : ($f->{-unused} && 1)
3653             )
3654             }
3655            
3656            
3657             sub cfpn { # Field Player: field name
3658             # (self, field || fieldname) -> cgi field name
3659 0 0 0 0 0   ref($_[1])
3660             ? $_[1]->{-namecgi}
3661             : (($_[0]->{-fphc}->{$_[1]} ||$_[0]->{-fphd}->{$_[1]} ||{})->{-namecgi} ||$_[1])
3662             }
3663            
3664            
3665             sub cfpnd { # Field Player: field name
3666             # (self, field || fieldname) -> db field name
3667 0 0 0 0 0   ref($_[1])
3668             ? $_[1]->{-namedb}
3669             : (($_[0]->{-fphc}->{$_[1]} ||$_[0]->{-fphd}->{$_[1]} ||{})->{-namedb} ||$_[1])
3670             }
3671            
3672            
3673             sub cfpv { # Field Player: field value
3674             # (self, field || fieldname) -> value
3675 0 0 0 0 1   my $f =ref($_[1])
3676             ? $_[1]
3677             : ($_[0]->{-fphc}->{$_[1]} ||$_[0]->{-fphd}->{$_[1]});
3678 0           !$f
3679             ? $_[0]->{-cgi}->param($_[1])
3680             : !$f->{-namecgi} || !defined($_[0]->{-cgi}->param($f->{-namecgi}))
3681             ? (exists($f->{-computed})
3682             ? (ref($f->{-computed}) eq 'CODE'
3683 0           ? &{$f->{-computed}}($_[0], $f)
3684             : ref($f->{-computed}) eq 'ARRAY'
3685 0 0 0       ? cfpv($_[0], @{$f->{-computed}})
    0          
    0          
    0          
    0          
3686             : $f->{-computed})
3687             : undef)
3688             : $_[0]->{-cgi}->param($f->{-namecgi})
3689             }
3690            
3691            
3692             sub cfpvl { # Field Player: field values list
3693             # (self, field || fieldname) -> [list]
3694 0 0 0 0 0   my $f =ref($_[1])
3695             ? $_[1]
3696             : ($_[0]->{-fphc}->{$_[1]} ||$_[0]->{-fphd}->{$_[1]});
3697             !$f
3698             ? []
3699             : !$f->{-values}
3700             ? (!$f->{-labels}
3701             ? []
3702 0           : (do{ local $_ =cfpv(@_);
3703 0           my $ll =ref($f->{-labels}) eq 'CODE'
3704 0 0         ? &{$f->{-labels}}($_[0], $f, $_)
3705             : $f->{-labels};
3706 1     1   16 use locale;
  1         2  
  1         10  
3707 0           [sort {lc($ll->{$a}) cmp lc($ll->{$b})
  0            
3708             } keys %$ll]}))
3709             : ref($f->{-values}) eq 'CODE'
3710 0 0         ? (do{ local $_ =cfpv(@_);
  0 0          
    0          
    0          
3711 0           &{$f->{-values}}($_[0], $f, $_)})
  0            
3712             : $f->{-values}
3713             }
3714            
3715            
3716             sub cfpvv { # Field Player: field value or default
3717             # (self, field || fieldname) -> value
3718 0     0 1   my $v =cfpv(@_);
3719 0 0         defined($v) ? $v : cfpvd(@_)
3720             }
3721            
3722            
3723             sub cfpvd { # Field Player: field default value
3724             # (self, field || fieldname) -> value
3725 0 0 0 0 0   my $f =ref($_[1])
3726             ? $_[1]
3727             : ($_[0]->{-fphc}->{$_[1]} ||$_[0]->{-fphd}->{$_[1]});
3728 0           !$f
3729             ? undef
3730             : exists($f->{-computed})
3731             ? ( ref($f->{-computed}) eq 'CODE'
3732 0           ? &{$f->{-computed}}($_[0], $f)
3733             : ref($f->{-computed}) eq 'ARRAY'
3734 0           ? cfpvv($_[0], @{$f->{-computed}})
3735             : $f->{-computed})
3736             : !exists($f->{-value})
3737             ? ($f->{-values} ||$f->{-labels} ? cfpvl($_[0], $f)->[0] : undef)
3738             : ref($f->{-value}) eq 'CODE'
3739 0           ? &{$f->{-value}}($_[0], $f)
3740             : ref($f->{-value}) eq 'ARRAY'
3741 0 0 0       ? cfpvv($_[0], @{$f->{-value}})
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3742             : $f->{-value}
3743             }
3744            
3745            
3746             sub cfpvp { # Field Player: field previous value
3747             # (self, field || fieldname) -> value
3748 0 0 0 0 0   $_[0]->{-cgi}->param((ref($_[1])
      0        
3749             ? $_[1]->{-namecgi} ||''
3750             : (($_[0]->{-fphc}->{$_[1]} ||$_[0]->{-fphd}->{$_[1]} ||{})->{-namecgi} ||$_[1])
3751             ) .'__PV_')
3752             }
3753            
3754            
3755             sub cfpvc { # Field Player: field value changed since form open?
3756             # (self, field || fieldname) -> changed?
3757 0     0 0   my ($v1, $v0) =(cfpv(@_), cfpvp(@_));
3758 0 0 0       defined($v1) && defined($v0)
    0 0        
3759             ? $v1 ne $v0
3760             : !defined($v1) && !defined($v0)
3761             ? 0
3762             : 1
3763             }
3764            
3765            
3766             sub cfpvcc { # Field Player: field value changed in the last form submit?
3767             # (self, field || fieldname) -> changed?
3768 0 0 0 0 0   my $f =ref($_[1])
3769             ? $_[1]
3770             : ($_[0]->{-fphc}->{$_[1]} ||$_[0]->{-fphd}->{$_[1]});
3771 0 0 0       my $fn =ref($f) ? $f->{-namecgi} ||'' : '';
3772 0 0 0       $f->{-onchange} ||$f->{-values}
      0        
3773             ? $_[0]->{-cgi}->param("${fn}__C_") ||!defined($_[0]->{-cgi}->param("${fn}__C_"))
3774             : cfpvc(@_)
3775             }
3776            
3777            
3778             sub cfpaction { # Field Player: execute action
3779             # (self, {action}||'action'
3780             # , '-preact'||'-action', {key field}) -> success
3781 0     0 1   my ($s, $act, $ord, $rp, $f) =@_;
3782 0           my $r =1;
3783 0 0         my $af=ref($act) eq 'HASH' ? $act : {};
3784 0 0         my $ae=ref($act) eq 'HASH' ? $act->{$ord} : $act;
3785 0   0       my $frm =$f->{-formdb}|| $af->{-formdb} ||'';
3786 0   0       my $frn =$f->{-record}|| $af->{-record} ||'';
3787 0           my $frk =undef;
3788 0     0     my $ffc =sub{ my $f =$_[1];
3789 0 0 0       !ref($f)
      0        
      0        
      0        
      0        
3790             || !$f->{-namedb} || $f->{-key}
3791             || !$f->{-formdb} || ($f->{-formdb} ne $frm)
3792             || (($f->{-record}||'') ne $frn)
3793 0           };
3794 0           my $vy =0;
3795             my $fvu =sub{ return(undef)
3796 0           if (ref($_[1]->{-values}) eq 'ARRAY')
3797 0 0 0 0     && !scalar(@{$_[1]->{-values}});
3798 0           my $v =cfpvv(@_);
3799 0 0 0       $v =undef if defined($_[1]->{-undef}) && defined($v) && ($_[1]->{-undef} eq $v);
      0        
3800 0 0 0       $vy=1 if defined($v) && ($v ne '') && (!$_[1]->{-master} ||$_[1]->{-key});
      0        
      0        
3801 0 0 0       $v =cfpvv($_[0], $_[1]->{-master}) if $_[1]->{-master} && !$_[1]->{-key};
3802 0 0 0       return($v) if !$_[2] || (defined($_[1]->{-vftran}) && !$_[1]->{-vftran});
      0        
3803 0 0 0       !defined($v)
    0          
3804             ? $v
3805             : (ref($_[1]->{-labels}) eq 'HASH') && exists($_[1]->{-labels}->{$v})
3806             ? $_[1]->{-labels}->{$v}
3807             : $v;
3808 0           };
3809 0           local $_;
3810 0 0 0       if ($frn || $s->{-fpbn}) {
3811 0 0         my $n =$frn =~/^(.+?)\d+$/ ? $1 : $frn;
3812 0 0 0       if ($n ne ($s->{-fpbn}||'')) {
3813 0           $s->{-fpbn} =$n; # buffer values
3814 0           $s->{-fpbv} =undef; # buffer name == record common name
3815 0 0         if ($ae =~/^(?:vfentry|entry)$/) {
3816 0           foreach my $ff (@{$s->{-fpl}}) {
  0            
3817 0 0 0       next if &$ffc($s, $ff) || !$ff->{-master};
3818 0           $frk =$ff;
3819 0           last;
3820             }
3821             }
3822             }
3823             }
3824 0 0 0       if (!$ae) {
    0 0        
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3825             }
3826             elsif (ref($ae) eq 'CODE' && ($ord eq '-action')) {
3827 0 0         $r =eval{&$ae($s, $act, $ord, $rp, $f, $_ =cfpvv($s,$f), cfpvp($s,$f)
  0            
3828 0           , {map {&$ffc($s, $_)
3829             ? ()
3830             : ($_->{-namedb} => &$fvu($s, $_))
3831             } cfpused($s)}
3832             )}
3833             }
3834             elsif (ref($ae) eq 'CODE') { # -preact
3835 0 0 0       $r =eval{&$ae($s, $act, $ord, $rp, $f, $_ =cfpvv($s, $f), cfpvp($s,$f)
  0            
3836 0           , {map {&$ffc($s, $_) || !defined(cfpv($s, $_))
3837             ? ()
3838             : ($_->{-namedb} => cfpv($s, $_))
3839 0           } @{$s->{-fpl}}}
3840             )}
3841             }
3842             elsif ($ae =~/^(?:vfentry|entry)$/ && ref($s->{-fpbv})) {
3843 0 0         $r =shift @{$s->{-fpbv}} if scalar(@{$s->{-fpbv}});
  0            
  0            
3844 0 0         $r ={} if !$r;
3845             }
3846             elsif ($ae eq 'vfentry') { # -preact
3847 0   0       my $fs =$f->{-vfname} ||$af->{-vfname};
3848 0           my $fn =undef;
3849 0           my $fv =undef;
3850 0 0 0       if ($frk && $fs && ($fn =$frk->{-namedb}) && defined($fv=cfpv($s, $frk->{-master}))) {
    0 0        
      0        
3851 0 0   0     $s->{-fpbv} =$f->{-namedb}
3852             ? $s->vfdata($fs, sub{defined($_->{$fn}) && ($_->{$fn} eq $fv)})
3853 0 0         : [];
3854 0 0 0       $r =shift @{$s->{-fpbv}} if $s->{-fpbv} && scalar(@{$s->{-fpbv}});
  0            
  0            
3855 0 0         $r ={} if !$r;
3856             }
3857             elsif ($fs) {
3858 0           $r =undef;
3859 0 0 0       if (defined($fv=cfpv($s, $f))) {
    0          
    0          
3860 0           $fn =$f->{-namedb}
3861             }
3862             elsif ($af->{-namedb} && ($fv =cfpv($s, $af))) {
3863 0           $fn =$af->{-namedb};
3864             }
3865             elsif ($fn =cfpnd($s, cfpv($s, $af))) {
3866 0           $fv =cfpv($s, $fn)
3867             }
3868 0 0 0       if ($fn && defined($fv)) {
3869 0           $r =undef;
3870 0           my $fa =$s->vfdata($fs);
3871 0           foreach my $e (@$fa) {
3872 0 0 0       next if !defined($e->{$fn}) || ($e->{$fn} ne $fv);
3873 0           $r =$e;
3874             last
3875 0           }
3876 0 0         $@="Not found '$fn'=\"$fv\""
3877             if !$r;
3878             }
3879             else {
3880 0 0         $@ =$fn
3881             ? "Key '$fn' not defined at vfentry('$fs')"
3882             : "Key not defined at vfentry('$fs')"
3883             }
3884             }
3885             else {
3886 0           $@ ="Nothing to do at 'vfentry', '-vfname' not defined"
3887             }
3888             }
3889             elsif ($ae eq 'vfhash') { # -preact
3890 0   0       my $fs =$f->{-vfname} ||$af->{-vfname};
3891 0           my $fn =undef;
3892 0           my $fv =undef;
3893 0 0 0       if (defined($fv=cfpv($s, $f))) {
    0          
    0          
3894 0           $fn =$f->{-namedb}
3895             }
3896             elsif ($af->{-namedb} && ($fv =cfpv($s, $af))) {
3897 0           $fn =$af->{-namedb};
3898             }
3899             elsif ($fn =cfpnd($s, cfpv($s, $af))) {
3900 0           $fv =cfpv($s, $fn)
3901             }
3902 0           $r =undef;
3903 0 0         if (!$fs) {
    0          
    0          
3904 0           $@ ="Nothing to do at 'vfhash', '-vfname' not defined"
3905             }
3906             elsif (!$fn) {
3907 0           $@ ="Key not defined at 'vfhash'"
3908             }
3909             elsif (!defined($fv)) {
3910 0           $@ ="Key '$fn' not defined at 'vfhash'"
3911             }
3912             else {
3913 0           $r =$s->vfhash($fs, $fn, $fv);
3914 0 0         $@="Not found '$fn'=\"$fv\""
3915             if !$r;
3916             }
3917             }
3918             elsif ($ae eq 'entry') { # -preact
3919 0           my $fn =undef;
3920 0           my $fv =undef;
3921 0 0 0       if (!$frm) {
    0 0        
    0 0        
    0 0        
      0        
      0        
3922 0           $r =undef;
3923 0           $@ ="Form not defined"
3924             }
3925             elsif ($frk && ($fn=$frk->{-namedb}) && ($fv =cfpv($s, $frk->{master}))) {
3926 0 0         $s->{-fpbv} =$f->{-namedb}
3927 0 0         ? eval{$s->connect()
3928             && $s->query(-form=>$frm
3929             ,-fields=>'*'
3930             ,-where=>"'$fn'=" .$s->arsquot($fv))}
3931             : [];
3932 0 0         if ($s->{-fpbv}) {
3933 0 0         $r =shift @{$s->{-fpbv}} if scalar(@{$s->{-fpbv}});
  0            
  0            
3934 0 0         $r ={} if !$r;
3935             }
3936             else {
3937 0           $r =undef
3938             }
3939             }
3940             elsif ($f && ($fv =cfpv($s, $f))) {
3941 0 0         $r =eval{$s->connect()
  0            
3942             && $s->entry(-form=>$frm
3943             ,-id=>$fv)};
3944             }
3945             elsif ( (($fn =$af->{-namedb}) && defined($fv =cfpv($s, $af)))
3946             || (($fn =cfpnd($s, cfpv($s, $af))) && defined($fv =cfpv($s, $fn)))
3947             ) {
3948 0 0         $r =eval{$s->connect()
  0            
3949             && $s->query(-form=>$frm
3950             ,-fields=>'*'
3951             ,-where=>"'$fn'=" .$s->arsquot($fv))};
3952 0 0         if ($r) {
3953 0           $r =shift @$r;
3954 0 0         $@ ="Not found '$fn'=\"$fv\""
3955             if !$r
3956             }
3957             }
3958             else {
3959 0           $r =undef;
3960 0           $@ ="Key not defined"
3961             }
3962             }
3963             elsif ($ae eq 'entryNew') { # -preact
3964 0 0         $r =eval{$s->connect()
  0 0          
3965             && $s->entryNew(-form => $frm)}
3966             if $frm;
3967             }
3968             elsif ($ae eq 'entryIns') { # -action
3969 0   0       my $fs =$f->{-vfname} ||$af->{-vfname};
3970 0 0 0       $r =eval{$s->connect()
  0 0          
3971             && $s->entryIns(-form=>$frm
3972 0 0         , map { &$ffc($s, $_) ||(exists($_->{-entryIns}) && !$_->{-entryIns})
3973             ? ()
3974             : ($_->{-namedb} => &$fvu($s, $_))
3975             } cfpused($s))}
3976             if $frm;
3977 0 0         $r =1 if ref($r);
3978 0 0 0       if (!$r) {
    0 0        
    0 0        
    0 0        
    0 0        
      0        
3979 0 0         $@ ="Unknown 'entryIns' error" if !$@
3980             }
3981             elsif (!$fs ||!$f->{-key}) {
3982             }
3983             elsif (($af->{-vfclear} || $f->{-vfclear}) && $s->{"${fs}-calc"}) {
3984 0           $s->vfclear($fs);
3985             }
3986             elsif (($af->{-vfrenew} || $f->{-vfrenew}) && $s->{"${fs}-store"}) {
3987 0           eval{$s->vfclear($fs); $s->vfrenew($fs)}
  0            
  0            
3988             }
3989             elsif ($af->{-vfedit} || $f->{-vfedit}) {
3990 0   0       my $fn =$f->{-namedb} ||$af->{-namedb};
3991 0 0         my $ft =defined($f->{-vftran}) ? $f->{-vftran} : $af->{-vftran};
3992 0           my $fv =cfpv($s, $f);
3993 0           my $fa =$s->vfdata($fs);
3994 0 0 0       push @$fa, {$f->{-namedb} ? ($f->{-namedb}=>$r) : ()
3995 0 0         ,map { &$ffc($s, $_) ||(exists($_->{-vfstore}) && !$_->{-vfstore})
3996             ? ()
3997             : ($_->{-namedb} => &$fvu($s, $_, $ft))
3998             } cfpused($s)};
3999 0           $s->vfstore($fs);
4000 0           $s->vfclear($fs);
4001             }
4002             }
4003             elsif ($ae eq 'entryUpd') { # -action
4004 0   0       my $fs =$f->{-vfname} ||$af->{-vfname};
4005 0 0 0       $r =eval{$s->connect()
  0 0 0        
4006             && $s->entryUpd(-form=>$frm, -id=>cfpvv($s,$f)
4007 0 0         , map { &$ffc($s, $_) ||(exists($_->{-entryUpd}) && !$_->{-entryUpd})
4008             ? ()
4009             : ($_->{-namedb} => &$fvu($s, $_))
4010             } cfpused($s))}
4011             if $frm && cfpvv($s,$f);
4012 0 0 0       if (!$r) {
    0 0        
    0 0        
    0 0        
    0 0        
      0        
4013 0 0         $@ ="Unknown 'entryUpd' error" if !$@
4014             }
4015             elsif (!$f->{-key} ||!$fs) {
4016             }
4017             elsif (($af->{-vfclear} || $f->{-vfclear}) && $s->{"${fs}-calc"}) {
4018 0           $s->vfclear($fs);
4019             }
4020             elsif (($af->{-vfrenew} || $f->{-vfrenew}) && $s->{"${fs}-store"}) {
4021 0           eval{$s->vfclear($fs); $s->vfrenew($fs)}
  0            
  0            
4022             }
4023             elsif ($af->{-vfedit} || $f->{-vfedit}) {
4024 0   0       my $fn =$f->{-namedb} ||$af->{-namedb};
4025 0 0         my $ft =defined($f->{-vftran}) ? $f->{-vftran} : $af->{-vftran};
4026 0           my $fv =cfpv($s, $f);
4027 0           my $fa =$s->vfdata($fs);
4028 0           foreach my $e (@$fa) {
4029 0 0 0       next if !defined($e->{$fn}) || ($e->{$fn} ne $fv);
4030 0           foreach my $f1 (cfpused($s)) {
4031 0 0 0       next if &$ffc($s, $f1) ||(exists($f1->{-vfstore}) && !$f1->{-vfstore});
      0        
4032 0           $e->{$f1->{-namedb}} =&$fvu($s, $f1, $ft);
4033             }
4034 0           last;
4035             }
4036 0           $s->vfstore($fs);
4037 0           $s->vfclear($fs);
4038             }
4039             }
4040             elsif ($act eq 'entryDel') { # -action
4041 0   0       my $fs =$f->{-vfname} ||$af->{-vfname};
4042 0 0 0       $r =eval{$s->connect()
  0 0          
4043             && $s->entryDel(-form=>$frm
4044             , -id=>cfpvv($s,$f))}
4045             if $frm && cfpvv($s,$f);
4046 0 0 0       if (!$r) {
    0 0        
    0 0        
    0 0        
    0 0        
      0        
4047 0 0         $@ ="Unknown 'entryDel' error" if !$@
4048             }
4049             elsif (!$fs ||!$f->{-key}) {
4050             }
4051             elsif (($af->{-vfclear} || $f->{-vfclear}) && $s->{"${fs}-calc"}) {
4052 0           $s->vfclear($fs);
4053             }
4054             elsif (($af->{-vfrenew} || $f->{-vfrenew}) && $s->{"${fs}-store"}) {
4055 0           eval{$s->vfclear($fs); $s->vfrenew($fs)}
  0            
  0            
4056             }
4057             elsif ($af->{-vfedit} || $f->{-vfedit}) {
4058 0   0       my $fn =$f->{-namedb} ||$af->{-namedb};
4059 0           my $fv =cfpv($s, $f);
4060 0           my $fa =$s->vfdata($fs);
4061 0           my ($i,$j) =(0, undef);
4062 0           foreach my $e (@$fa) {
4063 0 0 0       if (defined($e->{$fn}) && ($e->{$fn} eq $fv)) {
4064 0           $j =$i;
4065 0           last;
4066             }
4067 0           $i++
4068             }
4069 0           splice(@$fa, $i, 1);
4070 0           $s->vfstore($fs);
4071 0           $s->vfclear($fs);
4072             }
4073             }
4074             elsif ($ae eq 'entrySave') { # -action
4075 0 0         my $a =cfpvv($s,$f) ? 'entryUpd' : cfpvp($s,$f) ? 'entryDel' : 'entryIns';
    0          
4076 0 0         if ($a eq 'entryIns') { # $vy= 1 if cfpvv($s,$f)
4077 0 0 0       map { &$ffc($s, $_) ||(exists($_->{-entryIns}) && !$_->{-entryIns})
  0            
4078             ? ()
4079             : ($_->{-namedb} => &$fvu($s, $_))
4080             } cfpused($s);
4081 0 0 0       $a = $vy
    0          
    0          
4082             ? $a
4083             : ($a eq 'entryIns')
4084             ? ''
4085             : ($a eq 'entryUpd') && cfpvp($s,$f)
4086             ? 'entryDel'
4087             : $a;
4088             }
4089 0 0 0       $s->{-cgi}->param($f->{-namecgi}, cfpvp($s,$f))
4090             if ($a eq 'entryDel') && $f->{-namecgi};
4091 0 0         $r =!$a
    0          
4092             ? 1
4093             : ref($act) eq 'HASH'
4094             ? cfpaction($s, {%$act, -action => $a}, @_[2..$#_])
4095             : cfpaction($s, $a, @_[2..$#_])
4096             }
4097 0 0 0       if ((ref($r) eq 'HASH') && ($ord eq '-preact')) {
4098 0 0 0       foreach my $f1 (map { &$ffc($s, $_) || !$_->{-namecgi}
  0            
  0            
4099             ? ()
4100             : ($_)
4101             } @{$s->{-fpl}}) {
4102 0 0         next if !exists($r->{$f1->{-namedb}});
4103 0           my $u =$s->cfpused($f1);
4104 0           my $v =$r->{$f1->{-namedb}};
4105 0 0 0       if (defined($v)
4106             || defined($s->{-cgi}->param($f1->{-namecgi}))) {
4107 0           $s->{-cgi}->param($f1->{-namecgi}, $v);
4108 0 0 0       $s->{-cgi}->param($f1->{-namecgi} .'__C_', '')
      0        
4109             if $u && ($f1->{-values} || $f1->{-labels});
4110             }
4111 0 0 0       if (defined($v)
    0 0        
    0 0        
4112             && (defined($f1->{-vftran}) ? $f1->{-vftran} : defined($f->{-vftran}) ? $f->{-vftran} : $af->{-vftran})
4113             && (ref($f1->{-labels}) eq 'HASH') && !exists($f1->{-labels}->{$v})) {
4114 0           foreach my $k (keys %{$f1->{-labels}}) {
  0            
4115 0 0         next if $v ne $f1->{-labels}->{$k};
4116 0           $v =$k;
4117 0           $s->{-cgi}->param($f1->{-namecgi}, $v);
4118 0           last;
4119             }
4120 0 0 0       print &{$s->{-fpmsg}}($s, 'Warning'
  0   0        
      0        
      0        
      0        
4121             , ($af->{-namelbl} ||$af->{-namecgi})
4122             .': '
4123             ."'" .($f1->{-namelbl}||$f1->{-namedb})
4124             ."' == ?\"$v\"?")
4125             if $u
4126             && !exists($f1->{-labels}->{$v})
4127             && (defined($f1->{-lbtran}) && !$f1->{-lbtran})
4128             }
4129             }
4130             }
4131             $r
4132 0           }
4133            
4134            
4135             sub cfprun { # Field Player: run
4136             # (self, msg sub{}
4137             # , form row sub{}, form top, form bottom) -> success
4138 0     0 1   my ($s, $cmsg, $cfld, $cfld0, $cfld1) =@_;
4139 0 0 0       my $hmsg =ref($cmsg) eq 'HASH'
    0          
4140             ? $cmsg
4141             : ($s->{-lang} ||'') =~/^ru/i
4142             ? {'Error'=>'Îøèáêà', 'Warning'=>'Ïðåäóïðåæäåíèå', 'Success'=>'Óñïåøíî'
4143             ,'Executing'=>'Âûïîëíåíèå', 'Done'=>'Âûïîëíåíî'}
4144             : {};
4145 0 0 0 0     $cmsg =sub{"\n
    0 0        
    0          
4146             .($_[1] =~/^(?:Error|Warning)/ ? ' color="red"' : '')
4147             .'>'
4148             .(defined($_[1]) ? $_[0]->{-cgi}->escapeHTML($hmsg->{$_[1]} ||$_[1]) : 'undef')
4149             .": "
4150             .(defined($_[2]) ? $_[0]->{-cgi}->escapeHTML($hmsg->{$_[2]} ||$_[2]) : 'undef')
4151             .""
4152             # 'Error', 'Warning',
4153             # 'Executing', 'Done'('Success', 'Error')
4154             }
4155 0 0 0       if !$cmsg || (ref($cmsg) ne 'CODE');
4156             my $emsg =sub{
4157 0 0   0     $CGI::Carp::CUSTOM_MSG
4158             ? &$CGI::Carp::CUSTOM_MSG($_[1])
4159             : print(&$cmsg($_[0], 'Error', $_[1]))
4160 0           };
4161 0           $cfld =sub{"\n
"
4162             . ($_[1]->{-namehtml}
4163 0 0 0 0     ? &{$_[1]->{-namehtml}}(@_)
4164             : $_[0]->{-cgi}->escapeHTML($_[1]->{-namelbl}||''))
4165             . "\n"
4166             . $_[2]
4167             . "
4168             }
4169 0 0         if !$cfld;
4170 0 0         $cfld0="\n" if !$cfld0;
4171 0 0         $cfld1="\n
" if !$cfld1;
4172 0           $s->cgi();
4173 0           cfpinit($s);
4174 0           local $s->{-fpmsg} =$cmsg;
4175 0           my $err;
4176             my $act;
4177 0           my $acf;
4178 0           my $aec;
4179 0           my $arv;
4180 0           foreach my $f (@{$s->{-fpl}}) {
  0            
4181 0 0 0       next if (ref($f) ne 'HASH')
      0        
4182             || (exists($f->{-used}) && !$f->{-used});
4183 0 0 0       if ($f->{-preact} && ($f->{-preact} !~/^\d$/) && cfpvv($s, $f)) {
      0        
4184 0           $acf =1;
4185 0 0         $act =[] if !$act;
4186 0           push @$act, $f
4187             }
4188 0 0 0       if ($f->{-action} && ($f->{-action} !~/^\d$/) && cfpvv($s, $f)) {
      0        
4189 0           $aec =cfpvv($s, $f);
4190             }
4191 0 0 0       if ($f->{-key} && $act && !$err) {
      0        
4192 0           $arv =1;
4193 0           foreach my $a (@$act) {
4194 0           $arv =cfpaction($s, $a, '-preact', $arv, $f);
4195 0 0         next if $arv;
4196 0           $err =$@;
4197             last
4198 0           }
4199 0           $act =undef;
4200 0 0         if (!$arv) {
4201 0   0       &$emsg($s, $err ||"Unknown 'cfpaction' error");
4202 0           $err =1;
4203 0           last;
4204             }
4205             }
4206 0 0         if ($f->{-key}) {
4207 0           $act =undef;
4208             }
4209 0 0         next if !cfpused($s, $f);
4210 0           my $fn =cfpn($s, $f);
4211 0 0         if (!$f->{-reset}
  0 0          
    0          
    0          
    0          
4212             ? undef
4213             : ref($f->{-reset}) eq 'CODE'
4214 0           ? &{$f->{-reset}}($s, $f)
4215             : ref($f->{-reset}) eq 'ARRAY'
4216 0           ? grep {cfpvcc($s, $_)} @{$f->{-reset}}
4217             # ??? read from URL interpreted as changed listbox
4218             : $f->{-reset}
4219             ? cfpvcc($s, $f->{-reset})
4220             : undef
4221             ) {
4222 0           $s->{-cgi}->delete($fn);
4223             }
4224 0           my $fv =exists($f->{-computed})
4225             ? (ref($f->{-computed}) eq 'CODE'
4226 0           ? &{$f->{-computed}}($s, $f)
4227             : ref($f->{-computed}) eq 'ARRAY'
4228 0 0         ? cfpvv($s, @{$f->{-computed}})
    0          
    0          
4229             : $f->{-computed})
4230             : cfpvv($s, $f);
4231 0           local $_ =$fv;
4232 0 0 0       if (!($f->{-action} || $f->{-preact}) && $f->{-namecgi}) {
      0        
4233 0 0         if (defined($fv)) {
4234 0 0 0       if ((defined($f->{-lbtran}) ? $f->{-lbtran} : 0)
    0 0        
4235             && (ref($f->{-labels}) eq 'HASH') && !exists($f->{-labels}->{$fv})) {
4236 0           foreach my $k (keys %{$f->{-labels}}) {
  0            
4237 0 0         next if $fv ne $f->{-labels}->{$k};
4238 0           $fv =$k;
4239 0           last;
4240             }
4241 0 0 0       print &$cmsg($s, 'Warning'
      0        
4242             , "'" .($f->{-namelbl} ||$f->{-namecgi} ||$f->{-namedb})
4243             ."' == ?\"$fv\"?")
4244             if !exists($f->{-labels}->{$fv})
4245             && !$f->{-lbadd}
4246             }
4247 0 0         if ((defined($f->{-lbadd}) ? $f->{-lbadd} : 0)) {
    0          
4248 1 0 0 1   6625 $f->{-values} =do{use locale;
  1         4  
  1         9  
  0            
4249 0           [sort {lc($f->{-labels}->{$a}) cmp lc($f->{-labels}->{$b})} keys %{$f->{-labels}}]}
  0            
  0            
4250             if (ref($f->{-labels}) eq 'HASH')
4251             && !$f->{-values};
4252 0           push @{$f->{-values}}, $fv
  0            
4253             if (ref($f->{-values}) eq 'ARRAY')
4254 0 0 0       && !grep /^\Q$fv\E$/, @{$f->{-values}};
4255             }
4256             }
4257 0 0         $f->{-labels} =&{$f->{-labels}}($s, $f, $_ =$fv)
  0            
4258             if ref($f->{-labels}) eq 'CODE';
4259 0 0         $f->{-values} =&{$f->{-values}}($s, $f, $_ =$fv)
  0            
4260             if ref($f->{-values}) eq 'CODE';
4261 1 0 0 1   235 $f->{-values} =do{use locale;
  1         3  
  1         5  
  0            
4262 0           [sort {lc($f->{-labels}->{$a}) cmp lc($f->{-labels}->{$b})} keys %{$f->{-labels}}]}
  0            
  0            
4263             if $f->{-labels}
4264             && !$f->{-values};
4265 0 0 0       if ($f->{-values}
      0        
4266             && (!defined($fv) || !grep /^\Q$fv\E$/, @{$f->{-values}})) {
4267 0           $fv =$f->{-values}->[0];
4268 0 0         $fv ='' if !defined($fv);
4269 0 0         $s->{-cgi}->delete("${fn}__C_") if $f->{-change};
4270             }
4271 0 0         if (defined($fv)) {
4272 0           $s->{-cgi}->param($fn, $fv);
4273 0 0         $s->{-cgi}->param("${fn}__PV_", $fv)
4274             if !defined($s->{-cgi}->param("${fn}__PV_"));
4275             }
4276             else {
4277 0           $s->{-cgi}->delete($fn);
4278             }
4279             }
4280 0           foreach my $q ('-change', '-changelb') {
4281 0 0         next if !$f->{$q};
4282 0 0         last if !cfpvcc($s, $f);
4283 0 0         my $c =ref($f->{$q}) eq 'CODE' ? &{$f->{$q}}($s, $f, $_ =$fv) : $f->{$q};
  0            
4284 0 0         $c =ref($c) ne 'HASH' ? undef : ref($c->{$fv}) eq 'HASH' ? $c->{$fv} : $c;
    0          
4285 0 0         if (ref($c) eq 'HASH') {
4286 0           foreach my $k (keys %$c) {
4287 0 0         next if $k =~/^-/;
4288 0           defined($c->{$k})
4289             ? $s->{-cgi}->param(cfpn($s, $k)
4290             , ref($c->{$k}) eq 'CODE'
4291 0 0         ? &{$c->{$k}}($s, $f, $_ =$fv)
    0          
4292             : $c->{$k}
4293             )
4294             : $s->{-cgi}->delete(cfpn($s, $k))
4295             }
4296             }
4297             }
4298 0 0 0       if (my $ev =!$aec || !$f->{-error}
  0 0 0        
    0          
    0          
4299             ? undef
4300             : ref($f->{-error}) eq 'CODE'
4301             ? &{$f->{-error}}($s, $f, $_ =$fv, cfpvp($s, $f), $aec)
4302             : !ref($f->{-error}) && (!defined($fv) || ($fv eq ''))
4303             ? $f->{-error}
4304             : undef
4305             ) {
4306 0           print &$cmsg($s, 'Error', "'" .$f->{-namelbl} ."' - $ev");
4307 0           $err =1;
4308             }
4309 0 0 0       if (my $ev =!$f->{-warn}
  0 0          
    0          
    0          
4310             ? undef
4311             : ref($f->{-warn}) eq 'CODE'
4312             ? &{$f->{-warn}}($s, $f, $_ =$fv, cfpvp($s, $f), $aec)
4313             : !ref($f->{-warn}) && (!defined($fv) || ($fv eq ''))
4314             ? $f->{-warn}
4315             : undef
4316             ) {
4317 0           print &$cmsg($s, 'Warning', "'" .$f->{-namelbl} ."' - $ev");
4318             }
4319             }
4320             return(undef)
4321 0 0         if $err;
4322 0           $act = $acf =$arv =undef;
4323 0           foreach my $f (@{$s->{-fpl}}) {
  0            
4324 0 0 0       next if (ref($f) ne 'HASH')
      0        
4325             || (exists($f->{-used}) && !$f->{-used});
4326 0 0         next if !cfpused($s, $f);
4327 0 0 0       if ($f->{-action} && ($f->{-action} !~/^\d$/) && cfpvv($s, $f)) {
      0        
4328 0           $acf =1;
4329 0 0         $act =[] if !$act;
4330 0           push @$act, $f
4331             }
4332 0 0 0       if ($f->{-key} && $act && !$err) {
      0        
4333 0           $arv =1;
4334 0           foreach my $a (@$act) {
4335 0 0 0       print &$cmsg($s, 'Executing', ($a->{-namelbl} ||$a->{-namecgi} ||'') .' ', $arv)
      0        
4336             if $a->{-namelbl} ||$a->{-namecgi};
4337 0           $arv =cfpaction($s, $a, '-action', $arv, $f);
4338 0 0         next if $arv;
4339 0           $err =$@;
4340 0           last;
4341             }
4342 0           $act =undef;
4343 0 0         if (!$arv) {
4344 0   0       &$emsg($s, $err ||"Unknown 'cfpaction' error");
4345 0           $err =1;
4346 0           last;
4347             }
4348             }
4349 0 0         if ($f->{-key}) {
4350 0           $act =undef;
4351             }
4352             }
4353 0 0         if ($acf) {
4354 0 0         print &$cmsg($s, 'Done', $err ? ('Error', $@) : ('Success', $arv))
4355             }
4356             return(undef)
4357 0 0         if $err;
4358 0 0         return(1)
4359             if $acf;
4360 0           foreach my $f (@{$s->{-fpl}}) {
  0            
4361 0 0 0       next if (ref($f) ne 'HASH')
      0        
4362             || (exists($f->{-used}) && !$f->{-used});
4363 0 0 0       next if exists($f->{-widget}) && !defined($f->{-widget});
4364 0 0         next if !$f->{-namecgi};
4365 0           my $u =cfpused($s, $f);
4366 0 0 0       next if $u && !($f->{-hidden} ||((ref($f->{-values}) eq 'ARRAY') && !scalar(@{$f->{-values}})));
      0        
4367 0 0         print defined(cfpvp($s, $f))
    0          
    0          
    0          
4368             ? ' 4369             .$s->{-cgi}->escapeHTML(cfpvp($s, $f))
4370             .'" />' ."\n"
4371             : ''
4372             , !$u
4373             ? ( defined($s->{-cgi}->param($f->{-namecgi}))
4374             ? ' 4375             .$s->{-cgi}->escapeHTML($s->{-cgi}->param($f->{-namecgi}))
4376             .'" />' ."\n"
4377             : '')
4378             : defined(cfpvv($s, $f))
4379             ? ' 4380             .$s->{-cgi}->escapeHTML(cfpvv($s, $f))
4381             .'" />' ."\n"
4382             : '';
4383             }
4384 0 0         print ref($cfld0) ? &{$cfld0}($s) : $cfld0;
  0            
4385 0           my $bb ='';
4386 0           foreach my $f (@{$s->{-fpl}}) {
  0            
4387 0 0 0       next if (ref($f) ne 'HASH')
      0        
4388             || (exists($f->{-used}) && !$f->{-used});
4389 0 0         next if !cfpused($s, $f);
4390 0 0 0       next if exists($f->{-widget}) && !defined($f->{-widget});
4391 0 0 0       next if $f->{-hidden} ||((ref($f->{-values}) eq 'ARRAY') && !scalar(@{$f->{-values}}));
  0   0        
4392 0   0       my $bf =$f->{-action} ||$f->{-preact};
4393 0 0 0       if ($f->{-action} ||$f->{-preact}) {
    0          
4394 0 0         $bb .=' ' if $bb;
4395 0           $bb .= exists($f->{-widget}) && !$f->{-widget}
4396             ? ''
4397             : !ref($f->{-widget}) && $f->{-widget}
4398             ? $f->{-widget}
4399             : ref($f->{-widget}) eq 'CODE'
4400 0           ? &{$f->{-widget}}($s, $f, cfpvv($s, $f), cfpvp($s, $f))
4401             : !$f->{-namecgi}
4402             ? ''
4403             : ref($f->{-widget}) eq 'HASH'
4404             ? $s->{-cgi}->submit(-name=>$f->{-namecgi}, -title=>$f->{-namecmt}, -value=>$f->{-namelbl}
4405 0 0         , %{$f->{-widget}})
4406             : $s->{-cgi}->submit(-name=>$f->{-namecgi}, -title=>$f->{-namecmt}, -value=>$f->{-namelbl}
4407 0 0 0       , map {defined($f->{$_}) ? ($_=>$f->{$_}) : ()} qw(-class -style));
    0 0        
    0          
    0          
    0          
4408             next
4409 0           }
4410             elsif ($bb) {
4411 0           print &$cfld($s, {}, $bb);
4412 0           $bb ='';
4413             }
4414 0           print &$cfld($s
4415             , $f->{-action} ||$f->{-preact}
4416             ? {}
4417             : $f
4418             , (!$f->{-widget0}
4419             ? ''
4420             : ref($f->{-widget0}) eq 'CODE'
4421 0           ? &{$f->{-widget0}}($s, $f, cfpvv($s, $f), cfpvp($s, $f))
4422             : $f->{-widget0})
4423             . (!($f->{-action} || $f->{-preact}) && $f->{-namecgi} && defined(cfpvp($s, $f))
4424             ? ' 4425             .$s->{-cgi}->escapeHTML(cfpvp($s, $f))
4426             .'" />'
4427             : ''
4428             )
4429             . (!ref($f->{-widget}) && exists($f->{-widget})
4430             ? $f->{-widget}
4431             : ref($f->{-widget}) eq 'CODE'
4432 0 0         ? &{$f->{-widget}}($s, $f, cfpvv($s, $f), cfpvp($s, $f))
4433             : !$f->{-namecgi}
4434             ? ''
4435             : ref($f->{-widget}) eq 'HASH'
4436             ? ( $f->{-values}
4437             ? $s->cgiselect(-name=>$f->{-namecgi}, -title=>$f->{-namecmt}
4438             , -onchange=>1
4439 0           , map {defined($f->{$_}) ? ($_=>$f->{$_}) : ()} qw(-values -labels)
4440             , -id => $f->{-namecgi}
4441 0           , %{$f->{-widget}})
4442             : $f->{-rows}
4443             ? $s->cgitext(-name=>$f->{-namecgi}, -title=>$f->{-namecmt}
4444             , -id => $f->{-namecgi}
4445 0           , %{$f->{-widget}})
4446             : $f->{-action} ||$f->{-preact}
4447             ? $s->{-cgi}->submit(-name=>$f->{-namecgi}, -title=>$f->{-namecmt}, -value=>$f->{-namelbl}
4448             , -id => $f->{-namecgi}
4449 0           , %{$f->{-widget}})
4450             : $s->cgistring(-name=>$f->{-namecgi}, -title=>$f->{-namecmt}
4451             , -id => $f->{-namecgi}
4452 0           , %{$f->{-widget}})
4453             )
4454             : ( $f->{-values}
4455             ? $s->cgiselect(-name=>$f->{-namecgi}, -title=>$f->{-namecmt}
4456             , -id => $f->{-namecgi}
4457             , -onchange=>1
4458 0 0         , map { my $v =ref($f->{$_}) eq 'CODE' ? &{$f->{$_}}($s, $f, cfpvv($s, $f), cfpvp($s, $f)) : $f->{$_};
  0            
4459 0 0         defined($v) ? ($_=>$v) : ()} qw(-values -labels -onchange -readonly -disabled -class -style))
4460             : $f->{-rows}
4461             ? $s->cgitext(-name=>$f->{-namecgi}, -title=>$f->{-namecmt}
4462             , -id => $f->{-namecgi}
4463 0 0         , map { my $v =ref($f->{$_}) eq 'CODE' ? &{$f->{$_}}($s, $f, cfpvv($s, $f), cfpvp($s, $f)) : $f->{$_};
  0            
4464 0 0         defined($v) ? ($_=>$v) : ()} qw(-rows -columns -maxlength -readonly -class -style))
4465             : $f->{-action} ||$f->{-preact}
4466             ? $s->{-cgi}->submit(-name=>$f->{-namecgi}, -title=>$f->{-namecmt}, -value=>$f->{-namelbl}
4467             , -id => $f->{-namecgi}
4468 0 0         , map { my $v =ref($f->{$_}) eq 'CODE' ? &{$f->{$_}}($s, $f, cfpvv($s, $f), cfpvp($s, $f)) : $f->{$_};
  0            
4469 0 0         defined($v) ? ($_=>$v) : ()} qw(-class -style))
4470             : $s->cgistring(-name=>$f->{-namecgi}, -title=>$f->{-namecmt}
4471             , -id => $f->{-namecgi}
4472 0 0         , map { my $v =ref($f->{$_}) eq 'CODE' ? &{$f->{$_}}($s, $f, cfpvv($s, $f), cfpvp($s, $f)) : $f->{$_};
  0            
4473 0 0         defined($v) ? ($_=>$v) : ()} qw(-size -maxlength -readonly -disabled -class -style))
4474             )
4475             )
4476             . (!$f->{-widget1}
4477             ? ''
4478             : ref($f->{-widget1}) eq 'CODE'
4479 0 0 0       ? &{$f->{-widget1}}($s, $f, cfpvv($s, $f), cfpvp($s, $f))
    0 0        
    0 0        
    0 0        
    0 0        
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4480             : $f->{-widget1})
4481             );
4482             }
4483 0 0         if ($bb) {
4484 0           print &$cfld($s, {}, $bb);
4485 0           $bb ='';
4486             }
4487 0 0         print ref($cfld1) ? &{$cfld1}($s) : $cfld1;
  0            
4488 0 0         $err ? undef : 1
4489             }