File Coverage

blib/lib/DBIx/FileSystem.pm
Criterion Covered Total %
statement 69 1333 5.1
branch 15 640 2.3
condition 4 152 2.6
subroutine 15 51 29.4
pod 0 38 0.0
total 103 2214 4.6


line stmt bran cond sub pod time code
1             #
2             # DBIx::FileSystem;
3             #
4             # Manage database tables with a simulated filesystem shell environment
5             #
6             # Mar 2003 Alexander Haderer
7             #
8             # License:
9             #
10             # This program is free software; you can redistribute it and/or modify
11             # it under the terms of the GNU General Public License as published by
12             # the Free Software Foundation; either version 2 of the License, or
13             # (at your option) any later version.
14             #
15             # This program is distributed in the hope that it will be useful,
16             # but WITHOUT ANY WARRANTY; without even the implied warranty of
17             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18             # GNU General Public License for more details.
19             #
20             # You should have received a copy of the GNU General Public License
21             # along with this program; if not, write to the Free Software
22             # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23             #
24             # Last Update: $Author: marvin $
25             # Update Date: $Date: 2007/12/13 15:06:46 $
26             # Source File: $Source: /home/cvsroot/tools/FileSystem/FileSystem.pm,v $
27             # CVS/RCS Revision: $Revision: 1.22 $
28             # Status: $State: Exp $
29             #
30              
31             package DBIx::FileSystem;
32              
33 3     3   86957 use strict;
  3         8  
  3         149  
34 3     3   17 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS );
  3         5  
  3         261  
35 3     3   17 use Exporter;
  3         10  
  3         471  
36              
37             # for access class: return results
38 3     3   16 use constant OK => 0; # everything ok
  3         5  
  3         286  
39 3     3   16 use constant NOFILE => 1; # file not found in db
  3         6  
  3         217  
40 3     3   14 use constant NFOUND => 2; # more than one entry found
  3         6  
  3         149  
41 3     3   24 use constant ERROR => 3; # nothing found, errorstring set
  3         6  
  3         325  
42              
43             $DBIx::FileSystem::VERSION = '1.7';
44              
45             @ISA = qw( Exporter );
46             @EXPORT = qw( );
47             @EXPORT_OK = qw(
48             &recreatedb
49             &mainloop
50             OK
51             NOFILE
52             NFOUND
53             ERROR
54             );
55             %EXPORT_TAGS = ( symbols => [ qw( OK NOFILE NFOUND ERROR ) ] );
56              
57 3     3   16 use vars qw( $OUT $vwd $dbh );
  3         13  
  3         166  
58              
59 3     3   8970 use DBI;
  3         96273  
  3         275  
60 3     3   4237 use Term::ReadLine;
  3         14175  
  3         122  
61 3     3   2015 use POSIX qw{tmpnam};
  3         19077  
  3         24  
62              
63 3     3   3528 use Fcntl;
  3         15  
  3         64582  
64              
65             ########################################################################
66             ########################################################################
67             ## classical interface: the shell
68             ########################################################################
69             ########################################################################
70              
71              
72              
73             ########################################################################
74             # c o m m a n d s
75             ########################################################################
76             my %commands =
77             ('cd'=> { func => \&com_cd,
78             doc => "change to directory: 'cd DIR'" },
79             'help' => { func => \&com_help,
80             doc => "display help text: 'help [command]'" },
81             'quit' => { func => \&com_quit,
82             doc => "quit it" },
83             'ls' => { func => \&com_ls,
84             doc => "list dirs and files" },
85             'ld'=> { func => \&com_ld,
86             doc => "list long dirs and files with comments" },
87             'll' => { func => \&com_ll,
88             doc => "list long files with comments" },
89             'rm' => { func => \&com_rm,
90             doc => "remove file: 'rm FILE'" },
91             'cp' => { func => \&com_cp,
92             doc => "copy file: 'cp OLD NEW'" },
93             'cat' => { func => \&com_cat,
94             doc => "show contents of a file: 'cat FILE'" },
95             'sum' => { func => \&com_sum,
96             doc => "show summary of a file: 'sum FILE'" },
97             'vi' => { func => \&com_vi,
98             doc => "edit/create a file: 'vi FILE'" },
99             'ver' => { func => \&com_ver,
100             doc => "show version" },
101             'vgrep' => { func => \&com_vgrep,
102             doc => "grep var/value pairs in all files: vgrep PATTERN" },
103             'wrefs' => { func => \&com_wref,
104             doc => "show who references a file: 'wrefs FILE'" },
105             );
106              
107              
108             ########################################################################
109             # C o n s t a n t s
110             ########################################################################
111              
112             # for ls output
113             my $NUM_LS_COL = 4;
114             my $LS_COL_WIDTH = 16;
115             my $EDITOR = $ENV{EDITOR};
116             $EDITOR = "/usr/bin/vi" unless $EDITOR;
117              
118              
119             ########################################################################
120             # m a i n
121             #
122             # input:
123             # vdirs: reference to vdir hash
124             # PRG: program name for the shell-program
125             # VERSION four digit version string for program/database version
126             # DBCONN DBI connect string for the database
127             # DBUSER database user
128             #
129             # returns nothing
130             ########################################################################
131              
132             my $vdirs; # reference to vdir hash
133             # $vwd ; # current virtual working directory (exported)
134              
135             # my $dbh; # database handle (exported)
136             my $term;
137             # $OUT; # the stdout (exported)
138              
139             my $DBCONN; # DBI database connect string
140             my $DBUSER; # DBI database user
141             my $DBPWD; # DBI password
142             my $VERSION;
143              
144             my $PRG; # program name of the shell
145              
146              
147             sub mainloop(\%$$$$$\%) {
148              
149 0     0 0 0 my $customcmds;
150 0         0 ($vdirs,$PRG,$VERSION,$DBCONN,$DBUSER,$DBPWD,$customcmds) = @_;
151              
152             # merge custom commands, if any
153 0 0       0 if( defined $customcmds ) {
154 0         0 foreach my $cucmd (keys (%{$customcmds} ) ) {
  0         0  
155 0 0       0 if( defined $commands{$cucmd} ) {
156 0         0 die "$PRG: redefinition of command '$cucmd' by customcommands";
157             }
158 0 0       0 unless( defined $customcmds->{$cucmd}{func} ) {
159 0         0 die "$PRG: customcommand '$cucmd': elem func not set";
160             }
161 0 0       0 unless( defined $customcmds->{$cucmd}{doc} ) {
162 0         0 die "$PRG: customcommand '$cucmd': elem doc not set";
163             }
164 0         0 $commands{$cucmd} = $customcmds->{$cucmd};
165             }
166             }
167              
168             # connect to db
169 0 0       0 ($dbh = DBI->connect( $DBCONN, $DBUSER, $DBPWD,
170             {ChopBlanks => 1, AutoCommit => 1, PrintError => 0}))
171             || die "$PRG: connect to '$DBCONN' failed:\n", $DBI::errstr;
172              
173             # check vdirs
174 0 0       0 if( check_vdirs_struct() ) {
175 0 0       0 $dbh->disconnect || die "$PRG: Disconnect failed. Reason: ", $DBI::errstr;
176 0         0 die "$PRG: check 'vdirs' structure in $PRG\n";
177             }
178              
179             # check database
180 0 0       0 if( check_db_tables() ) {
181 0 0       0 $dbh->disconnect || die "$PRG: Disconnect failed. Reason: ", $DBI::errstr;
182 0         0 die "$PRG: database wrong: run '$PRG recreatedb' to recreate tables\n";
183             }
184              
185             # readline settings
186 0         0 $term = new Term::ReadLine 'dbshell console';
187 0   0     0 $OUT = $term->OUT || \*STDOUT;
188 0         0 $term->ornaments( 0 );
189 0         0 $term->Attribs->{attempted_completion_function} = \&dbshell_completion;
190              
191 0         0 my $line; # command line
192             my $cmd; # the command
193 0         0 my @arg; # the command's parameters
194              
195 0         0 my $prompttemplate = "$PRG (/%s): ";
196 0         0 my $prompt = sprintf( $prompttemplate, $vwd );
197              
198             # the loop
199 0         0 while ( defined ($line = $term->readline($prompt)) ) {
200             # remove whitespace
201 0         0 $line =~ s/^\s*//;
202 0         0 $line =~ s/\s*//;
203 0         0 ($cmd, @arg ) = split( ' ', $line );
204 0 0       0 next unless defined $cmd;
205            
206 0         0 my $command = $commands{$cmd};
207 0 0       0 if( defined $command ) {
208 0 0       0 last if &{$command->{func}}( @arg );
  0         0  
209             }else{
210 0         0 print $OUT "unknown command '$cmd', try 'help'\n";
211             }
212 0         0 $prompt = sprintf( $prompttemplate, $vwd );
213             }
214 0 0       0 $dbh->disconnect || die "$PRG: Disconnect failed. Reason: ", $DBI::errstr;
215 0         0 return;
216             }
217              
218              
219             sub recreatedb(\%$$$$$) {
220              
221 0     0 0 0 ($vdirs,$PRG,$VERSION,$DBCONN,$DBUSER,$DBPWD) = @_;
222              
223             # connect to db
224 0 0       0 ($dbh = DBI->connect( $DBCONN, $DBUSER, $DBPWD,
225             {ChopBlanks => 1, AutoCommit => 1, PrintError => 0}))
226             || die "$PRG: connect to '$DBCONN' failed:\n", $DBI::errstr;
227              
228             # check vdirs
229 0 0       0 if( check_vdirs_struct() ) {
230 0         0 die "$PRG: check 'vdirs' structure in $PRG\n";
231             }
232              
233 0         0 recreate_db_tables();
234              
235 0 0       0 $dbh->disconnect || die "$PRG: Disconnect failed. Reason: ", $DBI::errstr;
236 0         0 return;
237             }
238              
239              
240             ########################################################################
241             # c o m m a n d f u n c t i o n s
242             ########################################################################
243              
244             ########################################################################
245             # com_help()
246             #
247             sub com_help() {
248 0     0 0 0 my $arg = shift;
249 0 0       0 if( defined $arg ) {
250 0 0       0 if( defined $commands{$arg} ) {
251 0         0 print $OUT "$arg\t$commands{$arg}->{doc}\n";
252             }else{
253 0         0 print $OUT "no help for '$arg'\n";
254             }
255             }else{
256 0         0 foreach my $i (sort keys(%commands) ) {
257 0         0 print $OUT "$i\t$commands{$i}->{doc}\n";
258             }
259             }
260 0         0 return 0;
261             }
262              
263             ########################################################################
264             # com_ls()
265             #
266             sub com_ls() {
267 0     0 0 0 my @files;
268             my $i;
269              
270 0         0 my $x = shift;
271 0 0       0 if( defined $x ) {
272 0         0 print $OUT "ls: usage: $commands{ls}->{doc}\n";
273 0         0 return 0;
274             }
275              
276             # get dirs
277 0         0 foreach $i (sort keys(%{$vdirs}) ) {
  0         0  
278 0         0 push @files, "($i)";
279             }
280              
281             # get files
282 0 0       0 if( length($vwd) ) {
283 0         0 my $st;
284 0         0 my $col = $vdirs->{$vwd}{fnamcol};
285 0         0 $st = $dbh->prepare("select $col from $vwd order by $col");
286 0 0       0 unless( $st ) {
287 0         0 print $OUT "$PRG: can't prepare ls query '$vwd':\n " . $dbh->errstr;
288 0         0 return 0;
289             }
290 0 0       0 unless( $st->execute() ) {
291 0         0 print $OUT "$PRG: can't exec ls query '$vwd':\n " . $dbh->errstr;
292 0         0 return 0;
293             }
294 0         0 while( $i = $st->fetchrow_array() ) {
295 0         0 push @files, "$i";
296             }
297 0         0 $st->finish();
298             }
299              
300             # show it
301 0         0 my $numrow = int( $#files / $NUM_LS_COL ) + 1;
302 0         0 my $r = 0;
303 0         0 my $c = 0;
304 0         0 my $placeh = $LS_COL_WIDTH - 2;
305 0         0 for( $r=0; $r<$numrow; $r++ ) {
306 0         0 for( $c=0; $c<$NUM_LS_COL; $c++ ) {
307 0         0 $i = $c*$numrow+$r;
308 0 0       0 printf $OUT "%-${placeh}s ", $files[$i] if $i <= $#files;
309             }
310 0         0 print $OUT "\n";
311             }
312 0         0 return 0;
313             }
314              
315             ########################################################################
316             # com_ld()
317             #
318             sub com_ld() {
319 0     0 0 0 my @files;
320             my @com; # comments
321 0         0 my $i;
322 0         0 my $x = shift;
323 0 0       0 if( defined $x ) {
324 0         0 print $OUT "ls: usage: $commands{ld}->{doc}\n";
325 0         0 return 0;
326             }
327              
328             # get dirs
329 0         0 foreach $i (sort keys(%{$vdirs}) ) {
  0         0  
330 0         0 push @files, "($i)";
331 0         0 push @com, $vdirs->{$i}{desc};
332             }
333              
334             # show it
335 0         0 my $maxlen = 0;
336 0         0 foreach $i (@files) {
337 0 0       0 if( length($i) > $maxlen ) {$maxlen = length($i); }
  0         0  
338             }
339              
340 0         0 for( $i=0; $i<=$#files; $i++ ) {
341 0         0 printf $OUT "%-${maxlen}s| %s\n", $files[$i], $com[$i];
342             }
343 0         0 print $OUT "\n";
344 0         0 com_ll();
345 0         0 return 0;
346             }
347              
348             ########################################################################
349             # com_ll()
350             #
351             sub com_ll() {
352 0     0 0 0 my @files;
353             my @com; # comments
354 0         0 my $i;
355 0         0 my $c;
356              
357 0         0 my $x = shift;
358 0 0       0 if( defined $x ) {
359 0         0 print $OUT "ls: usage: $commands{ll}->{doc}\n";
360 0         0 return 0;
361             }
362              
363             # get files
364 0 0       0 if( defined $vdirs->{$vwd}{comcol} ) {
365 0         0 my $comcol = $vdirs->{$vwd}{comcol};
366 0         0 my $col = $vdirs->{$vwd}{fnamcol};
367 0         0 my $st;
368 0         0 $st = $dbh->prepare("select $col, $comcol from $vwd order by $col");
369 0 0       0 unless( $st ) {
370 0         0 print $OUT "$PRG: can't prepare ll query '$vwd':\n " . $dbh->errstr;
371 0         0 return 0;
372             }
373 0 0       0 unless( $st->execute() ) {
374 0         0 print $OUT "$PRG: can't exec ll query '$vwd':\n " . $dbh->errstr;
375 0         0 return 0;
376             }
377 0         0 while( ($i,$c) = $st->fetchrow_array() ) {
378 0 0       0 $c = "" unless defined $c;
379 0         0 push @files, "$i";
380 0         0 push @com, "$c";
381             }
382 0         0 $st->finish();
383             }else{
384 0         0 my $st;
385 0         0 my $col = $vdirs->{$vwd}{fnamcol};
386 0         0 $st = $dbh->prepare("select $col from $vwd order by $col");
387 0 0       0 unless( $st ) {
388 0         0 print $OUT "$PRG: can't prepare ls query '$vwd':\n " . $dbh->errstr;
389 0         0 return 0;
390             }
391 0 0       0 unless( $st->execute() ) {
392 0         0 print $OUT "$PRG: can't exec ls query '$vwd':\n " . $dbh->errstr;
393 0         0 return 0;
394             }
395 0         0 while( $i = $st->fetchrow_array() ) {
396 0         0 push @files, "$i";
397 0         0 push @com, "";
398             }
399 0         0 $st->finish();
400             }
401              
402             # show it
403 0         0 my $maxlen = 0;
404 0         0 foreach $i (@files) {
405 0 0       0 if( length($i) > $maxlen ) {$maxlen = length($i); }
  0         0  
406             }
407              
408 0         0 for( $i=0; $i<=$#files; $i++ ) {
409 0         0 printf $OUT "%-${maxlen}s| %s\n", $files[$i], $com[$i];
410             }
411 0         0 return 0;
412             }
413              
414             ########################################################################
415             # com_cd()
416             #
417             sub com_cd() {
418 0     0 0 0 my ($arg,$x) = @_;
419 0 0 0     0 if( defined $arg and !defined $x) {
420 0 0       0 if( exists $vdirs->{$arg} ) {
421 0         0 $vwd = "$arg";
422             }else{
423 0         0 print $OUT "no such directory '$arg'\n";
424             }
425             }else{
426 0         0 print $OUT "cd: usage: $commands{cd}->{doc}\n";
427             }
428 0         0 return 0;
429             }
430              
431              
432             ########################################################################
433             # com_quit()
434             #
435             sub com_quit() {
436 0     0 0 0 return 1;
437             }
438              
439             ########################################################################
440             # com_ver()
441             #
442             sub com_ver() {
443 0     0 0 0 print $OUT " DBIx-FileSystem Version: $DBIx::FileSystem::VERSION\n";
444 0         0 print $OUT " $PRG \%vdirs version: $VERSION\n";
445 0         0 return 0;
446             }
447              
448             ########################################################################
449             # com_rm()
450             #
451             sub com_rm() {
452 0     0 0 0 my $r;
453 0         0 my ($arg,$x) = @_;
454 0 0 0     0 if( defined $arg and !defined $x ) {
455 0 0       0 if( $vdirs->{$vwd}{edit} ) {
456 0 0 0     0 if( $vdirs->{$vwd}{defaultfile} and $vdirs->{$vwd}{defaultfile} eq $arg ) {
457 0         0 print $OUT "rm: error: cannot remove default file '$arg'\n";
458             }else{
459 0         0 my @reffiles = get_who_refs_me( $vwd, $arg );
460 0 0       0 if( $#reffiles == -1 ) {
461 0         0 my $rmerr;
462 0 0       0 if( exists $vdirs->{$vwd}{rmcheck} ) {
463 0         0 $rmerr = &{$vdirs->{$vwd}->{rmcheck}}( $vwd, $arg, $dbh);
  0         0  
464             }
465 0 0       0 if( defined $rmerr ) {
466 0         0 print $OUT "rm: cannot remove: $rmerr\n";
467             }else{
468 0         0 my $fnc = $vdirs->{$vwd}{fnamcol};
469 0         0 $r = $dbh->do( "delete from $vwd where $fnc='$arg'");
470 0 0       0 if( !defined $r ) {
    0          
471 0         0 print $OUT "rm: database error:\n" . $dbh->errstr;
472             }elsif( $r==0 ) {
473 0         0 print $OUT "rm: no such file '$arg'\n";
474             }
475             }
476             }else{
477 0         0 print $OUT "rm: cannot remove: file '$arg' referenced by:\n ";
478 0         0 print $OUT join( "\n ", @reffiles );
479 0         0 print $OUT "\n";
480             }
481             }
482             }else{
483 0         0 print $OUT "rm: error: read only directory '/$vwd'\n";
484             }
485             }else{
486 0         0 print $OUT "rm: usage: $commands{rm}{doc}\n";
487             }
488 0         0 return 0;
489             }
490              
491              
492             ########################################################################
493             # com_cp()
494             #
495             sub com_cp() {
496 0     0 0 0 my $r;
497 0         0 my ($old,$new,$x) = @_;
498 0 0 0     0 if( defined $old and defined $new and !defined $x) {
      0        
499 0 0       0 if( $vdirs->{$vwd}{edit} ) {
500 0         0 my $fnc = $vdirs->{$vwd}{fnamcol};
501 0 0 0     0 if( (length($new)<=$vdirs->{$vwd}{cols}{$fnc}{len}) and !($new=~/\W+/)) {
502 0         0 my $fnc = $vdirs->{$vwd}{fnamcol};
503 0         0 my $insert = "insert into $vwd (";
504 0         0 my $select = "select ";
505 0         0 my $cols = $vdirs->{$vwd}{cols};
506 0         0 foreach my $col (sort keys(%{$cols}) ) {
  0         0  
507 0         0 $insert .= "$col,";
508 0 0       0 if( $col eq $fnc ) {
    0          
509 0         0 $select .= "'$new',";
510             }elsif( exists $vdirs->{$vwd}{cols}{$col}{uniq} ) {
511 0         0 $select .= "NULL,";
512             }else{
513 0         0 $select .= "$col,";
514             }
515             }
516 0         0 chop $insert;
517 0         0 chop $select;
518 0         0 $insert .= ")";
519 0         0 $select .= " from $vwd where $fnc='$old'";
520 0         0 $r = $dbh->do( "$insert $select");
521 0 0 0     0 if( !defined $r or $r!=1 ) {
522 0         0 print "cp: error: no file '$old' or file '$new' exists\n";
523             }
524             }else{
525 0         0 print $OUT "cp: error: illegal or to long filename '$new'\n";
526             }
527             }else{
528 0         0 print $OUT "cp: error: read only directory '/$vwd'\n";
529             }
530             }else{
531 0         0 print $OUT "cp: usage: $commands{cp}{doc}\n";
532             }
533 0         0 return 0;
534             }
535              
536              
537             ########################################################################
538             # com_sum()
539             #
540             sub com_sum() {
541 0     0 0 0 my ($arg,$x) = @_;
542 0 0 0     0 if( defined $arg and !defined $x ) {
543 0 0       0 if( print_file( $OUT, $arg, 0 ) == 1 ) {
544 0         0 print $OUT "sum: no such file '$arg'\n";
545             }
546             }else{
547 0         0 print $OUT "sum: usage: $commands{sum}{doc}\n";
548             }
549 0         0 return 0;
550             }
551              
552             ########################################################################
553             # com_cat()
554             #
555             sub com_cat() {
556 0     0 0 0 my ($arg,$x) = @_;
557              
558 0 0 0     0 if( defined $arg and !defined $x ) {
559 0 0       0 if( print_file( $OUT, $arg, 1 ) == 1 ) {
560 0         0 print $OUT "cat: no such file '$arg'\n";
561             }
562             }else{
563 0         0 print $OUT "cat: usage: $commands{cat}{doc}\n";
564             }
565 0         0 return 0;
566             }
567              
568             ########################################################################
569             # com_vi()
570             #
571             sub com_vi() {
572 0     0 0 0 my ($arg,$x) = @_;
573 0         0 my $tmpf;
574             my $tmpf_mtime;
575 0         0 my $r; # 0: file printed exists / create update SQL string
576             ; # 1: file printed did not exist / create insert SQL string
577 0         0 my $err;
578 0         0 my $sql;
579 0         0 my $ln = 1; # line number where editor starts
580              
581 0 0 0     0 if( defined $arg and !defined $x ) {
582 0 0       0 if( $vdirs->{$vwd}{edit} ) {
583 0         0 my $fnc = $vdirs->{$vwd}{fnamcol};
584 0 0 0     0 if( (length($arg)<=$vdirs->{$vwd}{cols}{$fnc}{len}) and !($arg=~/\W+/)) {
585 0         0 while( 1 ) { $tmpf = tmpnam();
  0         0  
586 0 0       0 sysopen( FN, $tmpf, O_RDWR | O_CREAT | O_EXCL ) && last; }
587 0         0 $r = print_file( \*FN, $arg, 2 );
588 0         0 close( FN );
589 0         0 $tmpf_mtime = (stat $tmpf)[9]; # remember mtime of tempfile
590 0 0 0     0 if( $r==0 or $r==1 ) {
591 0         0 while( 1 ) {
592 0         0 system( "$EDITOR +$ln $tmpf" );
593 0         0 ($ln,$err,$sql) = create_sql_from_file( $tmpf, $vwd, $arg, $r );
594 0 0       0 if( defined $err ) {
595 0         0 my $inp = want_to_edit_again( $err );
596 0 0       0 next if $inp eq 'y';
597 0 0       0 last if $inp eq 'n';
598             }
599             ### print $OUT ">>>$sql<<<\n"; ######### hierhierhier
600 0 0 0     0 if( length($sql) and $tmpf_mtime != (stat $tmpf)[9] ) {
601 0         0 my $res = $dbh->do( $sql );
602 0 0       0 if( !defined $res ) {
    0          
603 0         0 my $inp=want_to_edit_again( "save to database:\n".$dbh->errstr);
604 0 0       0 if($inp eq 'y') { $ln = 1; next; }
  0         0  
  0         0  
605             }elsif( $res == 0 ) {
606 0         0 print $OUT "\n\n\n\n\nvi: nothing saved\n";
607             }
608             }else{
609 0         0 print $OUT "\n\n\n\n\nvi: nothing saved\n";
610             }
611 0         0 last;
612             }
613             }else{
614 0         0 print $OUT "vi: no such file '$arg'\n";
615             }
616 0         0 unlink( $tmpf );
617             }else{
618 0         0 print $OUT "vi: error: illegal or too long filename '$arg'\n";
619             }
620             }else{
621 0         0 print $OUT "vi: error: read only directory '/$vwd'\n";
622             }
623             }else{
624 0         0 print $OUT "vi: usage: $commands{vi}{doc}\n";
625             }
626 0         0 return 0;
627             }
628              
629             ########################################################################
630             # com_wref()
631             #
632             sub com_wref() {
633 0     0 0 0 my ($arg,$x) = @_;
634 0 0 0     0 if( defined $arg and !defined $x ) {
635 0         0 my @reffiles = get_who_refs_me( $vwd, $arg );
636 0 0       0 if( $#reffiles > -1 ) {
637 0         0 print $OUT join( "\n", @reffiles );
638 0         0 print $OUT "\n";
639             }else{
640 0         0 print $OUT "wrefs: no one references '$arg'\n";
641             }
642             }else{
643 0         0 print $OUT "wrefs: usage: $commands{wrefs}{doc}\n";
644             }
645 0         0 return 0;
646             }
647              
648             ########################################################################
649             # com_vgrep()
650             #
651             sub com_vgrep() {
652 0     0 0 0 my ($arg,$x) = @_;
653 0 0 0     0 if( defined $arg and !defined $x ) {
654 0         0 do_vgrep( $arg );
655             }else{
656 0         0 print $OUT "vgrep: usage: $commands{vgrep}{doc}\n";
657             }
658 0         0 return 0;
659             }
660              
661              
662              
663              
664              
665              
666             ########################################################################
667             # c o m p l e t i o n
668             ########################################################################
669              
670             # from p5-ReadLine example 'FileManager'
671              
672             # Attempt to complete on the contents of TEXT. START and END bound
673             # the region of rl_line_buffer that contains the word to complete.
674             # TEXT is the word to complete. We can use the entire contents of
675             # rl_line_buffer in case we want to do some simple parsing. Return
676             # the array of matches, or NULL if there aren't any.
677             sub dbshell_completion {
678 0     0 0 0 my ($text, $line, $start, $end) = @_;
679            
680 0         0 my @matches = ();
681              
682             # If this word is at the start of the line, then it is a command
683             # to complete. Otherwise it is the name of a file in the current
684             # directory.
685 0 0       0 if ($start == 0) {
    0          
686 0         0 @matches = $term->completion_matches($text, \&command_generator);
687             }elsif($line =~ /^cd\s.*/ ) {
688 0         0 @matches = $term->completion_matches($text, \&vdir_generator);
689             }else{
690 0         0 @matches = $term->completion_matches($text, \&vfile_generator);
691             }
692              
693 0         0 return @matches;
694             }
695              
696             # from p5-ReadLine example 'FileManager'
697             # Generator function for command completion. STATE lets us know
698             # whether to start from scratch; without any state (i.e. STATE == 0),
699             # then we start at the top of the list.
700              
701             ## Term::ReadLine::Gnu has list_completion_function similar with this
702             ## function. I defined new one to be compared with original C version.
703             {
704             my $list_index;
705             my @name;
706              
707             sub command_generator {
708 0     0 0 0 my ($text, $state) = @_;
709 0         0 $text =~ s/\./\\\./g;
710 0         0 $text =~ s/\*/\\\*/g;
711 0         0 $text =~ s/\[/\\\[/g;
712 0         0 $text =~ s/\]/\\\]/g;
713 0         0 $text =~ s/\$/\\\$/g;
714 0         0 $text =~ s/\^/\\\^/g;
715              
716             # If this is a new word to complete, initialize now. This
717             # includes saving the length of TEXT for efficiency, and
718             # initializing the index variable to 0.
719 0 0       0 unless ($state) {
720 0         0 $list_index = 0;
721 0         0 @name = keys(%commands);
722             }
723              
724             # Return the next name which partially matches from the
725             # command list.
726 0         0 while ($list_index <= $#name) {
727 0         0 $list_index++;
728 0 0       0 return $name[$list_index - 1]
729             if ($name[$list_index - 1] =~ /^$text/);
730             }
731             # If no names matched, then return NULL.
732 0         0 return undef;
733             }
734             }
735              
736             {
737             my $list_index;
738             my @name;
739              
740             sub vdir_generator {
741 0     0 0 0 my ($text, $state) = @_;
742 0         0 $text =~ tr/a-zA-Z0-9_\///cd;
743 0         0 $text =~ s/\./\\\./g;
744 0         0 $text =~ s/\*/\\\*/g;
745 0         0 $text =~ s/\[/\\\[/g;
746 0         0 $text =~ s/\]/\\\]/g;
747 0         0 $text =~ s/\$/\\\$/g;
748 0         0 $text =~ s/\^/\\\^/g;
749            
750             # If this is a new word to complete, initialize now. This
751             # includes saving the length of TEXT for efficiency, and
752             # initializing the index variable to 0.
753 0 0       0 unless ($state) {
754 0         0 $list_index = 0;
755 0         0 @name = keys(%{$vdirs});
  0         0  
756             }
757              
758             # Return the next name which partially matches
759 0         0 while ($list_index <= $#name) {
760 0         0 $list_index++;
761 0 0       0 return $name[$list_index - 1]
762             if ($name[$list_index - 1] =~ /^$text/);
763             }
764             # If no names matched, then return NULL.
765 0         0 return undef;
766             }
767             }
768              
769             {
770             my $list_index;
771             my @name;
772              
773             sub vfile_generator {
774 0     0 0 0 my ($text, $state) = @_;
775 0         0 $text =~ tr/a-zA-Z0-9_\///cd;
776 0         0 $text =~ s/\./\\\./g;
777 0         0 $text =~ s/\*/\\\*/g;
778 0         0 $text =~ s/\[/\\\[/g;
779 0         0 $text =~ s/\]/\\\]/g;
780 0         0 $text =~ s/\$/\\\$/g;
781 0         0 $text =~ s/\^/\\\^/g;
782              
783 0 0       0 unless ($state) {
784 0         0 undef @name;
785 0         0 $list_index = 0;
786 0         0 my $st;
787 0         0 my $col = $vdirs->{$vwd}{fnamcol};
788 0         0 $st = $dbh->prepare("select $col from $vwd order by $col");
789 0 0       0 unless( $st ) {
790 0         0 print $OUT "$PRG: prep completion query '$vwd':\n " . $dbh->errstr;
791 0         0 return undef;
792             }
793 0 0       0 unless( $st->execute() ) {
794 0         0 print $OUT "$PRG: exec completion query '$vwd':\n " . $dbh->errstr;
795 0         0 return undef;
796             }
797 0         0 my $i;
798 0         0 while( $i = $st->fetchrow_array() ) {
799 0         0 push @name, $i;
800             }
801 0         0 $st->finish();
802             }
803              
804             # Return the next name which partially matches
805 0         0 while ($list_index <= $#name) {
806 0         0 $list_index++;
807 0 0       0 return $name[$list_index - 1]
808             if ($name[$list_index - 1] =~ /^$text/);
809             }
810             # If no names matched, then return NULL.
811 0         0 return undef;
812             }
813             }
814              
815             ########################################################################
816             # c h e c k i n g & c r e a t i o n
817             ########################################################################
818              
819             ########################################################################
820             # check_vdirs_struct()
821             #
822             sub check_vdirs_struct() {
823 0     0 0 0 my $pre = "internal error: vdirs structure:\n ";
824 0         0 foreach my $dir (keys(%{$vdirs}) ) {
  0         0  
825             # init refby:
826             # a hash holding the dir (key) and list of columns (value) this dir
827             # is referenced by. Will be set up 57 lines later (# setup refby)
828 0         0 $vdirs->{$dir}->{refby} = {};
829             }
830              
831 0         0 foreach my $dir (sort keys(%{$vdirs}) ) {
  0         0  
832 0 0       0 $vwd = $dir unless defined $vwd; # set $vwd to alphabetic first dir
833              
834 0 0       0 unless( defined $vdirs->{$dir}->{desc}) {
835 0         0 print "$pre dir '$dir': 'desc' missing\n";
836 0         0 return 1;
837             }
838 0 0       0 unless( defined $vdirs->{$dir}->{edit}) {
839 0         0 print "$pre dir '$dir': 'edit' missing\n";
840 0         0 return 1;
841             }
842              
843 0 0       0 unless( defined $vdirs->{$dir}->{cols}) {
844 0         0 print "$pre dir '$dir': 'cols' missing\n";
845 0         0 return 1;
846             }
847              
848 0 0       0 unless( defined $vdirs->{$dir}->{refby}) {
849 0         0 print "$pre dir '$dir': 'refby' missing \n";
850 0         0 return 1;
851             }
852              
853 0         0 my $fnamcol = $vdirs->{$dir}{fnamcol};
854 0 0       0 unless( defined $fnamcol) {
855 0         0 print "$pre dir '$dir': 'fnamcol' missing\n";
856 0         0 return 1;
857             }
858 0 0       0 unless( defined $vdirs->{$dir}{cols}{$fnamcol} ) {
859 0         0 print "$pre dir '$dir', fnamcol set to '$fnamcol', but column missing\n";
860 0         0 return 1;
861             }
862 0 0       0 if( $vdirs->{$dir}{cols}{$fnamcol}{type} ne 'char' ) {
863 0         0 print "$pre dir '$dir', fnamcol-column '$fnamcol' type must be 'char'\n";
864 0         0 return 1;
865             }
866 0 0       0 if( $vdirs->{$dir}{edit} == 1 ) {
867 0 0       0 unless( defined $vdirs->{$dir}{cols}{$fnamcol}{len} ) {
868 0         0 print "$pre dir '$dir', fnamcol-column '$fnamcol': missing 'len'\n";
869 0         0 return 1;
870             }
871             }
872 0 0       0 if( $vdirs->{$dir}{cols}{$fnamcol}{len} + 2 > $LS_COL_WIDTH ) {
873 0         0 my $maxlen = $LS_COL_WIDTH - 2;
874 0         0 print "$pre dir '$dir', fnamcol-column '$fnamcol' len > $maxlen\n";
875 0         0 return 1;
876             }
877              
878 0         0 my $comcol = $vdirs->{$dir}{comcol};
879 0 0       0 if( defined $comcol) {
880 0 0       0 unless( defined $vdirs->{$dir}{cols}{$comcol} ) {
881 0         0 print "$pre dir '$dir', comcol set to '$comcol', but column missing\n";
882 0         0 return 1;
883             }
884 0 0       0 if( $vdirs->{$dir}{cols}{$comcol}{type} ne 'char' ) {
885 0         0 print "$pre dir '$dir', comcol-column '$comcol' type must be 'char'\n";
886 0         0 return 1;
887             }
888 0 0       0 unless( defined $vdirs->{$dir}{cols}{$comcol}{len} ) {
889 0         0 print "$pre dir '$dir', comcol-column '$comcol': missing 'len'\n";
890 0         0 return 1;
891             }
892             }
893              
894 0         0 my %varnames = (); # duplicate check: key=varname value=column name
895 0         0 my $cols = $vdirs->{$dir}{cols};
896 0         0 foreach my $col (keys(%{$cols} )) {
  0         0  
897             # check for deprecated 'delcp' option
898 0 0       0 if( exists $cols->{$col}{delcp} ) {
899 0         0 $cols->{$col}{uniq} = 1;
900 0         0 print "\nWARNING: $PRG: internal vdirs struct:\n dir '$dir', column '$col', option 'delcp' deprecated, use 'uniq'\n\n";
901             }
902              
903             # check for 'type' / 'ref'
904 0 0 0     0 unless( defined $cols->{$col}{type} || defined $cols->{$col}{ref} ) {
905 0         0 print "$pre dir '$dir', column '$col', either 'type' or 'ref' must be set\n";
906 0         0 return 1;
907             }
908 0 0 0     0 if( defined $cols->{$col}{ref} and !defined $vdirs->{$cols->{$col}{ref}}){
909 0         0 print "$pre dir '$dir', column '$col', elem 'ref': no dir '$cols->{$col}{ref}'\n";
910 0         0 return 1;
911             }
912              
913             # check for flags
914 0 0       0 if( exists $cols->{$col}{flags} ) {
915 0 0       0 if( $cols->{$col}{type} ne 'int' ) {
916 0         0 print "$pre dir '$dir', column '$col', when using 'flags' type must be 'int'\n";
917 0         0 return 1;
918             }
919 0 0       0 unless( ref( $cols->{$col}{flags} ) eq "HASH" ) {
920 0         0 print "$pre dir '$dir', column '$col', 'flags' must be a hash\n";
921 0         0 return -1;
922             }
923 0         0 foreach my $i (sort keys(%{$cols->{$col}{flags} }) ) {
  0         0  
924 0 0       0 if( $i =~ /\D/ ) {
925 0         0 print "$pre dir '$dir', column '$col', flags: bitno must be an int\n";
926 0         0 return 1;
927             }
928 0 0       0 unless( ref( $cols->{$col}{flags}{$i} ) eq "ARRAY" ) {
929 0         0 print "$pre dir '$dir', column '$col', bitno '$i': missing array with flagname + flagdescritpion\n";
930 0         0 return -1;
931             }
932 0 0       0 unless( defined $cols->{$col}{flags}{$i}->[0] ) {
933 0         0 print "$pre dir '$dir', column '$col', bitno '$i': missing flagname\n";
934 0         0 return -1;
935             }
936 0 0       0 if( $cols->{$col}{flags}{$i}->[0] =~ / / ) {
937 0         0 print "$pre dir '$dir', column '$col', bitno '$i': flagname must be a single word\n";
938 0         0 return -1;
939             }
940 0 0       0 unless( defined $cols->{$col}{flags}{$i}->[1] ) {
941 0         0 print "$pre dir '$dir', column '$col', bitno '$i': missing flagdescription\n";
942 0         0 return -1;
943             }
944             }
945             }
946              
947             # check for enums
948 0 0       0 if( exists $cols->{$col}{enums} ) {
949 0 0       0 if( $cols->{$col}{type} ne 'int' ) {
950 0         0 print "$pre dir '$dir', column '$col', when using 'enums' type must be 'int'\n";
951 0         0 return 1;
952             }
953 0 0       0 unless( ref( $cols->{$col}{enums} ) eq "HASH" ) {
954 0         0 print "$pre dir '$dir', column '$col', 'enums' must be a hash\n";
955 0         0 return -1;
956             }
957 0         0 foreach my $i (sort keys(%{$cols->{$col}{enums} }) ) {
  0         0  
958 0 0       0 if( $i =~ /\D/ ) {
959 0         0 print "$pre dir '$dir', column '$col', enums: enumvalue must be an int\n";
960 0         0 return 1;
961             }
962 0 0       0 unless( ref( $cols->{$col}{enums}{$i} ) eq "ARRAY" ) {
963 0         0 print "$pre dir '$dir', column '$col', enumvalue '$i': missing array with enumname + enumdescritpion\n";
964 0         0 return -1;
965             }
966 0 0       0 unless( defined $cols->{$col}{enums}{$i}->[0] ) {
967 0         0 print "$pre dir '$dir', column '$col', enumvalue '$i': missing enumname\n";
968 0         0 return -1;
969             }
970 0 0       0 if( $cols->{$col}{enums}{$i}->[0] =~ / / ) {
971 0         0 print "$pre dir '$dir', column '$col', enumvalue '$i': enumname must be a single word\n";
972 0         0 return -1;
973             }
974 0 0       0 unless( defined $cols->{$col}{enums}{$i}->[1] ) {
975 0         0 print "$pre dir '$dir', column '$col', enumvalue '$i': missing enumdescription\n";
976 0         0 return -1;
977             }
978             }
979             }
980              
981             # setup refby
982 0 0       0 if( defined $cols->{$col}{ref} ) {
983 0         0 push @{$vdirs->{$cols->{$col}{ref}}{refby}{$dir} }, $col;
  0         0  
984             }
985              
986 0 0 0     0 if( defined $cols->{$col}{type} and $vdirs->{$dir}{edit}==1) {
987 0 0 0     0 if( $cols->{$col}{type} ne 'char' and
      0        
      0        
      0        
988             $cols->{$col}{type} ne 'int' and
989             $cols->{$col}{type} ne 'smallint' and
990             $cols->{$col}{type} ne 'inet' and
991             $cols->{$col}{type} ne 'cidr' )
992             {
993 0         0 print "$pre dir '$dir', column '$col', type must be one of char/int/smallint/inet/cidr when edit=1\n";
994 0         0 return 1;
995             }
996             }
997              
998 0 0       0 unless( defined $cols->{$col}{var} ) {
999 0         0 print "$pre dir '$dir', column '$col', missing elem 'var'\n";
1000 0         0 return 1;
1001             }
1002 0 0       0 unless( defined $cols->{$col}{desc} ) {
1003 0         0 print "$pre dir '$dir', column '$col', missing elem 'desc'\n";
1004 0         0 return 1;
1005             }
1006 0 0       0 unless( defined $cols->{$col}{pos} ) {
1007 0         0 print "$pre dir '$dir', column '$col', missing elem 'pos'\n";
1008 0         0 return 1;
1009             }
1010              
1011             # check for duplicate var
1012 0         0 my $varname = $cols->{$col}{var};
1013 0 0       0 if( defined $varnames{ $varname } ) {
1014 0         0 print "$pre dir '$dir', var '$varname' used for columns '$col' and '$varnames{$varname}'\n";
1015 0         0 return 1;
1016             }
1017 0         0 $varnames{ $varname } = $col;
1018              
1019             }
1020             }
1021 0         0 return 0;
1022             }
1023              
1024             ########################################################################
1025             # check_db_tables()
1026             #
1027             sub check_db_tables() {
1028 0     0 0 0 my $st;
1029              
1030             # check version no of db tables
1031 0         0 $st = $dbh->prepare("select value from tablestatus where tag='version' ");
1032 0 0       0 unless( $st ) {
1033 0         0 print "$PRG: can't prepare query 'version':\n " . $dbh->errstr;
1034 0         0 return 1;
1035             }
1036 0 0       0 unless( $st->execute() ) {
1037 0         0 print "$PRG: can't execute query 'version':\n " . $dbh->errstr;
1038 0         0 return 1;
1039             }
1040            
1041 0         0 my ($dbversion) = $st->fetchrow_array();
1042 0 0       0 unless( $dbversion ) {
1043 0         0 print "$PRG: can't query db: table version\n";
1044 0         0 return 1;
1045             }
1046            
1047 0         0 $st->finish();
1048 0 0       0 if( $VERSION ne $dbversion ) {
1049 0         0 print
1050             "$PRG: version mismatch: $PRG='$VERSION' dbtables='$dbversion'\n";
1051 0         0 return 1;
1052             }
1053              
1054             # check (existence) of other tables
1055 0         0 foreach my $i (sort keys(%{$vdirs}) ) {
  0         0  
1056 0         0 $st = $dbh->prepare("select * from $i limit 1");
1057 0 0       0 unless( $st ) {
1058 0         0 print "$PRG: can't prepare query '$i':\n " . $dbh->errstr;
1059 0         0 return 1;
1060             }
1061 0 0       0 unless( $st->execute() ) {
1062 0         0 print "$PRG: can't execute query '$i':\n " . $dbh->errstr;
1063 0         0 return 1;
1064             }
1065 0         0 my @dummy = $st->fetchrow_array();
1066 0         0 $st->finish();
1067             }
1068 0         0 return 0; # all Ok
1069             }
1070              
1071              
1072              
1073             ########################################################################
1074             # recreate_db_tables();
1075             #
1076             sub recreate_db_tables() {
1077 0     0 0 0 my $r;
1078 0         0 $dbh->do( "drop table tablestatus" );
1079 0         0 $r = $dbh->do(
1080             qq{ create table tablestatus ("tag" char(16),
1081             "value" char(16) PRIMARY KEY) } );
1082 0 0       0 unless( $r ) {
1083 0         0 print "$PRG: create table tablestatus:\n " . $dbh->errstr;
1084 0         0 return;
1085             }
1086 0         0 $r = $dbh->do(
1087             qq{ insert into tablestatus (tag, value) values ('version','$VERSION' )});
1088 0 0       0 unless( $r ) {
1089 0         0 print "$PRG: insert version into tablestatus:\n " . $dbh->errstr;
1090 0         0 return;
1091             }
1092              
1093             # recreate other tables
1094 0         0 foreach my $tab (sort keys(%{$vdirs}) ) {
  0         0  
1095 0         0 $dbh->do( "drop table $tab" );
1096 0         0 my $create = "create table $tab (";
1097 0         0 my $cols = $vdirs->{$tab}{cols};
1098 0         0 foreach my $col (keys(%{$cols}) ) {
  0         0  
1099 0 0       0 if( defined $cols->{$col}{ref} ) {
1100 0         0 my $rdir = $cols->{$col}{ref};
1101 0         0 my $rfnc = $vdirs->{$rdir}{fnamcol};
1102 0 0       0 if( defined $vdirs->{$rdir}{cols}{$rfnc}{len} ) {
1103 0         0 $create .= "$col $vdirs->{$rdir}{cols}{$rfnc}{type}($vdirs->{$rdir}{cols}{$rfnc}{len})";
1104             }else{
1105 0         0 $create .= "$col $vdirs->{$rdir}{cols}{$rfnc}{type}";
1106             }
1107             }else{
1108 0 0       0 if( defined $cols->{$col}{len} ) {
1109 0         0 $create .= "$col $cols->{$col}{type}($cols->{$col}{len})";
1110             }else{
1111 0         0 $create .= "$col $cols->{$col}{type}";
1112             }
1113 0 0       0 $create .= " $cols->{$col}{colopt}" if defined $cols->{$col}{colopt};
1114             }
1115 0         0 $create .= ",";
1116             }
1117 0         0 chop $create;
1118 0         0 $create .= ")";
1119 0         0 $r = $dbh->do( $create );
1120 0 0       0 unless( $r ) {
1121 0         0 print "$PRG: create table $tab:\n " . $dbh->errstr;
1122 0         0 return;
1123             }
1124 0 0       0 my $df = $vdirs->{$tab}{defaultfile} if exists $vdirs->{$tab}{defaultfile};
1125 0 0       0 if( $df ) {
1126 0         0 my $fnc = $vdirs->{$tab}{fnamcol};
1127 0 0 0     0 if( (length($df)<=$vdirs->{$tab}{cols}{$fnc}{len}) and !($df=~/\W+/)) {
1128 0         0 $r = $dbh->do( "insert into $tab ($fnc) values ('$df')");
1129 0 0 0     0 if( !defined $r or $r==0 ) {
1130 0         0 print "ERROR: couldn't create default entry '$df' in '/$tab':" .
1131             $dbh->errstr;
1132             }
1133             }else{
1134 0         0 print "ERROR: illegal or to long default filename '$df' in '/$tab'\n";
1135             }
1136             }
1137             }
1138 0         0 return;
1139              
1140             } # recreate_db_tables()
1141              
1142             ########################################################################
1143             # print_file( FH, fnam, verbose );
1144             # create new pseudo file for cat/vi from database
1145             # FH: file handle for output
1146             # fnam: the filename (key from db)
1147             # verbose: 0: exclude comments, print only if fnam exists
1148             # 1: include comments, print only if fnam exists
1149             # 2: include comments, always print: print values if fnam exists,
1150             # else print NULL values
1151             # return:
1152             # 0: Ok
1153             # 1: file does not exist, (but NULL valued file was printed if verbose=2)
1154             # 2: other error
1155             #
1156             sub print_file() {
1157 0     0 0 0 my $FH = shift;
1158 0         0 my $fnam = shift;
1159 0         0 my $verbose = shift;
1160              
1161 0         0 my @vars;
1162             my @dbvars;
1163 0         0 my $var;
1164 0         0 my $maxvarlen = 0;
1165 0         0 my @values;
1166             my @defaults;
1167 0         0 my @descs;
1168 0         0 my @isref;
1169 0         0 my @flags;
1170 0         0 my @enums;
1171 0         0 my $select = "select ";
1172 0         0 my $retval = 2;
1173              
1174             # prepare db query
1175 0         0 my $fnc = $vdirs->{$vwd}{fnamcol};
1176 0         0 my $cols = $vdirs->{$vwd}{cols};
1177 0         0 foreach my $col (sort {$cols->{$a}{pos} <=> $cols->{$b}{pos}}
  0         0  
  0         0  
1178             keys(%{$cols}) )
1179             {
1180 0 0       0 next if $col eq $fnc;
1181 0         0 $var = $cols->{$col}{var};
1182 0 0       0 if( length($var) > $maxvarlen ) {$maxvarlen = length($var); }
  0         0  
1183 0         0 push @vars, $var;
1184 0         0 push @dbvars,$col;
1185 0         0 push @descs, $cols->{$col}{desc};
1186 0 0       0 push @isref, exists $cols->{$col}{ref} ? $cols->{$col}{ref} : undef;
1187 0 0       0 push @flags, exists $cols->{$col}{flags} ? $cols->{$col}{flags} : undef;
1188 0 0       0 push @enums, exists $cols->{$col}{enums} ? $cols->{$col}{enums} : undef;
1189 0         0 $select .= "$col,";
1190             }
1191 0         0 chop $select;
1192 0         0 $select .= " from $vwd where $fnc=?";
1193            
1194             # query db
1195 0         0 my $st;
1196 0         0 $st = $dbh->prepare( $select );
1197 0 0       0 unless( $st ) {
1198 0         0 print $FH "$PRG: can't prep print query '$vwd':\n " . $dbh->errstr;
1199 0         0 return 2;
1200             }
1201 0 0       0 unless( $st->execute( $fnam ) ) {
1202 0         0 print $FH "$PRG: can't exec print query 1 '$vwd' :\n " . $dbh->errstr;
1203 0         0 return 2;
1204             }
1205 0         0 @values = $st->fetchrow_array();
1206 0         0 $st->finish();
1207              
1208 0 0 0     0 if( $vdirs->{$vwd}{defaultfile} and $vdirs->{$vwd}{defaultfile} ne $fnam ) {
1209 0 0       0 unless( $st->execute( $vdirs->{$vwd}{defaultfile} ) ) {
1210 0         0 print $FH "$PRG: can't exec print query 2 '$vwd':\n " . $dbh->errstr;
1211 0         0 return 2;
1212             }
1213 0         0 @defaults = $st->fetchrow_array();
1214             }
1215 0         0 $st->finish();
1216              
1217             # print it
1218 0         0 my $em = "*unset*";
1219              
1220 0 0       0 if( $verbose == 0 ) {
1221 0 0       0 if( @values ) {
1222             # print short version (command 'sum')
1223 0         0 $retval = 0;
1224 0         0 for( my $i=0; $i<= $#values; $i++ ) {
1225 0 0       0 print $FH &var_value_s( $maxvarlen, $vars[$i], $values[$i],
1226             $defaults[$i], $flags[$i], $enums[$i],
1227             @defaults ? 1 : 0
1228             );
1229             }
1230             }else{
1231 0         0 $retval = 1;
1232             }
1233             }else{
1234             # verbose == 1: (print long) 2: (print long, even if file does not exist)
1235 0         0 my $newfilemsg = "";
1236 0         0 my $print_it = 0;
1237 0 0       0 if( @values ) {
1238             # file exists
1239 0         0 $retval = 0;
1240 0         0 $print_it = 1;
1241             }else{
1242             # file does not exist
1243 0         0 $retval = 1;
1244 0 0       0 if( $verbose == 2 ) {
1245 0         0 $newfilemsg = "#\n# NEW FILE NEW FILE NEW FILE NEW FILE\n#\n";
1246 0         0 $print_it = 1;
1247 0         0 for( my $i=0; $i<= $#vars; $i++ ) {
1248 0         0 $values[$i] = undef;
1249             }
1250             }
1251             }
1252 0 0       0 if( $print_it == 1 ) {
1253             # command 'cat/vi': long version
1254 0         0 print $FH "$newfilemsg" ;
1255 0         0 print $FH "#\n# Settings for $vdirs->{$vwd}{cols}{$fnc}{desc} '$fnam'" ;
1256 0 0 0     0 if( $vdirs->{$vwd}{defaultfile} and
1257             $vdirs->{$vwd}{defaultfile} ne $fnam ) {
1258 0         0 print $FH " (defaults: '$vdirs->{$vwd}{defaultfile}')";
1259             }
1260 0         0 print $FH "\n#\n".
1261             "# - this is a comment, comments always start in the first column.\n".
1262             "# - all lines begin in the first column or are blank lines\n".
1263             "# - a unset variable will write NULL into the database column\n";
1264 0 0 0     0 if( $vdirs->{$vwd}{defaultfile} and
1265             $vdirs->{$vwd}{defaultfile} ne $fnam ) {
1266 0         0 print $FH "# - unset variables use the default values\n";
1267             }
1268 0         0 print $FH "#\n";
1269 0         0 for( my $i=0; $i<= $#values; $i++ ) {
1270             # variable with comment header
1271 0         0 printf $FH "\n# %-50s(%s)\n", $vars[$i], $dbvars[$i];
1272 0         0 foreach my $descline (split '\n', $descs[$i] ) {
1273 0         0 print $FH "# $descline\n";
1274             }
1275 0         0 print $FH "#\n";
1276 0 0       0 if( @defaults ) {
1277 0         0 my $def;
1278 0 0 0     0 if( defined $defaults[$i] and defined $flags[$i] ) {
    0 0        
    0          
1279 0         0 $def = build_flags( $defaults[$i], $flags[$i] );
1280             }elsif( defined $defaults[$i] and defined $enums[$i] ) {
1281 0         0 $def = build_enums( $defaults[$i], $enums[$i] );
1282             }elsif( defined $defaults[$i] ) {
1283 0         0 $def = $defaults[$i];
1284             }
1285 0         0 print $FH "# default: ";
1286 0 0       0 print $FH defined $def ? "$def\n#\n" : "$em\n#\n";
1287             }
1288 0         0 print $FH &var_value_v( $vars[$i],$values[$i],$isref[$i],
1289             $flags[$i],$enums[$i] );
1290             }
1291 0         0 print $FH "\n# end of file '$fnam'\n";
1292             }
1293             }
1294 0         0 return $retval;
1295              
1296             } # print_file()
1297              
1298             ########################################################################
1299             # var_value_v( var, value, ref, flags, enums )
1300             # return a var = value string for verbose print_file()
1301             # var: variable name (long version for cat/vi)
1302             # value: the value of var or undef
1303             # ref: the dir/table referenced by this var or undef
1304             # flags: anon hashref with flags setup from vdir or undef
1305             # enums: anon hashref with enums setup from vdir or undef
1306             # return:
1307             # the string to be printed
1308             #
1309             sub var_value_v() {
1310 0     0 0 0 my ($var, $value, $ref, $flags, $enums ) = @_;
1311 0         0 my $s = '';
1312 0 0       0 if( defined $ref ) {
    0          
    0          
1313             # query db
1314 0         0 my $rval;
1315             my $st;
1316 0         0 my $select =
1317             "select $vdirs->{$ref}{fnamcol} from $ref order by $vdirs->{$ref}{fnamcol}";
1318 0         0 $s .= "# This is a reference to a file in dir '$ref'.\n";
1319 0         0 $st = $dbh->prepare( $select );
1320 0 0       0 unless( $st ) {
1321 0         0 $s .= "$PRG: can't prep var query '$ref':\n " . $dbh->errstr;
1322 0         0 return $s;
1323             }
1324 0 0       0 unless( $st->execute( ) ) {
1325 0         0 $s .= "$PRG: can't exec var query '$ref' :\n " . $dbh->errstr;
1326 0         0 return $s;
1327             }
1328 0 0       0 $s .= "$var = \n" unless defined $value;
1329 0         0 my $found = 0;
1330 0         0 while( ($rval) = $st->fetchrow_array() ) {
1331 0 0 0     0 if( defined $value and $value eq $rval ) {
1332 0         0 $found = 1;
1333             }else{
1334 0         0 $s .= "#";
1335             }
1336 0         0 $s .= "$var = $rval\n";
1337             }
1338 0         0 $st->finish();
1339 0 0 0     0 if( $found == 0 and defined $value ) {
1340 0         0 $s .= "### NOTE: File '$value' does not exist in dir '$ref'!\n";
1341 0         0 $s .= "### NOTE: This value will be rejected when saving!\n";
1342 0         0 $s .= "$var = $value\n";
1343             }
1344             }elsif( defined $flags ) {
1345 0         0 my $i;
1346 0         0 my $maxlen = 0;
1347 0         0 for( $i=0; $i<32; $i++ ) {
1348 0 0       0 if( exists $flags->{$i} ) {
1349 0 0       0 if( length( $flags->{$i}[0] ) > $maxlen ) {
1350 0         0 $maxlen = length( $flags->{$i}[0] );
1351             }
1352             }
1353             }
1354 0         0 $s .= "# Flags:\n";
1355 0 0       0 my $hash = defined $value ? '' : '#';
1356 0         0 my $on = "$hash On:\n";
1357 0         0 my $off = "$hash Off:\n";
1358 0         0 for( $i=0; $i<32; $i++ ) {
1359 0 0       0 if( exists $flags->{$i} ) {
1360 0         0 my $first = 1;
1361 0         0 foreach my $dscline (split '\n', $flags->{$i}[1] ) {
1362 0 0       0 if( $first ) {
1363 0         0 $first = 0;
1364 0         0 $s .= sprintf( "# %${maxlen}s: %s\n",$flags->{$i}[0], $dscline );
1365             }else{
1366 0         0 $s .= sprintf( "# %${maxlen}s %s\n", ' ', $dscline );
1367             }
1368             }
1369 0 0 0     0 if( defined $value and ($value & (1<<$i) ) ) {
1370 0         0 $on .= "$hash $flags->{$i}[0]\n";
1371             }else{
1372 0         0 $off .= "$hash $flags->{$i}[0]\n";
1373             }
1374             }
1375             }
1376 0 0       0 if( defined $value ) {
1377 0         0 $s .= "#\n$var = {\n$on$off}\n";
1378             }else{
1379 0         0 $s .= "#\n$var = \n#$var = {\n$on$off#}\n";
1380             }
1381              
1382             }elsif( defined $enums ) {
1383 0         0 my $i;
1384 0         0 my $maxlen = 0;
1385 0         0 foreach $i (sort keys(%{$enums}) ) {
  0         0  
1386 0 0       0 if( length( $enums->{$i}[0] ) > $maxlen ) {
1387 0         0 $maxlen = length( $enums->{$i}[0] );
1388             }
1389             }
1390 0         0 $s .= "# Enums:\n";
1391 0         0 my $selected = " Selected:\n";
1392 0         0 my $avail = " Available:\n";
1393 0 0 0     0 if( defined $value and !exists $enums->{$value} ) {
1394 0         0 $selected .= " *unknown-enum-value*\n";
1395             }
1396 0         0 foreach $i (sort keys(%{$enums}) ) {
  0         0  
1397 0         0 my $first = 1;
1398 0         0 foreach my $dscline (split '\n', $enums->{$i}[1] ) {
1399 0 0       0 if( $first ) {
1400 0         0 $first = 0;
1401 0         0 $s .= sprintf( "# %${maxlen}s: %s\n",$enums->{$i}[0], $dscline );
1402             }else{
1403 0         0 $s .= sprintf( "# %${maxlen}s %s\n", ' ', $dscline );
1404             }
1405             }
1406 0 0 0     0 if( defined $value and $value == $i) {
1407 0         0 $selected .= " $enums->{$i}[0]\n";
1408             }else{
1409 0         0 $avail .= " $enums->{$i}[0]\n";
1410             }
1411             }
1412 0         0 $s .= "#\n$var = {\n$selected$avail}\n";
1413              
1414             }else{
1415 0         0 $s .= "$var = ";
1416 0 0       0 $s .= "$value" if defined $value;
1417 0         0 $s .= "\n";
1418             }
1419 0         0 return $s;
1420              
1421             } # var_value_v()
1422              
1423             ########################################################################
1424             # var_value_s( aligned, var, value, flags, enums, hasdefault )
1425             # return a var = value string for short output (sum & vgrep)
1426             # maxvarlen: if not 0: align all '=' using $maxvarlen, else: no alignment
1427             # var: variable name (long version for cat/vi)
1428             # value: the value of var or undef
1429             # default: the default value of var or undef
1430             # flags: anon hashref with flags setup from vdir or undef
1431             # enums: anon hashref with enums setup from vdir or undef
1432             # hasdefault: 1: we have a defaults file 0: we don't have
1433             # return:
1434             # the string to be printed
1435             #
1436             sub var_value_s() {
1437 0     0 0 0 my ($maxvarlen,$var,$value,$default,$flags,$enums,$hasdefault) = @_;
1438 0         0 my $s = '';
1439 0         0 my $i;
1440              
1441 0 0       0 if( defined $flags ) {
    0          
1442 0         0 $value = build_flags( $value, $flags );
1443 0         0 $default = build_flags( $default, $flags );
1444             }elsif( defined $enums ) {
1445 0         0 $value = build_enums( $value, $enums );
1446 0         0 $default = build_enums( $default, $enums );
1447             }
1448              
1449 0 0       0 if( $maxvarlen ) {
1450 0         0 $s = sprintf( "%-${maxvarlen}s ", $var );
1451             }else{
1452 0         0 $s = "$var ";
1453             }
1454 0 0       0 if( $hasdefault ) {
1455 0 0       0 if( defined $value ) {
1456 0         0 $s .= "= $value\n";
1457             }else{
1458 0 0       0 $s .= defined $default ? "-> $default\n" : "-> *unset*\n";
1459             }
1460             }else{
1461 0 0       0 $s .= defined $value ? "= $value\n" : "= *unset*\n";
1462             }
1463 0         0 return $s;
1464              
1465             } # var_value_s()
1466              
1467             ########################################################################
1468             # build_flags( value, flags )
1469             # return a string containing all flags set in value
1470             # value: the value of var or undef
1471             # flags: anon hashref with flags setup from vdir or undef
1472             # return:
1473             # the string of set flags if any flags are set
1474             # '' if no flags set
1475             # undef if value or flags is undef
1476             #
1477             sub build_flags() {
1478 0     0 0 0 my ( $value, $flags ) = @_;
1479 0         0 my $s;
1480             my $i;
1481              
1482 0 0 0     0 if( defined $flags and defined $value ) {
1483 0         0 $s = '';
1484 0         0 for( $i=0; $i<32; $i++ ) {
1485 0 0       0 if( exists $flags->{$i} ) {
1486 0 0       0 if( $value & (1<<$i) ) {
1487 0         0 $s .= "$flags->{$i}[0],";
1488             }
1489             }
1490             }
1491 0         0 chop $s; # chop ,
1492             }
1493 0         0 return $s;
1494              
1495             } # build_flags()
1496              
1497             ########################################################################
1498             # build_enums( value, enums )
1499             # return a string containing the enum set in value
1500             # value: the value of var or undef
1501             # enums: anon hashref with enums setup from vdir or undef
1502             # return:
1503             # the string of set enum if enum is set
1504             # undef if - value is undef
1505             # - enum is undef
1506             # - value is not contained in enums
1507             #
1508             sub build_enums() {
1509 0     0 0 0 my ( $value, $enums ) = @_;
1510 0         0 my $s;
1511             my $i;
1512              
1513 0 0 0     0 if( defined $enums and defined $value ) {
1514 0 0       0 if( exists $enums->{$value} ) {
1515 0         0 $s = "$enums->{$value}[0]";
1516             }else{
1517 0         0 $s = "*unknown-enum-value*";
1518             }
1519             }
1520 0         0 return $s;
1521              
1522             } # build_enums()
1523              
1524              
1525             ########################################################################
1526             # get_who_refs_me( dir, file )
1527             # return all files referenced by FILE
1528             # dir: an existing directory
1529             # file: the (probably existing) file within DIR which references
1530             # to be checked
1531             # return:
1532             # - a list of strings in format "dir/file" if references are found
1533             # - empty list if no references are found
1534             # - a list whith one entry holding the errormessage in case of an error
1535             #
1536             sub get_who_refs_me() {
1537 0     0 0 0 my ($dir,$file) = @_;
1538 0         0 my @res = ();
1539              
1540 0         0 foreach my $refdir (sort keys(%{$vdirs->{$dir}{refby}}) ) {
  0         0  
1541 0         0 my $select = "select $vdirs->{$refdir}{fnamcol} from $refdir where ";
1542 0         0 my @rcols = @{$vdirs->{$dir}{refby}{$refdir}};
  0         0  
1543 0         0 my $st;
1544 0         0 map { $_ .= "='$file'" } @rcols;
  0         0  
1545 0         0 $select .= join( " or ", @rcols );
1546 0         0 $select .= " order by $vdirs->{$refdir}{fnamcol}";
1547              
1548 0         0 $st = $dbh->prepare( $select );
1549 0 0       0 unless( $st ) {
1550 0         0 push @res,"$PRG: can't prep wrefs query '$file':\n " . $dbh->errstr;
1551 0         0 return @res;
1552             }
1553 0 0       0 unless( $st->execute( ) ) {
1554 0         0 push @res,"$PRG: can't exec wrefs query '$file':\n " . $dbh->errstr;
1555 0         0 return @res;
1556             }
1557 0         0 my $reffile;
1558 0         0 while( ($reffile) = $st->fetchrow_array() ) {
1559 0         0 push @res, "$refdir/$reffile";
1560             }
1561 0         0 $st->finish();
1562             }
1563 0         0 return @res;
1564             }
1565              
1566             ########################################################################
1567             # create_sql_from_file( tempfile, dir, vfile, insert_flag );
1568             #
1569             # tmpfile: Absolute path to temporary file on local disk holding
1570             # the edited parameters
1571             # vdir: exisiting virtual dir (table)
1572             # vfile: A file (db-row) for which to generate the $sql SQL code
1573             # insert_flag: 0: $sql --> 'update' string 1: $sql --> 'insert' string
1574             #
1575             # return
1576             # a list: ($lineno,$err, $sql):
1577             # - $lineno: when an error was detected: the errornous line
1578             # - $err: when an error was detected: a one line error text, else: undef
1579             # when $err is set then $sql is invalid
1580             # - $sql: when no error was detected: a SQL insert/update string or ''
1581             # if nothing to do, when $err is set: trash or undef
1582             #
1583             #
1584             sub create_sql_from_file( ) {
1585 0     0 0 0 my ($tmpfile,$vdir,$vfile,$insert_flag) = @_;
1586 0         0 my $lineno = 0;
1587 0         0 my $line;
1588             my $var;
1589 0         0 my $val;
1590 0         0 my $err;
1591 0         0 my $sql1;
1592 0         0 my $sql2;
1593 0         0 my %varcol; # translataion varname -> columnname
1594 0         0 my %isset; # flags: variable already set? 1: yes
1595 0         0 my %filevars; # variables from file for phase 2
1596 0         0 my %filevarslineno; # lineno of variables from file for phase 2
1597              
1598 0 0       0 if( $insert_flag ) {
1599 0         0 $sql1 = "insert into $vdir ($vdirs->{$vdir}{fnamcol},";
1600 0         0 $sql2 = " values('$vfile',";
1601             }else{
1602 0         0 $sql1 = "update $vdir set ";
1603 0         0 $sql2 = " where $vdirs->{$vdir}{fnamcol}='$vfile'";
1604             }
1605             # setup varname translation
1606 0         0 my $cols = $vdirs->{$vdir}{cols};
1607 0         0 foreach my $col ( keys( %{$cols} ) ) {
  0         0  
1608 0         0 $varcol{ $cols->{$col}{var} } = $col;
1609             }
1610              
1611             # phase 1: do the basic checks, remember var values and their lineno for
1612             # phase 2 check (user supplied check functions)
1613 0 0       0 open( TF, $tmpfile ) or return ( 1,"can't open tempfile '$tmpfile'", undef );
1614 0         0 MAIN: while( ) {
1615 0         0 $line = $_;
1616 0         0 $lineno++;
1617 0         0 chop( $line );
1618 0         0 $line =~ s/^\s*//; # remove leading space
1619 0 0       0 next MAIN if $line =~ /^$/; # skip empty lines
1620 0 0       0 next MAIN if $line =~ /^\#.*/; # skip comment lines
1621 0 0       0 unless( $line =~ /=/ ) { # missing = ?
1622 0         0 $err = "line $lineno: missing '='";
1623 0         0 last MAIN;
1624             }
1625 0         0 ($var,$val) = split( /=/, $line, 2 );
1626 0         0 $var =~ s/\s*$//; # remove trailing space
1627 0         0 $val =~ s/^\s*//; # remove leading space
1628 0         0 $val =~ s/\s*$//; # remove trailing space
1629              
1630 0 0 0     0 if( length($var)==0 or $var =~ /\W+/ ) { # var name ok?
1631 0         0 $err = "line $lineno: syntax error";
1632 0         0 last MAIN;
1633             }
1634              
1635             # check if variable name exists
1636 0 0       0 if( defined $varcol{$var} ) {
1637 0 0       0 if( defined $isset{$var} ) {
1638 0         0 $err = "line $lineno: variable '$var' set twice";
1639 0         0 last MAIN;
1640             }
1641              
1642 0         0 my $col = $varcol{$var};
1643 0         0 my $vlen = length( $val );
1644 0 0       0 if( $vlen > 0 ) {
1645             # check types
1646 0 0       0 if( defined $cols->{$col}{ref} ) {
    0          
    0          
    0          
    0          
    0          
1647             # type ref
1648 0         0 my $rdir = $cols->{$col}{ref};
1649 0         0 my $rfnc = $vdirs->{$rdir}{fnamcol};
1650 0 0       0 if( defined $vdirs->{$rdir}{cols}{$rfnc}{len} ) {
1651 0         0 my $rlen = $vdirs->{$rdir}{cols}{$rfnc}{len};
1652 0 0       0 if( $vlen > $rlen ) {
1653 0         0 $err = "line $lineno: value longer than $rlen";
1654 0         0 last MAIN;
1655             }
1656             }else{
1657 0 0       0 if( $vlen > 1 ) {
1658 0         0 $err = "line $lineno: value longer than 1";
1659 0         0 last MAIN;
1660             }
1661             }
1662             # check if val exists in referneced table
1663 0         0 my $st;
1664             my $dbval;
1665 0         0 $st = $dbh->prepare("select $rfnc from $rdir where $rfnc=?");
1666 0 0       0 unless( $st ) {
1667 0         0 $err = "$PRG: internal error: prepare 'exist' query '$rdir':\n ";
1668 0         0 $err .= $dbh->errstr;
1669 0         0 last MAIN;
1670             }
1671 0 0       0 unless( $st->execute( $val ) ) {
1672 0         0 $err = "$PRG: internal error: exec 'exist' query '$rdir':\n ";
1673 0         0 $err .= $dbh->errstr;
1674 0         0 last MAIN;
1675             }
1676 0         0 $dbval = $st->fetchrow_array();
1677 0         0 $st->finish();
1678 0 0       0 unless( defined $dbval ) {
1679 0         0 $err = "line $lineno: reference '$val' does no exist in '$rdir'";
1680 0         0 last MAIN;
1681             }
1682 0 0       0 if( $insert_flag ) {
1683 0         0 $sql1 .= "$col,";
1684 0         0 $sql2 .= "'$val',";
1685             }else{
1686 0         0 $sql1 .= "$col='$val',";
1687             }
1688 0         0 $filevars{$col} = $val;
1689 0         0 $filevarslineno{$col} = $lineno;
1690              
1691             }elsif( $cols->{$col}{type} eq 'char' ) {
1692             # type char
1693 0 0       0 if( defined $cols->{$col}{len} ) {
1694 0 0       0 if( $vlen > $cols->{$col}{len} ) {
1695 0         0 $err = "line $lineno: value longer than $cols->{$col}{len}";
1696 0         0 last MAIN;
1697             }
1698             }else{
1699 0 0       0 if( $vlen > 1 ) {
1700 0         0 $err = "line $lineno: value longer than 1";
1701 0         0 last MAIN;
1702             }
1703             }
1704 0 0       0 if( $insert_flag ) {
1705 0         0 $sql1 .= "$col,";
1706 0         0 $sql2 .= $dbh->quote( $val ) . ",";
1707             }else{
1708 0         0 $sql1 .= "$col=" . $dbh->quote( $val ) . ",";
1709             }
1710 0         0 $filevars{$col} = $val;
1711 0         0 $filevarslineno{$col} = $lineno;
1712              
1713             }elsif( $cols->{$col}{type} eq 'int' ) {
1714             # type int
1715 0 0       0 if( exists $cols->{$col}{flags} ) { # flags: process the flags
    0          
1716 0 0       0 if( $val eq '{' ) {
1717 0         0 $val = 0;
1718 0         0 my $mode = '{';
1719 0         0 my $l;
1720             my $flagfound;
1721 0         0 FLAGS: while( defined ( $l = ) ) {
1722 0         0 chop( $l );
1723 0         0 $lineno++;
1724 0         0 $l =~ s/\s*$//; # remove trailing space
1725 0         0 $l =~ s/^\s*//; # remove leading space
1726 0 0       0 next FLAGS if $l =~ /^$/; # skip empty lines
1727 0 0       0 next FLAGS if $l =~ /^\#.*/; # skip comment lines
1728 0 0       0 if( $l eq 'On:' ) { $mode = 'on'; next FLAGS; }
  0         0  
  0         0  
1729 0 0       0 if( $l eq 'Off:' ) { $mode = 'off'; next FLAGS; }
  0         0  
  0         0  
1730 0 0       0 if( $l eq '}' ) {
1731 0 0       0 $val = 'NULL' if $mode eq '{';
1732 0         0 $mode = '}';
1733 0         0 last FLAGS;
1734             }
1735 0         0 $flagfound = 0;
1736 0         0 foreach my $bit ( keys( %{$cols->{$col}{flags}} ) ) {
  0         0  
1737 0 0       0 if( $cols->{$col}{flags}{$bit}[0] eq $l ) {
1738 0         0 $flagfound = 1;
1739 0 0       0 $val |= (1<<$bit) if $mode eq 'on';
1740 0         0 last;
1741             }
1742             }
1743 0 0       0 unless( $flagfound ) {
1744 0         0 $err = "line $lineno: unknown flag '$l' for '$var'";
1745 0         0 last MAIN;
1746             }
1747             } # loop FLAGS
1748              
1749 0 0       0 if( $mode ne '}' ) {
1750 0         0 $err = "line $lineno: missing '}' from flags section";
1751 0         0 last MAIN;
1752             }
1753             }else{
1754 0         0 $err = "line $lineno: flags must start with '{'";
1755 0         0 last MAIN;
1756             }
1757             }elsif( exists $cols->{$col}{enums} ) { # enums: process the enums
1758              
1759 0 0       0 if( $val eq '{' ) {
1760 0         0 $val = 'NULL';
1761 0         0 my $mode = '{';
1762 0         0 my $l;
1763             my $enumfound;
1764 0         0 ENUMS: while( defined ( $l = ) ) {
1765 0         0 chop( $l );
1766 0         0 $lineno++;
1767 0         0 $l =~ s/\s*$//; # remove trailing space
1768 0         0 $l =~ s/^\s*//; # remove leading space
1769 0 0       0 next ENUMS if $l =~ /^$/; # skip empty lines
1770 0 0       0 next ENUMS if $l =~ /^\#.*/; # skip comment lines
1771 0 0       0 if( $l eq 'Selected:' ) { $mode = 'sel'; next ENUMS; }
  0         0  
  0         0  
1772 0 0       0 if( $l eq 'Available:' ) { $mode = 'ava'; next ENUMS; }
  0         0  
  0         0  
1773 0 0       0 if( $l eq '}' ) { $mode = '}'; last ENUMS; }
  0         0  
  0         0  
1774 0         0 $enumfound = 0;
1775 0         0 foreach my $enumval ( keys( %{$cols->{$col}{enums}} ) ) {
  0         0  
1776 0 0       0 if( $cols->{$col}{enums}{$enumval}[0] eq $l ) {
1777 0         0 $enumfound = 1;
1778 0 0       0 if( $mode eq 'sel' ) {
1779 0 0       0 if( $val eq 'NULL' ) {
1780 0         0 $val = $enumval;
1781             }else{
1782 0         0 $err = "line $lineno: only one elem may be selected for '$var'";
1783 0         0 last MAIN;
1784             }
1785             }
1786 0         0 last;
1787             }
1788             }
1789 0 0       0 unless( $enumfound ) {
1790 0         0 $err = "line $lineno: unknown enum tag '$l' for '$var'";
1791 0         0 last MAIN;
1792             }
1793             } # loop ENUMS
1794 0 0       0 if( $mode ne '}' ) {
1795 0         0 $err = "line $lineno: missing '}' from enums section";
1796 0         0 last MAIN;
1797             }
1798             }else{
1799 0         0 $err = "line $lineno: enums must start with '{'";
1800 0         0 last MAIN;
1801             }
1802             }else{ # no flags,no enums, normal int
1803 0 0       0 unless( $val =~ /^-?\d+$/ ) {
1804 0         0 $err = "line $lineno: value not an integer";
1805 0         0 last MAIN;
1806             }
1807 0 0 0     0 if( $val <= -2147483648 or $val >= 2147483647 ) {
1808 0         0 $err = "line $lineno: value out of int range";
1809 0         0 last MAIN;
1810             }
1811             }
1812 0 0       0 if( $insert_flag ) {
1813 0         0 $sql1 .= "$col,";
1814 0         0 $sql2 .= "$val,";
1815             }else{
1816 0         0 $sql1 .= "$col=$val,";
1817             }
1818 0         0 $filevars{$col} = $val;
1819 0         0 $filevarslineno{$col} = $lineno;
1820              
1821             }elsif( $cols->{$col}{type} eq 'smallint' ) {
1822             # type smallint
1823 0 0       0 unless( $val =~ /^-?\d+$/ ) {
1824 0         0 $err = "line $lineno: value not an integer";
1825 0         0 last MAIN;
1826             }
1827 0 0 0     0 if( $val <= -32768 or $val >= 32767 ) {
1828 0         0 $err = "line $lineno: value out of smallint range";
1829 0         0 last MAIN;
1830             }
1831 0 0       0 if( $insert_flag ) {
1832 0         0 $sql1 .= "$col,";
1833 0         0 $sql2 .= "$val,";
1834             }else{
1835 0         0 $sql1 .= "$col=$val,";
1836             }
1837 0         0 $filevars{$col} = $val;
1838 0         0 $filevarslineno{$col} = $lineno;
1839              
1840             }elsif( $cols->{$col}{type} eq 'cidr' ) {
1841             # type cidr
1842 0         0 my $st;
1843             my $dbval;
1844 0         0 $st = $dbh->prepare( "select cidr '$val'" );
1845 0 0       0 unless( $st ) {
1846 0         0 $err = "$PRG: internal error: select cidr\n ";
1847 0         0 $err .= $dbh->errstr;
1848 0         0 last MAIN;
1849             }
1850 0 0       0 unless( $st->execute( ) ) {
1851 0         0 $err = $dbh->errstr;
1852 0         0 last MAIN;
1853             }
1854 0         0 ($dbval) = $st->fetchrow_array();
1855 0         0 $st->finish();
1856              
1857 0 0       0 if( $insert_flag ) {
1858 0         0 $sql1 .= "$col,";
1859 0         0 $sql2 .= "'$val',";
1860             }else{
1861 0         0 $sql1 .= "$col='$val',";
1862             }
1863 0         0 $filevars{$col} = $val;
1864 0         0 $filevarslineno{$col} = $lineno;
1865              
1866             }elsif( $cols->{$col}{type} eq 'inet' ) {
1867             # type inet
1868 0         0 my $st;
1869             my $dbval;
1870 0         0 $st = $dbh->prepare( "select inet '$val'" );
1871 0 0       0 unless( $st ) {
1872 0         0 $err = "$PRG: internal error: select inet\n ";
1873 0         0 $err .= $dbh->errstr;
1874 0         0 last MAIN;
1875             }
1876 0 0       0 unless( $st->execute( ) ) {
1877 0         0 $err = $dbh->errstr;
1878 0         0 last MAIN;
1879             }
1880 0         0 ($dbval) = $st->fetchrow_array();
1881 0         0 $st->finish();
1882              
1883 0 0       0 if( $insert_flag ) {
1884 0         0 $sql1 .= "$col,";
1885 0         0 $sql2 .= "'$val',";
1886             }else{
1887 0         0 $sql1 .= "$col='$val',";
1888             }
1889 0         0 $filevars{$col} = $val;
1890 0         0 $filevarslineno{$col} = $lineno;
1891              
1892             }else{
1893             # type unknown!
1894 0         0 $err = "line $lineno: unsupported datatype from vdirs for $var";
1895 0         0 last MAIN;
1896             }
1897             }else{ # $vlen == 0
1898 0 0       0 if( $insert_flag ) {
1899 0         0 $sql1 .= "$col,";
1900 0         0 $sql2 .= "NULL,";
1901             }else{
1902 0         0 $sql1 .= "$col=NULL,";
1903             }
1904 0         0 $filevars{$col} = undef;
1905 0         0 $filevarslineno{$col} = $lineno;
1906             }
1907 0         0 $isset{$var} = 1; # remember that this var is set
1908             }else{
1909 0         0 $err = "line $lineno: unknown variable '$var'";
1910 0         0 last MAIN;
1911             }
1912             }
1913 0         0 close( TF );
1914 0 0       0 if( $insert_flag ) {
1915 0         0 chop( $sql1 );
1916 0         0 chop( $sql2 );
1917 0         0 $sql1 .= ")";
1918 0         0 $sql2 .= ")";
1919             }else{
1920 0 0       0 if( chop( $sql1 ) ne ',' ) {
1921             # no columns to update
1922 0         0 $sql1 = "";
1923 0         0 $sql2 = "";
1924             }
1925             }
1926              
1927             # phase 2: if basic check didn't show an error, do the user supplied checks
1928              
1929 0         0 my $hasuniqcols = 0;
1930 0         0 $filevars{ $vdirs->{$vdir}{fnamcol} } = $vfile; # add our filename to hash
1931 0 0       0 if( !defined $err ) {
1932 0         0 foreach my $col (keys(%filevars) ) {
1933 0         0 my $valerr;
1934 0 0       0 if( exists $cols->{$col}{uniq} ) { $hasuniqcols = 1; }
  0         0  
1935 0 0       0 if( exists $cols->{$col}{valok} ) {
1936 0         0 $valerr = &{$cols->{$col}{valok}}( $filevars{$col}, \%filevars, $dbh );
  0         0  
1937 0 0       0 if( defined $valerr ) {
1938 0         0 $err = "line $filevarslineno{$col}: $valerr";
1939 0         0 $lineno = $filevarslineno{$col};
1940 0         0 last;
1941             }
1942             }
1943             }
1944             }
1945              
1946             # phase 3: check if there are columns/vars that have to be uniq
1947              
1948 0         0 my $fnc = $vdirs->{$vwd}{fnamcol};
1949 0 0 0     0 if( !defined $err and $hasuniqcols == 1 ) {
1950 0         0 foreach my $col (keys(%filevars) ) {
1951 0         0 my $valerr = "";
1952 0 0       0 if( exists $cols->{$col}{uniq} ) {
1953 0         0 my $st;
1954             my $dbval;
1955 0         0 $st = $dbh->prepare(
1956             "select $fnc from $vwd where $col=? and $fnc != '$vfile'");
1957 0 0       0 unless( $st ) {
1958 0         0 $err = "$PRG: internal error: prepare 'uniq' query '$vwd':\n ";
1959 0         0 $err .= $dbh->errstr;
1960 0         0 last;
1961             }
1962 0 0       0 unless( $st->execute( "$filevars{$col}" ) ) {
1963 0         0 $err = "$PRG: internal error: exec 'uniq' query '$vwd':\n ";
1964 0         0 $err .= $dbh->errstr;
1965 0         0 last;
1966             }
1967 0         0 while( ($dbval) = $st->fetchrow_array() ) {
1968 0         0 $valerr .= " $dbval";
1969             }
1970 0         0 $st->finish();
1971 0 0       0 if( $valerr ne "" ) {
1972 0         0 $err = "line $filevarslineno{$col}: uniq value '$filevars{$col}' " .
1973             "already in file(s): $valerr";
1974 0         0 $lineno = $filevarslineno{$col};
1975 0         0 last;
1976             }
1977             }
1978             }
1979             }
1980 0         0 return ( $lineno, $err, "$sql1$sql2" );
1981              
1982             } # create_sql_from_file()
1983              
1984             ########################################################################
1985             # want_to_edit_again( errortext )
1986             # ask the user if he wants to edit again
1987             # errortext: one line error text
1988             # return:
1989             # 'y' or 'n'
1990             #
1991             sub want_to_edit_again() {
1992 0     0 0 0 my $errortext = shift;
1993 0         0 my $inp = '';
1994 0         0 my $IN = $term->IN;
1995 0         0 print $OUT "\n\n\n\n\n\n\n$errortext\n";
1996 0   0     0 while( $inp ne 'y' and $inp ne 'n' ) {
1997 0         0 print $OUT "Do you want to edit again ('n' will abort) [y/n] ? ";
1998 0         0 $inp = <$IN>;
1999 0 0       0 $inp = '\n' unless defined $inp;
2000 0         0 chop $inp;
2001             }
2002 0         0 return $inp;
2003             }
2004              
2005             ########################################################################
2006             # do_vgrep( pattern );
2007             # grep all val/value pairs in vwd for pattern and print matching lines
2008             # pattern: the pattern to grep for
2009             #
2010             # return:
2011             # nothing
2012             #
2013             sub do_vgrep() {
2014 0     0 0 0 my $pattern = quotemeta shift;
2015              
2016 0         0 my @vars;
2017             my @dbvars;
2018 0         0 my $var;
2019 0         0 my @values;
2020 0         0 my @defaults;
2021 0         0 my @flags;
2022 0         0 my @enums;
2023 0         0 my $fnam;
2024 0         0 my $em = "*unset*";
2025 0         0 my $hasdefault;
2026              
2027             # prepare db query
2028 0         0 my $fnc = $vdirs->{$vwd}{fnamcol};
2029 0         0 my $select = "select $fnc,";
2030 0         0 my $seldef = "select ";
2031 0         0 my $cols = $vdirs->{$vwd}{cols};
2032 0         0 my $fnlen = $cols->{$fnc}{len};
2033 0         0 foreach my $col (sort {$cols->{$a}{pos} <=> $cols->{$b}{pos}}
  0         0  
  0         0  
2034             keys(%{$cols}) )
2035             {
2036 0 0       0 next if $col eq $fnc;
2037 0         0 $var = $cols->{$col}{var};
2038 0         0 push @vars, $var;
2039 0         0 push @dbvars,$col;
2040 0 0       0 push @flags, exists $cols->{$col}{flags} ? $cols->{$col}{flags} : undef;
2041 0 0       0 push @enums, exists $cols->{$col}{enums} ? $cols->{$col}{enums} : undef;
2042 0         0 $select .= "$col,";
2043 0         0 $seldef .= "$col,";
2044             }
2045 0         0 chop $select;
2046 0         0 chop $seldef;
2047 0         0 $select .= " from $vwd order by $fnc";
2048 0         0 $seldef .= " from $vwd where $fnc=?";
2049            
2050             # query default if available
2051 0 0       0 if( $vdirs->{$vwd}{defaultfile} ) {
2052 0         0 my $st;
2053 0         0 $st = $dbh->prepare( $seldef );
2054 0 0       0 unless( $st ) {
2055 0         0 print $OUT "$PRG: prep vgrep default query '$vwd':\n " . $dbh->errstr;
2056 0         0 return;
2057             }
2058 0 0       0 unless( $st->execute( $vdirs->{$vwd}{defaultfile} ) ) {
2059 0         0 print $OUT "$PRG: exec vgrep default query '$vwd':\n " . $dbh->errstr;
2060 0         0 return;
2061             }
2062 0         0 @defaults = $st->fetchrow_array();
2063 0         0 $st->finish();
2064             }
2065            
2066             # query all files
2067 0         0 my $st;
2068 0         0 $st = $dbh->prepare( $select );
2069 0 0       0 unless( $st ) {
2070 0         0 print $OUT "$PRG: prep vgrep query '$vwd':\n " . $dbh->errstr;
2071 0         0 return;
2072             }
2073 0 0       0 unless( $st->execute() ) {
2074 0         0 print $OUT "$PRG: exec vgrep query 1 '$vwd' :\n " . $dbh->errstr;
2075 0         0 return;
2076             }
2077              
2078             # print result
2079 0         0 while (($fnam, @values ) = $st->fetchrow_array() ) {
2080 0 0       0 if( @values ) {
2081 0         0 for( my $i=0; $i<= $#values; $i++ ) {
2082 0 0 0     0 if( $vdirs->{$vwd}{defaultfile} and
2083             $vdirs->{$vwd}{defaultfile} ne $fnam ) {
2084 0         0 $hasdefault = 1;
2085             }else{
2086 0         0 $hasdefault = 0;
2087             }
2088            
2089 0         0 my $line = &var_value_s( 0, $vars[$i], $values[$i],
2090             $defaults[$i], $flags[$i], $enums[$i],
2091             $hasdefault
2092             );
2093 0 0       0 printf $OUT "%${fnlen}s: %s", $fnam, $line if $line =~ /$pattern/i;
2094             }
2095             }
2096             }
2097 0         0 $st->finish();
2098            
2099 0         0 return;
2100             }
2101              
2102              
2103             ########################################################################
2104             ########################################################################
2105             ## obejct orientated interface: the access class for config database
2106             ########################################################################
2107             ########################################################################
2108              
2109             ########################################################################
2110             # new();
2111             # contructor for DBIx::FileSystem access class
2112             # parameter:
2113             # dbconn: database connect string used for DBI database connect
2114             # dbuser: database user
2115             # dbpasswd: database user's password
2116             # progdbver: program's databaase layout version string
2117             #
2118             # return: the object
2119             #
2120             sub new {
2121 1     1 0 23 my $class = shift;
2122 1         28 my %params = @_;
2123 1         3 my $self = {};
2124 1         3 bless( $self, $class );
2125              
2126 1         8 $self->{dbh} = undef;
2127 1         3 $self->{err} = "Ok";
2128              
2129             # initialize object
2130 1         3 FINI: while( 1 ) {
2131 1 50 33     10 if( exists $params{dbconn} and defined( $params{dbconn} ) ){
2132 1         2 $self->{dbconn} = $params{dbconn};
2133             }else{
2134 0         0 $self->{dbconn} = undef;
2135 0         0 $self->{err} = "parameter 'dbconn' undefined";
2136 0         0 last FINI;
2137             }
2138 1 50 33     20 if( exists $params{progdbver} and defined( $params{progdbver} ) ) {
2139 1         3 $self->{progdbver} = $params{progdbver};
2140             }else{
2141 0         0 $self->{progdbver} = undef;
2142 0         0 $self->{err} = "parameter 'progdbver' undefined";
2143 0         0 last FINI;
2144             }
2145 1         12 $self->{dbh} = DBI->connect( $self->{dbconn},
2146             $params{dbuser}, $params{dbpasswd},
2147             { PrintError => 0, AutoCommit => 1,
2148             ChopBlanks =>1 } );
2149 0 0       0 unless( $self->{dbh} ) {
2150 0         0 $self->{err} = "connect: " . $DBI::errstr;
2151 0         0 last FINI;
2152             }
2153 0         0 last FINI;
2154             }
2155              
2156 0         0 return $self;
2157              
2158             } # new()
2159              
2160             ########################################################################
2161             # DESTROY();
2162             # parameter: none
2163             #
2164             # return: nothing
2165             #
2166             sub DESTROY {
2167 1     1   1420 my $self = shift;
2168              
2169 1 50       5 $self->{dbh}->disconnect() if defined $self->{dbh};
2170              
2171 1         2 $self->{dbh} = undef;
2172 1         2 $self->{dbconn} = undef;
2173 1         3 $self->{progdbver} = undef;
2174 1         2 $self->{err} = "object destroyed";
2175              
2176 1         6 return;
2177              
2178             } # DESTROY()
2179              
2180             ########################################################################
2181             # database_bad();
2182             # check if the database connection is ok. If not, set an errormessage into
2183             # the errorbuffer
2184             #
2185             # parameter: none
2186             #
2187             # return: 0: database ok
2188             # 1: database wrong
2189             #
2190             sub database_bad {
2191 0     0 0 0 my $self = shift;
2192 0         0 my $ret = 1;
2193              
2194 0 0       0 if( defined $self->{dbh} ) {
2195             # check version number
2196 0         0 my $st = $self->{dbh}->prepare(
2197             "SELECT value FROM tablestatus WHERE tag='version'" );
2198 0 0       0 if( $st ) {
2199 0 0       0 if( $st->execute() ) {
2200 0         0 my ($dbdbver) = $st->fetchrow_array();
2201 0 0       0 if( $dbdbver eq $self->{progdbver} ) {
2202 0         0 $ret = 0;
2203             }else{
2204 0         0 $self->{err} =
2205             "version mismatch: program <--> db ('$self->{progdbver}' <--> '$dbdbver')";
2206             }
2207 0         0 $st->finish();
2208             }else{
2209 0         0 $self->{err} = "exec query dbversion: " . $self->{dbh}->errstr;
2210             }
2211             }else{
2212 0         0 $self->{err} = "prepare qry dbversion: " . $self->{dbh}->errstr;
2213             }
2214             }
2215 0 0       0 if( $ret ) {
2216 0 0       0 $self->{dbh}->disconnect() if defined $self->{dbh};
2217 0         0 $self->{dbh} = undef;
2218             }
2219 0         0 return $ret;
2220              
2221             } # database_bad()
2222              
2223             ########################################################################
2224             # get_err();
2225             # read the last error message from the error buffer
2226             # parameter: none
2227             #
2228             # return: last errorstring
2229             #
2230             sub get_err {
2231 0     0 0 0 my $self = shift;
2232 0         0 return $self->{err};
2233              
2234             } # get_err()
2235              
2236             ########################################################################
2237             # get_conf_by_var();
2238             #
2239             # parameter:
2240             # in:
2241             # $dir: the directory (table) to search in
2242             # $defaultfname: the filename of the defaultfile if availalble,
2243             # else undef
2244             # $fnamcol: the column which contains the symbolic filename
2245             # in/out:
2246             # \%vars: a hashref pointing to a hash containing the column
2247             # names to fetch as a key, values will be set by function
2248             # in: \%searchvars a hashref pointing to a hash containing the values to
2249             # to use as a filter (SQL WHERE part). Key: column name
2250             # value: The value or an anon array-ref with
2251             # [ 'compare-operator', 'value-to-search-for' ]
2252             #
2253             # return: OK Ok, one file found, \%vars filled with values from db
2254             # NOFILE no file found, \%vars's values will be undef
2255             # NFOUND more than one file found, \%vars's values will be undef
2256             # ERROR error, call method get_err to pick the error message
2257             # \%vars's values will be undef
2258             #
2259             sub get_conf_by_var {
2260 0     0 0 0 my $self = shift;
2261 0         0 my $dir = shift;
2262 0         0 my $defaultfname =shift;
2263 0         0 my $fnamcol = shift;
2264 0         0 my $vars = shift;
2265 0         0 my $searchvars = shift;
2266              
2267 0         0 my $r = ERROR;
2268 0         0 my $st;
2269              
2270 0 0       0 unless( defined $self->{dbh} ) {
2271 0         0 $self->{err} = "DBIx::FileSystem object not initialized";
2272 0         0 return $r;
2273             }
2274              
2275             # check parameter
2276 0 0 0     0 if( !defined $dir or $dir eq '' ) {
2277 0         0 $self->{err} = "get_conf_by_var(): parameter 'dir' is empty";
2278 0         0 return $r;
2279             }
2280 0 0 0     0 if( !defined $fnamcol or $fnamcol eq '' ) {
2281 0         0 $self->{err} = "get_conf_by_var(): parameter 'fnamcol' is empty";
2282 0         0 return $r;
2283             }
2284 0 0       0 if( ref( $vars ) ne 'HASH' ) {
2285 0         0 $self->{err} = "get_conf_by_var(): parameter 'vars' is no hashref";
2286 0         0 return $r;
2287             }
2288 0 0       0 if( keys( %{$vars} ) == 0 ) {
  0         0  
2289 0         0 $self->{err} = "get_conf_by_var(): hash 'vars' is empty";
2290 0         0 return $r;
2291             }
2292 0 0       0 if( ref( $searchvars ) ne 'HASH' ) {
2293 0         0 $self->{err} = "get_conf_by_var(): parameter 'searchvars' is no hashref";
2294 0         0 return $r;
2295             }
2296 0 0       0 if( keys( %{$searchvars} ) == 0 ) {
  0         0  
2297 0         0 $self->{err} = "get_conf_by_var(): hash 'searchvars' is empty";
2298 0         0 return $r;
2299             }
2300              
2301 0         0 foreach my $v ( keys %{$vars} ) {
  0         0  
2302 0         0 $vars->{$v} = undef;
2303             }
2304              
2305 0         0 DB: while( 1 ) {
2306 0         0 my %extra;
2307 0         0 my $qry = '';
2308 0         0 my $res;
2309              
2310             # check query parameters against defaultfile
2311 0 0       0 if( defined $defaultfname ) {
2312 0         0 foreach my $searchvar (keys %{$searchvars} ) {
  0         0  
2313 0         0 $qry = "SELECT count($fnamcol) FROM $dir WHERE $searchvar" .
2314             $self->sqlize( $searchvars->{$searchvar} ) .
2315             " AND $fnamcol = '$defaultfname'";
2316 0         0 $st = $self->{dbh}->prepare( "$qry" );
2317 0 0       0 unless( $st ) {
2318 0         0 $self->{err} = "prepare extra qry: " . $self->{dbh}->errstr;
2319 0         0 last DB;
2320             }
2321 0 0       0 if( $st->execute() ) {
2322 0         0 ($res) = $st-> fetchrow_array();
2323 0 0 0     0 if( defined $res and $res == 1 ) {
2324 0         0 $extra{$searchvar} = " OR $searchvar IS NULL";
2325             }else{
2326 0         0 $extra{$searchvar} = "";
2327             }
2328 0         0 $st->finish();
2329             }else{
2330 0         0 $self->{err} = "exec extra qry: " . $self->{dbh}->errstr;
2331 0         0 last DB;
2332             }
2333             }
2334             }else{
2335 0         0 foreach my $searchvar (keys %{$searchvars} ) {
  0         0  
2336 0         0 $extra{$searchvar} = "";
2337             }
2338             }
2339              
2340             # base query
2341              
2342 0         0 $qry = "SELECT ";
2343 0         0 foreach my $var (keys %{$vars} ) {
  0         0  
2344 0         0 $qry .= "$var,";
2345             }
2346 0         0 chop $qry;
2347 0         0 $qry .= " FROM $dir WHERE ";
2348 0         0 my $rest = 0;
2349 0         0 foreach my $searchvar (keys %{$searchvars} ) {
  0         0  
2350 0 0       0 $qry .= " AND " if $rest;
2351 0         0 $qry .= "( $searchvar" . $self->sqlize( $searchvars->{$searchvar} ) .
2352             "$extra{$searchvar} )";
2353 0 0       0 $rest = 1 unless $rest;
2354             }
2355             ### print "qry: '$qry'\n";
2356              
2357 0         0 $res = $self->{dbh}->selectall_arrayref( $qry, { Slice => {} } );
2358 0 0 0     0 if( !defined $res or defined $self->{dbh}->{err} ) {
2359 0         0 $self->{err} = "get_conf_by_var(): query: " . $self->{dbh}->errstr;
2360 0         0 last DB;
2361             }
2362              
2363 0 0       0 if( @$res == 0 ) {
    0          
2364 0         0 $self->{err} = "no file found";
2365 0         0 $r = NOFILE;
2366 0         0 last DB;
2367             }elsif( @$res == 1 ) {
2368 0         0 foreach my $col (keys %{$res->[0]} ) {
  0         0  
2369 0         0 $vars->{$col} = $res->[0]->{$col};
2370             }
2371 0         0 $r = OK;
2372             }else{
2373 0         0 $self->{err} = "more than one file found";
2374 0         0 $r = NFOUND;;
2375 0         0 last DB;
2376             }
2377              
2378             # read defaults from defaultfile if necessary
2379              
2380 0 0       0 if( defined $defaultfname ) {
2381 0         0 my %sv = ( $fnamcol => $defaultfname );
2382 0         0 my %v = %{$vars};
  0         0  
2383 0         0 $r = $self->get_conf_by_var( $dir, undef, $fnamcol, \%v, \%sv );
2384              
2385 0 0       0 if( $r == OK ) {
2386 0         0 foreach my $var ( keys %v ) {
2387 0 0       0 $vars->{$var} = $v{$var} unless defined $vars->{$var};
2388             }
2389             }else{
2390 0 0       0 if( $r == NOFILE ) {
    0          
2391 0         0 $self->{err} = "defaultfile '$dir/$defaultfname' not found";
2392             }elsif( $r == NFOUND ) {
2393 0         0 $self->{err} = "more than one file '$dir/$defaultfname' found";
2394             }
2395 0         0 foreach my $v ( keys %{$vars} ) {
  0         0  
2396 0         0 $vars->{$v} = undef;
2397             }
2398 0         0 $r = ERROR;
2399             }
2400             }
2401              
2402 0         0 last DB;
2403              
2404             } # while( DB )
2405              
2406 0         0 return $r;
2407              
2408             } # get_conf_by_var()
2409              
2410             ########################################################################
2411             # sqlize();
2412             # build the right-hand-side of the WHERE part, incl. compare operator.
2413             # respect quoting of strings, integer values and 'undef' / NULL
2414             # parameter:
2415             # $val: the value to SQLize
2416             #
2417             # return: the sqlized string
2418             #
2419             sub sqlize {
2420 0     0 0 0 my $self = shift;
2421 0         0 my $val = shift;
2422 0         0 my $r;
2423 0 0       0 if( ! defined $val ) {
    0          
2424 0         0 $r = " IS NULL";
2425             }elsif( ref( $val ) eq 'ARRAY' ) {
2426 0 0 0     0 if( defined $val->[0] and defined $val->[1] ) {
2427 0 0       0 if( $self->isanumber( $val->[1] ) ) {
2428 0         0 $r = " $val->[0] $val->[1]";
2429             }else{
2430 0         0 $r = " $val->[0] " . $self->{dbh}->quote( $val->[1] );
2431             }
2432             }else{
2433 0         0 $r = " IS NULL";
2434             }
2435             }else{
2436 0 0       0 if( $self->isanumber( $val ) ) {
2437 0         0 $r = "=$val";
2438             }else{
2439 0         0 $r = "=" . $self->{dbh}->quote( $val );
2440             }
2441             }
2442              
2443 0         0 return $r;
2444              
2445             } # sqlize()
2446              
2447              
2448             ########################################################################
2449             # isanumber();
2450             # check if $str is a number or not
2451             # parameter:
2452             # $str
2453             #
2454             # return: 0 $val is string
2455             # 1 $val is number
2456             #
2457             sub isanumber() {
2458 41     41 0 21531 my $self = shift;
2459 41         96 my $str = shift;
2460 41         60 my $r = 1;
2461              
2462 41 100       269 if( !defined $str ) {
    100          
    100          
    100          
    100          
2463 1         2 $r = 0;
2464             }elsif( $str eq '' ) {
2465 1         3 $r = 0;
2466             }elsif( $str =~ / / ) {
2467 7         10 $r = 0;
2468             }elsif( $str =~ /infinity/i ) {
2469 2         3 $r = 0;
2470             }elsif( $str =~ /nan/i ) {
2471 2         4 $r = 0;
2472             }else{
2473 28         41 $! = 0;
2474 28         165 my ($num, $unparsed ) = POSIX::strtod( $str );
2475 28 100 66     138 if( ($unparsed != 0) || $!) {
2476 9         16 $r = 0;
2477             }
2478             }
2479 41         108 return $r;
2480              
2481             } # isanumber()
2482              
2483              
2484             ########################################################################
2485             ########################################################################
2486             ########################################################################
2487             ########################################################################
2488              
2489             1;
2490             __END__