vfu-4.10/0000755000175000001440000000000011231160740011044 5ustar cadeusersvfu-4.10/rx/0000755000175000001440000000000011204630317011477 5ustar cadeusersvfu-4.10/rx/aenea.ftp0000644000175000001440000000001411040351114013247 0ustar cadeusers192.168.4.4 vfu-4.10/rx/README0000644000175000001440000000237711204630247012372 0ustar cadeusers RX_* TOOLS README $Id: README,v 1.2 2005/06/03 00:34:57 cade Exp $ This is preliminary documentation to the `RX_*' utilities. The main purpose of rx_* is to provide standard archive-like interface to various containers (archives, ftp sites, etc). It is mainly used with VFU file manager which can be found at http://cade.datamax.bg/vfu. `FTP' archives contain just info how to connect to the required site. example1: text file named: soul.ftp ---cut--- soul.tetida.org cade secretpassword ---cut--- command line: rx_auto v soul.ftp /pub will show all files in the `/pub' directory at the FTP site soul.tetida.org. you can use dash `-' as username and password to mimic anonymous access: example2: text file named: cade.jane.org ---cut--- jane.tetida.org - - ---cut--- command line: rx_ftp x cade.jane.ftp pub/welcome.txt will extract/download welcome.txt file from he pub directory at the jane.tetida.org FTP site. username will be `anonymouse' and password will be `current_username@current_hostname' (from the environment) For more details and if you have problems contact me: Vladi Belperchinov-Shabanski Good luck! vfu-4.10/rx/rx_auto0000755000175000001440000000240011234421153013101 0ustar cadeusers#!/usr/bin/perl ############################################################################# # # rx_* dispatcher and handlers for VFU File Manager # (c) Vladi Belperchinov-Shabanski "Cade" 2002 # http://cade.webbg.com # $Id: rx_auto,v 1.5 2006/08/05 20:15:40 cade Exp $ # # usage: # rx_* l archive directory # list archive directory # rx_* v archive # list entire archive # rx_* x archive files... # extract one file # rx_* x archive @listfile # extract list of files # ############################################################################# use strict; my $CTTL = 16; # cache time to live in seconds my $file = $ARGV[1]; for( glob "/tmp/*.rx.cache" ) { # clean cache--silently skip errors next unless time() - file_mtime( $_ ) > $CTTL; unlink $_; } my $rx = choose( $file ) or die "$0: this file type is not nown to me, sorry\n"; exec( $rx, @ARGV ); sub choose { local $_ = shift; return "rx_tar" if /\.(?:tar(?:\.(?:z|gz|bz2))?|t[bgx]z)$/i; return "rx_zip" if /\.(?:zip|jar|pk3|egg|maff)$/i; return "rx_deb" if /\.deb$/i; return "rx_ftp" if /\.ftp$/i; return "rx_rar" if /\.rar$/i; return "rx_rpm" if /\.rpm$/i; return undef; } sub file_mtime { return (stat($_[0]))[9]; } vfu-4.10/rx/jane.ftp0000644000175000001440000000002011204630247013121 0ustar cadeuserslocalhost - - - vfu-4.10/rx/rx_deb0000755000175000001440000000525011204630247012674 0ustar cadeusers#!/usr/bin/perl ############################################################################# # # rx_* dispatcher and handlers for VFU File Manager # (c) Vladi Belperchinov-Shabanski "Cade" 2002 # http://cade.webbg.com # $Id: rx_deb,v 1.4 2002/11/07 23:22:21 cade Exp $ # # usage: # rx_* l archive directory # list archive directory # rx_* v archive # list entire archive # rx_* x archive files... # extract one file # rx_* x archive @listfile # extract list of files # ############################################################################# use strict; my $cmd = lc shift @ARGV; my $archive = shift @ARGV; my $cache = "$archive.data.tar.gz.rx.cache"; $cache =~ s/^(.+)\/([^\/]+)$/$2/; if ( $cmd eq "l" || $cmd eq "v" || $cmd eq "x" ) { if( ! -e "/tmp/$cache" ) { # cache not found--fill it system( "ar p \"$archive\" data.tar.gz > \"/tmp/$cache\"" ); chmod oct(600), "/tmp/$cache"; # a bit late but still... :) } else { utime time(), time(), "/tmp/$cache"; # update last modification time of the cache } chdir( "/tmp" ); system( "rx_tar", $cmd, $cache, @ARGV ); } else { die $0 . ": wrong command.\n"; } =pod if ( $command eq "v" ) { $dir = shift @ARGV; if ( $dir ) { $dir .= "/" unless $dir =~ /\/$/; } if ( $dir eq "DATA/" ) { open( i, "ar p $archive data.tar.gz | gzip -dc | tar tvf - |"); while() { chop; s/\s+->\s+\S+$//; if (/^(.[\-rwxsStT]{9})\s+\S+\s+(\d+)\s+(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d)(:\d\d)?\s+(\S+[^\/])$/) { print "NAME:$9\nSIZE:$2\nMODE:$1\nTIME:$3$4$5$6$7\n\n"; } } close( i ); } else { # these are standard ones print "NAME:control\n\nNAME:debian-binary\n\nNAME:DATA/\n\n"; # FIXME: here should take ar list and get files' sizes etc... } } # view command ends here elsif ( $command eq "x" ) { if ( $ARGV[0] eq "control" ) { system( "ar p $archive control.tar.gz | gzip -d | tar xvf - control" ); } elsif ( $ARGV[0] eq "debian-binary" ) { system( "ar p $archive debian-binary > debian-binary" ); } else { if ( $ARGV[0] =~ /^\@(.+)$/ ) { $listfile = $1; } else { $listfile = "/tmp/rx_tar.list." . $$; open( o, ">$listfile" ); while( $_ = shift @ARGV ) { s/^DATA\///; print o "$_\n"; } close( o ); } system( "mkdir -p DATA; cd DATA; ar p $archive data.tar.gz | gzip -d | tar xvf - -T $listfile" ); unlink $listfile; } } =cut vfu-4.10/rx/rx_ftp0000755000175000001440000000435411204630247012737 0ustar cadeusers#!/usr/bin/perl ############################################################################# # # rx_* dispatcher and handlers for VFU File Manager # (c) Vladi Belperchinov-Shabanski "Cade" 2002 # http://cade.webbg.com # $Id: rx_ftp,v 1.4 2002/11/07 23:37:46 cade Exp $ # # usage: # rx_* l archive directory # list archive directory # rx_* v archive # list entire archive # rx_* x archive files... # extract one file # rx_* x archive @listfile # extract list of files # ############################################################################# # # BUGS: # - cannot show recursively entire site # - cannot copy/extract directories # # TODO: # - cache? # ############################################################################# use Net::FTP; use strict; my $cmd = lc shift @ARGV; my $archive = shift @ARGV; my $cache = "/tmp/$archive.rx.cache"; $cache =~ s/^(\/tmp\/)(.+)\/([^\/]+)$/$1$3/; my $i; open $i, $archive; my $host = <$i>; my $user = <$i>; my $pass = <$i>; close $i; chop($host); chop($user); chop($pass); my $ftp = Net::FTP->new( $host ) or die "$0: cannot connect to $host\n"; $user = 'anonymous' if $user eq '-'; $pass = "$ENV{USER}\@$ENV{HOSTNAME}" if $pass eq '-'; $ftp->login( $user, $pass ) or die "$0: cannot login as $user into $host\n"; if ( $cmd eq "l" || $cmd eq "v" ) { my $dir = shift @ARGV; $ftp->cwd( $dir ); my @list = $ftp->dir(); for( @list ) { my @D = split /\s+/, $_; my $N = pop @D; my $M = $D[0]; my $S = $D[4]; $N .= '/' if $M =~ /^d/i; print "NAME:$N\nSIZE:$S\nMODE:$M\n\n"; } } elsif ( $cmd eq "x" ) { my @list; if ( $ARGV[0] =~ /^\@(.+)$/ ) { my $i; open $i, $1; @list = <$i>; close $i; chop( @list ); } else { @list = @ARGV; } for my $e ( @list ) { $e =~ s/^\///; my $p; my $l; if( $e =~ /^(.+\/)([^\/]+)$/ ) { $l = $2; $p = $1; }; mkpath( $p ); # print "$e:$p:$l\n"; $ftp->get( $e, "$p$l" ); } } else { die $0 . ": wrong command.\n"; } sub mkpath { my $p = shift; my @p = split /\//, $p; my $cp; while( @p ) { $cp .= shift( @p ) . '/'; mkdir $cp; print ">>$cp\n"; } } vfu-4.10/rx/rx_rar0000755000175000001440000000425211234421504012724 0ustar cadeusers#!/usr/bin/perl ############################################################################# # # rx_* dispatcher and handlers for VFU File Manager # (c) Vladi Belperchinov-Shabanski "Cade" 2002 # http://cade.webbg.com # $Id: rx_rar,v 1.2 2002/11/07 23:22:21 cade Exp $ # # usage: # rx_* l archive directory # list archive directory # rx_* v archive # list entire archive # rx_* x archive files... # extract one file # rx_* x archive @listfile # extract list of files # ############################################################################# use strict; my $cmd = lc shift @ARGV; my $archive = shift @ARGV; my $cache = "/tmp/$archive.rx.cache"; $cache =~ s/^(\/tmp\/)(.+)\/([^\/]+)$/$1$3/; if ( $cmd eq "l" || $cmd eq "v" ) { my $dir = shift @ARGV; if ( $dir ) { $dir .= "/" unless $dir =~ /\/$/; } if( ! -e $cache ) { # cache not found--fill it system( "unrar v '$archive' > '$cache'" ); chmod oct(600), $cache; # a bit late but still... :) } else { utime time(), time(), $cache; # update last modification time of the cache } my $in = 0; open( i, $cache ); while() { $in = ! $in and next if/^[\- ]{16,}$/; next unless $in; chop; s/^\s+//; my @D; push @D, $_; $_ = ; chop; s/^\s+//; push @D, split /\s+/; my $N = $D[0]; # name if ( $cmd eq "l" ) { next unless $N =~ s/^$dir([^\/]+\/?)$//; $N = $1; } my $S = $D[1]; my $T = $D[4] . $D[5]; $T =~ s/(\d\d)-(\d\d)-(\d\d)(\d\d):(\d\d)/$3$2$1$4$5/; $T = ( $3 < 70 ? '20' : '19' ) . $T; my $M = $D[6]; $N .= '/' if $M =~ /D/; print "NAME:$N\nSIZE:$S\nTIME:$T\nMODE:$M\n\n"; } close( i ); } elsif ( $cmd eq "x" ) { my $list; if ( $ARGV[0] =~ /^\@(.+)$/ ) { $list = $1; } else { $list = "/tmp/$$.rx.list"; open( o, ">$list" ); chmod oct(600), $list; print o "$_\n" for @ARGV; close( o ); } system( "unrar x $archive \@$list 1> /dev/null 2> /dev/null" ); unlink $list; } else { die $0 . ": wrong command.\n"; } vfu-4.10/rx/rx_rpm0000755000175000001440000000421411204630247012737 0ustar cadeusers#!/usr/bin/perl ############################################################################# # # rx_rpm handler for VFU File Manager # (c) Ralph Muller 2005 # $Id: rx_rpm,v 1.2 2005/06/16 00:07:38 cade Exp $ # # usage: # rx_* l archive directory # list archive directory # rx_* v archive # list entire archive # rx_* x archive files... # extract one file # rx_* x archive @listfile # extract list of files # ############################################################################# use strict; my $cmd = lc shift @ARGV; my $archive = shift @ARGV; my $cache = "/tmp/$archive.rx.cache"; $cache =~ s/^(\/tmp\/)(.+)\/([^\/]+)$/$1$3/; if ( $cmd eq "l" || $cmd eq "v" ) { my $dir = shift @ARGV; if ( $dir ) { $dir .= "/" unless $dir =~ /\/$/; } if( ! -e $cache ) { # cache not found--fill it system( "rpm2cpio \"$archive\" | cpio -tv --quiet > \"$cache\"" ); chmod oct(600), $cache; # a bit late but still... :) } else { utime time(), time(), $cache; # update last modification time of the cache } my $in = 0; open( my $i, $cache ); while(<$i>) { # $in = ! $in and next if/^[\- ]{16,}$/; # FixMe # next unless $in; chomp; s/\s+->\s+\S+$//; # no symlinks support? my @D = split /\s+/; my $N = $D[8]; # name # if ( $cmd eq "l" ) # { # next unless $N =~ s/^$dir([^\/]+\/?)$//; # FixMe # $N = $1; # } my $S = $D[4]; # my $T = $D[5] . " " . $D[6] . " " . $D[7]; # FixMe # $T =~ s/(\d\d)-(\d\d)-(\d\d)(\d\d):(\d\d)/$3$2$1$4$5/; # $T = ( $3 < 70 ? '20' : '19' ) . $T; # print "NAME:$N\nSIZE:$S\nTIME:$T\n\n"; print "NAME:$N\nSIZE:$S\n\n"; } close( $i ); } elsif ( $cmd eq "x" ) { my $list; if ( $ARGV[0] =~ /^\@(.+)$/ ) { $list = $1; } else { $list = "/tmp/$$.rx.list"; open( o, ">$list" ); chmod oct(600), $list; print o "$_\n" for @ARGV; close( o ); } system( "rpm2cpio $archive | cpio -iumd --quiet `cat $list`" ); unlink $list; } else { die $0 . ": wrong command.\n"; } vfu-4.10/rx/rx_tar0000755000175000001440000000547211234421257012740 0ustar cadeusers#!/usr/bin/perl ############################################################################# # # rx_* dispatcher and handlers for VFU File Manager # (c) Vladi Belperchinov-Shabanski "Cade" 2002 # http://cade.webbg.com # $Id: rx_tar,v 1.4 2002/11/07 23:22:21 cade Exp $ # # usage: # rx_* l archive directory # list archive directory # rx_* v archive # list entire archive # rx_* x archive files... # extract one file # rx_* x archive @listfile # extract list of files # ############################################################################# use strict; my $cmd = lc shift @ARGV; my $archive = shift @ARGV; my $cache = "/tmp/$archive.rx.cache"; $cache =~ s/^(\/tmp\/)(.+)\/([^\/]+)$/$1$3/; if ( $cmd eq "l" || $cmd eq "v" ) { my $dir = shift @ARGV; if ( $dir ) { $dir .= "/" unless $dir =~ /\/$/; } if( ! -e $cache ) { # cache not found--fill it system( "tar xvf \"$archive\" > \"$cache\"" ) if $archive =~ /\.tar$/i; system( "gzip -dc \"$archive\" | tar tvf - > \"$cache\"" ) if $archive =~ /\.tar\.g?z(\.rx\.cache)?$/i; system( "gzip -dc \"$archive\" | tar tvf - > \"$cache\"" ) if $archive =~ /\.tgz$/i; system( "xz -dc \"$archive\" | tar tvf - > \"$cache\"" ) if $archive =~ /\.txz$/i; system( "bzip2 -dc \"$archive\" | tar tvf - > \"$cache\"" ) if $archive =~ /\.tar\.bz2?$/i; chmod oct(600), $cache; # a bit late but still... :) } else { utime time(), time(), $cache; # update last modification time of the cache } open( i, $cache ); while() { chop; s/\s+->\s+\S+$//; # no symlinks support? my @D = split /\s+/; my $N = $D[5]; # name $N =~ s/^\.\///; $N =~ s/^\//\//; if ( $cmd eq "l" ) { next unless $N =~ s/^$dir([^\/]+\/?)$//; $N = $1; } my $T = "$D[3]$D[4]"; # time $T =~ s/[\-\s\:]//g; $T = substr( $T, 0, 12 ); print "NAME:$N\nSIZE:$D[2]\nMODE:$D[0]\nTIME:$T\n\n"; } close( i ); } elsif ( $cmd eq "x" ) { my $list; if ( $ARGV[0] =~ /^\@(.+)$/ ) { $list = $1; } else { $list = "/tmp/$$.rx.list"; open( o, ">$list" ); chmod oct(600), $list; print o "$_\n" for @ARGV; close( o ); } system( "tar xvf $archive -T $list" ) if $archive =~ /\.tar$/i; system( "gzip -dc $archive | tar xvf - -T $list" ) if $archive =~ /\.tar\.g?z(\.rx\.cache)?$/i; system( "gzip -dc $archive | tar xvf - -T $list" ) if $archive =~ /\.tgz$/i; system( "xz -dc $archive | tar xvf - -T $list" ) if $archive =~ /\.txz$/i; system( "bzip2 -dc $archive | tar xvf - -T $list" ) if $archive =~ /\.tar\.bz2?$/i; unlink $list; print "gzip -dc $archive | tar xvf - -T $list"; } else { die $0 . ": wrong command.\n"; } vfu-4.10/rx/rx_zip0000755000175000001440000000411411234421544012743 0ustar cadeusers#!/usr/bin/perl ############################################################################# # # rx_* dispatcher and handlers for VFU File Manager # (c) Vladi Belperchinov-Shabanski "Cade" 2002 # http://cade.webbg.com # $Id: rx_zip,v 1.3 2002/11/07 23:22:21 cade Exp $ # # usage: # rx_* l archive directory # list archive directory # rx_* v archive # list entire archive # rx_* x archive files... # extract one file # rx_* x archive @listfile # extract list of files # ############################################################################# use strict; my $cmd = lc shift @ARGV; my $archive = shift @ARGV; my $cache = "/tmp/$archive.rx.cache"; $cache =~ s/^(\/tmp\/)(.+)\/([^\/]+)$/$1$3/; if ( $cmd eq "l" || $cmd eq "v" ) { my $dir = shift @ARGV; if ( $dir ) { $dir .= "/" unless $dir =~ /\/$/; } if( ! -e $cache ) { # cache not found--fill it system( "unzip -l '$archive' > '$cache'" ); chmod oct(600), $cache; # a bit late but still... :) } else { utime time(), time(), $cache; # update last modification time of the cache } my $in = 0; open( i, $cache ); while() { $in = ! $in and next if/^[\- ]{16,}$/; next unless $in; chop; s/\s+->\s+\S+$//; # no symlinks support? my @D = split /\s+/, $_, 5; my $N = $D[4]; # name if ( $cmd eq "l" ) { next unless $N =~ s/^$dir([^\/]+\/?)$//; $N = $1; } my $S = $D[1]; my $T = $D[2] . $D[3]; $T =~ s/(\d\d)-(\d\d)-(\d\d)(\d\d):(\d\d)/$3$2$1$4$5/; $T = ( $3 < 70 ? '20' : '19' ) . $T; print "NAME:$N\nSIZE:$S\nTIME:$T\n\n"; } close( i ); } elsif ( $cmd eq "x" ) { my $list; if ( $ARGV[0] =~ /^\@(.+)$/ ) { $list = $1; } else { $list = "/tmp/$$.rx.list"; open( o, ">$list" ); chmod oct(600), $list; print o "'$_'\n" for @ARGV; close( o ); } system( "unzip $archive `cat $list` 1> /dev/null 2> /dev/null" ); unlink $list; } else { die $0 . ": wrong command.\n"; } vfu-4.10/FAQ0000644000175000001440000002604611172606420011412 0ustar cadeusers FREQUENTLY ASKED QUESTIONS ABOUT: VF File Manager for Unix/Linux ( VFU ) by Vladi Belperchinov-Shabanski "Cade" http://soul.datamax.bg/~cade/vfu $Id: FAQ,v 1.8 2005/06/05 22:02:05 cade Exp $ 1. What is `TP' field on the third line? This stands for "type" and means: [] -- directory <> -- link to directory -> -- link ** -- executable ++ -- character device ## -- socket () -- FIFO (pipe) == -- block device -- -- regular file 2. Does VFU follows directory links when calculating directory(ies) size? No. :) 3. I cannot see entire filename? Try '>' or '0' -- it will show only filenames... or try `1'..`6' to toggle different info entries. 4. What files are considered `executables' (i.e. marked `**') File is marked `**' if any of `x' modes are set (regardless owner, group, etc.) This means that if file has mode of -rwxr--r-- and you are not owner the file will be still marked as `**' but you won't be able to execute it! This behavior may be changed in the future but not for now. (in general `**' does NOT mean that you can execute it) 5. Do I need to set `HOME' environment variable under DOS, and where it is supposed to point? Yes. In general, the HOME directory is used to keep all configuration and status files. Well, if you don't set it, VFU will set HOME directory into TEMP ( c:/tmp/ under DOS ) But keep in mind that VFU is UNIX file manager in nature so it can use HOME under DOS for something else in the future, so it is recommended to set it. ( just to be safe :) ) 7. How can I use `JumpToMountpoint' function under DOS? The information for this function comes from the `/etc/mtab' file. This file show currently mounted file systems. Under DOS platform the only way is to simulate this file, which is quite simple -- You have just to create `_vfu.mtb' file in the HOME (see FAQ 6 above) directory. Content of this file is: (this is example) ---cut--- - c:/ - d:/ - j:/ ---cut--- Please note the leading `-', it must be here. However you can add whatever you want ( I mean paths ), but normally you just should add roots of all drives. 8. I've just created `some/newdir' in the current directory. VFU reported no error, but I cannot see it. Well, you just have to hit 'r' to reload directory content. I know this may be confusing at first, but you'll get used to it quite fast. :) 9. How can I exit to new directory from vfu (UNIX) On exit VFU always try to create file named `/tmp/vfu.exit.USERNAME` where `USERNAME' is current user's user name :) for example my filename will be named `/tmp/vfu.exit.cade'. To make use of this file you should define alias or function (bash) for it like this example: function vfu() { /usr/local/bin/vfu $*; cd `cat /tmp/vfu.exit.$USER`; rm -f /tmp/vfu.exit.$USER; } This is bash function that does the trick. If someone need this for other shell or with an alias then please contact me. After this you can use `q' to exit VFU and cd to the VFU's current working directory. You can change this filename by exporting new name in this way: export VFU_EXIT="/tmp/my.exit.file.$$" And VFU will use it instead of default one. NOTE: DOS version should work without this -- the `q'uit function will work standalone. 10. What is `Name###' sort order? And why should I RTFM?! :) This mode forces sort order as follows: file names are: `vs011.txt', `vs04.txt', `vs030.txt' sort order is : `Name' the result is : `vs011.txt', `vs030.txt', `vs04.txt' file names are: `vs011.txt', `vs04.txt', `vs030.txt' sort order is : `Name###' the result is : `vs04.txt', `vs011.txt', `vs030.txt' ...in a few words: if the file name (until first dot if exist) ends with number, VFU will sort them in regard to the numeric values found at the ends of the filenames. (real parsing re is "^(.*)([0123456789]+)(\\.(.*))?$" if you know what this means:)) NOTE: This mode drops all after the first dot! NOTE: This mode resets on exit! 11. How is done the tilde expansion in VFU? It works only in standard input line for getting directory name which is used for: chdir, copy, move... it won't work in vfu.conf or anywhere else. 12. What is the mask expansion and how it works? If no `*' or `?' found in the mask then: 1. add `*' at the end 2. if mask starts with `.' then add `*' to the front else 1. leave it `as is' Just try it -- if you don't like the expansion -- switch it off: Options(Toggles)/FilesMaskExpand and FileFindMaskExpand. 13. Where mask expansion applies and can I turn it off? Wherever you need to enter mask! (file list masking, global select, file find, etc...) You can turn it off form the `Options' (key `O') 14. Can I browse/view more than one file at the same time? Yes! You have just to select needed files and press 'B' (browse). Then use `1'..`0' to switch between files/slots. The limit is 10 files. 15. What `Show Real Free Space' option means? Most of the operating systems keep users from filling the entire disks. So there is two `free spaces' the one is the `real free space' ( i.e. physical one ) and `user free space' which is the free space available to any user. By default VFU shows the free space available to the user. If you want to use the real free space count -- turn this on. 16. How can I use the FTP support? NOTE! as of Nov.2002 VFU doesn't use `ftparc' anymore! Instead rx_ftp uses Net::FTP perl module. All you need to use FTP support is: a. install Net::FTP if you haven't done this already. b. create needed FTP file archives: example: create plain text file: cade-at-jane.ftp ---cut--- jane.tetida.org cade password ---cut--- This file has to contain three lines: host, username and password. c. Then from inside VFU press `+' or `ENTER' to enter FTP site just as it is plain archive file. More details could be found in the README file with rx_*. (rx directory under VFU main distribution directory) 17. I cannot enter archive/ftp! What's wrong? Since version 3.00 VFU uses external utilities to handle archives/ftp. These utilities are named rx_ext, where `ext' is archive type extensions. However VFU calls `rx_auto' which decides which specific `rx_*' to call. So the solution is: make sure rx_* utilities are in the path. Then test the result of `rx_auto l archive', it should return something like: ---cut--- NAME: some/name.ext SIZE: 1024 MODE: -rwx---rwx NAME: other/name.misc SIZE: 1110 MODE: ---------- ... ---cut--- 18. What is the interface to those rx_* tools? rx_* tools should provide the following commands: rx_ftp v archive directory view contents of `directory' of archive `archive' rx_ftp V archive directory view contents of `directory' of archive `archive' recursively (i.e. all filenames are with full path, `directory' is ignored ) rx_ftp x archive files... extract files from archive rx_ftp x archive @listfile extract files from archive (but get the list from file named `listfile') examples: rx_tar v vfu-3.01.tar.gz /vfu-3.01/vslib/ rx_tar V vfu-3.01.tar.gz rx_tar x vfu-3.01.tar.gz /vfu-3.01/ftparc/README The expected format that has to be returned for commands `v' and `V' is: ---cut--- NAME:filename SIZE:12345678 MODE:-rwxr-xr-- TIME:YYYYMMDDHHMMSS NAME:filename SIZE:12345678 MODE:-rwxr-xr-- TIME:YYYYMMDDHHMMSS ... ---cut--- Currently only NAME and SIZE are supported! The order for fields is random. Each entry is separated with empty line. `filename' contains only filename for `v' command and full path for `V' command. examples: `v' command: ---cut--- NAME:README SIZE:605 MODE:-rw-r--r-- TIME:200005231124 NAME:vfumenu.h SIZE:614 MODE:-rw-r--r-- TIME:200005191052 NAME:vfusetup.h SIZE:1327 MODE:-rw-r--r-- TIME:200008010017 NAME:makefile SIZE:3772 MODE:-rw-r--r-- TIME:200005191058 ---cut--- `V' command: ---cut--- NAME:vfu-3.02/vfu.1 SIZE:16773 MODE:-rw-r--r-- TIME:200008010118 NAME:vfu-3.02/build.netbsd SIZE:832 MODE:-rwxr-xr-x TIME:200006171605 NAME:vfu-3.02/README.DOS SIZE:430 MODE:-rw-r--r-- TIME:199902161511 NAME:vfu-3.02/TODO SIZE:685 MODE:-rw-r--r-- TIME:200006172251 NAME:vfu-3.02/ftparc/ftparc.cpp SIZE:7521 MODE:-rw-r--r-- TIME:200004161224 ---cut--- 19. What does Tools/RenameTools/SiplifyName do? First replaces all `special' symbols as `'&\"/ etc with _ then it compresses all repeating _'s and finally it replaces `_-_' with `-'. NOTE: I accept any suggestions for this feature behaviour! 20. How can I purge directory sizes cache? The sizes cache is flushed on directory tree rebuild. 21. Why I cannot execute image viewer (or any prog) on a file inside archive? It reports `file not found' error? The problem is when you want to spawn image viewer with `&' on background. At this point VFU has taken control back and temporary file/dir is removed. There is no slick solution to this and only workaround is to remove `&' from your command. 22. How to make VFU to handle Ctrl+Z, Ctrl+C? You have to export UNICON_NO_RAW environment variable: export UNICON_NO_RAW=1 vfu ... 23. Is it possible to see file sizes above 4GB properly? Yes, you have to compile this way: export CCDEF="-D_FILE_OFFSET_BITS=64" make or make CCDEF="-D_FILE_OFFSET_BITS=64" 99. I don't/do like feature X, can I turn it OFF/ON? I tried to give option for every arguable behavior of most features. So you have to check `Options' menu (key O inside VFU) and vfu.conf file to find out how to solve the problem. If this doesn't help contact me... vfu-4.10/vfu/0000755000175000001440000000000011312262432011645 5ustar cadeusersvfu-4.10/vfu/vfumenu.cpp0000644000175000001440000000242111310550064014034 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vfumenu.cpp,v 1.7 2003/01/26 21:48:42 cade Exp $ * */ #include #include "vfu.h" #include "vfuopt.h" #include "vfumenu.h" #include "vfuview.h" int vfu_toggle_box( int x, int y, const char *title, ToggleEntry* toggles ) { menu_box_info.bo = opt.menu_borders; menu_box_info.cn = cMENU_CN; menu_box_info.ch = cMENU_CH; menu_box_info.ti = cMENU_TI; int z = con_toggle_box( x, y, title, toggles, &menu_box_info ); vfu_redraw(); return z; } int vfu_menu_box( int x, int y, const char *title, VArray *va ) { menu_box_info.bo = opt.menu_borders; menu_box_info.cn = cMENU_CN; menu_box_info.ch = cMENU_CH; menu_box_info.ti = cMENU_TI; int z = con_menu_box( x, y, title, va, 0, &menu_box_info ); vfu_redraw(); return z; } int vfu_menu_box( const char* title, const char* menustr, int row ) { char t[256]; mb.undef(); VString str = menustr; while( str_len(str) ) { str_word(str,",", t); mb.push(t); } if ( row == -1 ) row = con_max_y() - 5 - mb.count(); return vfu_menu_box( 50, row, title, &mb ); } // eof vfumenu.cpp vfu-4.10/vfu/vfudir.cpp0000644000175000001440000006525311310550027013661 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vfudir.cpp,v 1.30 2007/12/16 13:44:10 cade Exp $ * */ #include "vfudir.h" #include "vfuopt.h" #include "vfuuti.h" #include "vfusys.h" #include "vfufiles.h" #include "vfuview.h" #include "vfumenu.h" VArray size_cache; /*###########################################################################*/ void __glob_gdn( const char* a_path, const char* a_fnpattern, VArray &a_va ) // glob getdirname { VString pat = a_fnpattern; pat += "*"; a_va.undef(); DIR *dir; dirent *de; if ( !a_path || a_path[0] == 0 ) dir = opendir("."); else dir = opendir( a_path ); if (dir) { while ( (de = readdir(dir)) ) { if ( strcmp( de->d_name, "." ) == 0 || strcmp( de->d_name, ".." ) == 0 ) continue; if ( a_fnpattern[0] == 0 || FNMATCH( pat, de->d_name)==0 ) { VString str; // = a_path; str += de->d_name; if ( file_is_dir( a_path + str ) ) { str += "/"; a_va.push(str); } } } closedir(dir); } } /* FIXME: must call sayX() at the end to clear... */ int vfu_get_dir_name( const char *prompt, VString &target, int should_exist ) { int res = -1; /* #ifdef _TARGET_UNIX_ leaveok(stdscr, FALSE); #endif */ VArray dir_list; say1(prompt); say2(""); int pos = 0; int page = 0; int ch = 0; int insert = 1; int firsthit = 1; pos = str_len( target ); //------------------------------------------------------------------ con_cshow(); say2( target, firsthit ? cINPUT2 : cINPUT ); while(1) { int mx = con_max_x() - 1; VString target_out = target; if ( (pos < page) || (pos+1 > page + mx) || (page > 0 && pos == page) ) page = pos - mx / 2; if ( page < 0 ) page = 0; str_trim_left( target_out, page ); str_sleft( target_out, mx ); str_pad( target_out, -mx ); if ( page > 0 ) str_set_ch( target_out, 0, '<' ); if ( str_len( target ) - page > mx ) str_set_ch( target_out, mx-1, '>' ); say2( target_out, firsthit ? cINPUT2 : cINPUT ); con_xy( pos-page+1, con_max_y() ); if (ch == 0) ch = con_getch(); if (ch == '\\') ch = '/'; /* dos hack :)) */ if ( ch == '/' && str_find( target, '/' ) == -1 && target[0] == '~' ) { target = tilde_expand( target ); str_fix_path( target ); pos = str_len( target ); ch = 0; } if ((ch == 8 || ch == KEY_BACKSPACE) && pos > 0) { pos--; str_del( target, pos, 1 ); } else if (ch == KEY_CTRL_A && str_len( target ) > 0) { int z = str_len( target )-1; if ( str_get_ch(target, z) == '/' ) z--; while ( z > 0 && str_get_ch(target,z) != '/' ) z--; z++; str_sleft(target,z); pos = z; } else if ( ch == 9 && str_len( target ) > 0) { int z; dir_list.undef(); VString dmain; /* main/base path */ VString dtail; /* item that should be expanded/glob */ dmain = str_file_path( target ); dtail = str_file_name_ext( target ); /* int lastslash = str_rfind(target, '/'); if ( lastslash == -1 ) { dmain = ""; dtail = target; } else { dmain = target; dtail = target; str_sleft( dmain, lastslash+1 ); str_trim_left( dtail, lastslash+1 ); } */ __glob_gdn( dmain, dtail, dir_list ); z = dir_list.count()-1; if (dir_list.count()) { if ( dir_list.count() > 1) { int mc = 0; /* match count */ int mi = 0; /* match letter index */ while(4) { mc = 0; int li; /* counter */ for ( li = 0; li < dir_list.count(); li++ ) { if ( str_get_ch( dir_list[ 0], mi ) == str_get_ch( dir_list[li], mi ) ) mc++; } if ( mc != dir_list.count() ) break; mi++; } target.setn( dmain + dir_list[0], str_len( dmain ) + mi ); pos = str_len( target ); say2( target, cINPUT ); con_xy( pos+1, con_max_y() ); vfu_beep(); ch = con_getch(); if ( ch != 9 ) { dir_list.undef(); continue; } dir_list.sort(); con_chide(); z = vfu_menu_box( 10, 5, "Complete...", &dir_list ); con_cshow(); ch = 0; } else ch = 0; if ( z != -1 ) { while( str_len( target ) > 0 && target[-1] != '/' ) str_chop( target ); target += dir_list[z]; } pos = str_len( target ); dir_list.undef(); if (ch != 0) continue; } else { /* no match found -- cannot complete */ vfu_beep(); } } else if (ch == 13) { res = 1; break; } else if (ch == 27) { target = ""; res = 0; break; } if (ch == KEY_CTRL_U) { target = ""; pos = 0; } else if (ch == KEY_CTRL_X) { char t[MAX_PATH]; if ( target[0] == '~' ) target = tilde_expand( target ); expand_path( target, t ); str_fix_path( t ); target = t; pos = str_len( target ); } else if (ch >= 32 && ch <= 255 ) // && pos < 70) { if (firsthit) { target = ""; pos = 0; } if (!insert) str_del( target, pos, 1 ); str_ins_ch( target, pos, ch ); pos++; } else if( ch == KEY_LEFT ) { if (pos > 0) pos--; } else if( ch == KEY_RIGHT ) { if (pos < str_len( target )) pos++; } else if ( ch == KEY_IC ) insert = !insert; else if ( ch == KEY_HOME ) pos = 0; else if ( ch == KEY_END ) pos = str_len(target); else if ( ch == KEY_DC && pos < str_len(target) ) str_del( target, pos, 1 ); else if ( ch == KEY_NPAGE || ch == KEY_PPAGE ) { con_chide(); int zz = vfu_hist_menu( 5, 5, ( ch == KEY_PPAGE ) ? "Dir Entry History" : "ChDir History", ( ch == KEY_PPAGE ) ? HID_GETDIR : HID_CHDIR ); con_cshow(); if (zz != -1) { const char* pc = vfu_hist_get( ( ch == KEY_PPAGE ) ? HID_GETDIR : HID_CHDIR, zz ); if ( pc ) { target = pc; pos = str_len( target ); } } } ch = 0; firsthit = 0; } con_chide(); //------------------------------------------------------------------ str_cut_spc( target ); if ( res == 1 && target[0] == '~' ) { target = tilde_expand( target ); str_fix_path( target ); } /* if ( target.len() > 0 ) { // well this tmp is kind of s... ama k'vo da pravi chovek :) // FIXME: dos version? if ( __ExpandGetDirName && target[0] != '/' #ifdef _TARGET_GO32_ && !( target[1] == ':' && target[2] == '/' ) #endif ) target = CPath + target; StrFixPath( target ); // add trailing slash if not exist } */ /* #ifdef _TARGET_UNIX_ leaveok(stdscr, TRUE); #endif */ if ( res == 1 && str_len( target ) > 0 && should_exist && !dir_exist( target )) { vfu_beep(); int ch = tolower( vfu_ask( "Directory does not exist! Create? " "( ENTER=Yes, ESC=cancel )", "\033\rcC" )); if ( ch == 27 ) { res = 0; target = ""; } else if ( ch == 13 ) if (make_path( target )) { if(tolower( vfu_ask( "Cannot create path! ( ESC=cancel, C=continue-anyway )", "\033Cc" )) == 27) { res = 0; target = ""; } } } say1(" "); say2(" "); if ( str_len( target ) > 0) { str_fix_path( target ); vfu_hist_add( HID_GETDIR, target ); } str_cut_spc( target ); ASSERT( res == 0 || res == 1 ); return res; } /*-----------------------------------------------------------------------*/ void vfu_chdir( const char *a_new_dir ) { char t[MAX_PATH]; VString target; if ( a_new_dir && a_new_dir[0] ) { target = a_new_dir; str_fix_path( target ); } else { target = vfu_hist_get( HID_CHDIR, 0 ); if (!vfu_get_dir_name( "ChDir to? (TAB, PageUp, PageDown, ^X, ^A)", target, 0 )) return; /* get_dir_name canceled */ } /* get_dir_name confirmed */ /* if ( work_path[0] != target[0] && DirTreeChanged && opt.AutoTree ) SaveTree(); */ if ( work_mode == WM_ARCHIVE ) { archive_name = ""; archive_path = ""; } vfu_hist_add( HID_CHDIR, work_path ); char ch = work_path[0]; if (opt.tree_cd) if (!dir_exist( target )) { int z = 0; if ( dir_tree.count() == 0 ) tree_load(); mb.undef(); z = tree_find( target, &mb ); if (z > 1) { z = vfu_menu_box( 10, 5, "Change dir to..." ); if (z > -1) target = mb.get(z); else return; } else if (z == 1) target = mb.get(0); } VString str = target; str_cut_spc( str ); #ifdef _TARGET_GO32_ if ( str[0] == '/' ) { str_ins_ch( str, 0, ':' ); str_ins_ch( str, 0, work_path[0] ); } else if ( str[1] == ':' && str[2] == 0 ) /* c: d: e: */ { expand_path( str, t ); str = t; } if ( str[1] == ':' && str[2] == '/' ) #else /* _TARGET_GO32_ -> i.e. _TARGET_UNIX_ here*/ if (str[0] == '/') #endif /* _TARGET_GO32_ */ { /* root directory */ target = str; } else { str = work_path + str; str_fix_path( str ); target = str_reduce_path( str ); } if (chdir( target ) != 0) { sprintf( t, "chdir: %s", target.data() ); say1( t ); say2errno(); return; } else { work_path = target; if ( work_mode == WM_ARCHIVE ) work_mode = WM_NORMAL; } if ( ch != work_path[0] ) tree_drop(); /* drop tree--it is for another drive*/ vfu_read_files(); } /*-----------------------------------------------------------------------*/ void vfu_chdir_history() { int z = vfu_hist_menu( 5, 5, "ChDir History", HID_CHDIR ); if (z == -1) return; do_draw = 1; //strcpy(opt.LastDir, CPath); vfu_chdir( vfu_hist_get( HID_CHDIR, z ) ); } /*###########################################################################*/ void tree_load() { if( dir_tree.fload( filename_tree ) ) say1( "DirTree load error." ); else { say1( "DirTree loaded ok." ); dir_tree_changed = 0; } } /*-----------------------------------------------------------------------*/ void tree_save() { if( dir_tree.fsave( filename_tree ) ) say1( "DirTree save error." ); else { say1( "DirTree saved ok." ); dir_tree_changed = 0; } } /*-----------------------------------------------------------------------*/ void tree_drop() { if ( dir_tree_changed ) tree_save(); dir_tree.undef(); dir_tree_changed = 0; } /*-----------------------------------------------------------------------*/ void tree_fix() { int z; for( z = dir_tree.count() - 1; z >= 0; z-- ) { VString s1 = dir_tree[z]; VString s2; if (z < dir_tree.count() - 1) s2 = dir_tree[z+1]; else s2 = ""; int i = -1; int n = str_count( s1, "/" ); int p = 0; while(n > 2) { i = str_find( s1, '/', i+1 ); int q = 0; if ( str_len( s2 ) > i ) q = s1[i] != s2[i]; if ( q || ( str_count(s2,"/",i+1) < 2)) { p = 1; str_set_ch(s1, i, '\\'); } n--; } if ( p ) dir_tree.set( z, s1 ); } } /*-----------------------------------------------------------------------*/ fsize_t __tree_rebuild_process( const char* path ) { if ( vfu_break_op() ) return -1; DIR* dir; dirent* de; struct stat st; fsize_t size = 0; char new_name[MAX_PATH]; dir = opendir( path ); if ( !dir ) return 0; while( (de = readdir(dir)) ) { if ( strcmp( de->d_name, "." ) == 0 || strcmp( de->d_name, ".." ) == 0 ) continue; sprintf(new_name, "%s%s", path, de->d_name); lstat(new_name, &st); int is_link = int(S_ISLNK(st.st_mode)); if (is_link) continue; #ifdef _TARGET_GO32_ dosstat(dir, &st); #else stat(new_name, &st); #endif int is_dir = S_ISDIR(st.st_mode); if ( is_dir ) { /* directory */ strcat( new_name, "/" ); int z; int trim = 0; for ( z = 0; z < trim_tree.count(); z++ ) { VString trim_temp = trim_tree[z]; str_fix_path( trim_temp ); if ( pathcmp(trim_temp, new_name) == 0 ) { /* trim_tree item found */ trim = 1; break; } } if (trim) continue; /* cut this branch */ int pos = dir_tree.count(); fsize_t dir_size = __tree_rebuild_process( new_name ); if ( dir_size < 0 ) { /* canceled */ closedir(dir); return -1; } dir_tree.ins( pos, new_name ); size_cache_set( new_name, dir_size ); size += dir_size; } else { /* file */ size += file_st_size( &st ); } } closedir(dir); /* show some progress :) */ say2( str_dot_reduce( path, con_max_x()-1 ) ); return size; } void tree_rebuild() { #ifdef _TARGET_GO32_ // we do need only files sizes -- so the other stuff under dos is unneeded :) _djstat_flags = _STAT_INODE | _STAT_EXEC_EXT | _STAT_EXEC_MAGIC | _STAT_EXEC_MAGIC | _STAT_DIRSIZE | _STAT_ROOT_TIME | _STAT_WRITEBIT; // _djstat_flags = 0; #endif dir_tree.undef(); size_cache.undef(); say1( "Rebuilding tree..." ); __tree_rebuild_process( "/" ); tree_fix(); #ifdef _TARGET_GO32_ _djstat_flags = 0; #endif dir_tree_changed = 1; tree_save(); } /*-----------------------------------------------------------------------*/ void tree_draw_item( int page, int index, int hilite ) { if ( page + index >= dir_tree.count() ) return; VString s1 = dir_tree[page+index]; str_trim_right(s1,1); VString s2 = s1; int j = str_rfind( s1,'/'); str_trim_right(s1,str_len(s2)-j-1); str_trim_left(s2,j+1); for(j = 0; j < str_len(s1); j++) { if (s1[j] == '/') str_set_ch(s1,j, '|'); else if (s1[j] == '\\') str_set_ch(s1,j, '\\'); else str_set_ch(s1,j, '+'); } if (opt.tree_compact) { str_replace(s1,"+", ""); str_replace(s1,"|", "| "); str_replace(s1,"\\"," "); str_trim_right(s1,2); s1 += "--"; } else { str_replace(s1,"+", " "); str_replace(s1,"\\", " "); s1 += "--"; } VString str = dir_tree[page+index]; str_tr( str,"\\", "/" ); VString sz; sz.fi( size_cache_get( str ) ); if ( sz == "-1" ) sz = "n/a"; else str_comma( sz ); str_pad( sz, 14 ); s1 = sz + " " + s1; int m = con_max_x() - 1; /* doesn't speed the code... :) */ if ( str_len( s1 ) > m ) { str_sleft( s1, m ); s2 = ""; } else if ( str_len( s1 ) + str_len( s2 ) > m ) { str_sleft( s2, m - str_len( s1 ) ); } con_xy(1,3+1+index); if (hilite) { con_puts( s1, cBAR ); con_puts( s2, cBAR ); con_ce( cBAR ); } else { con_puts( s1, cSTATUS ); con_puts( s2, cMESSAGE ); con_ce( cSTATUS ); } } /*-----------------------------------------------------------------------*/ void tree_draw_page( ScrollPos &scroll ) { VString str = " "; str_mul( str, con_max_x() ); str = " SiZE DiRECTORY" + str; str_sleft( str, con_max_x()-16 ); con_out(1,3, str, cHEADER ); int z = 0; for(z = 0; z < scroll.pagesize(); z++) { if (scroll.page() + z <= scroll.max()) { tree_draw_item( scroll.page(), z ); } else { con_xy( 1, 3+1+z ); con_puts( "~", cCYAN ); con_ce( cCYAN ); } } } /*-----------------------------------------------------------------------*/ void tree_draw_pos( ScrollPos &scroll, int opos ) { int z = scroll.pos() - scroll.page(); if ( opos != -1 ) tree_draw_item( scroll.page(), opos ); tree_draw_item( scroll.page(), z, 1 ); VString str; str = dir_tree[scroll.pos()]; str_tr( str,"\\", "/" ); VString sz; sz.fi( size_cache_get( str ) ); str_comma( sz ); str_pad( sz, 14 ); str = sz + " " + str; str = str_dot_reduce( str, con_max_x()-1 ); say1( str, cINFO ); say2( " Help: R Rebuild, S Incremental search, Z Recalc directory size", cINFO ); show_pos( scroll.pos()+1, scroll.max()+1 ); } /*-----------------------------------------------------------------------*/ void tree_view() { VString str; if (dir_tree.count() == 0) { tree_load(); if (dir_tree.count() == 0) tree_rebuild(); } say1( " " ); int new_pos = tree_index( work_path ); if ( new_pos == -1 ) new_pos = 0; BSet set; /* used for searching */ set.set_range1( 'a', 'z' ); set.set_range1( 'A', 'Z' ); set.set_range1( '0', '9' ); set.set_str1( "._-~" ); set.set_str1( "?*>[]" ); ScrollPos scroll; scroll.set_min_max( 0, dir_tree.count()-1 ); scroll.set_pagesize( PS+2 ); scroll.go( new_pos ); int key = 0; int opos = -1; int opage = -1; while( key != 27 && key != 13 && key != '-' && toupper( key ) != 'Q' && toupper( key ) != 'X' && key != KEY_ALT_X ) { if ( key >= 'A' && key <= 'Z' ) key = tolower( key ); if ( key == 's' ) { str = ""; say1( "Enter search pattern: ( use TAB to advance )" ); key = con_getch(); while( set.in( key ) || key == 8 || key == KEY_BACKSPACE || key == 9 ) { if ( key == 8 || key == KEY_BACKSPACE ) str_trim_right( str, 1 ); else if ( key != 9 ) str_add_ch( str, key ); say2( str ); if ( dir_tree.count() == 0 ) { key = con_getch(); continue; } int z; if ( key == 9 ) { z = scroll.pos() + 1; if (z > scroll.max() ) z = scroll.min(); } else z = scroll.pos(); int direction = 1; int found = 0; int loops = 0; VString s_mask = str; vfu_expand_mask( s_mask ); while(1) { if ( z > scroll.max() ) z = scroll.min(); if ( z < scroll.min() ) z = scroll.max(); VString str1 = dir_tree[z]; str_trim_right( str1, 1 ); int j = str_rfind(str1,'/'); if (j < 0) str1 = ""; else str_trim_left( str1, j+1 ); found = ( FNMATCH( s_mask, str1 ) == 0 ); if ( found ) break; z += direction; if ( loops++ > dir_tree.count() ) break; } if (found) { scroll.go(z); tree_draw_page( scroll ); tree_draw_pos( scroll, opos ); } key = con_getch(); } say1( "" ); say2( "" ); } else switch( key ) { case KEY_UP : scroll.up(); break; case KEY_DOWN : scroll.down(); break; case KEY_PPAGE : scroll.ppage(); break; case KEY_NPAGE : scroll.npage(); break; case KEY_HOME : scroll.home(); break; case KEY_END : scroll.end(); break; case 'r' : tree_rebuild(); scroll.set_min_max( 0, dir_tree.count()-1 ); scroll.home(); say1( "Rebuild done." ); break; case 'w' : tree_save(); break; case 'l' : tree_load(); scroll.set_min_max( 0, dir_tree.count()-1 ); scroll.home(); break; case 'z' : case KEY_CTRL_Z : str = dir_tree[scroll.pos()]; str_tr( str, "\\", "/" ); size_cache_set( str, vfu_dir_size( str ) ); tree_draw_page( scroll ); tree_draw_pos( scroll, opos ); say1( "Done." ); break; } if (opage != scroll.page()) tree_draw_page( scroll ); if (opos != scroll.pos() - scroll.page() || opage != scroll.page()) tree_draw_pos( scroll, opos ); opos = scroll.pos() - scroll.page(); opage = scroll.page(); key = con_getch(); } if ( key == 13 ) { str = dir_tree[scroll.pos()]; str_tr( str, "\\", "/" ); vfu_chdir( str ); } do_draw = 2; } /*###########################################################################*/ #define SIZE_CACHE_OFFSET 12 #define SIZE_CACHE_OFFSET_CLEAN (12+8+1) int size_cache_cmp( const char* s1, const char* s2 ) { return strcmp( s1 + SIZE_CACHE_OFFSET, s2 + SIZE_CACHE_OFFSET ); } VString size_cache_compose_key( const char *s, fsize_t size ) { const char *ps; char ss[MAX_PATH]; expand_path( s, ss ); ps = ss; char s_adler[16]; char s_size[32]; sprintf( s_size, "%012.0f", size ); //WARNING: THIS IS SIZE_CACHE_OFFSET sprintf( s_adler, "%08X", (unsigned int)str_adler32( ps ) ); VString str; str = str + s_size + "|" + s_adler + "|" + ps; return str; } int size_cache_index( const char *s ) { if ( size_cache.count() == 0 ) return -1; VString str = size_cache_compose_key( s, 0 ); int l = 0; int h = size_cache.count() - 1; int m = h; while(4) { int r = size_cache_cmp( size_cache[m], str ); if ( l == m && r != 0 ) return -1; if ( r > 0 ) h = m; else if ( r < 0 ) l = m; else return m; m = ( l + h ) / 2; } } fsize_t size_cache_get( const char *s ) { int z = size_cache_index( s ); if ( z != -1 ) { VString str = size_cache[z]; str_sleft( str, SIZE_CACHE_OFFSET ); return atof( str ); } else return -1; } void size_cache_set( const char *s, fsize_t size, int sort ) { int z = size_cache_index( s ); if ( z != -1 ) { size_cache.set( z, size_cache_compose_key( s, size ) ); } else { size_cache.push( size_cache_compose_key( s, size ) ); if( sort ) size_cache.sort( 0, size_cache_cmp ); } } // this function is used to add quickly entries to the cache // it REQUIRES that size_cache_sort() is called after it! void size_cache_append( const char *s, fsize_t size ) { size_cache.push( size_cache_compose_key( s, size ) ); } void size_cache_clean( const char *s ) { VString str = size_cache_compose_key( s, 0 ); str_trim_left( str, SIZE_CACHE_OFFSET_CLEAN ); int sl = str_len( str ); int z = 0; while( z < size_cache.count() ) { const char* ps = size_cache[z].data() + SIZE_CACHE_OFFSET_CLEAN; if ( ( strncmp( ps, str, sl ) == 0 && (ps[sl] == '/' || ps[sl] == 0) ) || ( size_cache[z][SIZE_CACHE_OFFSET_CLEAN] != '|' ) ) size_cache.del( z ); else z++; } } void size_cache_sort() { size_cache.sort( 0, size_cache_cmp ); } /*###########################################################################*/ /* return index in the dir_tree of directory named `s' or -1 if not found */ int __tree_index_last_cache = 0; /* cache-like -- keeps the last found index */ int tree_index( const char *s ) { int z = 0; int i = 0; int sl1; int sl2; if ( dir_tree.count() == 0 ) return -1; const char *s1 = s #ifdef _TARGET_GO32_ + 2; // to cut `d:' chars len #endif ; sl1 = strlen( s1 ); z = __tree_index_last_cache + 1; while(4) { if ( z >= dir_tree.count() ) z = 0; if ( z == __tree_index_last_cache ) break; const char *s2 = dir_tree[z]; sl2 = strlen( s2 ); if ( sl1 == sl2 ) { i = sl1; // or sl2 ... while ( i >= 0 && (s1[i] == s2[i] || (s1[i] == '/' && s2[i] == '\\')) ) i--; if ( i < 0 ) { __tree_index_last_cache = z; return z; } } ASSERT( z < dir_tree.count() ); ASSERT( z >= 0 ); z++; } return -1; } /*-----------------------------------------------------------------------*/ const char* tree_find( const char *s ) // return full path by dirname { VString str; int z = 0; int sl = strlen( s ); for ( z = 0; z < dir_tree.count(); z++ ) { str = dir_tree[z]; if ( str_len( str ) < sl ) continue; str_sright( str, sl ); if (pathcmp( (const char*)str, s ) == 0) { return dir_tree[z]; } } return NULL; } /*-----------------------------------------------------------------------*/ /* return count of found dirnames and stores them to va */ int tree_find( const char *s, VArray *va ) { VString str; int z = 0; int sl = strlen( s ); for ( z = 0; z < dir_tree.count(); z++ ) { str = dir_tree[z]; if ( str_len( str ) < sl ) continue; str_sright( str, sl ); if (pathcmp( str, s ) == 0) { str = dir_tree[z]; str_tr( str, "\\", "/" ); va->push( str ); } } return va->count(); } /*###########################################################################*/ fsize_t __dir_size_process( const char* path ) { if ( vfu_break_op() ) return -1; DIR* dir; dirent* de; struct stat st; fsize_t size = 0; char new_name[MAX_PATH]; dir = opendir( path ); if ( !dir ) return 0; while( (de = readdir(dir)) ) { if ( strcmp( de->d_name, "." ) == 0 || strcmp( de->d_name, ".." ) == 0 ) continue; sprintf(new_name, "%s%s", path, de->d_name); lstat(new_name, &st); int is_link = int(S_ISLNK(st.st_mode)); memset( &st, 0, sizeof(st) ); #ifdef _TARGET_GO32_ dosstat(dir, &st); #else stat(new_name, &st); #endif int is_dir = int(S_ISDIR(st.st_mode)); if ( is_link ) continue; /* skip links */ if ( is_dir ) { strcat( new_name, "/" ); fsize_t dir_size = __dir_size_process( new_name ); if ( dir_size == -1 ) { closedir(dir); return -1; } else { size += dir_size; size_cache_append( new_name, dir_size ); } } else size += file_st_size( &st ); } closedir(dir); /* show some progress :) */ say2( str_dot_reduce( path, con_max_x()-1 ) ); return size; } fsize_t vfu_dir_size( const char *s, int sort ) { char t[MAX_PATH]; expand_path( s, t ); size_cache_clean( t ); str_fix_path( t ); size_cache_clean( t ); fsize_t size = __dir_size_process( t ); size_cache_set( t, size, sort ); return size; } /*###########################################################################*/ /* eof vfudir.cpp */ vfu-4.10/vfu/see.h0000644000175000001440000001311611310547555012606 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: see.h,v 1.18 2006/08/05 20:15:13 cade Exp $ * */ #ifndef _SEE_H_ #define _SEE_H_ #include #define SEE_VERSION "4.10" #define MAX_SEARCH_LEN 128 #define MAX_PIPE_LEN 128 #define MAX_ESCAPE_KEYS 64 #define BUFF_SIZE (16*1024) struct SeeViewerOptions { SeeViewerOptions() { reset(); } void reset() { auto_size = 1; xmin = xmax = ymin = ymax = -1; /* auto */ cn = CONCOLOR( cWHITE, cBLACK ); ch = CONCOLOR( cWHITE, cBLUE ); cs = CONCOLOR( cBLACK, cWHITE ); status = 1; bsize = BUFF_SIZE; tabsize = 8; wrap = bsize; handle_bs = 1; handle_tab = 1; hex_mode = 0; dec_pos = 0; grid = 0; show_eol = 0; last_search[0] = 0; last_opt[0] = 0; hex_cols = 2; } int auto_size; int xmin, xmax, ymin, ymax; int cn; /* color normal */ int ch; /* color hilite */ int cs; /* color status line */ int status; /* show status line */ int bsize; /* block size (i.e. the longest line ) */ int tabsize; /* tab size usually 8 */ int wrap; /* word wrap */ int handle_bs; /* backspaces */ int handle_tab; /* tabs */ int hex_mode; /* in hex mode */ int dec_pos; /* show decimal positions in hex mode */ int grid; /* show hilite grid */ int show_eol; /* show end of lines with $ */ int hex_cols; /* 8-bytes columns to show in hex mode */ char last_search[MAX_SEARCH_LEN+1]; char last_opt[32]; }; #define FMT_OFF_T "l" #ifdef _FILE_OFFSET_BITS # if _FILE_OFFSET_BITS == 64 # undef FMT_OFF_T # define FMT_OFF_T "ll" # elif _FILE_OFFSET_BITS > 64 # error "cannot represent _FILE_OFFSET_BITS >64" # endif #endif class SeeViewer { SeeViewerOptions* opt; int escape_keys[MAX_ESCAPE_KEYS]; VString help_str; VRegexp re; FILE* f; VString fname; off_t fpos; off_t fsize; off_t line; off_t last_line; int end_reached; int col; int rows; int cols; int xlat; int freezed; int do_draw; char* buff; public: SeeViewer( SeeViewerOptions *a_opt ); ~SeeViewer(); /* add escape key which will cause run() exit */ void escape_on( int key ); /* set help message */ void set_help_string( const char* s ) { if ( s ) help_str = s; }; int open( const char* a_fname ); void close(); void status( const char* format, ... ); void filter( char *s, int size ); void filter( VString &s, int size ); void draw_hex(); void draw_txt(); void draw(); void up_txt(); void up_hex(); void down_txt(); void down_hex(); void up() { opt->hex_mode ? up_hex() : up_txt(); } void down() { opt->hex_mode ? down_hex() : down_txt(); } void home(); void end_hex(); void end_txt(); void end() { opt->hex_mode ? end_hex() : end_txt(); } void end2(); void go_to(); int find_next_txt( int rev = 0 ); int find_next_hex( int rev = 0 ); int find_next( int rev = 0 ) { opt->hex_mode ? find_next_hex(rev) : find_next_txt(rev); return 0; } int find( const char* opts ); void hex_edit(); void help(); int run(); double fpos_percent() const { return 100 * (double(fpos) / (fsize?fsize:1)); } protected: int read_text( off_t &cpos ); }; /**********************************************************************/ struct SeeEditorOptions { SeeEditorOptions() { reset(); } void reset() { auto_size = 1; xmin = xmax = ymin = ymax = -1; /* auto */ cn = CONCOLOR( cWHITE, cBLACK ); ch = CONCOLOR( cWHITE, cBLUE ); cs = CONCOLOR( cBLACK, cWHITE ); status = 1; tabsize = 8; max_line = 4096; handle_tab = 1; auto_indent = 0; insert = 1; last_search[0] = 0; no_case = 1; last_pipe_cmd[0] = 0; } int auto_size; int xmin, xmax, ymin, ymax; int cn; /* color normal */ int ch; /* color hilite */ int cs; /* color status line */ int status; /* show status line */ int tabsize; /* tab size usually 8 */ int max_line; /* word wrap */ int handle_tab; /* tabs */ int auto_indent; int insert; /* if editor is in `insert' mode */ char last_search[MAX_SEARCH_LEN+1]; int no_case; char last_pipe_cmd[MAX_PIPE_LEN]; }; class SeeEditor { SeeEditorOptions* opt; int escape_keys[MAX_ESCAPE_KEYS]; VString help_str; VString fname; VRegexp re; int col; int colpage; ScrollPos sv; /* vertical scroller */ VArray va; /* string/text cluster */ int mod; /* modify flag */ int rows; int cols; int freezed; int do_draw; public: SeeEditor( SeeEditorOptions *a_opt ); ~SeeEditor(); /* add escape key which will cause run() exit */ void escape_on( int key ); /* set help message */ void set_help_string( const char* s ) { if ( s ) help_str = s; }; int open( const char* a_fname ); void close(); void status( const char* format, ... ); int expand_tabs( VString &str, VString &map ); int real_col( int row = -1 ); void set_cursor(); void draw_line( int n ); void draw( int from = 0 ); int save(); int request_quit(); void up() { sv.up(); }; void down() { sv.down(); }; void left(); void right(); void home(); void end(); void go_to(); void kdel(); void kbs(); void kenter(); void kinsert( int ch ); void insert_file( const char* fn ); void remove_line( int n = -1 ); void remove_all(); void remove_trails( int n = -1 ); /* remove trailing spaces/tabs */ void insert_pipe_cmd(); int find_next(); int find( int no_case ); void help(); int run(); }; #endif /* _SEE_H_ */ vfu-4.10/vfu/vfu.h0000644000175000001440000002227011005727265012632 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vfu.h,v 1.18 2006/09/01 21:34:26 cade Exp $ * */ #ifndef _VFU_H_ #define _VFU_H_ /*############################################ INCLUDE's ###############*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(_TARGET_NETBSD_) || (defined(BSD) && BSD >= 199306) //FIXME: is the one above correct? should _TARGET_BSD_ be used? #include #else #include #endif #include "vfusetup.h" #include "vfusys.h" // for attrs_t /*############################################ COMPATIBILITY DEF's #####*/ #ifdef _TARGET_GO32_ #define S_ISLNK( p ) 0 #define S_ISSOCK( p ) 0 #define lstat(n,p) memset(p,0,sizeof(p)) #define cuserid(x) 0 #define FNMATCH_FLAGS FNM_CASEFOLD #define FNCASE 0 #define PATH_DELIMITER ";" #endif #ifdef _TARGET_UNIX_ #define FNMATCH_FLAGS 0 #define FNCASE 1 #define PATH_DELIMITER ":" #endif #define FNMATCH(p,s) fnmatch((p),(s),FNMATCH_FLAGS) #define FNMATCH_NC(p,s) fnmatch((p),(s),FNM_CASEFOLD) #define FNMATCH_OC(p,s,n) fnmatch((p),(s),(n)?FNM_CASEFOLD:FNMATCH_FLAGS) #ifdef _TARGET_GO32_ #define pathcmp strcasecmp #define pathncmp strncasecmp #else #define pathcmp strcmp #define pathncmp strncmp #endif typedef double fsize_t; /* used as big integer */ typedef char max_path_str_t[MAX_PATH]; /* */ /*############################################ GLOBAL DEFINES #########*/ /* history id's */ #define HID_GREP 10 #define HID_GS_MASK 20 #define HID_GS_GREP 30 #define HID_MKPATH 40 #define HID_FFMASK 50 #define HID_FFPATH 60 #define HID_FFGREP 70 #define HID_EE_TIME 80 // entry edit #define HID_EE_OWNER 90 // entry edit #define HID_SHELL_PAR 100 #define HID_FMASK 110 #define HID_COMMANDS 120 #define HID_GETDIR 130 #define HID_CHDIR 140 #define HID_SEQ_PREFIX 150 #define HID_SEQ_SUFFIX 160 #define HID_SEQ_DIGPOS 170 #define HID_SEQ_START 180 #define HID_OMODE 190 // octal mode #define VFU_CHECK_LIST_POS(n) \ { ASSERT( files_list[n] != NULL ); \ ASSERT( n >= 0 && n < files_count ); } /*######################################################################*/ /* file class type */ class TF { char* _name; /* name with extension ( ref. _fname ) */ char* _name_ext; /* extension ( ref. _fname ) */ char* _ext; /* extension ( ref. _fname ) */ struct stat _st; char _type_str[3]; int _is_link; int _is_dir; mode_str_t _mode_str; fsize_t _size; char* _view; /* up to screen width */ int _color; /* view colors */ /* !!! this is used when full name required */ /* and this is not thread-safe :) */ static char _full_name[MAX_PATH]; void reset(); /* reset -- NULL all fields */ void refresh_view(); /* this is called by view() only! */ public: TF(); TF( const char* a_name, const struct stat* a_stat, int a_is_link ); ~TF(); const char* full_name( int fix = 0 ); const char* name() { ASSERT(_name); return (const char*)_name; } const char* name_ext() { ASSERT(_name_ext); return (const char*)_name_ext; } const char* ext() { ASSERT(_ext); return (const char*)_ext; } void set_name( const char* a_new_name ); const char* view(); void drop_view(); void update_stat( const struct stat* a_new_stat = NULL, int a_is_link = -1 ); const char* type_str() { return (const char*)_type_str; } const char* mode_str() { return (const char*)_mode_str; } const struct stat* st() { return (const struct stat*)&_st; } void set_size( fsize_t a_new_size ); fsize_t size() { if ( _is_dir && _size == -1 ) return 0; else return _size; } int is_link() { return _is_link; } int is_dir() { return _is_dir; } int color() { return _color; } /* public member variables */ int sel; /* this saves set/get_sel() functions :) */ int x; /* misc used extra field */ }; /*######################################################################*/ #define WM_NORMAL 0 #define WM_ARCHIVE 1 /* work context */ extern int work_mode; extern VString work_path; /* archive context */ extern VString archive_name; extern VString archive_path; extern VArray archive_extensions; extern VString external_panelizer; extern VArray list_panelizer; extern TF* files_list[MAX_FILES]; /* file list statistics */ extern int files_count; extern fsize_t files_size; extern int sel_count; extern fsize_t sel_size; /* file system statistics */ extern fsize_t fs_free; extern fsize_t fs_total; extern fsize_t fs_block_size; /* index in the files list */ /* NOTE: following defines are kept for historical reasons :) */ extern ScrollPos file_list_index; #define FLI (file_list_index.pos()) #define FLP (file_list_index.page()) #define PS (file_list_index.pagesize()) #define FGO(n) (file_list_index.go(n)) /* some world wide variables */ extern VString startup_path; extern VString home_path; extern VString tmp_path; extern VString rc_path; /* files masks */ extern VString files_mask; extern VArray files_mask_array; /* misc */ extern int print_help_on_exit; /*############################################ GLOBAL STRUCTS #########*/ extern VArray dir_tree; extern int dir_tree_changed; extern VArray file_find_results; // filefind results extern VArray path_bookmarks; /*######################################################################*/ extern VArray user_externals; extern VArray history; extern VArray see_filters; extern VArray panelizers; extern VArray mb; /* menu boxes */ extern VArray trim_tree; extern VArray view_profiles; extern VString view_profile; /*############################################ CONFIG SETTINGS #########*/ extern VString ext_colors[16]; extern VString shell_browser; extern VString shell_editor; extern VString shell_diff; extern VString shell_prog; extern VString user_id_str; extern VString group_id_str; extern VString host_name_str; extern VString filename_opt; extern VString filename_conf; extern VString filename_history; extern VString filename_tree; extern VString filename_size_cache; extern VString filename_ffr; /* file find results */ /*######################################################################*/ extern int do_draw; extern int do_draw_status; /*######################################################################*/ /* Message issues */ void say( int line, int attr, const char* format, ... ); void say1(const char *a_str, int attr = cMESSAGE ); void say2(const char *a_str, int attr = cMESSAGE ); void say2errno(); void saycenter( int line, int attr, const char *a_str ); void say1center(const char *a_str, int attr = cMESSAGE ); void say2center(const char *a_str, int attr = cMESSAGE ); /* Main things */ void vfu_help(); void vfu_help_cli(); void vfu_init(); void vfu_run(); void vfu_cli(); void vfu_done(); void vfu_reset_screen(); void vfu_signal( int sig ); void vfu_exit_path( const char *a_path ); int vfu_exit( const char* a_path ); void vfu_options(); void vfu_toggle_view_fields( int ch ); /* Support op's */ void vfu_shell( const char* a_command, const char* a_options ); void vfu_tools(); void vfu_command(); void vfu_file_find( int menu ); void vfu_file_find_results(); void vfu_directories_sizes( int a_which_one ); void vfu_change_file_mask( const char* a_new_mask ); void bookmark_goto( int a_n ); void bookmark_set( int a_n, const char* a_path ); const char* bookmark_get( int a_n ); void bookmark_hookup(); void update_status(); int vfu_user_external_find( int key, const char* ext, const char* type, VString *shell_line ); void vfu_user_external_exec( int a_key ); void vfu_user_menu(); void vfu_inc_search(); void vfu_goto_filename( const char* fname ); /* Main files op's */ int vfu_edit_attr( char *attrs ); void vfu_edit_entry( ); void vfu_rename_file_in_place(); void vfu_browse( const char* a_fname, int no_filters = 0 ); void vfu_browse_selected_files(); void vfu_edit( const char* a_fname ); void vfu_action_plus( int ); void vfu_action_minus(); void vfu_global_select(); void vfu_sort_menu(); void vfu_read_files_menu(); void vfu_clipboard( int act ); void vfu_jump_to_mountpoint( int all ); #endif//_VFU_H_ vfu-4.10/vfu/see.cpp0000644000175000001440000013520311310547651013140 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: see.cpp,v 1.32 2006/08/05 20:15:13 cade Exp $ * */ #include #include #include "see.h" #ifndef ASSERT #define ASSERT assert #endif #define CHKPOS ASSERT( fpos >= 0 ); ASSERT( fpos <= fsize ) char HEXCHARS[] = "0123456789ABCDEF"; char bg_xlat_table[2][64] = { " ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º¼¾¿€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—?™šœžŸ", "abwgdevzijklmnoprstufhc`[]yxuqABWGDEVZIJKLMNOPRSTUFHC`[]YXUQ" }; char bgw_xlat_table[2][64] = { "àáâãäåæçèéêëìíîïðñòóôõö÷øùúüþÿÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÜÞß", "abwgdevzijklmnoprstufhc`[]yxuqABWGDEVZIJKLMNOPRSTUFHC`[]YXUQ" }; #define MAXCOLS 1024 /*--------------------------------------------------------------------*/ SeeViewer::SeeViewer( SeeViewerOptions *a_opt ) { opt = a_opt; memset( &escape_keys, 0, sizeof(escape_keys)); f = NULL; line = last_line = 1; col = 0; end_reached = 0; fpos = fsize = 0; fname = ""; freezed = 0; do_draw = 0; if ( opt->auto_size ) { opt->xmin = 1; opt->ymin = 1; opt->xmax = con_max_x(); opt->ymax = con_max_y(); } rows = opt->ymax - opt->ymin - (opt->status != 0) + 1; cols = opt->xmax - opt->xmin + 1; //FIXME: fix bsize! +32? buff = new char[opt->bsize + 32]; /* +32 for tab expansion */ help_str = "+-----------------------------------------------------------------------------+\n" "| SeeViewer v" SEE_VERSION " (c) Vladi Belperchinov-Shabanski |\n" "| |\n" "| Key TextMode HexMode Compatibility |\n" "| --------+--------------------+--------------------+------------------------ |\n" "| UpArrow | one line back | 16 bytes back | P = Home |\n" "| DnArrow | one line forward | 16 bytes forward | B = PgUp |\n" "| LtArrow | col -8 ( `.' `>' ) | 1 byte back | SPC = PgDn |\n" "| RtArrow | col +8 ( `,' `<' ) | 1 byte forward | ENTER = DnArrow |\n" "| Home | go to line 1 | go to byte 0 | |\n" "| End | go to last line | go to last byte | |\n" "| Ctrl+E | -'- (no line info) | go to last byte | l -- BG DOS xlate (slow)|\n" "| PgUp/Dn | one page back/forw | one page back/forw | L -- BG WIN xlate (slow)|\n" "| --------+--------------------+--------------------+------------------------ |\n" "| TAB -- switch between Text and Hex mode | ESC -- exit |\n" "| 1..0 -- switch to slot 1 .. slot 10 | Alt+X -- exit |\n" "| W w -- text wrap (TEXT) or wide screen (HEX) | - -- exit |\n" "| + -- goto line/pos (+line/pos, -line/pos) | d -- show dec.pos (HEX) |\n" "| I -- binary edit (HEX) | o -- show EOL's (TEXT) |\n" "| F S -- find string (F=no case, S=case sense) | r -- show ruler (TEXT) |\n" "| \\ / -- regexp search (\\=no case, /=case sense) | a -- filter backspaces |\n" "| E -- hex pattern search | t -- tab expansion |\n" "| N F3 -- find next, M -- find next backwards | g G -- grid (HEX) |\n" "+-----------------------------------------------------------------------------+"; } /*--------------------------------------------------------------------*/ SeeViewer::~SeeViewer() { close(); if ( buff ) delete buff; buff = NULL; } /*--------------------------------------------------------------------*/ /* add escape key which will cause run() exit */ void SeeViewer::escape_on( int key ) { int z = 0; while( z < MAX_ESCAPE_KEYS-1 ) { if (!escape_keys[z]) { escape_keys[z] = key; return; } z++; } } /*--------------------------------------------------------------------*/ int SeeViewer::open( const char* a_fname ) { if (!buff) return 1; if (f) fclose( f ); xlat = 0; f = NULL; line = 0; col = 0; last_line = 0; end_reached = 0; fpos = fsize = 0; fname = a_fname; freezed = 0; do_draw = 0; f = fopen( fname, "r" ); if (!f) return 2; fsize = file_size( f ); return 0; } /*--------------------------------------------------------------------*/ void SeeViewer::close() { if ( f ) fclose( f ); f = NULL; } /*--------------------------------------------------------------------*/ void SeeViewer::status( const char* format, ... ) { char buf[1024]; va_list vlist; va_start( vlist, format ); vsnprintf( buf, 1024, format, vlist ); va_end( vlist ); VString str; str = "| "; str += buf; if (str_len(str) >= cols) str_sleft( str, (cols-2) ); else str_pad( str, -(cols-2) ); str += "|"; con_out( opt->xmin, opt->ymax, str, opt->cs ); } /*--------------------------------------------------------------------*/ //FIXME: 2 versions not needed void SeeViewer::filter( char *s, int size ) { int z; for ( z = 0; z < size; z++ ) if ( (unsigned char)s[z] < 32 ) s[z] = '.'; if (xlat == 1) str_tr( s, bg_xlat_table[0], bg_xlat_table[1] ); else if (xlat == 2) str_tr( s, bgw_xlat_table[0], bgw_xlat_table[1] ); } void SeeViewer::filter( VString &s, int size ) { int z; for ( z = 0; z < size; z++ ) if ( (unsigned char)s[z] < 32 ) s[z] = '.'; if (xlat == 1) str_tr( s, bg_xlat_table[0], bg_xlat_table[1] ); else if (xlat == 2) str_tr( s, bgw_xlat_table[0], bgw_xlat_table[1] ); } /*--------------------------------------------------------------------*/ void SeeViewer::draw_hex() { CHKPOS; int rowsz; // row size int needw; // needed screen width con_max_x(); while(4) { rowsz = opt->hex_cols * 8; // row size needw = 10 + 2 + // offset rowsz * 3 + rowsz / 8 + 2 + // hexdump rowsz; // ascii if ( opt->hex_cols == 1 ) break; if ( needw > con_max_x() ) opt->hex_cols = 1; else break; } if ( needw > con_max_x() ) { status( "HEX mode not available for this screen width" ); return; } fseeko( f, fpos, SEEK_SET ); int rs = fread( buff, 1, rowsz * rows, f ); int x; int y; VString offset; VString hexdump; VString ascii; char t[256]; for( y = 0; y < rows; y++ ) { sprintf( t, opt->dec_pos ? "%10"FMT_OFF_T"d":"%010"FMT_OFF_T"X", fpos + rowsz * y ); offset = t; ascii = ""; hexdump = ""; for( x = 0; x < rowsz; x++ ) { if ( y * rowsz + x >= rs ) { break; } else { int c = (unsigned char)buff[y * rowsz + x]; sprintf( t, "%02X ", c ); hexdump += t; str_add_ch( ascii, c < 32 ? '.' : c ); if ( (x + 1) % 8 == 0 && x > 0 && x < rowsz - 1 ) hexdump += "- "; } } if ( hexdump == "" ) hexdump = "~"; filter( ascii, str_len(ascii) ); str_pad( hexdump, -( rowsz * 3 + (opt->hex_cols - 1) * 2 ) ); str_pad( ascii, -rowsz ); VString line = offset + "| " + hexdump + "|" + ascii; if ( hexdump[0] == '~' ) line = "~"; str_pad( line, -cols ); con_out( 1, y+1, line, (opt->grid && y % 2 == 0) ? opt->ch : opt->cn ); } status( "%3.0f%% | Pos. %4"FMT_OFF_T"d of %4"FMT_OFF_T"d | Alt+H Help | %s", fpos_percent(), fpos, fsize, fname.data() ); } /*--------------------------------------------------------------------*/ void SeeViewer::draw_txt() { CHKPOS; if ( line == -1 ) last_line = -1; off_t cpos = fpos; int z = 0; int y = 0; VString str; if( ftello(f) != cpos ) fseeko( f, cpos, SEEK_SET ); // FIXME: ? for( y = 0; y < rows; y++ ) { if ( cpos >= fsize ) { str = "~"; str_pad( str, -cols ); con_out( 1, y+1, str, (opt->grid && y%2==0) ? opt->ch : opt->cn ); continue; } z = read_text( cpos ); while ( z > 0 && ( buff[z-1] == '\r' || buff[z-1] == '\n' ) ) z--; buff[z] = 0; filter( buff, z ); int show_lmark = 0; int show_rmark = 0; int show_eol = -1; if ( col > 0 ) { if (col >= z) { buff[0] = 0; show_lmark = 1; z = 0; } else { str_trim_left( buff, col ); z -= col; } } if ( z > cols ) { buff[cols] = 0; show_rmark = 1; } else { if ( opt->show_eol && !show_lmark ) show_eol = z+1; } str_pad( buff, -cols ); con_out( 1, opt->ymin+y, buff, (opt->grid && y%2==0) ? opt->ch : opt->cn); if ( re.ok() && re.m( buff ) ) con_out( re.sub_sp(0)+1, opt->ymin+y, re.sub(0), CONCOLOR( cBLACK, cWHITE ) ); if (show_lmark) con_out(1,opt->ymin+y,"<",chRED); if (show_rmark) con_out( opt->xmax, opt->ymin+y, ">", chRED ); if (show_eol != -1) con_out( show_eol, opt->ymin+y, "$", chGREEN ); } status( "%3.0f%% | Pos. %4"FMT_OFF_T"d | Line %4"FMT_OFF_T"d of %4"FMT_OFF_T"d%c|%4d+ | Alt+H Help | %s", fpos_percent(), fpos, line, last_line, end_reached?' ':'?', col+1, fname.data() ); } /*--------------------------------------------------------------------*/ void SeeViewer::draw() { (opt->hex_mode) ? draw_hex() : draw_txt(); if ( xlat == 1 ) con_out( opt->xmax - 7, opt->ymin, "BG XLAT", chRED ); if ( xlat == 2 ) con_out( opt->xmax - 10, opt->ymin, "BGWIN XLAT", chRED ); } /*--------------------------------------------------------------------*/ void SeeViewer::up_hex() { CHKPOS; fpos -= opt->hex_cols * 8; if ( fpos < 0 ) fpos = 0; line = -1; // hex moving invalidates text line position } void SeeViewer::up_txt() { CHKPOS; off_t cpos = fpos; if ( cpos == 0 ) return; int i = opt->wrap; if ( cpos - i < 0 ) i = cpos; cpos -= i; fseeko( f, cpos, SEEK_SET ); int res = fread( buff, 1, i, f ); ASSERT( res == i ); if ( buff[i-1] == '\n' ) i--; while( i > 0 && buff[i-1] != '\n' ) i--; if ( i > 0 ) { memmove( buff, buff + i, res - i ); // make buffer contain only last line buff[res - i] = 0; } fpos -= res - i; if ( fpos < 0 ) fpos = 0; if ( fpos == 0 ) line = 1; if ( line > 1 ) line--; } /*--------------------------------------------------------------------*/ void SeeViewer::down_hex() { CHKPOS; fpos += opt->hex_cols * 8; if ( fpos > fsize ) fpos = fsize; line = -1; // hex moving invalidates text line position } void SeeViewer::down_txt() { CHKPOS; int z = 0; if ( fpos == fsize ) return; if ( fseeko( f, fpos, SEEK_SET ) ) return; int res = fread( buff, 1, opt->wrap, f ); z = 0; while( z < res && buff[z] != '\n' ) z++; if (buff[z] == '\n') z++; buff[z] = 0; fpos += z; if ( line >= 0 ) line++; if ( line > last_line ) last_line = line; if ( fpos > fsize ) fpos = fsize; if ( fpos == fsize && last_line != -1 ) end_reached = 1; } /*--------------------------------------------------------------------*/ void SeeViewer::home() { fpos = 0; line = 1; } /*--------------------------------------------------------------------*/ void SeeViewer::end_hex() { fpos = fsize; end2(); } void SeeViewer::end_txt() { if (end_reached) { end2(); return; } while ( fpos < fsize ) { if ( con_kbhit() && con_getch() == 27 ) return; down(); if (line % 768 == 0) status( " Going down.... line: %6"FMT_OFF_T"d (%3.0f%%) press ESCAPE to cancel ", line, fpos_percent() ); } end2(); } /*--------------------------------------------------------------------*/ void SeeViewer::end2() { int z = 0; if (!end_reached) line = -1; else line = last_line; fpos = fsize; for ( z = 0; z < 2 * rows / 3; z++ ) up(); } /*--------------------------------------------------------------------*/ void SeeViewer::go_to() { VString sss; if(opt->hex_mode) { sprintf( sss, "x%"FMT_OFF_T"X", fpos ); status( " Goto pos: " ); if (!TextInput( 15, opt->ymax, "", 20, 20, &sss )) { draw(); return; } off_t new_pos = fpos; str_cut_spc( sss ); str_up( sss ); if ( sss[0] == '-' ) new_pos = (sss[1] == 'X') ? hex2long( (const char*)sss+2 ) : atol( (const char*)sss+1 ); else if ( sss[0] == '+' ) new_pos += (sss[1] == 'X') ? hex2long( (const char*)sss+2 ) : atol( (const char*)sss+1 ); else new_pos = (sss[0] == 'X') ? hex2long( (const char*)sss+1 ) : atol( (const char*)sss ); if ( new_pos >= 0 && new_pos < fsize ) fpos = new_pos; draw(); } else { if ( last_line == -1 ) { status( "Cannot determine line number..." ); return; } sprintf( sss, "%"FMT_OFF_T"d", line); status( " Goto line: " ); if (!TextInput( 15, opt->ymax, "", 20, 20, &sss )) { draw(); return; } off_t new_line = line; str_cut_spc( sss ); str_up( sss ); if ( sss[0] == '-' ) new_line -= atol( (const char*)sss+1 ); else if ( sss[0] == '+' ) new_line += atol( (const char*)sss+1 ); else new_line = atol( (const char*)sss ); if (new_line < 0) new_line = 0; if (last_line != -1 && end_reached && new_line > last_line) new_line = last_line; if (new_line == line) { draw(); return; } if (new_line > line) while( new_line != line && fpos < fsize ) { if ( con_kbhit() && con_getch() == 27 ) return; down(); if ( line % 768 == 0) status( " Going down.... line: %6"FMT_OFF_T"d -- %3.0f%% (press ESCAPE to cancel) ", line, fpos_percent() ); } else while( new_line != line && fpos > 0 ) { if ( con_kbhit() && con_getch() == 27 ) return; up(); if ( line % 768 == 0) status( " Going up.... line: %6"FMT_OFF_T"d -- %3.0f%% (press ESCAPE to cancel) ", line, fpos_percent() ); } draw(); } } /*--------------------------------------------------------------------*/ int SeeViewer::find_next_hex( int rev ) { //FIXME: implement!!! return 0; } int SeeViewer::find_next_txt( int rev ) { if ( ! re.ok() ) { re.comp( opt->last_search, opt->last_opt ); } if ( ! re.ok() ) { status( "No search pattern..." ); return 1; } off_t opos = fpos; VString msg; if ( ! rev ) down(); while(4) { rev ? up() : down(); if ( line % 768 == 0) status( "Searching.... line: %6"FMT_OFF_T"d -- %3.0f%% (press ESCAPE to cancel) ", line, fpos_percent() ); if ( re.m( buff ) ) { off_t spos = re.sub_sp( 0 ); if ( ! rev ) up(); draw(); spos += fpos; status( "Pattern `%s' found at pos: %"FMT_OFF_T"d (0x%"FMT_OFF_T"X)", opt->last_search, spos, spos ); break; } if ( (! rev && fpos == fsize) || ( rev && fpos == 0 ) ) { fpos = opos; fseeko( f, opos, SEEK_SET ); status( "Pattern `%s' not found...", opt->last_search ); break; } if ( con_kbhit() && con_getch() == 27 ) { fpos = opos; fseeko( f, opos, SEEK_SET ); status( "Search canceled..." ); break; } } return 0; } /*--------------------------------------------------------------------*/ int SeeViewer::find( const char* opts ) { VString sss; status( "Find %s: ", opts ); int ii = str_len(sss)+2; sss = opt->last_search; if(!TextInput( opt->xmin+ii, opt->ymax, "", opt->xmax-ii-4, opt->xmax-ii-4, &sss )) { draw(); return 1; } str_sleft( sss, MAX_SEARCH_LEN ); strcpy( opt->last_search, sss ); strcpy( opt->last_opt, opts ); re.comp( opt->last_search, opt->last_opt ); return find_next(); } /*--------------------------------------------------------------------*/ void SeeViewer::hex_edit() { if (!opt->hex_mode) { status( "HexEdit is available only in HEX mode :)" ); return; } int rowsz = opt->hex_cols * 8; // row size int in_text = 0; // if text is edited int editbs = rows * rowsz; unsigned char *editb = new unsigned char[editbs]; fseeko( f, fpos, SEEK_SET ); editbs = fread( editb, 1, editbs, f ); if ( editbs == 0 ) { delete editb; status( "Nothing to edit or read error..." ); return; } int epos = 0; int bytepos = 0; /* first or second byte part? :) */ status( "WARNING: HEX EDITING MODE! ENTER = SAVE, ESC = CANCEL, TAB = TOGGLE EDIT MODE !" ); con_cshow(); int key = 0; while(4) { if (in_text) con_xy( 13 + rowsz * 3 + (opt->hex_cols - 1) * 2 + 1 + epos % rowsz, 1 + epos / rowsz ); else con_xy( 13 + (epos % rowsz) * 3 + 2 * ( epos % rowsz / 8 ) + bytepos, 1 + epos / rowsz ); if ( key == 0 ) key = con_getch(); if ( key == 27 ) break; if ( key == 13 ) { /* will commit changes -- file should be reopened for RW */ fclose( f ); f = fopen( fname, "r+b" ); fseeko( f, fpos, SEEK_SET ); int r = fwrite( editb, 1, editbs, f ); fclose( f ); if ( r != editbs ) { status( "Write error (press a key)" ); con_beep(); con_getch(); } f = fopen( fname, "rb" ); break; } switch( key ) { case 9 : in_text = !in_text; break; case KEY_RIGHT : if (bytepos == 0 && !in_text) bytepos = 1; else if (epos < editbs - 1) { epos++; if (!in_text) bytepos = 0; } break; case KEY_LEFT : if (bytepos == 1 && !in_text ) bytepos = 0; else if (epos > 0) { epos--; if (!in_text) bytepos = 1; } break; case KEY_DOWN : if ( epos + rowsz < editbs ) epos += rowsz; break; case KEY_UP : if ( epos - rowsz >= 0 ) epos -= rowsz; break; case KEY_PPAGE : epos = epos % rowsz; break; case KEY_NPAGE : epos = editbs - editbs % rowsz + epos % rowsz; if (epos >= editbs) epos = editbs - 1; break; case KEY_HOME : epos = epos - epos % rowsz; bytepos = 0; break; case KEY_END : epos = epos + (rowsz - epos%rowsz - 1); if (epos >= editbs) epos = editbs - 1; break; } if ( !in_text && key > 0 && key < 255 && strchr( HEXCHARS, toupper(key) ) ) { int n = str_find( HEXCHARS, toupper(key) ); char tmp[2]; tmp[0] = HEXCHARS[n]; tmp[1] = 0; con_puts( tmp, chRED ); if (bytepos == 0) { editb[epos] = (n << 4) + ( editb[epos] & 0x0F ); } else { editb[epos] = (n ) + ( editb[epos] & 0xF0 ); } tmp[0] = editb[epos]; filter( tmp, 1 ); con_xy( 13 + rowsz * 3 + (opt->hex_cols - 1) * 2 + 1 + epos % rowsz, 1 + epos / rowsz); con_puts( tmp, chRED ); key = KEY_RIGHT; } else if ( in_text && key >= 32 && key < 255 ) { char tmp[3]; tmp[0] = key; tmp[1] = 0; con_puts( tmp, chRED ); con_xy( 13 + (epos % rowsz) * 3 + 2 * ( epos % rowsz / 8 ), 1 + epos / rowsz ); sprintf( tmp, "%02X", key ); tmp[2] = 0; con_puts( tmp, chRED ); editb[epos] = key; key = KEY_RIGHT; } else key = 0; } con_chide(); delete editb; draw(); } /*--------------------------------------------------------------------*/ void SeeViewer::help() { con_out( 1, 1, help_str ); do_draw = 1; con_getch(); } /*--------------------------------------------------------------------*/ int SeeViewer::run() { CHKPOS; if (!f) return 27; int ch = 0; draw(); while(ch != 27) { if ( do_draw ) { draw(); do_draw = 0; } ch = con_getch(); if( ch == 0 ) ch = KEY_CTRL_L; if ( ch == 27 || ch == '-' || ch == 'q' || ch == KEY_ALT_X || ch == KEY_BACKSPACE ) return ch; int z = 0; while( escape_keys[z] ) if ( escape_keys[z++] == ch ) return ch; switch(ch) { case KEY_F1 : case KEY_ALT_H : case 'h' : case 'H' : help(); break; case KEY_UP : up(); draw(); break; case 13 : case KEY_DOWN : down(); draw(); break; case 'b' : case 'B' : case KEY_PPAGE : for ( z = 0; z < rows; z++ ) up(); draw(); break; case ' ' : case KEY_NPAGE : for ( z = 0; z < rows; z++ ) down(); draw(); break; case 'p' : case 'P' : case KEY_HOME : if (fpos == 0) col = 0; else home(); draw(); break; case KEY_END : end(); draw(); break; case KEY_CTRL_E : end2(); draw(); break; case KEY_CTRL_L : if ( opt->auto_size ) { opt->xmin = 1; opt->ymin = 1; opt->xmax = con_max_x(); opt->ymax = con_max_y(); } rows = opt->ymax - opt->ymin - (opt->status != 0) + 1; cols = opt->xmax - opt->xmin + 1; con_cs(); draw(); break; case '>' : case '.' : case KEY_RIGHT : if (opt->hex_mode) { if (fpos < fsize) fpos++; draw(); } else { if (col < opt->wrap-10) { col += (ch == '>') ? 1 : 8; draw(); } } break; case '<' : case ',' : case KEY_LEFT : if (opt->hex_mode) { if (fpos > 0) fpos--; draw(); } else { if (col > 0) { col -= (ch=='<')?1:8; if (col < 0) col = 0; draw(); } } break; case 9 : opt->hex_mode = !opt->hex_mode; if (!opt->hex_mode) { fpos++; if ( fpos > fsize ) fpos = fsize; up(); } draw(); break; case 'g' : case 'G' : opt->grid = !opt->grid; draw(); break; case 'W' : case 'w' : if ( opt->hex_mode ) { opt->hex_cols++; draw(); } else { opt->wrap = (opt->wrap < opt->bsize)? opt->bsize : cols; draw(); status( (opt->wrap == cols)? " Wrap ON" : " Wrap OFF" ); } break; case 'l' : xlat = (xlat == 1) ? 0 : 1; draw(); break; case 'L' : xlat = (xlat == 2) ? 0 : 2; draw(); break; case 'f' : case 'F' : find( "i" ); break; case 's' : case 'S' : find( "f" ); break; case 'e' : case 'E' : find( "fh" ); break; case '/' : find( "r" ); break; //FIXME: remove 'r', use 'f' case '\\' : find( "ri" ); break; case KEY_F(3) : case 'n' : case 'N' : find_next( 0 ); break; case 'm' : case 'M' : find_next( 1 ); break; case '+' : go_to(); break; case 'd' : case 'D' : if (opt->hex_mode) { opt->dec_pos = !opt->dec_pos; draw(); } break; case 'o' : case 'O' : if (!opt->hex_mode) { opt->show_eol = !opt->show_eol; draw(); } break; case 'a' : case 'A' : if (!opt->hex_mode) { opt->handle_bs = !opt->handle_bs; draw(); status( opt->handle_bs? " BackSpace handling ON" : " BackSpace handling OFF" ); } break; case 't' : case 'T' : if (!opt->hex_mode) { opt->handle_tab = !opt->handle_tab; draw(); status( opt->handle_tab? " TAB expansion ON" : " TAB expansion OFF" ); } break; case 'r' : case 'R' : if (!opt->hex_mode) { int z = 0; VString ruler; while ( str_len(ruler) < opt->xmax ) { ruler += "|0-------"; z++; ruler += z % 10; } str_sleft( ruler, opt->xmax ); con_out( 1, 1, ruler, opt->ch ); } break; case 'i' : case 'I' : hex_edit(); break; } } return ch; /* 27 */ } /*--------------------------------------------------------------------*/ /* read ahead with tab and backspace expansion */ /* result goes into `buff', the margin is `wrap' */ int SeeViewer::read_text( off_t &cpos ) { buff[0] = 0; int z = 0; unsigned char ch; while( z < opt->wrap ) { if ( cpos >= fsize ) break; ch = fgetc( f ); cpos++; if (opt->handle_bs && ch == 8) { if (z > 0) z--; continue; } if (opt->handle_tab && ch == 9) { ASSERT( opt->tabsize > 0 ); int i = ((z/opt->tabsize)+1) * opt->tabsize - z; while( z < opt->wrap && i > 0 ) { buff[z] = ' '; z++; i--; } continue; } buff[z] = ch; z++; if ( ch == '\n' ) break; } return z; } /**********************************************************************/ /**********************************************************************/ #define SEEDCOL (col - colpage + 1) /* screen column */ #define SEEDROW (sv.pos() - sv.page() + 1) /* screen row */ SeeEditor::SeeEditor( SeeEditorOptions *a_opt ) { opt = a_opt; memset( &escape_keys, 0, sizeof(escape_keys)); fname = ""; col = 0; colpage = 0; mod = 0; freezed = 0; if ( opt->auto_size ) { opt->xmin = 1; opt->ymin = 1; opt->xmax = con_max_x(); opt->ymax = con_max_y(); } rows = opt->ymax - opt->ymin - (opt->status != 0) + 1; cols = opt->xmax - opt->xmin + 1; sv.set_min_max( 0, va.count() - 1 ); sv.set_pagesize( rows ); sv.go( 0 ); help_str = "+-----------------------------------------------------------------------------+\n" "| SeeEditor v" SEE_VERSION " (c) Vladi Belperchinov-Shabanski |\n" "| ^ is Ctrl+key, @ is Alt+key, # is Shift+key |\n" "| |\n" "| Up_Arrow or ^P -- one line up ESC -- request exit |\n" "| Down_Arrow or ^N -- one line down (will prompt for save) |\n" "| Left_Arrow or ^B -- one char left ^W -- pipe cmd input as text |\n" "| Right_Arrow or ^F -- one char right @F -- find string (no case) |\n" "| Page_Up or ^U -- one page up @S -- find next (with case) |\n" "| Page_Down or ^V -- one page down @G -- find next |\n" "| Home or ^A -- goto beg. of line F3 -- find next |\n" "| End or ^E -- goto end of line ^L -- redraw screen |\n" "| Del or ^D -- del. char under cursor ~pattern is regexp search |\n" "| Backspace or ^H -- del. char to the left \\pattern is normal search |\n" "| ^K^U -- goto beg. of file pattern is same as \\pattern |\n" "| ^K^V -- goto end of file |\n" "| ^Y -- delete current line ^T -- toggle auto indent |\n" "| F1 or @H -- this help screen ^C -- quit without save NOW! |\n" "| F2 or ^K^D or ^S -- save file ^X -- Save All and Quit Now |\n" "| |\n" "| No UNDO! If you make a mistake -- quit the file without saving it! |\n" "| --------------------------------------------------------------------------- |\n" "| You can replace this editor with external one -- see VFU docs for details! |\n" "+-----------------------------------------------------------------------------+"; } /*--------------------------------------------------------------------*/ SeeEditor::~SeeEditor() { } /*--------------------------------------------------------------------*/ /* add escape key which will cause run() exit */ void SeeEditor::escape_on( int key ) { int z = 0; while( z < MAX_ESCAPE_KEYS-1 ) { if (!escape_keys[z]) { escape_keys[z] = key; return; } z++; } } /*--------------------------------------------------------------------*/ int SeeEditor::open( const char* a_fname ) { if ( va.count() || str_len( fname ) ) close(); fname = a_fname; remove_all(); insert_file( fname ); if (access( fname, F_OK )) { mod = 1; va.push( "" ); /* hack if new file */ } sv.set_min_max( 0, va.count() - 1 ); sv.go( 0 ); col = colpage = 0; mod = 0; return 0; } /*--------------------------------------------------------------------*/ void SeeEditor::close() { if ( mod ) /* if modified */ if ( request_quit() ) return; /* request denied */ fname = ""; col = 0; colpage = 0; sv.go( 0 ); va.undef(); mod = 0; con_chide(); } /*--------------------------------------------------------------------*/ void SeeEditor::status( const char* format, ... ) { char buf[1024]; va_list vlist; va_start( vlist, format ); vsnprintf( buf, 1024, format, vlist ); va_end( vlist ); VString str; str = "| "; str += buf; if (str_len(str) >= cols) str_sleft( str, (cols-2) ); else str_pad( str, -(cols-2) ); str += "|"; con_out( opt->xmin, opt->ymax, str, opt->cs ); set_cursor(); } /*--------------------------------------------------------------------*/ int SeeEditor::expand_tabs( VString &str, VString &map ) { int res = 0; int i = 0; map = ""; str_pad( map, str_len( str ) ); while( ( i = str_find( str, '\t' ) ) > -1 ) { int j; ASSERT( opt->tabsize > 0 ); j = ( i / opt->tabsize + 1 ) * opt->tabsize; j = j - i; res += (j - 1); str_del( str, i, 1 ); while( j-- ) { str_ins_ch( str, i, ' ' ); str_ins_ch( map, i, '+' ); } str_del( map, i, 1 ); str_ins_ch( map, i, '*' ); } return res; } /*--------------------------------------------------------------------*/ int SeeEditor::real_col( int row ) { int c = col; if (row == -1) row = sv.pos(); VString str = va[row]; VString map; if ( expand_tabs( str, map ) ) { str_sleft( map, col ); c -= str_count( map, "+" ); } return c; } /*--------------------------------------------------------------------*/ void SeeEditor::set_cursor() { con_xy( SEEDCOL, SEEDROW ); } /*--------------------------------------------------------------------*/ void SeeEditor::draw_line( int n ) { if ( freezed ) return; ASSERT( sv.max() == va.count() - 1 ); if ( n > sv.max() ) { VString sss = "~"; str_pad( sss, - cols ); con_out( 1, ( n - sv.page() ) + 1, sss, opt->cn ); } else { VString map; VString str = va[n]; expand_tabs( str, map ); str_trim_left( str, colpage ); str_sleft( str, cols ); str_pad( str, - cols ); con_out( 1, ( n - sv.page() ) + 1, str, opt->cn ); } set_cursor(); } /*--------------------------------------------------------------------*/ void SeeEditor::draw( int from ) { if ( freezed ) return; int z; con_chide(); if ( from > -1 ) /* from == -1 to update status line only */ for( z = from; z < rows; z++ ) draw_line( sv.page() + z ); con_cshow(); status( "%s | %3.0f%% | Line:%5d of%5d |%4d+ %s | Alt+H Help | %s", mod?"MOD!":"----", (100.0*sv.pos())/(sv.max()?sv.max():1), sv.pos()+1, sv.max()+1, col+1, opt->insert?"INS":"ovr", fname.data() ); set_cursor(); } /*--------------------------------------------------------------------*/ int SeeEditor::save() { remove_trails(); if (va.fsave( fname )) { status( "Cannot save file: %s! ", fname.data() ); return 0; } else { status( "File saved ok" ); mod = 0; return 1; } } /*--------------------------------------------------------------------*/ int SeeEditor::request_quit() { if ( mod == 0 ) return 0; /* ok -- not modified */ while(4) { con_beep(); status( "File is modified! Press: Save, Quit, Cancel" ); con_chide(); int k = con_getch(); con_cshow(); if ( k == 'S' || k == 's' ) { if(!save()) { status( "Cannot save file! Press: Save, Quit, Cancel" ); continue; /* error saving file */ } else return 0; /* okay */ } if ( k == 'Q' || k == 'q' ) { mod = 0; /* considered unmodified at that point */ return 0; /* okay */ } if ( k == 27 ) { return 1; /* denied */ } } } /*--------------------------------------------------------------------*/ void SeeEditor::left() { if (col <= 0) return; VString str = va[sv.pos()]; VString map; if ( expand_tabs( str, map ) ) { col--; while (col > 0 && map[col] == '+') col--; } else col--; if (SEEDCOL < 1) colpage--; } /*--------------------------------------------------------------------*/ void SeeEditor::right() { VString str = va[sv.pos()]; VString map; if ( expand_tabs( str, map ) ) { col++; while (map[col] == '+') col++; } else col++; if (SEEDCOL > cols) colpage++; } /*--------------------------------------------------------------------*/ void SeeEditor::home() { col = colpage = 0; } /*--------------------------------------------------------------------*/ void SeeEditor::end() { remove_trails( sv.pos() ); VString str = va[sv.pos()]; VString map; expand_tabs( str, map ); col = str_len( str ); if (SEEDCOL > cols) { colpage = col - cols/2; if (colpage < 0) colpage = 0; draw(); } } /*--------------------------------------------------------------------*/ void SeeEditor::go_to() { } /*--------------------------------------------------------------------*/ void SeeEditor::kdel() { VString str = va[sv.pos()]; int c = real_col(); if (c >= str_len( str )) { if ( sv.pos() == sv.max() ) return; mod = 1; VString nstr = va[sv.pos()+1]; /* next string (below) */ if ( c > str_len( str ) ) str_pad( str, -c, ' ' ); /* the line is short -- pad with spaces */ str += nstr; va[ sv.pos() ] = str; va.del( sv.pos()+1 ); sv.set_min_max( 0, va.count() - 1 ); draw(); /* FIXME: from ROW to the end of the page */ } else { mod = 1; str_del( va[ sv.pos() ], c, 1 ); draw_line( sv.pos() ); } } /*--------------------------------------------------------------------*/ void SeeEditor::kbs() { VString str = va[sv.pos()]; int c = real_col(); if ( c > str_len( str ) ) { left(); return; } else if (c == 0) { if (sv.pos() == 0) return; up(); end(); kdel(); } else { left(); kdel(); } } /*--------------------------------------------------------------------*/ void SeeEditor::kenter() { mod = 1; if ( va.count() == 0 ) va.push( "" ); int c = real_col(); VString str = va[sv.pos()]; VString nstr = str; str_sleft( str, c ); str_trim_left( nstr, c ); va.set( sv.pos(), str ); va.ins( sv.pos()+1, nstr ); sv.set_min_max( 0, va.count()-1 ); sv.down(); col = 0; /* !!! here should go the auto indenting... */ if ( opt->auto_indent && sv.pos() > 1) { str = va[sv.pos()-1]; int z = 0; int nc = 0; while( z < str_len(str) && (str[z] == ' ' || str[z] == '\t') ) { if ( str[z] == '\t' ) nc += opt->tabsize; else nc++; z++; } str = va[sv.pos()]; col = nc; while( nc-- ) str_ins_ch( str, 0, ' ' ); va.set( sv.pos(), str ); } if ( SEEDCOL > opt->xmax || SEEDCOL < 1 ) { colpage = col - cols/2; if (colpage < 0) colpage = 0; draw(); } else draw(); /* FIXME: from ROW to the end of the page */ } /*--------------------------------------------------------------------*/ void SeeEditor::kinsert( int ch ) { if ( ch < 0 || ch > 255 ) return; if ( ch == 13 || ch == 10 ) { kenter(); return; } mod = 1; if ( va.count() == 0 ) va.push( "" ); VString str = va[sv.pos()]; int c = real_col(); if (!opt->insert) str_del( str, c, 1 ); if ( str_len(str) < c ) str_pad( str, -c, ' ' ); str_ins_ch( str, c, ch ); va.set( sv.pos(), str ); right(); if ( SEEDCOL > opt->xmax || SEEDCOL < 1 ) { colpage = col - cols/2; if (colpage < 0) colpage = 0; draw(); } else draw(); /* FIXME: from ROW to the end of the page */ } /*--------------------------------------------------------------------*/ void SeeEditor::insert_file( const char* fn ) { mod = va.count(); /* FIXME: this should insert file in current position! */ va.fload( fname ); remove_trails(); sv.set_min_max( 0, va.count() - 1 ); } /*--------------------------------------------------------------------*/ void SeeEditor::remove_line( int n ) { if ( n == -1 ) n = sv.pos(); ASSERT( sv.max() == va.count() - 1 ); if ( n < 0 || n > sv.max() ) return; mod = 1; if ( n == sv.max() ) { if ( str_len( va[n] ) == 0 ) return; va.set( n, "" ); } else { va.del( n ); sv.set_min_max( 0, va.count() - 1 ); sv.go( sv.pos() ); } draw(); } /*--------------------------------------------------------------------*/ void SeeEditor::remove_all() { while( va.count() ) { remove_line( 0 ); mod = 1; } } /*--------------------------------------------------------------------*/ void SeeEditor::remove_trails( int n ) /* remove trailing spaces/tabs */ { if ( n != -1 ) { ASSERT( sv.max() == va.count() - 1 ); if ( n < 0 || n > sv.max() ) return; VString str = va[n]; str_cut_right( str, " \t\n\r" ); va.set( n, str ); } else for ( int z = 0; z < va.count(); z++ ) { VString str = va[z]; str_cut_right( str, " \t\n\r" ); va.set( z, str ); } } /*--------------------------------------------------------------------*/ void SeeEditor::insert_pipe_cmd() { VString sss = "Command to pipe in: "; int ii = str_len( sss )+2; status( sss ); sss = opt->last_pipe_cmd; if(!TextInput( opt->xmin+ii, opt->ymax, "", opt->xmax-ii-4, opt->xmax-ii-4, &sss )) { draw(); return; } str_sleft( sss, MAX_SEARCH_LEN ); strcpy( opt->last_pipe_cmd, sss ); FILE* f = popen( opt->last_pipe_cmd, "r" ); if ( !f ) { status( "Command execution failed..." ); status( opt->last_pipe_cmd ); return; } char ch; freezed = 1; while( (ch = fgetc( f ) ) != EOF ) kinsert( ch ); freezed = 0; pclose( f ); draw(); } /*--------------------------------------------------------------------*/ int SeeEditor::find_next() { if ( opt->last_search[0] == 0 ) { status( "No pattern" ); return 0; } int z; int pos = -1; for ( z = sv.pos() + 1; z <= sv.max(); z++ ) { VString str = va[z]; if ( opt->no_case ) str_up( str ); if ( opt->last_search[0] == '~' ) pos = str_find_regexp( str, opt->last_search + 1 ); else if ( str[0] == '\\' ) pos = str_find( str, opt->last_search + 1 ); else pos = str_find( str, opt->last_search ); if ( pos != -1 ) break; } if ( pos != -1 ) { sv.go( z ); col = pos; if (SEEDCOL > cols) { colpage = col - cols/2; if (colpage < 0) colpage = 0; } do_draw = 1; return 1; } else { status( "Pattern not found" ); return 0; } } /*--------------------------------------------------------------------*/ int SeeEditor::find( int no_case ) { VString sss; status( "Find %s: ", no_case?"(no case)":"(case sense)" ); int ii = str_len(sss)+2; sss = opt->last_search; if(!TextInput( opt->xmin+ii, opt->ymax, "", opt->xmax-ii-4, opt->xmax-ii-4, &sss )) { draw(); return 1; } str_sleft( sss, MAX_SEARCH_LEN ); strcpy( opt->last_search, sss ); opt->no_case = no_case; if ( opt->no_case ) str_up( opt->last_search ); return find_next(); } /*--------------------------------------------------------------------*/ void SeeEditor::help() { con_out( 1, 1, help_str ); do_draw = 1; con_getch(); } /*--------------------------------------------------------------------*/ int SeeEditor::run() { con_cshow(); draw(); set_cursor(); int key; int pend = 0; /* used for double key-strokes as ^K^x command */ while(4) { int ox = SEEDCOL; int oy = SEEDROW; int orp = sv.page(); int ocp = colpage; int oi = opt->insert; pend = 0; key = con_getch(); if( key == 0 ) key = KEY_CTRL_L; if (key == KEY_CTRL_C) { mod = 0; /* it is `quit' i.e. no save so this should be ok */ return key; } if (key == KEY_CTRL_X) { save(); return key; } else if ( key == 27 || key == KEY_ALT_X ) { if ( request_quit() == 0 ) return key; else continue; } if ( key == KEY_CTRL_K ) { pend = key; con_out( SEEDCOL, SEEDROW, "^K", opt->cs ); set_cursor(); key = con_getch(); draw_line( sv.pos() ); } switch( key ) { case KEY_CTRL_N : case KEY_DOWN : down(); break; case KEY_CTRL_P : case KEY_UP : up(); break; case KEY_CTRL_B : case KEY_LEFT : left(); break; case KEY_CTRL_F : case KEY_RIGHT : right(); break; case KEY_CTRL_U : if ( pend == KEY_CTRL_K ) sv.home(); else sv.ppage(); break; case KEY_PPAGE : sv.ppage(); break; case KEY_CTRL_V : if ( pend == KEY_CTRL_K ) sv.end(); else sv.npage(); break; case KEY_NPAGE : sv.npage(); break; case KEY_CTRL_A : case KEY_HOME : home(); break; case KEY_CTRL_E : case KEY_END : end(); break; case KEY_INSERT : opt->insert = !opt->insert; break; case KEY_CTRL_Y : remove_line(); break; /* SeedKxxx functions are for KEYxxx handles */ case KEY_ALT_H : case KEY_F1 : help(); break; case KEY_CTRL_S : case KEY_F2 : save(); break; case KEY_CTRL_D : if ( pend == KEY_CTRL_K ) save(); else kdel(); break; case KEY_ALT_F : find( 1 ); break; case KEY_ALT_S : find( 0 ); break; case KEY_ALT_G : case KEY_F3 : find_next(); break; case KEY_DEL : kdel(); break; #ifndef _TARGET_GO32_ case KEY_BACKSPACE : #endif case KEY_CTRL_H : kbs(); break; case 10 : case 13 : kenter(); break; case KEY_CTRL_L : if ( opt->auto_size ) { opt->xmin = 1; opt->ymin = 1; opt->xmax = con_max_x(); opt->ymax = con_max_y(); } rows = opt->ymax - opt->ymin - (opt->status != 0) + 1; cols = opt->xmax - opt->xmin + 1; sv.set_pagesize( rows ); con_cs(); draw(); break; case KEY_CTRL_W : insert_pipe_cmd(); break; case KEY_CTRL_T : opt->auto_indent = !opt->auto_indent; status( (opt->auto_indent) ? "AutoIndent ON" : "AutoIndent OFF" ); break; case KEY_ALT_0 : case KEY_ALT_1 : case KEY_ALT_2 : case KEY_ALT_3 : case KEY_ALT_4 : case KEY_ALT_5 : case KEY_ALT_6 : case KEY_ALT_7 : case KEY_ALT_8 : case KEY_ALT_9 : if (key == KEY_ALT_0) key = KEY_ALT_9+1; return key; case 27 : return key; default : kinsert( key ); break; } if ( do_draw || orp != sv.page() || ocp != colpage || oi != opt->insert ) { draw(); set_cursor(); do_draw = 0; } else if ( ox != SEEDCOL || oy != SEEDROW ) { draw( -1 ); /* just update status line */ set_cursor(); } } } /***eof****************************************************************/ vfu-4.10/vfu/vfusetup.h0000644000175000001440000000610411310547564013712 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vfusetup.h,v 1.13 2007/02/12 06:14:42 cade Exp $ * */ #ifndef _SETUP_H_ #define _SETUP_H_ /* * * This file is used to setup some global parameters as * files locations and other similar things... * (it is separated from vfu.h just to keep it clear) * */ #define VFU_VERSION "4.10" #define HEADER "VF/U v" VFU_VERSION " (" __DATE__ ") by (c) Vladi Belperchinov-Shabanski `Cade' 1996-2009" #define CONTACT " [http://cade.datamax.bg]" #ifdef _TARGET_GO32_ #define FILENAME_OPT "vfu.opt" #define FILENAME_CONF "vfu.cfg" #define FILENAME_TREE "vfu.tre" #define FILENAME_SIZE_CACHE "vfu.siz" #define FILENAME_HISTORY "vfu.hst" #define FILENAME_FFR "vfu.ffr" #else #define FILENAME_OPT "vfu.options" #define FILENAME_CONF "vfu.conf" #define FILENAME_TREE "vfu.tree" #define FILENAME_SIZE_CACHE "vfu.size" #define FILENAME_HISTORY "vfu.history" #define FILENAME_FFR "vfu.ffr" #endif #ifndef FILENAME_CONF_GLOBAL0 #define FILENAME_CONF_GLOBAL0 "/etc/" FILENAME_CONF #endif #ifndef FILENAME_CONF_GLOBAL1 #define FILENAME_CONF_GLOBAL1 "/usr/local/etc/" FILENAME_CONF #endif #ifndef FILENAME_CONF_GLOBAL2 #define FILENAME_CONF_GLOBAL2 "/usr/lib/vfu/" FILENAME_CONF #endif #define RX_TEMP_LIST "RX_TEMP_LIST" #define MAX_FILES 128000 /* colors */ #define cPLAIN (cNORMAL) // normal white #define cHEADER (chRED) // files list headers #define cINFO (chYELLOW) // general info messages #define cINFO2 (chYELLOW) // bottom information panel #define cINPUT (CONCOLOR(chWHITE,cBLUE)) // normal input lines #define cINPUT2 (CONCOLOR(cBLACK,cWHITE)) // selected input lines #define cMESSAGE (cWHITE) // all messages #define cSTATUS (cCYAN) // status messages (progress info) #define cSTATUS2 (chCYAN) // alt status messages (copy progress info) #define cWARNING (CONCOLOR(chWHITE,cRED)) // warning messages #define cBAR (CONCOLOR(chWHITE,cBLUE)) // inverted select bar (dir tree) #define cTAG (CONCOLOR(cRED,cWHITE)) // currently selected file #define cMENU_CN (CONCOLOR(chWHITE,cBLUE)) // menu normal #define cMENU_CH (CONCOLOR(chWHITE,cGREEN)) // menu highlite #define cMENU_TI (CONCOLOR(chWHITE,cMAGENTA)) // menu title /* mono config -- never tested! */ /* #define cPLAIN (cWHITE) #define cHEADER (CONCOLOR(cBLACK,cWHITE)) #define cINFO (chWHITE) #define cINFO2 (CONCOLOR(cBLACK,cWHITE)) #define cINPUT (CONCOLOR(cWHITE,cBLACK)) #define cINPUT2 (CONCOLOR(cBLACK,cWHITE)) #define cMESSAGE (chWHITE) #define cSTATUS (cWHITE) #define cSTATUS2 (chWHITE) #define cWARNING (CONCOLOR(cBLACK,cWHITE)) #define cBAR (CONCOLOR(cBLACK,cWHITE)) #define cTAG cBAR #define cMENU_CN (CONCOLOR(cWHITE,cBLACK)) // menu normal #define cMENU_CH (CONCOLOR(cBLACK,cWHITE)) // menu highlite #define cMENU_TI (CONCOLOR(cBLACK,cWHITE)) // menu title */ /* colors setup end */ #endif //_SETUP_H_ vfu-4.10/vfu/makefile0000644000175000001440000001070711172612224013354 0ustar cadeusers ### MAKEMAKE STARTS HERE ####################################################### ### Created by makemake.pl on Wed Dec 29 04:48:32 2004 ######################### ### GLOBAL TARGETS ############################################################# default: all re: rebuild li: link all: vfu clean: clean-vfu rebuild: rebuild-vfu link: link-vfu ### GLOBAL (AND USER) DEFS ##################################################### AR = ar rv CC = gcc LD = gcc MKDIR = mkdir -p RANLIB = ranlib RMDIR = rm -rf RMFILE = rm -f SRC = *.c *.cpp *.cc *.cxx ### TARGET 1: vfu ############################################################## CC_1 = g++ LD_1 = g++ AR_1 = ar rv RANLIB_1 = ranlib CCFLAGS_1 = -I../vslib -I/usr/include/ncurses -O2 $(CCDEF) LDFLAGS_1 = -L../vslib -lvslib -lvscon -lpcre -lncurses $(LDDEF) DEPFLAGS_1 = ARFLAGS_1 = TARGET_1 = vfu ### SOURCES FOR TARGET 1: vfu ################################################## SRC_1= \ see.cpp \ vfu.cpp \ vfuarc.cpp \ vfucopy.cpp \ vfudir.cpp \ vfufiles.cpp \ vfumenu.cpp \ vfuopt.cpp \ vfusys.cpp \ vfutools.cpp \ vfuuti.cpp \ vfuview.cpp \ #### OBJECTS FOR TARGET 1: vfu ################################################# OBJ_1= \ .OBJ.vfu/see.o \ .OBJ.vfu/vfu.o \ .OBJ.vfu/vfuarc.o \ .OBJ.vfu/vfucopy.o \ .OBJ.vfu/vfudir.o \ .OBJ.vfu/vfufiles.o \ .OBJ.vfu/vfumenu.o \ .OBJ.vfu/vfuopt.o \ .OBJ.vfu/vfusys.o \ .OBJ.vfu/vfutools.o \ .OBJ.vfu/vfuuti.o \ .OBJ.vfu/vfuview.o \ ### TARGET DEFINITION FOR TARGET 1: vfu ######################################## .OBJ.vfu: $(MKDIR) .OBJ.vfu vfu: .OBJ.vfu $(OBJ_1) $(LD_1) $(OBJ_1) $(LDFLAGS_1) -o $(TARGET_1) clean-vfu: $(RMFILE) $(TARGET_1) $(RMDIR) .OBJ.vfu rebuild-vfu: clean-vfu vfu link-vfu: .OBJ.vfu $(OBJ_1) $(RMFILE) vfu $(LD_1) $(OBJ_1) $(LDFLAGS_1) -o $(TARGET_1) ### TARGET OBJECTS FOR TARGET 1: vfu ########################################### .OBJ.vfu/see.o: see.cpp see.cpp see.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c see.cpp -o .OBJ.vfu/see.o .OBJ.vfu/vfu.o: vfu.cpp vfu.cpp vfu.h vfusetup.h vfusys.h vfuopt.h see.h vfuuti.h \ vfufiles.h vfucopy.h vfudir.h vfuview.h vfumenu.h vfuarc.h vfutools.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c vfu.cpp -o .OBJ.vfu/vfu.o .OBJ.vfu/vfuarc.o: vfuarc.cpp vfuarc.cpp vfuarc.h vfu.h vfusetup.h vfusys.h vfuuti.h vfuopt.h \ see.h vfudir.h vfucopy.h vfufiles.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c vfuarc.cpp -o .OBJ.vfu/vfuarc.o .OBJ.vfu/vfucopy.o: vfucopy.cpp vfucopy.cpp vfu.h vfusetup.h vfusys.h vfudir.h vfumenu.h \ vfuuti.h vfufiles.h vfuview.h vfuopt.h see.h vfucopy.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c vfucopy.cpp -o .OBJ.vfu/vfucopy.o .OBJ.vfu/vfudir.o: vfudir.cpp vfudir.cpp vfudir.h vfu.h vfusetup.h vfusys.h vfuopt.h see.h \ vfuuti.h vfufiles.h vfuview.h vfumenu.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c vfudir.cpp -o .OBJ.vfu/vfudir.o .OBJ.vfu/vfufiles.o: vfufiles.cpp vfufiles.cpp vfu.h vfusetup.h vfusys.h vfufiles.h vfuopt.h \ see.h vfuuti.h vfuview.h vfumenu.h vfudir.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c vfufiles.cpp -o .OBJ.vfu/vfufiles.o .OBJ.vfu/vfumenu.o: vfumenu.cpp vfumenu.cpp vfu.h vfusetup.h vfusys.h vfuopt.h see.h vfuuti.h \ vfumenu.h vfuview.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c vfumenu.cpp -o .OBJ.vfu/vfumenu.o .OBJ.vfu/vfuopt.o: vfuopt.cpp vfuopt.cpp vfu.h vfusetup.h vfusys.h vfuopt.h see.h vfuuti.h \ vfudir.h vfuview.h vfumenu.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c vfuopt.cpp -o .OBJ.vfu/vfuopt.o .OBJ.vfu/vfusys.o: vfusys.cpp vfusys.cpp vfu.h vfusetup.h vfusys.h vfuuti.h vfumenu.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c vfusys.cpp -o .OBJ.vfu/vfusys.o .OBJ.vfu/vfutools.o: vfutools.cpp vfutools.cpp vfumenu.h vfuuti.h vfu.h vfusetup.h vfusys.h \ vfucopy.h vfuview.h vfuopt.h see.h vfufiles.h vfutools.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c vfutools.cpp -o .OBJ.vfu/vfutools.o .OBJ.vfu/vfuuti.o: vfuuti.cpp vfuuti.cpp vfu.h vfusetup.h vfusys.h vfuuti.h vfumenu.h \ vfudir.h vfuopt.h see.h vfuview.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c vfuuti.cpp -o .OBJ.vfu/vfuuti.o .OBJ.vfu/vfuview.o: vfuview.cpp vfuview.cpp vfu.h vfusetup.h vfusys.h vfufiles.h vfuview.h \ vfuopt.h see.h vfuuti.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c vfuview.cpp -o .OBJ.vfu/vfuview.o ### MAKEMAKE ENDS HERE ######################################################### vfu-4.10/vfu/mm.conf0000644000175000001440000000053711172612241013133 0ustar cadeusers# # (c) Vladi Belperchinov-Shabanski "Cade" 1996-2002 # http://soul.datamax.bg/~cade # # $Id: mm.conf,v 1.7 2003/05/06 10:57:26 cade Exp $ # [vfu] CC = g++ LD = g++ CCFLAGS = -I../vslib -I/usr/include/ncurses -O2 $(CCDEF) LDFLAGS = -L../vslib -lvslib -lvscon -lpcre -lncurses $(LDDEF) SRC = *.cpp vfu-4.10/vfu/vfufiles.h0000644000175000001440000000243211005727265013653 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vfufiles.h,v 1.5 2003/01/26 21:48:42 cade Exp $ * */ #ifndef _VFUFILES_H_ #define _VFUFILES_H_ const char* file_type_str( mode_t mode, int is_link ); /*###########################################################################*/ void vfu_rescan_files( int a_recursive = 0 ); void vfu_read_files( int a_recursive = 0 ); int vfu_add_file( const char* fname, const struct stat *st, int is_link ); void vfu_read_archive_files( int a_recursive ); void vfu_read_local_files( int a_recursive ); void vfu_read_external_files(); void vfu_read_pszlist_files(); int vfu_fmask_match( const char* fname ); /*###########################################################################*/ void vfu_file_entry_move(); /*###########################################################################*/ int namenumcmp( const char* s1, const char* s2 ); int ficmp(int fn1, TF *f2); void __vfu_sort(int l, int r); void vfu_sort_files(); void vfu_arrange_files(); void vfu_pack_files_list(); /*###########################################################################*/ #endif //_VFUFILES_H_ vfu-4.10/vfu/vfusys.cpp0000644000175000001440000001731711103062460013716 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vfusys.cpp,v 1.8 2003/01/29 22:59:16 cade Exp $ * */ #include "vfu.h" #include "vfusys.h" #include "vfuuti.h" #include "vfumenu.h" #ifdef _TARGET_GO32_ #include #endif /*###########################################################################*/ void file_get_mode_str( const mode_t tm, mode_str_t &mod_str ) { strcpy( mod_str, MODE_OFF ); if (S_ISDIR(tm) ) mod_str[0] = 'd';else if (S_ISLNK(tm) ) mod_str[0] = 'l';else if (S_ISBLK(tm) ) mod_str[0] = 'b';else if (S_ISCHR(tm) ) mod_str[0] = 'c';else if (S_ISFIFO(tm)) mod_str[0] = 'f';else if (S_ISSOCK(tm)) mod_str[0] = 's'; if ((tm & S_IRUSR) != 0) mod_str[1] = 'r'; if ((tm & S_IWUSR) != 0) mod_str[2] = 'w'; if ((tm & S_IXUSR) != 0) mod_str[3] = 'x'; if ((tm & S_IRGRP) != 0) mod_str[4] = 'r'; if ((tm & S_IWGRP) != 0) mod_str[5] = 'w'; if ((tm & S_IXGRP) != 0) mod_str[6] = 'x'; if ((tm & S_IROTH) != 0) mod_str[7] = 'r'; if ((tm & S_IWOTH) != 0) mod_str[8] = 'w'; if ((tm & S_IXOTH) != 0) mod_str[9] = 'x'; #ifndef _TARGET_GO32_ if ((tm & S_ISUID) != 0) mod_str[3] = ((tm & S_IXUSR) != 0) ? 's' : 'S'; if ((tm & S_ISGID) != 0) mod_str[6] = ((tm & S_IXGRP) != 0) ? 's' : 'S'; if ((tm & S_ISVTX) != 0) mod_str[9] = ((tm & S_IXOTH) != 0) ? 't' : 'T'; #endif #ifdef _TARGET_GO32_ mod_str[4]=mod_str[5]=mod_str[6]=mod_str[7]=mod_str[8]=mod_str[9]='-'; #endif } /*---------------------------------------------------------------------------*/ int file_get_mode_str( const char *filename, mode_str_t &mod_str ) { strcpy( mod_str, MODE_OFF ); struct stat st; if ( stat(filename, &st) ) return 1; file_get_mode_str(st.st_mode, mod_str); return 0; } /*---------------------------------------------------------------------------*/ int file_set_mode_str( const char *filename, const mode_str_t mod_str ) { mode_str_t old_mod_str; mode_str_t new_mod_str; mode_t new_mode = 0; strcpy( new_mod_str, mod_str ); if (strchr( new_mod_str, '?' )) { if (file_get_mode_str(filename, old_mod_str)) return 1; if (new_mod_str[1] == '?') new_mod_str[1] = old_mod_str[1]; if (new_mod_str[2] == '?') new_mod_str[2] = old_mod_str[2]; if (new_mod_str[3] == '?') new_mod_str[3] = old_mod_str[3]; if (new_mod_str[4] == '?') new_mod_str[4] = old_mod_str[4]; if (new_mod_str[5] == '?') new_mod_str[5] = old_mod_str[5]; if (new_mod_str[6] == '?') new_mod_str[6] = old_mod_str[6]; if (new_mod_str[7] == '?') new_mod_str[7] = old_mod_str[7]; if (new_mod_str[8] == '?') new_mod_str[8] = old_mod_str[8]; if (new_mod_str[9] == '?') new_mod_str[9] = old_mod_str[9]; } if (new_mod_str[1] == 'r') new_mode |= S_IRUSR; if (new_mod_str[2] == 'w') new_mode |= S_IWUSR; if (new_mod_str[3] == 'x') new_mode |= S_IXUSR; if (new_mod_str[4] == 'r') new_mode |= S_IRGRP; if (new_mod_str[5] == 'w') new_mode |= S_IWGRP; if (new_mod_str[6] == 'x') new_mode |= S_IXGRP; if (new_mod_str[7] == 'r') new_mode |= S_IROTH; if (new_mod_str[8] == 'w') new_mode |= S_IWOTH; if (new_mod_str[9] == 'x') new_mode |= S_IXOTH; #ifndef _TARGET_GO32_ if (new_mod_str[3] == 's') { new_mode |= S_ISUID; new_mode |= S_IXUSR; } if (new_mod_str[3] == 'S') new_mode |= S_ISUID; if (new_mod_str[6] == 's') { new_mode |= S_ISGID; new_mode |= S_IXGRP; } if (new_mod_str[6] == 'S') new_mode |= S_ISGID; if (new_mod_str[9] == 't') { new_mode |= S_ISVTX; new_mode |= S_IXOTH; } if (new_mod_str[9] == 'T') new_mode |= S_ISVTX; #endif return ( chmod( filename, new_mode ) != 0 ); } /*---------------------------------------------------------------------------*/ int vfu_edit_attr( mode_str_t mod_str, int allow_masking ) { int mode_i[16]; if (allow_masking == 0) { /* "-rwxrwxrwx" */ for ( int z = 0; z < 16; z++ ) mode_i[z] = 1; mode_i[ 1] = (mod_str[1] != 'r'); mode_i[ 2] = (mod_str[2] != 'w'); mode_i[ 3] = (mod_str[3] != 'x'); mode_i[ 4] = (mod_str[4] != 'r'); mode_i[ 5] = (mod_str[5] != 'w'); mode_i[ 6] = (mod_str[6] != 'x'); mode_i[ 7] = (mod_str[7] != 'r'); mode_i[ 8] = (mod_str[8] != 'w'); mode_i[ 9] = (mod_str[9] != 'x'); mode_i[10] = !((mod_str[3] == 's') || (mod_str[3] == 'S')); mode_i[11] = !((mod_str[6] == 's') || (mod_str[6] == 'S')); mode_i[12] = !((mod_str[9] == 't') || (mod_str[9] == 'T')); if (mode_i[3]) mode_i[ 3] = !(mod_str[3] == 's'); if (mode_i[6]) mode_i[ 6] = !(mod_str[6] == 's'); if (mode_i[9]) mode_i[ 9] = !(mod_str[9] == 't'); } else { for ( int z = 0; z < 16; z++ ) mode_i[z] = 2; } const char* AONOFF1[] = { "YES", " - ", " ? ", NULL }; const char* AONOFF2[] = { "YES", " - ", NULL }; #define AONOFF ( allow_masking ? AONOFF1 : AONOFF2 ) ToggleEntry mode_toggles[] = { { ' ', "Read Owner", &mode_i[ 1], AONOFF }, { ' ', "Write Owner", &mode_i[ 2], AONOFF }, { ' ', "Exec/Srch Owner", &mode_i[ 3], AONOFF }, { ' ', "Read Group", &mode_i[ 4], AONOFF }, { ' ', "Write Group", &mode_i[ 5], AONOFF }, { ' ', "Exec/Srch Group", &mode_i[ 6], AONOFF }, { ' ', "Read Other", &mode_i[ 7], AONOFF }, { ' ', "Write Other", &mode_i[ 8], AONOFF }, { ' ', "Exec/Srch Other", &mode_i[ 9], AONOFF }, { ' ', "Set user id", &mode_i[10], AONOFF }, { ' ', "Set group id", &mode_i[11], AONOFF }, { ' ', "Sticky Bit", &mode_i[12], AONOFF }, { -1, "---", NULL, NULL }, }; if ( !vfu_toggle_box( 50, 5, "Change file Mode", mode_toggles ) ) return 0; if (mode_i[ 1] < 2) mod_str[1] = mode_i[ 1] == 0 ? 'r' : '-'; if (mode_i[ 2] < 2) mod_str[2] = mode_i[ 2] == 0 ? 'w' : '-'; if (mode_i[ 3] < 2) mod_str[3] = mode_i[ 3] == 0 ? 'x' : '-'; if (mode_i[ 4] < 2) mod_str[4] = mode_i[ 4] == 0 ? 'r' : '-'; if (mode_i[ 5] < 2) mod_str[5] = mode_i[ 5] == 0 ? 'w' : '-'; if (mode_i[ 6] < 2) mod_str[6] = mode_i[ 6] == 0 ? 'x' : '-'; if (mode_i[ 7] < 2) mod_str[7] = mode_i[ 7] == 0 ? 'r' : '-'; if (mode_i[ 8] < 2) mod_str[8] = mode_i[ 8] == 0 ? 'w' : '-'; if (mode_i[ 9] < 2) mod_str[9] = mode_i[ 9] == 0 ? 'x' : '-'; if (mode_i[10] < 2) if (mode_i[10] == 0) mod_str[3] = (mode_i[ 3] == 0) ? 's' : 'S'; if (mode_i[11] < 2) if (mode_i[11] == 0) mod_str[6] = (mode_i[ 6] == 0) ? 's' : 'S'; if (mode_i[12] < 2) if (mode_i[12] == 0) mod_str[9] = (mode_i[ 9] == 0) ? 't' : 'T'; return 1; } /*---------------------------------------------------------------------------*/ #ifdef _TARGET_GO32_ #include #include int file_get_sfn( const char *in, char *out ) { char src[MAX_PATH+32]; // jtbs char dst[MAX_PATH+32]; // jtbs strcpy( src, in ); __dpmi_regs r; dosmemput(src, strlen (src)+1, __tb); r.x.ax = 0x7160; /* Truename */ r.x.cx = 1; /* Get short name */ r.x.ds = r.x.es = __tb / 16; r.x.si = r.x.di = __tb & 15; __dpmi_int(0x21, &r); if (r.x.flags & 1 || r.x.ax == 0x7100) { strcpy( out, in ); return -1; } dosmemget (__tb, MAX_PATH, dst); strcpy( out, dst ); return 0; } int file_get_lfn( const char *in, char *out ) { char src[MAX_PATH+32]; // jtbs char dst[MAX_PATH+32]; // jtbs strcpy( src, in ); __dpmi_regs r; dosmemput(src, strlen (src)+1, __tb); r.x.ax = 0x7160; /* Truename */ r.x.cx = 2; /* Get long name */ r.x.ds = r.x.es = __tb / 16; r.x.si = r.x.di = __tb & 15; __dpmi_int(0x21, &r); if (r.x.flags & 1 || r.x.ax == 0x7100) { strcpy( out, in ); return -1; } dosmemget (__tb, MAX_PATH, dst); strcpy( out, dst ); return 0; } #endif /* _TARGET_GO32_ */ /*###########################################################################*/ /* eof vfusys.cpp */ vfu-4.10/vfu/vfutools.h0000644000175000001440000000076711005727265013722 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vfutools.h,v 1.7 2005/08/28 14:54:15 cade Exp $ * */ #ifndef _VFUTOOLS_H_ #define _VFUTOOLS_H_ #include "vfu.h" void vfu_tool_classify(); void vfu_tool_rename(); void vfu_tool_seq_rename(); void vfu_tool_replace_sym_org( int swap = 0 ); #endif //_VFUTOOLS_H_ // eof vfutools.h vfu-4.10/vfu/vfucopy.cpp0000644000175000001440000007442211310547772014070 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vfucopy.cpp,v 1.16 2005/06/05 22:00:10 cade Exp $ * */ #include "vfu.h" #include "vfudir.h" #include "vfumenu.h" #include "vfufiles.h" #include "vfuview.h" #include "vfusys.h" #include "vfucopy.h" /**************************************************************************** ** ** globals ** ****************************************************************************/ const char *CM_DESC[] = { "COPY", "MOVE", "LINK" }; char *copy_buff = NULL; int ignore_copy_errors = 0; /* actually it is used for copy/move/erase */ /* clipboard ***************************************************************/ const char *CB_DESC[] = { "COPY", "MOVE", "SYMLINK" }; VTrie Clipboard; CopyInfo clipboard_copy_info; /**************************************************************************** ** ** utilities ** ****************************************************************************/ fsize_t device_free_space( const char *target ) /* user free space, NOT real! */ { struct statfs stafs; statfs( str_file_path( target ), &stafs ); return ((fsize_t)(stafs.f_bsize)) * stafs.f_bfree; } /* * return 0 if src and dst are actually the same file */ int file_is_same( const char *src, const char *dst ) { #ifdef _TARGET_GO32_ char _f1[MAX_PATH]; char _f2[MAX_PATH]; _fixpath( src, _f1 ); _fixpath( dst, _f2 ); ASSERT( _f1[1] == ':' && _f2[1] == ':' ); return (strcasecmp( _f1, _f2 ) != 0); #else struct stat st1; struct stat st2; if(stat( src, &st1 )) return 1; if(stat( dst, &st2 )) return 1; return !( st1.st_dev == st2.st_dev && /* same device */ st1.st_ino == st2.st_ino ); /* same inode */ #endif } /* return 0 if src and dst are on the same device */ int device_is_same( const char *src, const char *dst ) { #ifdef _TARGET_GO32_ char _f1[MAX_PATH]; char _f2[MAX_PATH]; _fixpath( src, _f1 ); _fixpath( dst, _f2 ); ASSERT( _f1[1] == ':' && _f2[1] == ':' ); return ( _f1[0] != _f2[0] ); #else char *ch; struct stat st1; struct stat st2; char _f1[MAX_PATH]; char _f2[MAX_PATH]; strcpy( _f1, src ); ch = strrchr( _f1, '/' ); if (ch == NULL) _f1[0] = 0; else ch[1] = 0; strcat( _f1, "." ); strcpy( _f2, dst ); ch = strrchr( _f2, '/' ); if (ch == NULL) _f2[0] = 0; else ch[1] = 0; strcat( _f2, "." ); if(stat( _f1, &st1 )) return 1; if(stat( _f2, &st2 )) return 1; return !( st1.st_dev == st2.st_dev ); #endif } #ifdef _TARGET_GO32_ int fast_stat( const char* s, struct stat *st ) { /* NOTE: vfu does not use this info, so don't simulate it under DOS/WinXX -- otherwise it is too slow */ _djstat_flags = _STAT_INODE /* don't simulate inode info */ |_STAT_EXEC_EXT /* don't try recognize exe's */ |_STAT_EXEC_MAGIC /* don't try recognize exe's */ |_STAT_DIRSIZE /* don't get dir sizes */ |_STAT_ROOT_TIME; /* don't get root time */ int r = stat( s, st ); _djstat_flags = 0; return r; } #else #define fast_stat stat #endif /*###########################################################################*/ void show_copy_pos( fsize_t a_fc, /* file under copy current pos */ fsize_t a_fa, /* file under copy all size */ CopyInfo *copy_info ) /* totals info */ { char t[16]; fsize_t c1 = a_fc; fsize_t a1 = a_fa; fsize_t c2 = copy_info->current_size; fsize_t a2 = copy_info->files_size; ASSERT( a1 >= 0 && a2 >= 0 ); if ( a1 < 1 ) a1 = 1; if ( a2 < 1 ) a2 = 1; if ( c1 == a1 ) /* hack, every single 100% each is not meaningfull really */ sprintf( t, " %%%5.1f", (100.0*(c1+c2))/a2); else sprintf( t, "%5.1f%%%5.1f", (100.0*c1)/a1, (100.0*(c1+c2))/a2); con_out( con_max_x() - 12, con_max_y(), t, cSTATUS2 ); } /*###########################################################################*/ /* this will return 1 if copy should proceed and 0 if should not if destination exists it asks for interaction or proceed by the last answer... if dest. doesn't exist -- always return 1 */ int over_if_exist( const char* src, const char *dst, CopyInfo* copy_info ) { if ( access( dst, F_OK) ) return 1; /* doesn't exist -- copy... */ if ( copy_info->over_mode == OM_NEVER ) return 0; /* skip it */ if ( copy_info->over_mode == OM_ALWAYS ) return 1; /* overwrite! */ struct stat stat_src; struct stat stat_dst; fast_stat( src, &stat_src ); fast_stat( dst, &stat_dst ); if ( copy_info->over_mode == OM_ALWAYS_IF_MTIME && stat_src.st_mtime > stat_dst.st_mtime ) return 1; /* newer mtime, do it! */ int ch = 0; while(4) { vfu_redraw(); vfu_redraw_status(); VString str; char sttime[32]; char s_t = (stat_src.st_mtime == stat_dst.st_mtime)?'*':' '; // same time char s_s = (stat_src.st_size == stat_dst.st_size)?'*':' '; // same size char t[MAX_PATH]; time_str_compact( stat_src.st_mtime, sttime); str = file_st_size( &stat_src ); str_comma(str); sprintf(t, "SRC: %s%c %11s%c %s", sttime, s_t, str.data(), s_s, src ); say1(t); time_str_compact(stat_dst.st_mtime, sttime); str = file_st_size( &stat_dst ); str_comma(str); sprintf(t, "DST: %s%c %11s%c %s", sttime, s_t, str.data(), s_s, dst ); say2(t); vfu_beep(); vfu_menu_box( "Overwrite", "Y Yes,N No,A Always overwrite,V Never overwrite,I If newer (MODIFY),W Always if newer (MODIFY),D View differences, Abort (ESC)", -1 ); ch = menu_box_info.ec; if( ch == 'D' ) { VString diff = vfu_temp(); VString cmd; cmd = shell_diff + " '" + dst + "' '" + src + "' > " + diff; system( cmd ); vfu_browse( diff ); unlink( diff ); continue; } break; } say1( "" ); say2( "" ); switch (ch) { case 'Y' : return 1; case 'N' : return 0; case 'A' : copy_info->over_mode = OM_ALWAYS; return 1; case 'V' : copy_info->over_mode = OM_NEVER; return 0; case 'I' : return ( stat_src.st_mtime > stat_dst.st_mtime ); break; case 'W' : copy_info->over_mode = OM_ALWAYS_IF_MTIME; return 0; default : copy_info->abort = 1; return 0; } return 1; } /*###########################################################################*/ int vfu_copy_mode( const char* src, const char* dst ) { struct stat st; if (stat( src, &st )) return 1; /* FIXME: or silent? */ /* copy mode */ mode_str_t mode_str; file_get_mode_str( st.st_mode, mode_str ); file_set_mode_str( dst, mode_str ); /* copy access/modify time */ utimbuf utb = { 0, 0 }; utb.actime = st.st_atime; utb.modtime = st.st_mtime; utime( dst, &utb ); /* copy owner/group */ if (opt.copy_keep_mode) chown( dst, st.st_uid, st.st_gid ); return 0; } /*************************************************************************** ** ** COPY/MOVE/SYMLINK ** ****************************************************************************/ /* copy/move ***************************************************************/ // return 0 for ok int __vfu_file_copy( const char* src, const char* dst, CopyInfo* copy_info ) { errno = 0; /* clear error status */ fsize_t size = file_size( src ); if ( size == -1 ) return 1; if (!over_if_exist( src, dst, copy_info )) { copy_info->current_size += size; /* consider it ok */ return copy_info->abort ? CR_ABORT : CR_SKIP; /* ok */ } if ( file_exist( dst ) ) { /* destination file exists */ if ( file_is_same( src, dst ) == 0 ) return CR_SKIP; /* dst is src actually */ __vfu_file_erase( dst ); /* overwrite! */ } /* progress report */ VString str = dst; str = str_dot_reduce( str, con_max_x() - 10 ); str = "COPY TO: " + str; say1( str ); con_out( 1, con_max_y(), copy_info->description, cMESSAGE ); if ( !copy_info->no_free_check && !copy_info->no_info ) { fsize_t dev_free = device_free_space( dst ); if (size > dev_free ) { char t[128]; vfu_beep(); sprintf(t, "Insufficient disk space! Free: %.0f, Required: %.0f", dev_free, size ); say1( t ); say2( dst ); vfu_menu_box( "Error prompt", "C Continue anyway,S Skip file,N No free space check, Abort (ESC)", -1 ); switch (menu_box_info.ec) { case 'C' : break; case 'S' : return CR_SKIP; break; /* skip it */ case 'N' : copy_info->no_free_check = 1; break; default : copy_info->abort = 1; return CR_ABORT; break; /* abort! */ } } } ASSERT( copy_buff ); if ( copy_buff == NULL ) return 1; FILE *f1 = NULL; FILE *f2 = NULL; f1 = fopen( src, "rb" ); if (!f1) return 1; f2 = fopen( dst, "wb" ); if (!f2) { fclose(f1); return 1; } long z = 0; fsize_t cp = 0; /* current position in file */ int aborted = 0; do { if ( vfu_break_op() ) { aborted = 1; break; } z = fread(copy_buff, 1, COPY_BUFFER_SIZE, f1); if (z > 0) z = fwrite(copy_buff, 1, z, f2); if (z == -1) { fclose(f1); fclose(f2); unlink( dst ); /* remove dst if partially copied */ return 1; } cp += z; ASSERT( cp <= size ); show_copy_pos( cp, size, copy_info ); } while (z == COPY_BUFFER_SIZE); fclose(f1); fclose(f2); if ( cp < size ) { unlink( dst ); /* remove dst if partially copied */ if ( aborted ) return CR_ABORT; return 1; } ASSERT( cp == size ); if ( vfu_copy_mode( src, dst ) ) return 1; copy_info->current_size += size; show_copy_pos( 1, 1, copy_info ); return 0; } /*---------------------------------------------------------------------------*/ int __vfu_file_move( const char* src, const char* dst, CopyInfo* copy_info ) { errno = 0; /* clear error status */ if ( device_is_same( src, dst ) == 0 ) { /* same device */ if (!over_if_exist( src, dst, copy_info )) return copy_info->abort ? CR_ABORT : CR_SKIP; /* ok */ if ( file_exist( dst ) ) { if ( file_is_same( src, dst ) == 0 ) return CR_SKIP; /* dst is src actually */ /* FIXME: what if dst is symlink? */ if ( __vfu_file_erase( dst ) ) return 1; } if ( rename( src, dst ) ) return 1; } else { /* src and dst devices are different */ say2( "MOVING FILE" ); int r; r = __vfu_file_copy( src, dst, copy_info ); if ( r == CR_SKIP ) return CR_SKIP; if ( r == CR_ABORT ) return CR_ABORT; if ( r ) return 1; r = __vfu_file_erase( src ); if ( r && r != CR_SKIP ) return 1; } return 0; } /*---------------------------------------------------------------------------*/ int __vfu_dir_copy( const char* src, const char* dst, CopyInfo* copy_info ) { errno = 0; /* clear error status */ VString fname_src; /* used for directory entries */ VString fname_dst; /* used for directory entries */ if ( vfu_break_op() ) return CR_ABORT; /* canceled */ if ( file_is_same( src, dst ) == 0 ) return CR_SKIP; if ( make_path( dst ) ) { if ( ignore_copy_errors ) return CR_ABORT; /* cancel operation */ say1( dst ); say2errno(); vfu_menu_box( "Create dir error", "C Continue anyway,I Ignore further errors, Abort (ESC)", -1 ); if ( menu_box_info.ec != 'C' ) return CR_ABORT; /* cancel operation */ if ( menu_box_info.ec != 'I' ) { ignore_copy_errors = 1; return CR_ABORT; /* cancel operation */ } } DIR *dir; dirent *de; dir = opendir( src ); if (!dir) return 1; /* FIXME: report error? */ while( (de = readdir(dir)) ) { if (strcmp( de->d_name, ".") == 0) continue; if (strcmp( de->d_name, "..") == 0) continue; fname_src = src; fname_src += "/"; fname_src += de->d_name; fname_dst = dst; fname_dst += "/"; fname_dst += de->d_name; while(4) { int r = __vfu_copy( fname_src, fname_dst, copy_info ); if ( r == CR_ABORT ) { closedir(dir); return CR_ABORT; } if ( r && r != CR_SKIP ) { if ( ignore_copy_errors ) break; say1( fname_dst ); say2errno(); vfu_menu_box( "Copy/Move/SymLink error", "T Try again,S Skip/continue,I Ignore further errors, Abort (ESC)" ); if ( menu_box_info.ec == 'T' ) continue; /* while(4) */ else if ( menu_box_info.ec == 'S' ) break; /* consider it ok */ if ( menu_box_info.ec == 'I' ) { ignore_copy_errors = 1; break; } else { closedir(dir); return CR_ABORT; } } else break; /* copy (r) is ok -- exit error (while(4)) loop */ } /* while(4) */ } /* readdir() */ closedir( dir ); if ( vfu_copy_mode( src, dst ) ) return 1; return 0; } /*---------------------------------------------------------------------------*/ int __vfu_dir_move( const char* src, const char* dst, CopyInfo* copy_info ) { errno = 0; /* clear error status */ if ( file_is_same( src, dst ) == 0 ) return CR_SKIP; if ( device_is_same( src, dst ) == 0 ) { /* same device */ if ( rename( src, dst ) ) return 1; } else { /* different devices */ if ( __vfu_dir_copy( src, dst, copy_info ) ) { say1( "There were errors or files are skipped, you have to erase dir manually" ); return 1; } /* NOTE: whatever __vfu_dir_copy() returns it is considered as error even if it is CR_SKIP!, i.e. directory never erased unless everything went ok */ if ( __vfu_dir_erase( src ) ) return 1; } return 0; } /*---------------------------------------------------------------------------*/ int __vfu_link_copy( const char* src, const char* dst, CopyInfo* copy_info ) { #ifdef _TARGET_GO32_ ASSERT(!"Symlinks are not supported for this platform!"); return 0; #else errno = 0; /* clear error status */ if (!over_if_exist( src, dst, copy_info )) return copy_info->abort ? CR_ABORT : CR_SKIP; /* ok */ if ( file_exist( dst ) ) { /* destination file exists */ if ( file_is_same( src, dst ) == 0 ) return CR_SKIP; /* dst is src actually */ __vfu_file_erase( dst ); /* overwrite! */ } char t[MAX_PATH]; int z = readlink( src, t, sizeof(t)-1); if (z < 1) return 1; t[z] = 0; if (symlink( t, dst ) == -1) return 1; /* FIXME: should we keep src mode? does links have this? */ return 0; #endif /* _TARGET_UNIX_ */ } /*---------------------------------------------------------------------------*/ int __vfu_link_move( const char* src, const char* dst, CopyInfo* copy_info ) { int r; r = __vfu_link_copy( src, dst, copy_info ); if ( r == CR_SKIP ) return CR_SKIP; if ( r ) return 1; r = __vfu_link_erase( src ); if ( r && r != CR_SKIP ) return 1; return 0; } /* erase *******************************************************************/ // return 0 for ok, CR_ABORT for cancel, else for error int __vfu_dir_erase( const char* target, fsize_t* bytes_freed ) { errno = 0; /* clear error status */ VString fname; /* used for directory entries */ VString s; if ( vfu_break_op() ) return CR_ABORT; /* canceled */ if (!file_exist( target )) return 1; /* make it writeable so we can erase files in it */ file_set_mode_str( target, MODE_WRITE_ON ); DIR *dir; dirent *de; dir = opendir( target ); if (!dir) return 1; /* FIXME: report error? */ while( (de = readdir(dir)) ) { if (strcmp( de->d_name, ".") == 0) continue; if (strcmp( de->d_name, "..") == 0) continue; fname = target; fname += "/"; fname += de->d_name; while(4) { /* progress report */ say1( fname ); int r = __vfu_erase( fname, bytes_freed ); if ( r == CR_ABORT ) { closedir(dir); return CR_ABORT; } if ( r && r != CR_SKIP ) { if ( ignore_copy_errors ) break; say1( fname ); say2errno(); vfu_menu_box( "Erase error", "T Try again,S Skip/continue,I Ignore further errors, Abort (ESC)" ); if ( menu_box_info.ec == 'T' ) continue; /* while(4) */ else if ( menu_box_info.ec == 'S' ) break; /* consider it ok */ if ( menu_box_info.ec == 'I' ) { ignore_copy_errors = 1; break; } else { closedir(dir); return CR_ABORT; } } else break; } /* while(4) */ } /* readdir() */ closedir( dir ); /* show bytes freed if required */ if ( bytes_freed ) { VString t; t.fi( *bytes_freed ); str_comma( t ); t = "ERASE: " + t + " bytes freed."; say2(t); } say1( target ); return ( rmdir( target ) != 0 ); } /*---------------------------------------------------------------------------*/ int __vfu_file_erase( const char* target, fsize_t* bytes_freed ) { errno = 0; /* clear error status */ #ifdef _TARGET_GO32_ /* under dos write access rules and delete protection so we have to remove it first */ file_set_mode_str( target, MODE_WRITE_ON ); #endif fsize_t target_size = 0; if ( bytes_freed ) target_size = file_size( target ); int r = unlink( target ); if ( r == 0 && bytes_freed ) *bytes_freed += target_size; return (r != 0); } /*---------------------------------------------------------------------------*/ int __vfu_link_erase( const char* target, fsize_t* bytes_freed ) { errno = 0; /* clear error status */ #ifdef _TARGET_GO32_ return 0; /* always ok under dos */ #else return (unlink( target ) != 0); #endif } /* shells, call __*_*_*() above ********************************************/ int __vfu_copy( const char* src, const char* dst, CopyInfo* copy_info ) { int r = 0; if ( file_is_link( src ) ) r = __vfu_link_copy( src, dst, copy_info ); /* symlink */ else if ( file_is_dir( src ) ) r = __vfu_dir_copy( src, dst, copy_info ); /* directory */ else r = __vfu_file_copy( src, dst, copy_info ); /* regular file */ return r; } /*---------------------------------------------------------------------------*/ int __vfu_move( const char* src, const char* dst, CopyInfo* copy_info ) { int r = 0; if ( file_is_link( src ) ) r = __vfu_link_move( src, dst, copy_info ); /* symlink */ else if ( file_is_dir( src ) ) r = __vfu_dir_move( src, dst, copy_info ); /* directory */ else r = __vfu_file_move( src, dst, copy_info ); /* regular file */ return r; } /*---------------------------------------------------------------------------*/ int __vfu_symlink( const char* src, const char* dst, CopyInfo* copy_info ) { errno = 0; /* clear error status */ if (!over_if_exist( src, dst, copy_info )) return copy_info->abort ? CR_ABORT : CR_SKIP; /* ok */ if ( file_exist( dst ) ) { if ( file_is_same( src, dst ) == 0 ) return CR_SKIP; /* dst is src actually */ /* FIXME: what if dst is symlink? */ if ( __vfu_file_erase( dst ) ) return 1; } int r = symlink( src, dst ); return ( r != 0 ); } /*---------------------------------------------------------------------------*/ int __vfu_erase( const char* target, fsize_t* bytes_freed ) { int r = 0; if ( file_is_link( target ) ) r = __vfu_link_erase( target, bytes_freed ); /* symlink */ else if ( file_is_dir( target ) ) r = __vfu_dir_erase( target, bytes_freed ); /* directory */ else r = __vfu_file_erase( target, bytes_freed ); /* regular file */ return r; } /* high-level interface functions ******************************************/ void __copy_calc_totals( CopyInfo ©_info, int a_one ) { if ( opt.copy_calc_totals ) { copy_info.files_size = vfu_update_sel_size( a_one ); copy_info.files_count = a_one ? 1 : sel_count; /* not used */ copy_info.current_size = 0; copy_info.current_count = 0; /* not used */ if ( copy_info.files_size == -1 ) copy_info.no_info = 1; } else copy_info.no_info = 1; } void vfu_copy_files( int a_one, int a_mode ) { ignore_copy_errors = 0; if ( files_count == 0 ) { say1( "No files" ); return; } char t[MAX_PATH]; ASSERT( a_mode == CM_COPY || a_mode == CM_MOVE || a_mode == CM_LINK ); #ifdef _TARGET_GO32_ if ( a_mode == CM_LINK ) { say1( "LINK: SymLinks are NOT supported on this platform!" ); return; } #endif CopyInfo copy_info; if ( opt.copy_calc_totals == 2 ) /* PRELIMINARY copy calc totals */ __copy_calc_totals( copy_info, a_one ); VString target; if( opt.default_copy_to_cwd ) target = work_path; else target = opt.last_copy_path[ a_mode ]; const char* cm_mode_str[] = { "COPY", "MOVE", "LINK" }; VString str = cm_mode_str[ a_mode ]; if ( a_one ) str = str + " `" + files_list[FLI]->name_ext() + "' to:"; else str += " SELECTED FILES/DIRS to:"; if ( !vfu_get_dir_name( str, target ) ) return; expand_path( target, t ); /* str_reduce_path( NULL, t ); */ str_fix_path( t ); str_trim_right( t, 1 ); if ( file_exists( t ) && !file_is_dir( t ) ) { say1( "Target is file, not directory!" ); say2( t ); vfu_menu_box( "Error prompt", "C Continue anyway,E Erase first, Abort (ESC)", -1 ); if ( menu_box_info.ec == 'E' ) { unlink( t ); menu_box_info.ec = 'C'; } if ( menu_box_info.ec != 'C' ) return; /* abort */ } str_fix_path( t ); target = t; strcpy( opt.last_copy_path[ a_mode ], target ); if ( opt.copy_calc_totals == 1 ) /* copy calc totals if not PRELIMINARY */ __copy_calc_totals( copy_info, a_one ); copy_info.no_free_check = !opt.copy_free_space_check; copy_info.over_mode = OM_ASK; /* 0 */ copy_info.abort = 0; if ( !copy_info.no_free_check && !copy_info.no_info ) { fsize_t dev_free = device_free_space( target ); if (copy_info.files_size > dev_free ) { vfu_beep(); sprintf(t, "Insufficient disk space! Free: %.0f, Required: %.0f", dev_free, copy_info.files_size ); say1( t ); say2( target ); vfu_menu_box( "Error prompt", "C Continue anyway, Abort (ESC)", -1 ); if ( menu_box_info.ec != 'C' ) return; /* abort */ } } /* free space check */ copy_info.description = "FILE OPERATION: "; copy_info.description += cm_mode_str[ a_mode ]; copy_info.description += ": "; sprintf( t, "%.0f", copy_info.files_size ); str_comma( t ); copy_info.description += t; copy_info.description += " bytes."; ASSERT( !copy_buff ); copy_buff = new char[1024*1024]; ASSERT( copy_buff ); if (copy_buff == NULL) { say1( "Copy error: cannot allocate copy buffer" ); return; } int z; for ( z = 0; z < files_count; z++ ) { if ( vfu_break_op() ) break; /* cancel operation */ TF *fi = files_list[z]; if ( a_one && z != FLI ) continue; /* if one and not current -- skip */ if ( !a_one && !fi->sel ) continue; /* if not one and not selected -- skip */ /* copy logic: src -- is full current item path dst -- is target + name-ext only! */ VString src = fi->full_name(); VString dst = target; dst += fi->name_ext(); int r = 0; if ( a_mode == CM_COPY ) r = __vfu_copy( src, dst, ©_info ); else if ( a_mode == CM_MOVE ) r = __vfu_move( src, dst, ©_info ); else if ( a_mode == CM_LINK ) r = __vfu_symlink( src, dst, ©_info ); else ASSERT(!"Bad copy mode"); if ( r == 0 ) { if ( a_mode == CM_MOVE ) { delete fi; files_list[z] = NULL; } } else if ( r != CR_SKIP && r != CR_ABORT ) { say1( target ); say2errno(); vfu_menu_box( "Copy/Move error", "C Continue operation, Abort (ESC)" ); if ( menu_box_info.ec != 'C' ) r = CR_ABORT; } if ( r == CR_ABORT ) break; /* cancel operation */ } /* for files_list[] */ if ( a_mode == CM_MOVE ) vfu_pack_files_list(); update_status(); do_draw = 2; ASSERT( copy_buff ); delete [] copy_buff; copy_buff = NULL; say1( "" ); /* show bytes copied */ if ( copy_info.current_size > 0 ) { /* i.e. only if there *are* some bytes copied :) */ str.fi( copy_info.current_size ); str_comma( str ); str = copy_info.description + " DONE: " + str + " bytes copied."; } else { str = copy_info.description; str += " DONE"; } say2( str ); ignore_copy_errors = 0; } /*---------------------------------------------------------------------------*/ void vfu_erase_files( int a_one ) { ignore_copy_errors = 0; if ( files_count == 0 ) { say1( "No files" ); return; } fsize_t bytes_freed = 0; fsize_t *bytes_freed_ptr = opt.bytes_freed ? &bytes_freed : NULL; VString str; fsize_t erase_size = vfu_update_sel_size( a_one ); if ( erase_size != -1 ) { str.fi( erase_size ); str_comma( str ); } else { str = "( NO INFO! )"; } vfu_beep(); str = "ERASE: " + str + " bytes in: ( ENTER to confirm, other key to cancel )"; say1( str ); if ( a_one ) say2( files_list[FLI]->full_name() ); else say2( "SELECTED FILES/DIRS" ); char ch = con_getch(); say1(""); say2(""); if (ch != 13) return; int z; for ( z = 0; z < files_count; z++ ) { if ( vfu_break_op() ) break; /* cancel operation */ TF *fi = files_list[z]; if ( a_one && z != FLI ) continue; if ( !a_one && !fi->sel ) continue; VString target = fi->full_name(); int r = __vfu_erase( target, bytes_freed_ptr ); if ( r == 0 ) { delete fi; files_list[z] = NULL; } else if ( r != CR_ABORT && !ignore_copy_errors ) { say1( target ); say2errno(); vfu_menu_box( "Erase error", "C Continue operation,I Ignore further errors, Abort (ESC)" ); if ( menu_box_info.ec != 'C' && menu_box_info.ec != 'I' ) r = CR_ABORT; if ( menu_box_info.ec == 'I' ) ignore_copy_errors = 1; } if ( r == CR_ABORT ) break; /* cancel operation */ } /* for files_list[] */ vfu_pack_files_list(); update_status(); do_draw = 2; say1(""); /* show bytes freed if required */ if ( opt.bytes_freed ) { str.fi( bytes_freed ); str_comma( str ); str = "ERASE DONE: " + str + " bytes freed."; say2( str ); } else say2( "ERASE DONE" ); ignore_copy_errors = 0; } /*************************************************************************** ** ** CLIPBOARD ** ****************************************************************************/ void clipboard_add() { if( sel_count == 0 ) { say( 1, cINFO, "CLIPBOARD: no files selected, %d files already in clipboard", clipboard_copy_info.files_count ); return; } Clipboard.undef(); clipboard_copy_info.reset(); VString keep = "1"; int z; for ( z = 0; z < files_count; z++ ) { TF *fi = files_list[z]; if ( !fi->sel ) continue; Clipboard[ fi->full_name() ] = keep; } __copy_calc_totals( clipboard_copy_info, 0 ); clipboard_copy_info.no_free_check = !opt.copy_free_space_check; clipboard_copy_info.over_mode = OM_ASK; /* 0 */ clipboard_copy_info.abort = 0; say( 1, cINFO, "CLIPBOARD: %d files added.", clipboard_copy_info.files_count ); say2( "" ); } void clipboard_paste( int mode ) { VArray va = Clipboard.keys(); ASSERT( mode == CLIPBOARD_COPY || mode == CLIPBOARD_MOVE || mode == CLIPBOARD_SYMLINK ); ASSERT( !copy_buff ); copy_buff = new char[1024*1024]; ASSERT( copy_buff ); if (copy_buff == NULL) { say1( "Copy error: cannot allocate copy buffer" ); return; } va.reset(); const char* ps; while( (ps = va.next()) ) { VString dst = work_path + str_file_name_ext( ps ); int r; if ( mode == CLIPBOARD_SYMLINK ) r = __vfu_symlink( ps, dst, &clipboard_copy_info ); else if ( mode == CLIPBOARD_MOVE ) r = __vfu_move( ps, dst, &clipboard_copy_info ); else // if ( mode == CLIPBOARD_COPY ) r = __vfu_copy( ps, dst, &clipboard_copy_info ); if ( r == 0 ) clipboard_copy_info.ok_count++; if ( r != 0 && r != CR_SKIP && r != CR_ABORT ) { say1( dst + r ); say2errno(); vfu_menu_box( "Copy/Move/Symlink error", "C Continue operation, Abort (ESC)" ); if ( menu_box_info.ec != 'C' ) r = CR_ABORT; } if ( r == CR_ABORT ) break; // cancel operation } ASSERT( copy_buff ); delete [] copy_buff; copy_buff = NULL; vfu_rescan_files( 0 ); say( 1, cINFO, "CLIPBOARD: %s: %d of %d files processed ok", CB_DESC[ mode ], clipboard_copy_info.ok_count, clipboard_copy_info.files_count ); if ( mode == CLIPBOARD_MOVE ) clipboard_clear(); } void clipboard_clear() { if( clipboard_copy_info.files_count ) say( 2, cINFO, "CLIPBOARD: %d files removed", clipboard_copy_info.files_count ); else say( 2, cINFO, "CLIPBOARD: empty" ); Clipboard.undef(); clipboard_copy_info.reset(); } void clipboard_view() { mb = Clipboard.keys(); if( mb.count() == 0 ) { say2( "CLIPBOARD: empty" ); return; } vfu_menu_box( 5, 5, "File Clipboard Content" ); } void clipboard_menu( int act ) { if ( act == 0 ) { mb.undef(); mb.push( "A Add files to the clipboard" ); mb.push( "P Copy files here" ); mb.push( "O Move files here" ); mb.push( "L Symlink files here" ); mb.push( "E Clear clipboard" ); mb.push( "V View clipboard" ); VString fcnt = clipboard_copy_info.files_count; str_comma( fcnt ); VString fsize = clipboard_copy_info.files_size; str_comma( fsize ); mb.push( "--- " + fcnt + " files, " + fsize + " bytes" ); if ( vfu_menu_box( 5, 5, "File Clipboard " + fcnt + " files, " + fsize + " bytes" ) == -1 ) return; act = menu_box_info.ec; } act = toupper( act ); switch( act ) { case 'A': clipboard_add(); break; case 'P': clipboard_paste( CLIPBOARD_COPY ); break; case 'O': clipboard_paste( CLIPBOARD_MOVE ); break; case 'L': clipboard_paste( CLIPBOARD_SYMLINK ); break; case 'E': clipboard_clear(); break; case 'V': clipboard_view(); break; } } /*---------------------------------------------------------------------------*/ vfu-4.10/vfu/vfufiles.cpp0000644000175000001440000003513311310550046014200 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vfufiles.cpp,v 1.17 2006/08/05 20:15:13 cade Exp $ * */ #include "vfu.h" #include "vfufiles.h" #include "vfuopt.h" #include "vfuview.h" #include "vfumenu.h" #include "vfudir.h" /*###########################################################################*/ static char __file_stat_type_buf[3]; const char* file_type_str( mode_t mode, int is_link ) { strcpy(__file_stat_type_buf, "--"); if (S_ISDIR(mode) && is_link) strcpy(__file_stat_type_buf, "<>"); else // box, but not exact if (S_ISBLK(mode) ) strcpy(__file_stat_type_buf, "=="); else // block, stacked if (S_ISCHR(mode) ) strcpy(__file_stat_type_buf, "++"); else // like dots, separates if (S_ISFIFO(mode)) strcpy(__file_stat_type_buf, "()"); else // () pipe mimic if (S_ISSOCK(mode)) strcpy(__file_stat_type_buf, "@@"); else // internet if (is_link ) strcpy(__file_stat_type_buf, "->"); else // points, link if (S_ISDIR (mode)) strcpy(__file_stat_type_buf, "[]"); else // box if ((mode & S_IXOTH)||(mode & S_IXGRP)||(mode & S_IXUSR)) strcpy(__file_stat_type_buf, "**"); else // * marks executables ; return __file_stat_type_buf; } /*###########################################################################*/ /* actually this function is called only when 'R' key is pressed it calls vfu_read_files() and keeps selection and tag mark position update: now it is called and from vfu_shell when %r */ void vfu_rescan_files( int a_recursive ) { int z; int old_fli = FLI; int old_flp = FLP; VString keep = "1"; /* save selection, remember which files are selected */ VTrie savea; int savea_count = 0; if ( opt.keep_selection && sel_count > 0 ) { for ( z = 0; z < files_count ; z++) if ( files_list[z]->sel ) { savea[ files_list[z]->name() ] = keep; savea_count++; } } vfu_read_files( a_recursive ); /* restore selection */ if ( opt.keep_selection && savea_count > 0 ) { for ( z = 0; z < files_count ; z++ ) if ( savea.exists( files_list[z]->name() ) ) files_list[z]->sel = 1; update_status(); } file_list_index.set_page( old_flp ); file_list_index.set_pos( old_fli ); vfu_nav_update_pos(); } /*---------------------------------------------------------------------------*/ void vfu_read_files( int a_recursive ) { say1( "Rescanning files..." ); int z; /* clear files list -- delete all found entries */ for ( z = 0; z < MAX_FILES ; z++) if (files_list[z]) { delete files_list[z]; files_list[z] = NULL; } /* vfu_add_file() will need this */ files_count = 0; /* FIXME: perhaps we could check work_mode here? ... anyway will ASSERT it */ if ( archive_name != "" ) { ASSERT( work_mode == WM_ARCHIVE ); vfu_read_archive_files( a_recursive ); } else if ( external_panelizer != "" ) { ASSERT( work_mode == WM_NORMAL ); vfu_read_external_files(); } else if ( list_panelizer.count() ) { ASSERT( work_mode == WM_NORMAL ); vfu_read_pszlist_files(); } else { ASSERT( work_mode == WM_NORMAL ); vfu_read_local_files( a_recursive ); } /* update scroll parameters */ file_list_index.set_min_max( 0, files_count - 1 ); file_list_index.set_pagesize( con_max_y() - 7 ); update_status(); vfu_nav_update_pos(); vfu_sort_files(); vfu_drop_all_views(); FGO(0); /* this ignores the sort keep list position */ say1( "" ); say2( "" ); do_draw = 2; } /*---------------------------------------------------------------------------*/ int vfu_add_file( const char* fname, const struct stat *st, int is_link ) { if ( files_count == MAX_FILES ) return 1; VString ne = str_file_name_ext( fname ); if ( ne == "." || ne == ".." ) return 0; /* now try to hide `system/special' files */ if ( !opt.show_hidden_files ) { #ifdef _TARGET_GO32_ mode_str_t mode_str; file_get_mode_str( st->st_mode, mode_str ); if ( mode_str[7] == 'H' || mode_str[8] == 'S' ) return 0; #else if ( ne[0] == '.' ) return 0; #endif } if ( !S_ISDIR( st->st_mode ) ) /* mask is not allowed for dirs */ if ( vfu_fmask_match( ne ) ) return 0; /* doesn't match the mask */ TF *fi = new TF( fname, st, is_link ); files_list[files_count] = fi; files_count++; /* get dir sizes for directories, not symlinks */ if ( work_mode == WM_NORMAL && fi->is_dir() && !fi->is_link() ) fi->set_size( size_cache_get( fi->full_name( 1 ) ) ); /* get dir sizes for directories, symlinks */ if ( work_mode == WM_NORMAL && fi->is_dir() && fi->is_link() ) { char t[MAX_PATH]; expand_path( fi->full_name( 1 ), t ); str_fix_path( t ); fi->set_size( size_cache_get( t ) ); } /* show progress ... */ if ( files_count % 123 == 0 ) { sprintf( ne, "Rescanning files... (%5d) ", files_count); say1( ne ); } return 0; } /*---------------------------------------------------------------------------*/ int __vfu_ftw_add( const char* origin, const char* fname, const struct stat *st, int is_link, int flag ) { if ( vfu_break_op() ) return 1; if ( flag == FTWALK_DX ) return 0; /* exit directory */ VString str = fname; str_trim_left( str, str_len( origin ) ); return vfu_add_file( str, st, file_is_link( fname ) ); } void vfu_read_local_files( int a_recursive ) { ftwalk( ".", __vfu_ftw_add, a_recursive ? -1 : 1 ); if ( opt.auto_mount && files_count == 1 && ( FNMATCH( files_list[0]->name(), "automount" ) == 0 || FNMATCH( files_list[0]->name(), ".automount" ) == 0 ) ) { VString tmp_file_name; tmp_file_name += tmp_path; tmp_file_name += "vfu_automount_error."; tmp_file_name += user_id_str; VString str = work_path; chdir( "/" ); str = "mount " + str + " 2> " + tmp_file_name; say1( "AutoMount point detected, executing:" ); say2( str ); int err; if ( (err = system( str )) == 0) { //--------------- delete files_list[0]; files_list[0] = NULL; sel_count = 0; sel_size = 0; files_size = 0; files_count = 0; //--------------- chdir( work_path ); ftwalk( ".", __vfu_ftw_add, a_recursive ? -1 : 1 ); } else { char t[128]; FILE *f = fopen( tmp_file_name, "r" ); t[0] = 0; fgets( t, 100, f ); fclose(f); str_tr( t, "\n\r", " " ); say1( "AutoMount failed! ( press ESC ) reason:" ); say2( t ); con_beep(); con_getch(); } unlink( tmp_file_name ); } } /*---------------------------------------------------------------------------*/ void vfu_read_external_files() { /* FIXME: this is not completely correct: lines read are in most cases far less in length that MAX_PATH which is about 2-4K so in general case this will work fine... */ char tmp[MAX_PATH]; char tmp1[MAX_PATH]; if ( external_panelizer == "" ) return; say1( "Rescanning files...(external panelizer)" ); FILE *f = popen( external_panelizer, "r" ); while( fgets( tmp, MAX_PATH-1, f ) ) { str_cut( tmp, " \t\n\r" ); while( str_word( tmp, " \t:;", tmp1 ) ) { if (access( tmp1, F_OK )) continue; struct stat st; stat( tmp1, &st ); say2( tmp1 ); if ( vfu_add_file( tmp1, &st, file_is_link( tmp1 ) ) ) { pclose(f); external_panelizer = ""; /* reset -- there's no reload on this */ return; } } } pclose( f ); external_panelizer = ""; /* reset -- there's no reload on this */ } /*---------------------------------------------------------------------------*/ void vfu_read_pszlist_files() { int z; for ( z = 0; z < list_panelizer.count(); z++ ) { const char* pc = list_panelizer[z]; struct stat st; stat( pc, &st ); vfu_add_file( pc, &st, file_is_link( pc ) ); } list_panelizer.undef(); /* reset -- there's no reload on this */ } /*---------------------------------------------------------------------------*/ int vfu_fmask_match( const char* fname ) { int z; for(z = 0; z < files_mask_array.count(); z++) if ( FNMATCH(files_mask_array[z],fname) == 0) return 0; return 1; } /*###########################################################################*/ void vfu_pack_files_list() { int pos = 0; int next = 0; while( pos < files_count ) { if ( files_list[pos] == NULL ) { next = pos + 1; while ( next < files_count && files_list[next] == NULL ) next++; if ( next < files_count && files_list[next] != NULL ) { files_list[pos] = files_list[next]; files_list[next] = NULL; } else break; } else pos++; } files_count = 0; while ( files_count < MAX_FILES && files_list[files_count] ) files_count++; /* update scroll parameters */ file_list_index.set_min_max( 0, files_count - 1 ); file_list_index.set_pagesize( con_max_y() - 7 ); update_status(); vfu_nav_update_pos(); do_draw = 2; } /*###########################################################################*/ /* this compares Name20 and Name3 and returns second as smaller :) (or so) */ int namenumcmp( const char* s1, const char* s2 ) { VRegexp re1( "^(.*)([0123456789]+)(\\.(.*))?$" ); VRegexp re2( "^(.*)([0123456789]+)(\\.(.*))?$" ); if ( re1.m(s1) && re2.m(s2) ) { VString ss1; VString ss2; sprintf( ss1, "%020d", atoi(re1[2]) ); sprintf( ss2, "%020d", atoi(re1[2]) ); ss1 = re1[1] + ss1 + re1[3]; ss2 = re2[1] + ss2 + re2[3]; return pathcmp( ss1, ss2 ); } else { return pathcmp( s1, s2 ); } } /*---------------------------------------------------------------------------*/ int ficmp(int nf1, TF *f2) { TF *f1 = files_list[nf1]; int z = 0; /* keep dirs on top */ if ( f1->is_dir() && !f2->is_dir()) return -1; if (!f1->is_dir() && f2->is_dir()) return 1; z = 0; if (opt.sort_order == 'U') return 0; switch (opt.sort_order) { case 'N' : z = pathcmp(f1->name(), f2->name()); break; case 'M' : z = namenumcmp(f1->name(), f2->name()); break; case 'E' : z = pathcmp(f1->ext(), f2->ext()); break; case 'S' : z = (f2->size() < f1->size()) - (f2->size() > f1->size()); break; case 'T' : z = f1->st()->st_mtime - f2->st()->st_mtime; break; case 'H' : z = f1->st()->st_ctime - f2->st()->st_ctime; break; case 'C' : z = f1->st()->st_atime - f2->st()->st_atime; break; case 'A' : z = strcmp( f1->mode_str(), f2->mode_str() ); break; case 'O' : z = (f2->st()->st_uid > f1->st()->st_uid) - (f2->st()->st_uid < f1->st()->st_uid); if ( z == 0 ) z = (f2->st()->st_gid > f1->st()->st_gid) - (f2->st()->st_gid < f1->st()->st_gid); break; case 'G' : z = (f2->st()->st_gid > f1->st()->st_gid) - (f2->st()->st_gid < f1->st()->st_gid); if ( z == 0 ) z = (f2->st()->st_uid > f1->st()->st_uid) - (f2->st()->st_uid < f1->st()->st_uid); break; case 'Y' : z = strcmp( f1->type_str(), f2->type_str() ); break; default : ASSERT( !"Non valid sort order (opt.sort_order)" ); break; } if (z == 0) z = pathcmp(f1->name(), f2->name()); ASSERT( opt.sort_direction == 'A' || opt.sort_direction == 'D' ); if (z) { z = (z > 0) - (z < 0); if (opt.sort_direction == 'D') return -z; } return z; } /*---------------------------------------------------------------------------*/ void __vfu_sort(int l, int r) { int i; int j; int mid; TF *fi; TF *midf; i = l; j = r; mid = ((l+r) / 2); midf = files_list[mid]; do { while (ficmp(i,midf) == -1) i++; while (ficmp(j,midf) == 1) j--; if (i <= j) { fi = files_list[i]; files_list[i] = files_list[j]; files_list[j] = fi; i++; j--; } } while (i <= j); if (l < j) __vfu_sort(l, j); if (i < r) __vfu_sort(i, r); } /*---------------------------------------------------------------------------*/ void vfu_sort_files() { if (!files_count) return; VString str = files_list[FLI]->name(); __vfu_sort( 0, files_count - 1 ); do_draw = 1; if ( str != "" ) { int z = 0; for (z = 0; z < files_count; z++) if ( str == files_list[z]->name() ) { FGO(z); break; } } } /*---------------------------------------------------------------------------*/ void vfu_arrange_files() { int _ord; int _rev; mb.undef(); mb.push( "N Name" ); mb.push( "M Name### (RTFM)" ); mb.push( "E Extension" ); mb.push( "S Size" ); mb.push( "T Modify Time" ); mb.push( "H Change Time" ); mb.push( "C Access Time" ); mb.push( "A Attr/mode" ); mb.push( "O Owner" ); mb.push( "G Group" ); mb.push( "Y Type (TP)" ); mb.push( "U Unsorted" ); mb.push( "---" ); mb.push( "R Randomize" ); mb.push( "V Move Entry" ); mb.push( "---" ); mb.push( "D Modify Time (compat)" ); if ( vfu_menu_box( 50, 5, "Arrange" ) == -1 ) return; _ord = menu_box_info.ec; if ( _ord == 'D' ) _ord = 'T'; if (_ord == 'V' ) { vfu_file_entry_move(); return; } if (_ord == 'R') { /* Fisher-Yates shuffle */ int i = files_count - 1; while( i >= 0 ) { int j = rand() % ( i + 1 ); TF *tmp; tmp = files_list[i]; files_list[i] = files_list[j]; files_list[j] = tmp; i--; } do_draw = 2; return; } mb.undef(); mb.push( "A Ascending"); mb.push( "D Descending" ); if ( vfu_menu_box( 50, 5, "Order" ) == -1 ) return; _rev = menu_box_info.ec; opt.sort_order = _ord; opt.sort_direction = _rev; say1("Sorting..."); vfu_sort_files(); say1(""); } /*###########################################################################*/ void vfu_file_entry_move() { char t[128]; sprintf( t, "MOVE/REORDER File entry: %s", files_list[FLI]->name() ); say1( t ); say2( "Use Up/Down Arrows to reorder, ESC,ENTER when done." ); int key = 0; while( key != 13 && key != 27 ) // enter or esc { int old = FLI; switch(key) { case KEY_UP : vfu_nav_up(); break; case KEY_DOWN : vfu_nav_down(); break; } if ( old != FLI ) { TF* fi = files_list[old]; files_list[old] = files_list[FLI]; files_list[FLI] = fi; vfu_redraw(); } key = con_getch(); } say1( " " ); say2( " " ); } /*###########################################################################*/ /* eof vfufiles.cpp */ vfu-4.10/vfu/vfu.cpp0000644000175000001440000023612211310547667013175 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vfu.cpp,v 1.53 2007/12/16 13:52:50 cade Exp $ * */ #include "vfu.h" #include "vfuopt.h" #include "vfufiles.h" #include "vfucopy.h" #include "vfudir.h" #include "vfuview.h" #include "vfumenu.h" #include "vfuuti.h" #include "vfusys.h" #include "vfuarc.h" #include "vfutools.h" #include "see.h" /*######################################################################*/ /* work context */ int work_mode; VString work_path; /* archive context */ VString archive_name; VString archive_path; VArray archive_extensions; VString external_panelizer; VArray list_panelizer; TF* files_list[MAX_FILES]; /* file list statistics */ int files_count; fsize_t files_size; int sel_count; fsize_t sel_size; /* file system statistics */ fsize_t fs_free; fsize_t fs_total; fsize_t fs_block_size; /* index in the files list */ ScrollPos file_list_index; /* some world wide variables */ VString startup_path; VString home_path; VString tmp_path; VString rc_path; /* files masks */ VString files_mask; VArray files_mask_array; /* misc */ int print_help_on_exit; /*############################################ GLOBAL STRUCTS #########*/ VArray dir_tree; int dir_tree_changed; VString dir_tree_file; VArray file_find_results; // filefind results VArray path_bookmarks; /*######################################################################*/ VArray user_externals; VArray history; VArray see_filters; VArray panelizers; VArray mb; /* menu boxes */ VArray trim_tree; VArray view_profiles; VString view_profile; /*############################################ CONFIG SETTINGS #########*/ VString ext_colors[16]; VString shell_browser; VString shell_editor; VString shell_options; VString shell_diff; VString shell_prog; VString user_id_str; VString group_id_str; VString host_name_str; VString filename_opt; VString filename_conf; VString filename_history; VString filename_tree; VString filename_size_cache; VString filename_ffr; /* file find results */ char TF::_full_name[MAX_PATH]; /*######################################################################*/ int do_draw; int do_draw_status; /*######################################################################*/ /* Message issues */ char say_buf[1024]; VString say_str; void say( int line, int attr, const char* format, ... ) { ASSERT( line == 1 || line == 2 ); va_list vlist; va_start( vlist, format ); vsnprintf( say_buf, sizeof(say_buf), format, vlist ); va_end( vlist ); say_str = str_dot_reduce( say_buf, con_max_x()-1 ); con_out( 1, con_max_y() - ( (line == 1) ? 1 : 0 ), say_str, attr ); con_ce( attr ); } void say1(const char *a_str, int attr ) { say( 1, attr, "%s", a_str ); } void say2(const char *a_str, int attr ) { say( 2, attr, "%s", a_str ); } void say2errno() { VString str = "error: "; str += strerror(errno); say2( str ); } void saycenter( int line, int attr, const char *a_str ) { VString str = " "; int sl = str_len( a_str ); if ( sl < con_max_x() ) { sl = ( con_max_x() - sl ) / 2; str_mul( str, sl ); str = str + a_str; } say( line, attr, "%s", str.data() ); } void say1center(const char *a_str, int attr ) { saycenter( 1, attr, a_str ); } void say2center(const char *a_str, int attr ) { saycenter( 2, attr, a_str ); } /*######################################################################*/ void TF::reset() /* reset -- NULL all fields */ { _name = _name_ext = _ext = NULL; memset( &_st, 0, sizeof(_st) ); _type_str[0] = 0; _is_link = 0; _is_dir = 0; strcpy( _mode_str, MODE_OFF ); _size = -1; /* unknown -- get from stat? */ _view = NULL; _color = cPLAIN; sel = 0; } /*-----------------------------------------------------------------------*/ TF::TF() { reset(); } /*-----------------------------------------------------------------------*/ TF::TF( const char* a_name, const struct stat* a_stat, int a_is_link ) { reset(); set_name( a_name ); update_stat( a_stat, a_is_link ); } /*-----------------------------------------------------------------------*/ TF::~TF() { if ( _name ) delete [] _name; if ( _view ) delete [] _view; reset(); } /*-----------------------------------------------------------------------*/ const char* TF::full_name( int fix ) { ASSERT( _name ); if ( _name[0] == '/' ) { strcpy( _full_name, _name ); } else { if ( work_mode == WM_ARCHIVE ) strcpy( _full_name, archive_path ); else strcpy( _full_name, work_path ); strcat( _full_name, _name ); } if ( fix && _is_dir ) strcat( _full_name, "/" ); /* i.e. str_fix_path() */ return _full_name; } /*-----------------------------------------------------------------------*/ void TF::set_name( const char* a_new_name ) { if ( _name ) delete [] _name; _name = new char[ strlen(a_new_name) + 1 ]; ASSERT( _name ); /* this is run-time err but for now will be asserted */ strcpy( _name, a_new_name ); int last_slash = str_rfind( _name, '/' ); if ( last_slash == -1 ) _name_ext = _name; else _name_ext = _name + last_slash + 1; int last_dot = str_rfind( _name, '.' ); if ( last_dot == -1 || last_dot == 0 ) /* no dot or dot-file (hidden) */ _ext = _name + strlen( _name ); else _ext = _name + last_dot; _color = get_item_color( this ); /* this is duplicated here and in update_stat() */ drop_view(); } /*-----------------------------------------------------------------------*/ void TF::set_size( fsize_t a_new_size ) { _size = a_new_size; drop_view(); } /*-----------------------------------------------------------------------*/ void TF::drop_view() { if ( !_view ) return; delete [] _view; _view = NULL; } /*-----------------------------------------------------------------------*/ const char* TF::view() { if ( !_view ) refresh_view(); ASSERT(_view); return (const char*)_view; } /*-----------------------------------------------------------------------*/ void TF::refresh_view() { ASSERT( _name ); ASSERT( _name_ext ); ASSERT( _ext ); char stmode[16] = ""; // 10 + 1sep char stowner[16+64] = ""; /* +64 just to keep safe (not too much anyway) */ char stgroup[16+64] = ""; /* +64 just to keep safe (not too much anyway) */ char sttime[32] = ""; char stsize[16] = ""; char sttype[4] = ""; if ( !opt.long_name_view ) { if (opt.f_mode) { strcpy( stmode, _mode_str ); strcat( stmode, " " ); /* field separator */ } if (opt.f_owner) { struct passwd* _pwd = getpwuid(_st.st_uid); if (_pwd) sprintf( stowner, "%8s", _pwd->pw_name ); else sprintf( stowner, "%8d", _st.st_uid); stowner[8] = 0; /* safe */ strcat( stowner, " " ); /* field separator */ } if (opt.f_group) { struct group* _grp = getgrgid(_st.st_gid); if (_grp) sprintf( stgroup, "%8s", _grp->gr_name ); else sprintf( stgroup, "%8d", _st.st_gid); stgroup[8] = 0; /* safe */ strcat( stgroup, " " ); /* field separator */ } if (opt.f_time ) { time_str_compact( vfu_opt_time( _st ), sttime ); strcat( sttime, " " ); /* field separator */ } if (opt.f_size) { VString str; if ( _is_dir && _size == -1 ) str = "[DIR]"; else str = fsize_fmt( _size ); sprintf( stsize, "%14s", (const char*)(str) ); strcat( stsize, " " ); /* field separator */ } } /* if ( !opt.LongNameView ) */ if (opt.f_type || opt.long_name_view ) { strcpy( sttype, _type_str ); /* there is no field separator here! */ } VString name_view = _name; #ifdef _TARGET_UNIX_ /* links are supported only under UNIX */ if ( _is_link ) { name_view += " -> "; name_view += vfu_readlink( _name ); } #endif /* the three space separator below is for the tag and selection marks `>>#' */ VString view; view = view + stmode + stowner + stgroup + sttime + stsize + sttype + " " + name_view; int x = con_max_x(); if ( str_len( view ) > x ) str_sleft( view, x ); else str_pad( view, - x ); if ( _view ) delete [] _view; _view = new char[ con_max_x() + 1 ]; /* +1 for the zero :) */ strcpy( _view, view ); ASSERT( _view ); ASSERT( strlen( _view ) == (size_t)con_max_x() ); } /*-----------------------------------------------------------------------*/ void TF::update_stat( const struct stat* a_new_stat, int a_is_link ) { ASSERT( _name ); ASSERT( _name_ext ); ASSERT( _ext ); if ( a_new_stat ) memcpy( &_st, a_new_stat, sizeof(_st) ); else stat( _name, &_st ); _is_link = (a_is_link == -1) ? file_is_link( _name ) : a_is_link; _is_dir = S_ISDIR(_st.st_mode ); strcpy( _type_str, file_type_str( _st.st_mode, _is_link ) ); file_get_mode_str( _st.st_mode, _mode_str ); if ( _is_dir ) _size = -1; /* FIXME: some auto thing here? */ else _size = file_st_size( &_st ); _color = get_item_color( this ); drop_view(); } /*######################################################################*/ void vfu_help() { say1center( HEADER ); say2center( CONTACT ); mb.undef(); mb.push( "*keypad -- navigation keys" ); mb.push( "ENTER -- enter into directory/View file ( `+' and `=' too )"); mb.push( "BACKSPC -- chdir to prent directory ( `-' and ^H too )" ); mb.push( "TAB -- edit entry: filename, atrrib's/mode, owner, group"); mb.push( "R.Arrow -- rename current file " ); mb.push( "SPACE -- select/deselect current list item" ); mb.push( "ESC -- exit menu"); mb.push( "ESC+ESC -- exit menu"); mb.push( "1 -- toggle `mode' field on/off " ); mb.push( "2 -- toggle `owner' field on/off " ); mb.push( "3 -- toggle `group' field on/off " ); mb.push( "4 -- toggle `time' field on/off " ); mb.push( "5 -- toggle `size' field on/off " ); mb.push( "6 -- toggle `type' field on/off " ); mb.push( "7 -- toggle `time type' field change/modify/access time " ); mb.push( "8 -- turn on all fields" ); mb.push( "0 -- toggle long name view ( show only type and file name )" ); mb.push( "~ -- change current dir to HOME directory" ); mb.push( "A -- arrange/Sort file list" ); mb.push( "B -- browse/View selected/current file" ); mb.push( "Alt+B -- browse/View current file w/o filters" ); mb.push( "C -- copy selected/current file(s)" ); mb.push( "D -- change directory" ); mb.push( "Ctrl+D -- directory tree " ); mb.push( "Alt+D -- chdir history " ); mb.push( "E -- erase/remove selected/current file(s)!" ); mb.push( "F -- change file masks (space-delimited) "); mb.push( "Ctrl+F -- reset file mask to `*'" ); mb.push( "G -- global select/deselect" ); mb.push( "H -- this help text" ); mb.push( "I -- edit file" ); mb.push( "Q -- exit here ( to the current directory)"); mb.push( "R -- reload directory/refresh file list" ); mb.push( "Ctrl+R -- recursive reload... " ); mb.push( "Alt+R -- reload/tree menu" ); mb.push( "J -- jump to mountpoint" ); mb.push( "L -- symlink selected/currnet file(s) into new directory" ); mb.push( "Ctrl+L -- refresh/redraw entire screen" ); mb.push( "M -- move selected/current file(s)" ); mb.push( "N -- file find" ); mb.push( "Alt+N -- file find menu" ); mb.push( "O -- options/toggles menu" ); mb.push( "P -- file clipboard menu" ); /* mb.push( "Ctrl+C -- copy files to clipboard" ); mb.push( "Ctrl+X -- cut files to clipboard" ); mb.push( "Ctrl+V -- paste (copy) files from clipboard to current directory" ); */ mb.push( "T -- tools menu" ); mb.push( "U -- user menu (user external commands bound to menu) " ); mb.push( "X -- exit to old/startup directory "); mb.push( "Alt+X -- exit to old/startup directory "); mb.push( "Z -- calculate directories sizes menu" ); mb.push( "Ctrl+Z -- show size of the current (under the cursor >>) directory"); mb.push( "Alt+Z -- show all directories sizes ( or Alt+Z )" ); mb.push( "V -- edit vfu.conf file"); mb.push( "! -- shell (also available with '?')" ); mb.push( "/ -- command line" ); mb.push( "vfu uses these (one of) these config files:"); mb.push( " 1. $HOME/$RC_PREFIX/vfu/vfu.conf"); mb.push( " 2. $HOME/.vfu/vfu.conf"); mb.push( " 3. " FILENAME_CONF_GLOBAL0 ); mb.push( " 4. " FILENAME_CONF_GLOBAL1 ); mb.push( " 5. " FILENAME_CONF_GLOBAL2 ); mb.push( "" ); vfu_menu_box( 1, 4, "VFU Help ( PageUp/PageDown to scroll )" ); mb.undef(); do_draw = 1; } /*--------------------------------------------------------------------------*/ void vfu_init() { char t[MAX_PATH]; if( expand_path( "." ) == "" ) chdir( "/" ); work_mode = WM_NORMAL; getcwd( t, MAX_PATH-1 ); str_fix_path( t ); work_path = t; archive_name = ""; archive_path = ""; /* NOTE: archives' root directory is `' but not `/'! */ external_panelizer = ""; memset( &files_list, 0, sizeof(files_list) ); files_count = 0; files_size = 0; sel_count = 0; sel_size = 0; fs_free = 0; fs_total = 0; fs_block_size = 0; file_list_index.wrap = 0; /* file_list_index.* are setup by vfu_read_files() */ #ifdef _TARGET_GO32_ user_id_str = "dosuser"; group_id_str = "dos"; gethostname( t, MAX_PATH-1 ); host_name_str = t; __opendir_flags = __OPENDIR_FIND_HIDDEN; #else /* _TARGET_UNIX_ */ uid_t _uid = getuid(); gid_t _gid = getgid(); struct passwd* _pwd = getpwuid(_uid); struct group* _grp = getgrgid(_gid); if ( _pwd ) user_id_str = _pwd->pw_name; else user_id_str = (int)_uid; if ( _grp ) group_id_str = _grp->gr_name; else group_id_str = (int)_gid; gethostname( t, MAX_PATH-1 ); host_name_str = t; #endif startup_path = work_path; tmp_path = ""; if ( getenv( "TEMP" ) ) tmp_path = getenv( "TEMP" ); if ( getenv( "TMP" ) ) tmp_path = getenv( "TMP" ); if ( tmp_path == "" ) { #ifdef _TARGET_GO32_ tmp_path = "c:/tmp/"; #else tmp_path = "/tmp/"; #endif } else str_fix_path( tmp_path ); if ( getenv( "HOME" ) ) home_path = getenv( "HOME" ); else { home_path = tmp_path; home_path += user_id_str; home_path += "/"; make_path( home_path ); } #ifdef _TARGET_GO32_ str_tr( home_path, "\\", "/" ); #endif #ifdef _TARGET_GO32_ shell_diff = "fc"; #else shell_diff = "/usr/bin/diff"; #endif /* FIXME: this should something relevant to the home_path from above if $HOME does not exist(?) well still can accept /tmp/ as it is default now */ rc_path = get_rc_directory( "vfu" ); /* setup config files locations */ filename_opt = rc_path; filename_conf = rc_path; filename_tree = rc_path; filename_size_cache = rc_path; filename_history = rc_path; filename_ffr = rc_path; filename_opt += FILENAME_OPT; filename_conf += FILENAME_CONF; filename_tree += FILENAME_TREE; filename_size_cache += FILENAME_SIZE_CACHE; filename_history += FILENAME_HISTORY; filename_ffr += FILENAME_FFR; if ( access( filename_conf, R_OK ) != 0 ) { /* cannot find local/user conf file, try copy one */ if ( access( FILENAME_CONF_GLOBAL0, R_OK ) == 0 ) { VArray va; va.fload( FILENAME_CONF_GLOBAL0 ); va.fsave( filename_conf ); } else if ( access( FILENAME_CONF_GLOBAL1, R_OK ) == 0 ) { VArray va; va.fload( FILENAME_CONF_GLOBAL1 ); va.fsave( filename_conf ); } else if ( access( FILENAME_CONF_GLOBAL2, R_OK ) == 0 ) { VArray va; va.fload( FILENAME_CONF_GLOBAL2 ); va.fsave( filename_conf ); } } if ( access( filename_conf, R_OK ) != 0 ) { /* cannot find local/user conf file, try globals */ if ( access( FILENAME_CONF_GLOBAL0, R_OK ) == 0 ) filename_conf = FILENAME_CONF_GLOBAL0; else if ( access( FILENAME_CONF_GLOBAL1, R_OK ) == 0 ) filename_conf = FILENAME_CONF_GLOBAL1; else if ( access( FILENAME_CONF_GLOBAL2, R_OK ) == 0 ) filename_conf = FILENAME_CONF_GLOBAL2; /* if we get here then no readable conf file found */ } /* shell setup */ shell_prog = ""; if (getenv("SHELL")) shell_prog = getenv("SHELL"); #ifdef _TARGET_GO32_ if ( shell_prog == "" ) if(getenv("COMSPEC")) shell_prog = getenv("COMSPEC"); #endif if (getenv("VFU_SHELL")) shell_prog = getenv("VFU_SHELL"); /* this will load defaults first then load vfu.opt and at the end will load vfu.conf which will overwrite all if need to */ vfu_settings_load(); file_list_index.wrap = 0; /* just to be safe :) */ files_mask = "*"; files_mask_array = str_split( " ", files_mask ); view_profiles.push( "123456" ); view_profile = "123456"; /* setup menu colors */ menu_box_info.ti = 95; /* title */ menu_box_info.cn = 23; /* normal */ menu_box_info.ch = 47; /* selected */ ////////////////////////////////////////// // setup signals to VFUdone // this is a patch but at least will reset terminal and save settings signal( SIGINT , vfu_signal ); signal( SIGHUP , vfu_signal ); signal( SIGTERM , vfu_signal ); signal( SIGQUIT , vfu_signal ); // signal( SIGWINCH, vfu_signal ); // this is for xterm resize refresh handle // signal( SIGWINCH, VFUsignal ); // still doesn't work?... // HELP: I tried (as it is said in the curses-intro doc) // that I have to do endwin and wrefresh and all will be ok... // but it is not... :( ////////////////////////////////////////// srand( time( NULL ) ); do_draw = 1; vfu_read_files(); } /*--------------------------------------------------------------------------*/ void vfu_exit_path( const char *a_path ) { chdir( a_path ); #ifdef _TARGET_GO32_ return; // this is meaningless under DOS #else VString str; if ( getenv( "VFU_EXIT" ) ) str = getenv( "VFU_EXIT" ); else { str = tmp_path; str_fix_path( str ); str += "vfu.exit."; str += user_id_str; } FILE *f = fopen( str, "wt" ); file_set_mode_str( str, "-rw-------" ); if (!f) return; fputs( a_path, f); fclose(f); #endif } /*--------------------------------------------------------------------------*/ /* return 0 for exit-confirmed! */ int vfu_exit( const char* a_path ) { int z; mb.undef(); mb.push( "X Exit (to startup path)" ); mb.push( "Q Quit (to work path) " ); if ( a_path == NULL ) { vfu_beep(); z = vfu_menu_box( 50, 5, " Exit VFU?" ); if ( z == -1 ) return 1; z ? vfu_exit_path( work_path ) : vfu_exit_path( startup_path ); return 0; } else { vfu_exit_path( a_path ); return 0; } } /*--------------------------------------------------------------------------*/ void vfu_run() { say1center( HEADER ); say2center( CONTACT ); /* int oldFLI = -1; // quick view */ int ch = 0; while (4) { if (do_draw) { if ( do_draw > 2 ) vfu_reset_screen(); if ( do_draw > 1 ) do_draw_status = 1; vfu_redraw(); do_draw = 0; } if (do_draw_status) { vfu_redraw_status(); do_draw_status = 0; } /* TODO: quick view?... if ( work_mode == WM_NORMAL && files_count > 0 && oldFLI != FLI ) { oldFLI = FLI; const char* fn = files_list[FLI]->full_name(); file_save( "/tmp/vfu-quick-view", (void*)fn, strlen( fn ) ); } */ show_pos( FLI+1, files_count ); /* FIXME: should this be in vfu_redraw()? */ ch = con_getch(); if( ch == 0 ) ch = KEY_CTRL_L; if ( ch >= 'A' && ch <= 'Z' ) ch = tolower( ch ); say1( "" ); if ( user_id_str == "root" ) say2center( "*** WARNING: YOU HAVE GOT ROOT PRIVILEGES! ***" ); else say2( "" ); if ( work_mode == WM_NORMAL || work_mode == WM_ARCHIVE ) switch (ch) { /* actually this is ANY work_mode (since there are two modes only) */ case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' : case '8' : case '0' : vfu_toggle_view_fields( ch ); break; case '.' : vfu_toggle_view_fields( ch ); vfu_rescan_files( 0 ); break; case 's' : vfu_inc_search(); break; case KEY_CTRL_L: do_draw = 3; break; case 'q' : if( vfu_exit( work_path ) == 0 ) return; break; case KEY_ALT_X : case 'x' : if( vfu_exit( startup_path ) == 0 ) return; break; case 27 : if( vfu_exit( NULL ) == 0 ) return; break; case KEY_UP : vfu_nav_up(); break; case KEY_DOWN : vfu_nav_down(); break; case KEY_PPAGE : vfu_nav_ppage(); break; case KEY_NPAGE : vfu_nav_npage(); break; case KEY_CTRL_A : case KEY_HOME : vfu_nav_home(); break; case KEY_CTRL_E : case KEY_END : vfu_nav_end(); break; case 'h' : vfu_help(); break; case 'f' : vfu_change_file_mask( NULL ); break; case KEY_CTRL_F : vfu_change_file_mask( "*" ); break; case KEY_CTRL_D : tree_view(); break; case KEY_ALT_R : vfu_read_files_menu(); break; /* this will be in alt+r menu case 'R' : con_cs(); vfu_refresh_all_views(); do_draw = 1; break; */ case KEY_CTRL_R : vfu_rescan_files( 1 ); break; case 'r' : vfu_rescan_files( 0 ); break; case ' ' : vfu_nav_select(); break; #ifdef _TARGET_UNIX_ case KEY_BACKSPACE : #endif case 8 : case '-' : vfu_action_minus(); break; case 13 : case '+' : case '=' : vfu_action_plus( ch ); break; case KEY_LEFT : if (opt.lynx_navigation) vfu_action_minus(); break; case KEY_RIGHT : if (opt.lynx_navigation) vfu_action_plus( '+' ); else if ( work_mode == WM_NORMAL ) vfu_rename_file_in_place(); break; case 'd' : vfu_chdir( NULL ); break; case KEY_ALT_D : vfu_chdir_history(); break; case KEY_ALT_EQ : case '>' : opt.long_name_view = !opt.long_name_view; vfu_drop_all_views(); do_draw = 1; break; case 'a' : vfu_arrange_files(); break; case 'g' : vfu_global_select(); break; case 'o' : vfu_options(); break; case 'v' : vfu_edit_conf_file(); break; case '!' : case '?' : con_cs(); vfu_shell( shell_prog, 0 ); do_draw = 1; break; case 'u' : vfu_user_menu(); break; /* not documented unless here :) */ case KEY_CTRL_T : { char s[128]; say1( "Timing screen draws (x1000)..." ); clock_t t = clock(); for(int z = 0; z < 1000; z++) vfu_redraw(); t = clock() - t; sprintf(s,"Draw speed: %f dps.",(100.0/((double)t/CLOCKS_PER_SEC))); say1(s); break; } case '*' : FGO( rand() % files_count ); do_draw = 1; break; case 'z' : vfu_directories_sizes( 0 ); break; case KEY_ALT_Z : vfu_directories_sizes( 'A' ); break; case KEY_CTRL_Z : vfu_directories_sizes( 'Z' ); break; } if ( work_mode == WM_ARCHIVE ) switch (ch) { case 'c' : vfu_extract_files( 0 ); break; case KEY_ALT_C : vfu_extract_files( 1 ); break; } if ( work_mode == WM_NORMAL ) switch (ch) { case 'b' : case KEY_ALT_B : if ( ch == 'b' && sel_count > 0 ) vfu_browse_selected_files(); else { if ( files_count > 0 ) vfu_browse( files_list[FLI]->name(), ch == KEY_ALT_B ); else say1( "No files" ); } break; case 'n' : vfu_file_find( 0 ); break; case KEY_ALT_N : vfu_file_find( 1 ); break; case '~' : vfu_chdir( home_path ); break; case '/' : vfu_command(); break; case 'i' : if ( files_count > 0 ) vfu_edit( files_list[FLI]->name() ); else say1( "No files"); break; case 'm' : vfu_copy_files(sel_count == 0, CM_MOVE); break; case KEY_ALT_M : vfu_copy_files(1, CM_MOVE); break; case 'c' : vfu_copy_files(sel_count == 0, CM_COPY); break; case KEY_ALT_C : vfu_copy_files(1, CM_COPY); break; case 'l' : vfu_copy_files(sel_count == 0, CM_LINK); break; case KEY_ALT_L : vfu_copy_files(1, CM_LINK); break; case 'e' : vfu_erase_files(sel_count == 0); break; case KEY_ALT_E : vfu_erase_files(1); break; case 'j' : vfu_jump_to_mountpoint( 0 ); break; case KEY_ALT_J : vfu_jump_to_mountpoint( 1 ); break; case KEY_ALT_1 : bookmark_goto( '1' ); break; case KEY_ALT_2 : bookmark_goto( '2' ); break; case KEY_ALT_3 : bookmark_goto( '3' ); break; case KEY_ALT_4 : bookmark_goto( '4' ); break; case KEY_ALT_5 : bookmark_goto( '5' ); break; case KEY_ALT_6 : bookmark_goto( '6' ); break; case KEY_ALT_7 : bookmark_goto( '7' ); break; case KEY_ALT_8 : bookmark_goto( '8' ); break; case KEY_ALT_9 : bookmark_goto( '9' ); break; case '`' : bookmark_goto(-1 ); break; case 9 : vfu_edit_entry(); break; case 't' : vfu_tools(); break; case 'p' : clipboard_menu( 0 ); break; /* case KEY_CTRL_C : vfu_clipboard( 'C' ); break; // copy case KEY_CTRL_X : vfu_clipboard( 'X' ); break; // cut case KEY_CTRL_V : vfu_clipboard( 'V' ); break; // paste */ } if ( ( KEY_F1 <= ch && ch <= KEY_F10) || ( KEY_SH_F1 <= ch && ch <= KEY_SH_F10) || ( KEY_ALT_F1 <= ch && ch <= KEY_ALT_F10) || ( KEY_CTRL_F1 <= ch && ch <= KEY_CTRL_F10) || ( ch == KEY_IC) ) vfu_user_external_exec( ch ); } } /*--------------------------------------------------------------------------*/ void vfu_help_cli() { printf( "%s", HEADER "Command line switches:\n" " none -- run in interactive mode (DEFAULT)\n" " -h -- this help screen\n" " -i -- go temporarily into interactive mode\n" " -d path -- change current path to `path'\n" " -r -- rebuild DirTree (under DOS -- tip: see -d)\n" " -t -- view DirTree\n" " -v -- version information\n" "tips:\n" " 1. command line switches are executed in order!\n" " 2. example: vfu -d c:/dos/ -r -i\n" " 3. example: vfu -d c:/ -r -d d:/ -r -d e:/ -r\n" "compile information:\n" " target description: " _TARGET_DESCRIPTION_ "\n" " compile date: " __DATE__ "\n" ); } /*--------------------------------------------------------------------------*/ void vfu_cli( int argc, char* argv[] ) { VString temp; GETOPT((char*)"hrd:ti") { switch(optc) { case 'h' : print_help_on_exit = 1; break; case 'i' : vfu_run(); break; case 'd' : temp = optarg; #ifdef _TARGET_GO32_ str_tr( temp, "\\", "/" ); #endif vfu_chdir( temp ); break; case 'r' : con_out(1,1,HEADER,cINFO); temp = "Rebuilding directory tree ( work_path is"; temp += work_path; temp += " )"; say2( temp ); tree_rebuild(); break; case 't' : con_out(1,1,HEADER,cINFO); tree_view(); vfu_exit( work_path ); break; default: vfu_help_cli(); break; } } } /*--------------------------------------------------------------------------*/ void vfu_done() { /* if dir_tree.count is 0 don't save -- there's nothing to be saved */ if ( dir_tree.count() && dir_tree_changed ) tree_save(); vfu_settings_save(); } /*--------------------------------------------------------------------------*/ void vfu_reset_screen() { con_done(); con_init(); con_chide(); /* update scroll parameters */ file_list_index.set_min_max( 0, files_count - 1 ); file_list_index.set_pagesize( con_max_y() - 7 ); FGO( file_list_index.pos() ); vfu_drop_all_views(); vfu_redraw(); vfu_redraw_status(); } void vfu_signal( int sig ) { /* there is no simple solution... :/ if ( sig == SIGWINCH ) { signal( SIGWINCH, vfu_signal ); // (re)setup signal handler do_draw = 3; return; } */ vfu_done(); con_beep(); con_cs(); con_cshow(); con_done(); printf( "vfu: signal received: %d -- terminated\n", sig ); exit(200); } /*--------------------------------------------------------------------------*/ void vfu_toggle_view_fields( int ch ) { switch( ch ) { case '1' : opt.f_mode = !opt.f_mode; break; case '2' : opt.f_owner = !opt.f_owner; break; case '3' : opt.f_group = !opt.f_group; break; case '4' : opt.f_time = !opt.f_time; break; case '5' : opt.f_size = !opt.f_size; break; case '6' : opt.f_type = !opt.f_type; break; case '7' : opt.f_time_type++; if (opt.f_time_type > 2) opt.f_time_type = 0; break; case '8' : opt.f_mode = opt.f_owner = opt.f_group = opt.f_time = opt.f_size = opt.f_type = 1; break; case '0' : opt.long_name_view = !opt.long_name_view; break; case '.' : opt.show_hidden_files = !opt.show_hidden_files; break; default : return; /* cannot be reached really */ } vfu_drop_all_views(); } /*--------------------------------------------------------------------------*/ void vfu_shell( const char* a_command, const char* a_options ) { VString shell_line = a_command; VString o = a_options; VString status = ""; int res = vfu_update_shell_line( shell_line, o ); if (res) return; if ( str_find( o, '!' ) > -1 ) { // review shell_line say1( "Review shell line to be executed:" ); VString sl = shell_line; sl = str_dot_reduce( sl, con_max_x()-1 ); say2( sl ); con_getch(); } if ( str_find( o, 'n' ) == -1 ) /* [n]o console suspend */ { con_cs(); con_xy( 1, 1 ); con_cshow(); con_suspend(); } res = system( shell_line ); if ( res ) { sprintf( status, "*** execution failed, system() == %d ***", res ); } if ( str_find( o, 'w' ) != -1 ) /* [w]ait after shell */ { printf( "*** press enter ***" ); fflush( stdout ); fgetc( stdin ); } if ( str_find( o, 'n' ) == -1 ) /* [n]o console suspend */ { con_restore(); con_chide(); con_cs(); } chdir( work_path ); /* in case SHELL changed directory... (DOS only :)) */ if ( str_find( o, 'r' ) != -1 ) vfu_rescan_files(); do_draw = 2; if ( str_find( o, 'n' ) != -1 ) do_draw = 0; if ( str_find( o, 'i' ) != -1 ) vfu_nav_down(); say1(""); say2( status ); } /*--------------------------------------------------------------------------*/ void update_status() { int z; fsize_t s; sel_count = 0; sel_size = 0; files_size = 0; /* files list statistics */ for( z = 0; z < files_count; z++ ) { s = files_list[z]->size(); if ( files_list[z]->sel ) { sel_size += s; sel_count++; } files_size += s; } /* current fs statistics */ struct statfs stafs; statfs( ".", &stafs ); fs_free = (fsize_t)(stafs.f_bsize) * (opt.show_user_free?stafs.f_bavail:stafs.f_bfree); fs_total = (fsize_t)(stafs.f_bsize) * stafs.f_blocks; fs_block_size = (fsize_t)(stafs.f_bsize); do_draw_status = 1; } /*--------------------------------------------------------------------------*/ void vfu_edit( const char *fname ) { if ( files_count == 0 ) { say1( "No files"); return; } if ( files_list[FLI]->is_dir() ) { say1( "Cannot edit directory"); return; } con_cs(); if ( opt.internal_editor ) { opt.seo.cs = cINFO; SeeEditor editor( &opt.seo ); if( editor.open( fname ) == 0 ) { int r = 1; while ( r ) { editor.run(); r = editor.request_quit(); } } else say1( "Error loading file..." ); editor.close(); } else { VString str = shell_editor; if ( fname ) { str_replace( str, "%f", fname ); str_replace( str, "%F", fname ); } vfu_shell( str, "" ); } do_draw = 2; say1(""); say2(""); } /*--------------------------------------------------------------------------*/ void vfu_browse_selected_files() { /* FIXME: multiple files browsing should be back ASAP #define VFU_BROWSE_MAX_FILES 10 int i; // index int ic; // count for ( z = 0; z < files_count; z++ ) if ( files_list[z]->sel ) if ( !files_list[z]->is_dir() ) SeeAddFile( files_list[z]->full_name() ); //------ int z; for ( z = 0; z < files_count; z++ ) if ( files_list[z]->sel ) if ( !files_list[z]->is_dir() ) SeeAddFile( files_list[z]->full_name() ); SeeSLColor = cINFO; See(); do_draw = 2; say1(""); say2(""); */ } void vfu_browse( const char *fname, int no_filters ) { VString new_name = fname; VString tmp_name; if ( !no_filters && see_filters.count() > 0 ) { char full_fname[MAX_PATH]; expand_path( fname, full_fname ); int z; for ( z = 0; z < see_filters.count(); z++ ) { VArray split; split = str_split( ",", see_filters[z] ); VString mask = split[0]; VString str = split[1]; if ( FNMATCH( mask, str_file_name_ext( fname ) ) ) continue; /* found */ tmp_name = vfu_temp(); str_replace( str, "%f", fname ); str_replace( str, "%F", full_fname ); str += " > "; str += tmp_name; vfu_shell( str, "" ); chmod( tmp_name, S_IRUSR | S_IWUSR ); break; } } if ( tmp_name != "" ) new_name = tmp_name; if ( opt.internal_browser ) { opt.svo.cs = cINFO; SeeViewer viewer( &opt.svo ); if( viewer.open( new_name ) == 0 ) viewer.run(); else say1( "Error loading file..." ); viewer.close(); } else { VString str = shell_browser; if ( fname ) { str_replace( str, "%f", fname ); str_replace( str, "%F", fname ); } vfu_shell( str, "" ); } do_draw = 2; say1(""); say2(""); if ( tmp_name != "" ) unlink( tmp_name ); } /*--------------------------------------------------------------------------*/ void vfu_action_plus( int key ) { if ( files_count == 0 ) return; TF *fi = files_list[FLI]; if ( work_mode == WM_NORMAL ) { if ( fi->is_dir() ) { /* directory */ vfu_chdir( fi->name() ); } else { /* file */ int z; for ( z = 0; z < archive_extensions.count(); z++ ) if ( FNMATCH_OC( archive_extensions[z], fi->name_ext(), opt.lower_case_ext_config ) == 0 ) { z = -1; /* FIXME: this shouldn't be -1 for TRUE really :) */ break; } if ( z == -1 ) { /* yep this is archive */ work_mode = WM_ARCHIVE; archive_name = fi->name(); archive_path = ""; /* NOTE: archives' root dir is `' but not `/'! */ vfu_read_files(); say1( "ARCHIVE mode activated ( some keys/commands are disabled! )" ); } else if ( key == KEY_ENTER && vfu_user_external_find( KEY_ENTER, fi->ext(), fi->type_str(), NULL ) != -1 ) vfu_user_external_exec( KEY_ENTER ); else vfu_browse( fi->name() ); } } else { /* work_mode == WM_ARCHIVE */ if ( fi->is_dir() ) { /* directory */ VString p = fi->name(); str_fix_path( p ); archive_path += p; vfu_read_files(); } else if ( key == KEY_ENTER && vfu_user_external_find( KEY_ENTER, fi->ext(), fi->type_str(), NULL ) != -1 ) vfu_user_external_exec( KEY_ENTER ); else { /* file */ vfu_browse_archive_file(); } } } /*--------------------------------------------------------------------------*/ void vfu_action_minus() { VString o = work_path; /* save old path i.e. current */ if ( work_mode == WM_NORMAL ) { #ifdef _TARGET_GO32_ if ( work_path[1] == ':' && work_path[2] == '/' && work_path[3] == 0 ) return; #else if ( work_path[0] == '/' && work_path[1] == 0 ) return; #endif vfu_chdir( ".." ); } else if ( work_mode == WM_ARCHIVE ) { if ( str_len( archive_path ) > 0 ) { str_cut_right( archive_path, "/" ); int z = str_rfind( archive_path, "/" ); o = archive_path; o += "/"; if ( z != -1 ) str_sleft(archive_path,z+1); else archive_path = ""; vfu_read_files(); } else { o += archive_name; o += "/"; /* FIXME: is this required ? */ work_mode = WM_NORMAL; archive_name = ""; archive_path = ""; /* NOTE: this shouldn't be `/'! */ vfu_chdir( "." ); } } int z = 0; for ( z = 0; z < files_count; z++ ) { VString n; if ( work_mode == WM_ARCHIVE ) n = archive_path; else n = work_path; n += files_list[z]->name(); n += "/"; if ( pathcmp( o, n ) == 0 ) { FGO(z); break; } } do_draw = 1; } /*--------------------------------------------------------------------------*/ // global select / different // returns 0 for ok int vfu_cmp_files_crc32( const char* src, const char* dst, const char* name ) { char fn1[MAX_PATH]; char fn2[MAX_PATH]; struct stat stat_src; struct stat stat_dst; strcpy( fn1, src ); strcat( fn1, name ); strcpy( fn2, dst ); strcat( fn2, name ); if (access( fn1, F_OK )) return 1; if (access( fn2, F_OK )) return 2; if (stat( fn1, &stat_src )) return 3; if (stat( fn2, &stat_dst )) return 4; if (S_ISDIR( stat_src.st_mode )) return 5; if (S_ISDIR( stat_dst.st_mode )) return 6; if ( stat_src.st_size != stat_dst.st_size ) return 7; if ( file_crc32( fn1 ) != file_crc32( fn2 ) ) return 8; return 0; } #define GSAME_NAME 1 #define GSAME_EXT 2 #define GSAME_SIZE 3 #define GSAME_DATETIME 4 #define GSAME_DATE 5 #define GSAME_TIME 6 #define GSAME_TIME1 7 #define GSAME_OWNER 8 #define GSAME_GROUP 9 #define GSAME_MODE 10 #define GSAME_TYPE 11 #define TIMECMP_DT 0 // compare date and time #define TIMECMP_D 1 // compare only date #define TIMECMP_T 2 // compare only time #define TIMECMP_T1 3 // compare only time (to 1 minute round) // return 0=don't match and 1=match int vfu_time_cmp( time_t t1, time_t t2, int type = TIMECMP_DT ) { char tmp1[32]; char tmp2[32]; strcpy( tmp1, ctime(&t1) ); strcpy( tmp2, ctime(&t2) ); if ( type == TIMECMP_T ) { strcpy( tmp1, tmp1+11 ); tmp1[8] = 0; strcpy( tmp2, tmp2+11 ); tmp2[8] = 0; } else if ( type == TIMECMP_T1 ) { strcpy( tmp1, tmp1+11 ); tmp1[5] = 0; strcpy( tmp2, tmp2+11 ); tmp2[5] = 0; } else if ( type == TIMECMP_D ) { strcpy( tmp1+10, tmp1+19 ); strcpy( tmp2+10, tmp2+19 ); } return (strcmp( tmp1, tmp2 ) == 0); } void vfu_global_select_same( int same_mode ) { VString same_str; long same_int = 0; fsize_t same_fsize = 0; TF* fi = files_list[FLI]; switch( same_mode ) { case GSAME_NAME : same_str = fi->name(); break; case GSAME_EXT : same_str = fi->ext(); break; case GSAME_SIZE : same_fsize = fi->size(); break; case GSAME_DATETIME : case GSAME_DATE : case GSAME_TIME : case GSAME_TIME1 : same_int = vfu_opt_time( fi->st() ); break; case GSAME_OWNER : same_int = fi->st()->st_uid; break; case GSAME_GROUP : same_int = fi->st()->st_gid; break; case GSAME_MODE : same_int = fi->st()->st_mode; break; case GSAME_TYPE : same_str = fi->type_str(); break; default : return; } int z = 0; for (z = 0; z < files_count; z++) { fi = files_list[z]; int sel = 0; switch( same_mode ) { case GSAME_NAME : sel = (pathcmp(same_str, fi->name()) == 0); break; case GSAME_EXT : sel = (pathcmp(same_str, fi->ext()) == 0); break; case GSAME_SIZE : sel = (same_fsize == fi->size()); if ( fi->is_dir() ) sel = 0; break; case GSAME_DATETIME : sel = vfu_time_cmp(same_int, vfu_opt_time( fi->st())); break; case GSAME_DATE : sel = vfu_time_cmp(same_int, vfu_opt_time( fi->st() ), TIMECMP_D ); break; case GSAME_TIME : sel = vfu_time_cmp(same_int, vfu_opt_time( fi->st() ), TIMECMP_T ); break; case GSAME_TIME1 : sel = vfu_time_cmp(same_int, vfu_opt_time( fi->st() ), TIMECMP_T1 ); break; case GSAME_OWNER : sel = ((unsigned int)same_int == fi->st()->st_uid); break; case GSAME_GROUP : sel = ((unsigned int)same_int == fi->st()->st_gid); break; case GSAME_MODE : sel = ((unsigned int)same_int == fi->st()->st_mode); break; case GSAME_TYPE : sel = ( same_str == fi->type_str()); break; } fi->sel = sel; } } void vfu_global_select() { char ch; mb.undef(); mb.push( "S All" ); mb.push( "A All (+Dirs)" ); mb.push( "R Reverse" ); mb.push( "C Clear" ); mb.push( "P Pack" ); mb.push( "H Hide" ); mb.push( "D Different" ); mb.push( ". Hide dirs" ); mb.push( ", Hide dotfiles" ); mb.push( "= Mask add (+dirs)" ); mb.push( "+ Mask add (-dirs)" ); mb.push( "- Mask sub " ); mb.push( "L Same..." ); mb.push( "X EXtended select..." ); if ( vfu_menu_box( 50, 5, "Global Select" ) == -1 ) return; ch = menu_box_info.ec; if (ch == 'X') { if ( work_mode != WM_NORMAL ) { say1( "GlobalSelect/Extended not available in this mode." ); return; } mb.undef(); mb.push( "A Select to begin" ); mb.push( "E Select to end" ); mb.push( "--searching--" ); mb.push( "F Find string (no case)" ); mb.push( "S Scan string (case sense)" ); mb.push( "H Hex string" ); mb.push( "/ Regular expression" ); mb.push( "\\ Reg.exp (no case)" ); // mb.push( "--other--" ); // mb.push( "M Mode/Attributes" ); if ( vfu_menu_box( 50, 5, "Extended G.Select" ) == -1 ) return; ch = menu_box_info.ec; if (ch == 'S') ch = 'B'; /* 'B' trans scan */ if (ch == 'H') ch = 'E'; /* 'E' trans hex */ if (ch == 'A') ch = '<'; /* '<' trans to begin */ if (ch == 'E') ch = '>'; /* '>' trans to end */ } switch(ch) { case 'S' : { for (int z = 0; z < files_count; z++) if (!files_list[z]->is_dir()) files_list[z]->sel = 1; } break; case 'A' : { for (int z = 0; z < files_count; z++) files_list[z]->sel = 1; } break; case 'R' : { int z; for (z = 0; z < files_count; z++) if (!files_list[z]->is_dir()) files_list[z]->sel = !files_list[z]->sel; } break; case 'C' : { int z; for (z = 0; z < files_count; z++) files_list[z]->sel = 0; } break; case 'P' : { int z; for (z = 0; z < files_count; z++) { if (!files_list[z]->sel) { delete files_list[z]; files_list[z] = NULL; } } vfu_pack_files_list(); } break; case 'H' : { int z; for (z = 0; z < files_count; z++) { if (files_list[z]->sel) { delete files_list[z]; files_list[z] = NULL; } } vfu_pack_files_list(); } break; case '.' : { int z; for (z = 0; z < files_count; z++) { if (files_list[z]->is_dir()) { delete files_list[z]; files_list[z] = NULL; } } vfu_pack_files_list(); } break; case ',' : { int z; for (z = 0; z < files_count; z++) { if (files_list[z]->name()[0] == '.') { delete files_list[z]; files_list[z] = NULL; } } vfu_pack_files_list(); } break; case '+' : case '=' : case '-' : { VString m; int selaction = 0; if (ch != '-') selaction = 1; if (ch == '+') say1("Select by mask: (w/o directories)"); else if (ch == '=') say1("Select by mask: (with directories)"); else say1("Deselect by mask:"); if ( vfu_get_str( "", m, HID_GS_MASK )) { VArray sm; sm = str_split( " +", m ); while( (m = sm.pop()) != "" ) { if (opt.mask_auto_expand) vfu_expand_mask( m ); int z = 0; for (z = 0; z < files_count; z++) { if (files_list[z]->is_dir() && ch == '+') continue; if (FNMATCH(m,files_list[z]->name_ext()) == 0) files_list[z]->sel = selaction; } } } say1( " " ); say2( " " ); } break; case 'D' : { if ( work_mode != WM_NORMAL ) { say1( "GlobalSelect/Different not available in this mode." ); break; } VString target; if ( vfu_get_dir_name( "Target directory:", target )) { str_fix_path( target ); int z = 0; for (z = 0; z < files_count; z++) { if ( files_list[z]->is_dir() ) continue; say1( files_list[z]->name() ); files_list[z]->sel = (vfu_cmp_files_crc32( work_path, target, files_list[z]->name() ) != 0 ); } } say1( "Done." ); say2( " " ); } break; case '/': case '\\': case 'E': case 'F': case 'B': { say1(""); VString pat; if ( vfu_get_str( "Search string: ", pat, HID_GS_GREP ) ) { fsize_t size = 0; say1(""); say2(""); size = 0; for ( int z = 0; z < files_count; z++ ) { size += files_list[z]->size(); if ( files_list[z]->is_dir() ) continue; int pos = -1; switch( ch ) { case 'F': pos = file_string_search( pat, files_list[z]->name(), "i" ); break; case 'B': pos = file_string_search( pat, files_list[z]->name(), "" ); break; case 'E': pos = file_string_search( pat, files_list[z]->name(), "h" ); break; case '/': pos = file_string_search( pat, files_list[z]->name(), "r" ); break; case '\\': pos = file_string_search( pat, files_list[z]->name(), "ri" ); break; } files_list[z]->sel = ( pos > -1 ); char s[128]; sprintf( s, "Scanning %4.1f%% (%12.0f bytes in %s ) ", (100.0 * size) / (files_size+1.0), files_list[z]->size(), files_list[z]->name() ); say1( s ); } } say1(""); say2(""); break; } case 'L': { mb.undef(); mb.push( "N Name" ); mb.push( "E Extension" ); mb.push( "S Size" ); mb.push( "T Time" ); mb.push( "I Time (1 min.round)" ); mb.push( "D Date" ); mb.push( "M Date+Time" ); mb.push( "A Attr/Mode" ); #ifndef _TARGET_GO32_ mb.push( "O Owner" ); mb.push( "G Group" ); #endif mb.push( "Y Type (TP)" ); vfu_menu_box( 50, 5, "Select Same..." ); ch = menu_box_info.ec; switch ( ch ) { case 'N' : vfu_global_select_same( GSAME_NAME ); break; case 'E' : vfu_global_select_same( GSAME_EXT ); break; case 'S' : vfu_global_select_same( GSAME_SIZE ); break; case 'M' : vfu_global_select_same( GSAME_DATETIME ); break; case 'T' : vfu_global_select_same( GSAME_TIME ); break; case 'I' : vfu_global_select_same( GSAME_TIME1 ); break; case 'D' : vfu_global_select_same( GSAME_DATE ); break; case 'O' : vfu_global_select_same( GSAME_OWNER ); break; case 'G' : vfu_global_select_same( GSAME_GROUP ); break; case 'A' : vfu_global_select_same( GSAME_MODE ); break; case 'Y' : vfu_global_select_same( GSAME_TYPE ); break; } } break; case 'M': { mode_str_t mode_str; strcpy( mode_str, MODE_STRING ); if(vfu_edit_attr( mode_str, 0 )) { for ( int z = 0; z < files_count; z++ ) files_list[z]->sel = (strcmp( files_list[z]->mode_str()+1, mode_str+1 ) == 0); do_draw = 1; } } break; case '<' : { if( files_count > 0) for (int z = 0; z <= FLI; z++) if (!files_list[z]->is_dir()) files_list[z]->sel = 1; } break; case '>' : { if( files_count > 0) for (int z = FLI; z < files_count; z++) if (!files_list[z]->is_dir()) files_list[z]->sel = 1; } break; } update_status(); do_draw = 1; } /*--------------------------------------------------------------------------*/ int vfu_user_external_find( int key, const char* ext, const char* type, VString *shell_line ) { VArray split; VString str; VString ext_str = ext; VString type_str = type; if ( ext_str == "" ) ext_str = "."; ext_str += "."; type_str = "." + type_str + "."; int z; for ( z = 0; z < user_externals.count(); z++ ) { split = str_split( ",", user_externals[z] ); if ( key_by_name( split[1] ) != key ) continue; /* if key not the same -- skip */ if ( split[2] != "*" ) /* if we should match and extension */ { if ( opt.lower_case_ext_config ) { str_low( split[2] ); str_low( ext_str ); str_low( type_str ); } if ( str_find( split[2], ext_str ) == -1 && str_find( split[2], type_str ) == -1 ) continue; /* not found -- next one */ } if ( shell_line ) /* if not NULL -- store shell line into it */ (*shell_line) = split[3]; return z; } return -1; } /*--------------------------------------------------------------------------*/ void vfu_user_external_exec( int key ) { if ( files_count == 0 ) { say1( "Directory is empty: user externals are disabled!" ); return; } VString shell_line; TF *fi = files_list[FLI]; if (vfu_user_external_find( key, fi->ext(), fi->type_str(), &shell_line ) != -1) { if ( work_mode == WM_NORMAL ) vfu_shell( shell_line, "" ); else if ( work_mode == WM_ARCHIVE ) { vfu_user_external_archive_exec( shell_line ); } } else { char t[128]; sprintf( t, "No user external defined for this key and extension (%d,%s)", key, fi->ext() ); say1( t ); } } /*--------------------------------------------------------------------------*/ VString tools_last_target; void vfu_tools() { mb.undef(); mb.push( "R Real path" ); mb.push( "D ChDir to symlink path" ); mb.push( "G Go to symlink target" ); mb.push( "B Go back to last target" ); mb.push( "T Make directory" ); mb.push( "P Path bookmarks" ); mb.push( "A Rename tools..." ); mb.push( "C Classify files" ); if ( vfu_menu_box( 50, 5, "Tools" ) == -1 ) return; switch( menu_box_info.ec ) { case 'R' : { char s[MAX_PATH]; expand_path(files_list[FLI]->name(), s); say1( s ); break; } case 'D' : { if( ! files_list[FLI]->is_link() ) break; tools_last_target = files_list[FLI]->full_name(); if( ! files_list[FLI]->is_dir() ) break; vfu_chdir( expand_path( files_list[FLI]->name() ) ); break; } case 'G' : { if( ! files_list[FLI]->is_link() ) break; tools_last_target = files_list[FLI]->full_name(); VString target = vfu_readlink( files_list[FLI]->full_name() ); vfu_chdir( expand_path( str_file_path( target ) ) ); vfu_goto_filename( str_file_name_ext( target ) ); break; } case 'B' : { if( tools_last_target == "" ) break; VString target = tools_last_target; tools_last_target = files_list[FLI]->full_name(); vfu_chdir( expand_path( str_file_path( target ) ) ); vfu_goto_filename( str_file_name_ext( target ) ); break; } case 'T' : { VString str; if (vfu_get_str( "Make directory(ies) (use space for separator)", str, HID_MKPATH )) { int err = 0; int z; VArray ms; ms = str_split( " +", str ); for ( z = 0; z < ms.count(); z++ ) if( make_path(ms[z]) ) { say1( "Cannot create directory:" ); say2( ms[z] ); con_getch(); err++; } if ( err == 0 ) say1( "MKDIR: ok." ); break; } } break; case 'P' : bookmark_goto( -1 ); break; case 'A' : vfu_tool_rename(); break; case 'C' : vfu_tool_classify(); break; } } /*--------------------------------------------------------------------------*/ void bookmark_goto( int n ) { VString t; if ( n == -1 ) { int z; mb.undef(); mb.push( "A Bookmark current directory" ); mb.push( "` Change working directory" ); mb.push( "---" ); for( z = 1; z < 10; z++ ) { const char* ps = path_bookmarks.get( z-1 ); if( !ps ) break; sprintf(t, "%d %s", z%10, ps ); mb.push( str_dot_reduce( t, 60 ) ); } n = vfu_menu_box( 5, 5, "Path bookmarks"); if ( n == -1 ) return; n = menu_box_info.ec; } // FIXME: neshto ne raboti :/ switch( n ) { case '`' : vfu_chdir( NULL ); return; case 'A' : bookmark_hookup(); return; } if ( n >= '1' && n <= '9' && str_len( path_bookmarks[ n - '1' ] ) > 0 ) { vfu_chdir( path_bookmarks[ n - '1' ] ); return; } } void bookmark_hookup() { int found = -1; for( int z = 0; z < path_bookmarks.count(); z++ ) { if( work_path == path_bookmarks[z] ) found = z; } if( found > -1 ) { say1( "Current directory is already hooked", chRED ); return; } path_bookmarks.push( work_path ); if ( path_bookmarks.count() > 10 ) path_bookmarks.shift(); } /*--------------------------------------------------------------------------*/ void vfu_command() { VString cmd; if ( vfu_get_str( "Command: ", cmd, HID_COMMANDS ) ) vfu_shell( cmd, "" ); } /*--------------------------------------------------------------------------*/ void vfu_rename_file_in_place() { TF *fi = files_list[FLI]; int y = (file_list_index.pos() - file_list_index.page()) + 4; int x = tag_mark_pos + 3; VString str = fi->name(); if(TextInput( x, y, "", MAX_PATH, con_max_x() - tag_mark_pos - 4, &str ) && strcmp( fi->name(), str.data() ) ) { if ( file_exist(str) ) say1( "Cannot rename: destination name exists!" ); else if(rename(fi->name(), str.data()) == 0) { fi->set_name( str ); say1("RENAME: ok."); } else { say1("RENAME: failed."); say2errno(); } } do_draw = 1; } /*--------------------------------------------------------------------------*/ void vfu_change_file_mask( const char* a_new_mask ) { VString tmp = files_mask; int new_mask = 0; if ( a_new_mask ) { tmp = a_new_mask; new_mask = 1; } else { new_mask = vfu_get_str( "", tmp, HID_FMASK, 6, 1 ); do_draw = 1; } if(new_mask) { str_cut_spc( tmp ); if ( str_len( tmp ) < 1 ) tmp = "*"; files_mask = tmp; files_mask_array = str_split( " +", files_mask ); if ( opt.mask_auto_expand ) { int z; for ( z = 0; z < files_mask_array.count(); z++ ) vfu_expand_mask( files_mask_array[z] ); } vfu_read_files(); } } /*--------------------------------------------------------------------------*/ /* n == 0..nnn for nnn only, -1 current only, -2 all */ void vfu_directories_sizes( int n ) { int z; char t[256]; n = toupper( n ); if ( n == 0 ) { mb.undef(); mb.push( "E Specify directory" ); mb.push( "Z Directory under cursor" ); mb.push( ". Current directory `.'" ); mb.push( "S Selected directories" ); mb.push( "A All dir's in the list" ); if ( vfu_menu_box( 5, PS - 4, "Directory size of:" ) == -1 ) return; n = menu_box_info.ec; } if ( n == 'E' || n == '.' ) /* specific directory */ { VString target = work_path; if ( n == '.' ) target = work_path; else if ( !vfu_get_dir_name( "Calculate size of directory: ", target ) ) return; fsize_t dir_size = vfu_dir_size( target ); if ( dir_size == -1 ) return; VString dir_size_str; dir_size_str.fi( dir_size ); str_comma( dir_size_str ); sprintf( t, "Dir size of: %s", target.data() ); say1( t ); sprintf( t, "Size: %s bytes", dir_size_str.data() ); say2( t ); } else if ( n == 'A' || n == 'S' ) /* all or selected */ { for( z = 0; z < files_count; z++) { TF *fi = files_list[z]; if ( fi->is_dir() ) /* dirs */ { if ( n == 'S' && !fi->sel ) continue; /* if not sel'd and required -- skip */ /* if ( n == 'A' ) continue; // all */ say1( fi->name() ); fsize_t dir_size = vfu_dir_size( fi->name(), 0 ); if ( dir_size == -1 ) { say1(""); /* clear status text */ return; } fi->set_size( dir_size ); } } size_cache_sort(); say1(""); say2(""); } else if ( n == 'Z' ) /* single one, under cursor */ { VFU_CHECK_LIST_POS( FLI ); if ( files_list[FLI]->is_dir() ) { files_list[FLI]->set_size( vfu_dir_size( files_list[FLI]->name() ) ); say1(""); say2(""); } else say1("This is not directory..."); } do_draw = 1; update_status(); if ( opt.sort_order == 'S' && n < 0 ) vfu_sort_files(); } /*--------------------------------------------------------------------------*/ void vfu_edit_entry( ) { char errstr[128]; int one = ( sel_count == 0 ); int z; VString str; mb.undef(); mb.push( "M Mode" ); mb.push( "A Octal Mode" ); mb.push( "O Owner/Group" ); mb.push( "N Name (TAB)" ); mb.push( "T Time/Touch Mod+Acc Times" ); mb.push( "I Modify Time" ); mb.push( "E Access Time" ); mb.push( "L Edit SymLink Reference" ); if ( sel_count ) { /* available only when selection exist */ mb.push( "--"); mb.push( "+ Target: Toggle" ); mb.push( "C Target: Current File" ); mb.push( "S Target: Selection" ); } while(1) { while(1) { str = "Edit entry: "; str += one ? "current file" : "[ SELECTION ] "; menu_box_info.ac = 9; z = vfu_menu_box( 50, 5, str ); if ( z == -1 ) return; /* canceled */ if (menu_box_info.ac == -2 ) menu_box_info.ec = 'N'; if (menu_box_info.ec == '+') { one = !one; continue; } if (menu_box_info.ec == 'S') { one = 0; continue; } if (menu_box_info.ec == 'C') { one = 1; continue; } break; } if ( menu_box_info.ec == 'N' ) /* name (rename) */ { vfu_rename_file_in_place(); break; } else if ( menu_box_info.ec == 'M' || menu_box_info.ec == 'A' ) /* attributes/mode */ { mode_str_t new_mode; int ok = 1; int err = 0; if ( menu_box_info.ec == 'M' ) { if (one) { strcpy( new_mode, files_list[FLI]->mode_str() ); file_get_mode_str( files_list[FLI]->name(), new_mode); } else strcpy(new_mode, MODE_MASK); ok = vfu_edit_attr(new_mode, !one ); } else { say1( "Enter octal mode (i.e. 755, 644, 1777, etc.)" ); VString str; int z = vfu_get_str( "", str, HID_OMODE ); str_cut_spc( str ); mode_t m; sscanf( str, "%o", &m ); file_get_mode_str( m, new_mode ); ok = (z && str_len(str) > 0); } if( ok ) { for ( z = 0; z < files_count; z++ ) if ( (one && FLI == z) || (!one && files_list[z]->sel) ) { TF *fi = files_list[z]; if(file_set_mode_str(fi->name(), new_mode) == 0) { fi->update_stat(); do_draw = 1; } else err++; } } if (err) sprintf( errstr, "Change attr/mode errors: %d", err ); else strcpy( errstr, "Change attr/mode ok." ); say1( errstr ); if (err) say2errno(); break; } else if ( menu_box_info.ec == 'T' || menu_box_info.ec == 'I' || menu_box_info.ec == 'E' ) { char t[128]; strcpy( t, "Change times: " ); strcat( t, (menu_box_info.ec == 'T') ? "MODIFY,ACCESS" : ( (menu_box_info.ec == 'M') ? "MODIFY" : "ACCESS" ) ); strcat( t, one ? " for the current file:" : " for SELECTED FILES/DIRS:" ); strcat( t, " PLEASE KEEP THE FORMAT!" ); say1( t ); strcpy( t, time2str(time(NULL))); t[24] = 0; VString str = t; int z = vfu_get_str( "", str, HID_EE_TIME ); if( !(z && str_len(str) > 0) ) break; time_t new_time = str2time( str ); if ( new_time == 0 ) // well, this is 1.1.1970 but I consider it wrong { say1( "Wrong time string format." ); break; } int err = 0; struct utimbuf tb; for ( z = 0; z < files_count; z++ ) if ( (one && FLI == z) || (!one && files_list[z]->sel) ) { TF *fi = files_list[z]; tb.actime = fi->st()->st_atime; tb.modtime = fi->st()->st_mtime; if (menu_box_info.ec == 'M') tb.modtime = new_time; if (menu_box_info.ec == 'S') tb.actime = new_time; if (menu_box_info.ec == 'T') tb.modtime = new_time; if (menu_box_info.ec == 'T') tb.actime = new_time; if (utime( fi->name(), &tb ) == 0) { fi->update_stat(); do_draw = 1; } else err++; } if (err) sprintf( errstr, "Time touch errors: %d", err ); else strcpy( errstr, "Time touch ok." ); say1( errstr ); if (err) say2errno(); break; } else if ( menu_box_info.ec == 'O' ) { #ifdef _TARGET_GO32_ say1( "Change owner/group function is not supported under DOS filesystem" ); break; #endif VString str; if (one) say1("Enter new `user.group | user | .group' for current file:"); else say1("Enter new `user.group | user | .group' for all SELECTED files:"); if( !(vfu_get_str( "", str, HID_EE_OWNER ) && str_len(str) > 0) ) break; VRegexp re( "^ *([^\\.]*)(\\.([^\\.]*))? *$" ); if( ! re.m( str ) ) { say1("Format is 'uid.gid', for example 'cade.users', 'cade.', '.users'"); break; } int uid = -1; int gid = -1; struct passwd *pwd = getpwnam(re[1]); if ( pwd ) uid = pwd->pw_uid; struct group *grp = getgrnam(re[3]); if ( grp ) gid = grp->gr_gid; int err = 0; for ( z = 0; z < files_count; z++ ) if ( (one && FLI == z) || (!one && files_list[z]->sel) ) { TF *fi = files_list[z]; int u = uid; int g = gid; if (u == -1) u = fi->st()->st_uid; if (g == -1) g = fi->st()->st_gid; if(chown(fi->name(), u, g) == 0) { fi->update_stat(); do_draw = 1; } else err++; } if (err) sprintf( errstr, "Change owner/group errors: %d", err ); else strcpy( errstr, "Change owner/group ok." ); say1( errstr ); if (err) say2errno(); break; } else if ( menu_box_info.ec == 'L' ) { #ifdef _TARGET_GO32_ say1( "Edit SymLink reference is not supported under DOS filesystem" ); #else if (!one) { say1( "Cannot edit symlink reference for selection..." ); break; } TF* fi = files_list[FLI]; if ( !fi->is_link() ) { say1( "This is not a symlink..." ); break; } char t[MAX_PATH] = ""; t[ readlink( fi->name(), t, MAX_PATH-1 ) ] = 0; VString str = t; if ( vfu_get_str( "", str, 0 ) ) { fi->drop_view(); do_draw = 1; say2( "" ); if ( unlink( fi->name() ) || symlink( str, fi->name() ) ) { say1( "Edit SymLink reference error..." ); say2errno(); } else { say1( "Edit SymLink reference ok." ); } } #endif break; } else ; } return; } /*--------------------------------------------------------------------------*/ void vfu_jump_to_mountpoint( int all ) { VString str; char t[2048]; int z; VArray va; #ifdef _TARGET_UNIX_ if ( va.fload( "/etc/mtab" ) ) return; #endif #ifdef _TARGET_GO32_ str = home_path; str += "_vfu.mtb"; if ( va.fload( str ) return; if (all) { va.ins( 0, "- b:/" ); va.ins( 0, "- a:/" ); } #endif if (va.count() < 1) return; mb.undef(); for(z = 0; z < va.count(); z++) { str = va[z]; str_cut( str, " \t"); str_word( str, " \t", t ); /* get device name */ str_cut( str, " \t"); str_word( str, " \t", t ); /* get mount point */ va.set( z, t ); /* replace line with mount point only */ struct statfs stafs; statfs( t, &stafs ); int hk = ('A'+ z); /* hot key */ #ifdef _TARGET_GO32_ if (toupper(t[0]) >= 'A' && toupper(t[0]) <= 'Z' && toupper(t[1]) == ':') hk = toupper(t[0]); #endif sprintf( str, "%c | %8.1fM | %8.1fM | %-20s ", hk, stafs.f_bsize * (opt.show_user_free?stafs.f_bavail:stafs.f_bfree) / (1024.0*1024.0), stafs.f_bsize * stafs.f_blocks / (1024.0*1024.0), t ); mb.push(str); } menu_box_info.ac = KEY_CTRL_U; z = vfu_menu_box( 20, 5, "Jump to mount-point (free/total) Ctrl+U=umount" ); if ( z == -1 ) return; if (menu_box_info.ac == -2) { str = va[z]; str_fix_path( str ); if ( pathcmp( str, work_path ) == 0 ) { say1( "Warning: cannot unmount current directory" ); return; } str = "umount " + str + " 2> /dev/null"; sprintf( t, "Unmounting, exec: %s", str.data() ); say1( t ); if (system( str ) == 0) say1( "umount ok" ); else say1( "umount failed" ); } else vfu_chdir( va[z] ); } /*--------------------------------------------------------------------------*/ void vfu_user_menu() { VArray split; VArray lines; VString des; int z; mb.undef(); for ( z = 0; z < user_externals.count(); z++ ) { split = str_split( ",", user_externals[z] ); if ( strcasecmp( split[1], "menu" ) ) continue; /* not menu item -- skip */ /* FIXME: should we care about ext's or user will override this? */ /* split[2]; // extensions */ des = split[0]; if ( des != "---" ) /* not separator */ { /* fix menu hotkeys */ str_ins( des, 1, " " ); str_set_ch( des, 0, toupper(str_get_ch(des, 0)) ); } lines.push( split[3] ); mb.push( des ); } if ( mb.count() == 0 ) { say1("No menu user externals defined..."); return; } z = vfu_menu_box( 5, 5, "User menu (externals) " ); if ( z == -1 ) return; if ( work_mode == WM_NORMAL ) vfu_shell( lines[z], "" ); else if ( work_mode == WM_ARCHIVE ) { VString str = lines[z]; vfu_user_external_archive_exec( str ); } } /*--------------------------------------------------------------------------*/ void vfu_file_find_results() { do_draw = 2; if ( file_find_results.count() == 0 ) { say1("No file find results..."); return; } ConMenuInfo bi; bi.cn = cSTATUS; bi.ch = 31; bi.ti = cINFO; bi.ac = 'p'; say1center("------- ESC Exit ----- ENTER Chdir to target ----- P Panelize all results -----", cINFO ); say2(""); int z = con_full_box( 1, 1, "VFU File find results", &file_find_results, &bi ); if ( bi.ec == 13 ) { VString fname; VString str = file_find_results[z]; str_trim_left( str, str_find( str, " | " ) + 3 ); z = str_rfind( str, '/' ); fname = str; str_sleft( str, z+1 ); str_trim_left( fname, z+1 ); vfu_chdir( str ); for( z = 0; z < files_count; z++ ) if ( pathcmp( fname, files_list[z]->name_ext() ) == 0 ) { FGO(z); vfu_nav_update_pos(); break; } } else if ( tolower(bi.ec) == 'p' ) { list_panelizer.undef(); for ( z = 0; z < file_find_results.count(); z++ ) { VString str = file_find_results[z]; str_trim_left( str, str_find( str, " | " ) + 3 ); list_panelizer.push( str ); } vfu_read_files( 0 ); } file_find_results.fsave( filename_ffr ); con_cs(); } /*--------------------------------------------------------------------------*/ VArray __ff_masks; VString __ff_path; VString __ff_pattern; VString __ff_opt; int __ff_process( const char* origin, /* origin path */ const char* fname, /* full file name */ const struct stat* st, /* stat struture or NULL */ int is_link, /* 1 if link */ int flag ) { VString str; if ( flag == FTWALK_DX ) return 0; if ( vfu_break_op() ) return 1; if ( flag == FTWALK_D ) { str = fname; str = str_dot_reduce( str, con_max_x()-1 ); say2( str ); } const char *pc = strrchr( fname, '/' ); if (pc) pc++; else pc = fname; int add = 0; int z; for ( z = 0; z < __ff_masks.count(); z++ ) if ( FNMATCH( __ff_masks[z], pc ) == 0 ) { add = 1; break; } if ( add && __ff_pattern != "" ) add = ( file_string_search( __ff_pattern, fname, __ff_opt ) > -1 ); if (!add) return 0; char time_str[32]; char size_str[32]; time_str_compact( st->st_mtime, time_str ); if ( flag == FTWALK_D ) strcpy( size_str, "[DIR]" ); else size_str_compact( st->st_size, size_str ); str_pad( size_str, 5 ); str = ""; str = str + time_str + " " + size_str + " | " + fname; file_find_results.push( str ); str = str_dot_reduce( str, con_max_x()-1 ); con_puts( "\r" ); con_puts( str, cSTATUS ); con_puts( "\n" ); return 0; } void vfu_file_find( int menu ) { VString str; char ch; if (menu) { if ( vfu_menu_box("File find", "L Last find results,D Drop find results,N File find,F Find string (no case),S Scan string (case),B Scan string (case),E Hex string,/ Regular expresion,\\ Reg.exp (no case)", 5 ) == -1 ) return; ch = menu_box_info.ec; } else ch = 'N'; if ( ch == 'L' ) { if ( file_find_results.count() == 0 ) file_find_results.fload( filename_ffr ); vfu_file_find_results(); return; } if ( ch == 'D' ) { file_find_results.undef(); vfu_file_find_results(); /* FIXME: this will show `no results' warning */ return; } __ff_pattern = ""; if ( str_find( "FSB/\\", ch ) != -1 ) /* we want search for pattern */ { __ff_pattern = vfu_hist_get( HID_FFGREP, 0 ); if (!vfu_get_str( "Enter search pattern: ", __ff_pattern, HID_FFGREP )) return; if (ch == 'F' ) __ff_opt = "i "; else if (ch == 'S' ) __ff_opt = " "; else if (ch == 'B' ) __ff_opt = " "; else if (ch == 'E' ) __ff_opt = "h "; else if (ch == '/' ) __ff_opt = "r "; else if (ch == '\\') __ff_opt = "ri"; else ; } str = vfu_hist_get( HID_FFMASK, 0 ); if ( str == "" ) str = "*"; if (!vfu_get_str( "Enter find masks (space separated): ", str, HID_FFMASK )) return; __ff_masks = str_split( " +", str ); str = work_path; if (!vfu_get_dir_name( "Enter start path: ", str )) return; __ff_path = str; /*--------------------------------------*/ if ( opt.mask_auto_expand ) { int z; for ( z = 0; z < __ff_masks.count(); z++ ) vfu_expand_mask( __ff_masks[z] ); } con_cs(); con_ta( cINFO ); con_out( 1, 1, HEADER ); sprintf( str, "Find mask: %s", vfu_hist_get( HID_FFMASK, 0 ) ); con_out( 1, 2, str ); sprintf( str, "Start path: %s", __ff_path.data() ); con_out( 1, 3, str ); if ( __ff_pattern != "" ) { sprintf( str, "Containing pattern: %s", __ff_pattern.data() ); con_out( 1, 4, str ); } file_find_results.undef(); ftwalk( __ff_path, __ff_process ); vfu_file_find_results(); } /*--------------------------------------------------------------------------*/ void vfu_read_files_menu() { char t[1024]; VArray list; int z; VString str; mb.undef(); /* I don't format src like this but it gives clear idea what is all about */ mb.push( "T Rescan DirTree" ); list.push(""); mb.push( "F Rescan Files" ); list.push(""); mb.push( "R Rescan Files Recursive" ); list.push(""); mb.push( "L Refresh all views/screen (Ctrl+L)" ); list.push(""); if ( panelizers.count() > 0 ) { mb.push( "--panelizers---" ); list.push(""); for ( z = 0; z < panelizers.count(); z++ ) { str = panelizers[z]; str_word( str, ",", t ); /* fix menu hotkeys */ str_ins( t, 1, " " ); str_set_ch( t, 0, toupper(str_get_ch(t, 0)) ); mb.push(t); list.push(str); } } z = vfu_menu_box( 25, 5, "Read/Rescan Files" ); if ( z == -1 ) { return; } if ( str_len( list[z] ) ) { /* so panelizer has been choosed */ external_panelizer = list[z]; str = ""; /* no shell options by default */ vfu_update_shell_line( external_panelizer, str ); vfu_read_files( 0 ); } else switch(menu_box_info.ec) { case 'T' : tree_rebuild(); break; case 'F' : vfu_read_files( 0 ); break; case 'R' : vfu_read_files( 1 ); break; case 'L' : con_cs(); vfu_drop_all_views(); do_draw = 2; break; } } /*--------------------------------------------------------------------------*/ void vfu_inc_search() { VString str; say1( "Enter search pattern: ( use TAB to advance )" ); int key = con_getch(); VRegexp size_re("^size:(\\d+)$"); while( ( key >= 32 && key <= 255 ) || key == 8 || key == KEY_BACKSPACE || key == 9 ) { if ( key == 8 || key == KEY_BACKSPACE ) str_trim_right( str, 1 ); else if ( key != 9 ) str_add_ch( str, key ); say2( str ); if ( files_count == 0 ) { key = con_getch(); continue; } int z; if ( key == 9 ) { z = FLI+1; if ( z > file_list_index.max() ) z = file_list_index.min(); } else z = FLI; int direction = 1; int found = 0; int loops = 0; VString s_mask = str; int s_size = 0; if( size_re.m( str ) ) s_size = atoi( size_re[1] ); else vfu_expand_mask( s_mask ); while(1) { if ( z > file_list_index.max() ) z = file_list_index.min(); if ( z < file_list_index.min() ) z = file_list_index.max(); if( s_size ) found = files_list[z]->size() == s_size; else found = ( FNMATCH( s_mask, files_list[z]->name_ext() ) == 0 ); if ( found ) break; z += direction; if ( loops++ > files_count ) break; } if (found) { FGO(z); vfu_redraw(); show_pos( FLI+1, files_count ); } key = con_getch(); } say1( "" ); say2( "" ); } /*--------------------------------------------------------------------------*/ void vfu_goto_filename( const char* fname ) { if ( files_count == 0 ) return; for (int z = 0; z < files_count; z++) { if( strcmp( fname, files_list[z]->name_ext() ) ) continue; FGO(z); return; } } /*######################################################################*/ // #include /* memory allocation debug */ int main( int argc, char* argv[] ) { #ifndef NDEBUG // mtrace(); /* memory allocation debug */ #endif print_help_on_exit = 0; con_init(); con_cs(); con_fg( cNORMAL ); con_bg( cBLACK ); con_chide(); vfu_init(); argc > 1 ? vfu_cli( argc, argv ) : vfu_run(); /* ... :) */ vfu_done(); con_cs(); con_cshow(); con_done(); if( print_help_on_exit ) vfu_help_cli(); /* printf("%s\n [http://soul.datamax.bg/~cade/vfu]\nThank You for using VFU!\n\n", HEADER ); */ return 0; } /*######################################################################*/ vfu-4.10/vfu/vfu.vpj0000644000175000001440000000240611005727265013201 0ustar cadeusers[CONFIGURATIONS] activeconfig=,Release config=,Release [GLOBAL] workingdir=/home/cade/pro/vfu vcsproject=VCS:vfu macro=\n version=6.0 [ASSOCIATION] [FILES] see.cpp vfu.cpp vfu.h vfuarc.cpp vfuarc.h vfucopy.cpp vfucopy.h vfudir.cpp vfudir.h vfufiles.cpp vfufiles.h vfumenu.cpp vfumenu.h vfuopt.cpp vfuopt.h vfusetup.h vfusys.cpp vfusys.h vfutools.cpp vfutools.h vfuuti.cpp vfuuti.h vfuview.cpp vfuview.h [STATE] SCREEN: 800 600 -4 -4 800 549 0 0 N 0 0 0 0 651 494 CWD: /home/cade/pro/vfu FILEHIST: 9 /home/cade/pro/vfu/vfuopt.cpp /home/cade/pro/vfu/vfuopt.h /home/cade/pro/vfu/vfuview.cpp /home/cade/pro/vfu/vfudir.h /home/cade/pro/vfu/vfumenu.cpp /home/cade/pro/vfu/vfufiles.cpp /home/cade/pro/vfu/vfu.h /home/cade/pro/vfu/vfu.cpp /home/cade/get [COMPILER.Release] FILTEREXPANSION=1 1 0 1 1 includedirs=%(INCLUDE) tagfiles= reffile= compile=copts: concur|capture|menu: Compile:&Compilecmd: make %n.o make=copts: concur|capture|clear|saveall|menu: Build:&Buildcmd: make rebuild=copts: concur|capture|menu: Rebuild:&Rebuildcmd: debug=copts: menu: Debug:&Debugcmd: xxgdb [exename-here] execute=copts: concur|capture|clear|saveall|menu: Execute:E&xecutecmd: make && rxvt -ls -e vfu user1=copts: hide|menu: User 1:User 1cmd: user2=copts: hide|menu: User 2:User 2cmd: vfu-4.10/vfu/vfu.vpw0000644000175000001440000000477107653255340013231 0ustar cadeusers[ProjectFiles] vfu.vpj [CurrentProject] curproj=vfu.vpj [ProjectDates] vfu.vpj=20020309022333000 [TreeExpansion] vfu.vpj 0 [State] SCREEN: 1152 864 -3 -3 1152 814 0 0 N 0 0 0 0 976 468 CWD: /home/cade/pro/vslib BUFFER: BN="/home/cade/pro/vfu/vfu.cpp" BI: MA=1 74 1 TABS=1 3 WWS=0 IWT=0 ST=0 IN=1 BW=0 US=32000 RO=0 SE=1 SN=0 BIN=0 MN=C HM=0 MF=8 TL=0 MLL=0 ASE=0 LNL=6 LCF=0 CAPS=0 VIEW: LN=.60026 CL=40 LE=0 CX=39 CY=21 WI=5 BI=27 HT=0 HN=0 HF=0 HC=4 BUFFER: BN="/home/cade/pro/vfu/see.cpp" BI: MA=1 74 1 TABS=1 3 WWS=0 IWT=0 ST=0 IN=1 BW=0 US=32000 RO=0 SE=1 SN=0 BIN=0 MN=C HM=0 MF=9 TL=0 MLL=0 ASE=0 LNL=6 LCF=0 CAPS=0 VIEW: LN=.15056 CL=22 LE=0 CX=21 CY=14 WI=5 BI=28 HT=0 HN=0 HF=0 HC=4 BUFFER: BN="/home/cade/pro/vfu/see.h" BI: MA=1 74 1 TABS=1 3 WWS=0 IWT=0 ST=0 IN=1 BW=0 US=32000 RO=0 SE=1 SN=0 BIN=0 MN=C HM=0 MF=0 TL=0 MLL=0 ASE=0 LNL=6 LCF=0 CAPS=0 VIEW: LN=.3120 CL=76 LE=0 CX=75 CY=26 WI=5 BI=29 HT=0 HN=0 HF=0 HC=4 BUFFER: BN="/home/cade/pro/vfu/vfucopy.cpp" BI: MA=1 74 1 TABS=1 3 WWS=0 IWT=0 ST=0 IN=1 BW=0 US=32000 RO=0 SE=1 SN=0 BIN=0 MN=C HM=0 MF=8 TL=0 MLL=0 ASE=0 LNL=6 LCF=0 CAPS=0 VIEW: LN=.30356 CL=13 LE=0 CX=12 CY=36 WI=5 BI=14 HT=0 HN=0 HF=0 HC=4 BUFFER: BN="/home/cade/pro/vfu/vfucopy.h" BI: MA=1 74 1 TABS=1 3 WWS=0 IWT=0 ST=0 IN=1 BW=0 US=32000 RO=0 SE=1 SN=0 BIN=0 MN=C HM=0 MF=8 TL=0 MLL=0 ASE=0 LNL=6 LCF=0 CAPS=0 VIEW: LN=.4433 CL=19 LE=0 CX=18 CY=28 WI=5 BI=16 HT=0 HN=0 HF=0 HC=4 WINDOW: 125 125 658 511 0 0 N WF=0 WT=2 "alias-vga,10,0,1" BUFFER: BN="/home/cade/pro/vfu/vfucopy.cpp" VIEW: LN=.27075 CL=3 LE=0 CX=2 CY=2 WI=67 BI=14 HT=0 HN=0 HF=0 HC=4 WINDOW: 100 100 658 511 0 0 N WF=0 WT=3 "alias-vga,10,0,1" BUFFER: BN="/home/cade/pro/vfu/vfucopy.h" VIEW: LN=.4433 CL=19 LE=0 CX=18 CY=28 WI=66 BI=16 HT=0 HN=0 HF=0 HC=4 WINDOW: 0 0 658 315 0 0 N WF=0 WT=1 "alias-vga,10,0,1" BUFFER: BN="/home/cade/pro/vfu/vfu.cpp" VIEW: LN=.60026 CL=40 LE=0 CX=39 CY=21 WI=144 BI=27 HT=0 HN=0 HF=0 HC=4 WINDOW: 25 25 658 315 0 0 N WF=0 WT=4 "alias-vga,10,0,1" BUFFER: BN="/home/cade/pro/vfu/see.cpp" VIEW: LN=.15056 CL=22 LE=0 CX=21 CY=14 WI=145 BI=28 HT=0 HN=0 HF=0 HC=4 WINDOW: 50 50 658 315 0 0 M WF=0 WT=5 "alias-vga,10,0,1" BUFFER: BN="/home/cade/pro/vfu/see.h" VIEW: LN=.3120 CL=76 LE=0 CX=75 CY=26 WI=146 BI=29 HT=0 HN=0 HF=0 HC=4 FILEHIST: 9 /home/cade/pro/vfu/vfuopt.cpp /home/cade/pro/vslib/vstring.h /home/cade/pro/vslib/vstring.cpp /home/cade/pro/vfu/vfumenu.cpp /home/cade/pro/vfu/vfucopy.cpp /home/cade/pro/vfu/vfucopy.h /home/cade/pro/vfu/vfu.cpp /home/cade/pro/vfu/see.cpp /home/cade/pro/vfu/see.h vfu-4.10/vfu/vfu.vtg0000644000175000001440000074000007653255240013204 0ustar cadeusersVSDBÜ ÀàTAG_DATABASE_5.0`  P€ÿÿÿÿ@ÿÿÿÿ`ÿÿÿÿ`  P€ÿÿÿÿµ Å€€VS_OCCURRENCES€@ÿ vsOccurrenceNamevsFileId © Àvs_occur_name_ndx   vs_occur_fk_ndxÿÿÿÿ€@) VS_TAGS €ÿvsTagNamevsTypeIdvsTagFlagsvsClassIdvsFileId vsLineNumber vsSignature©```vs_tag_ndx€€€vs_file_fk_ndx©   vs_class_fk_ndx€ÿÿÿÿ1@5@VS_CLASSESvsClassId vsClassName!vsClassParentsÿ!vsClassOnlyÿ!vsClassSimple¹vs_class_id_ndx 5vs_class_ndx 5vs_cname_ndx 5vs_sname_ndxPÿÿÿÿ,@/@VS_TYPESvsTypeId@vsTypeName=vs_type_id_ndx=vs_type_ndx ÿÿÿÿ0@0@VS_EXTENSIONSvsExtensionIdÿvsExtensionName ÿÿÿÿÀÀVS_FILESÀvsFileIdvsFileNamevsFileModificationDate vsFileType vsFileIncludedByvsFileExtension5vs_file_id_ndx5vs_file_inc_ndx©   vs_file_ndx @ÿÿÿÿÿÿÿÿÿÿÿÿÀ.ufvÀ.ufvÀaufvÀaufvÀcufv Àcufv Àdufv Àdufv Àfufv ÀfufvÀmufvÀmufvÀoufvÀoufvÀsufvÀsufvÀsufvÀtufvÀtufvÀuufvÀuufvÀvufvÀvufvÀ@0ÿÿÿÿÿÿÿÿü22íÝ̺«šŠ{k[K7&öç×ȹªœŒ{jWG6&öçÕ®Ÿ~n\J9+çÒ·ÿÿÿÿ4@Options5@3@CopyInfo4@2@TF3@1@SeeEditor2@ÿÿÿÿSeeViewerÿÿÿÿÿÿÿÿ cÿÿÿÿ.@,tag/@-@+cursor.@,@*subproc-@+@)subfunc,@*@(group+@)@'file*@(@&include)@'@%task(@&@$procproto'@%@#eventtab&@$@"control%@#@!menu$@"@ form#@!@trigger"@ @view!@@index @@column@@table@@database@@friend@@import@@param@@lib@@prog@@prop@@func@@const@@lvar@@var@@package@@destr@@ constr@@ interface@ @ label@ @ union @ @ class @ @enum @ @enumc @@struct @@gvar@@typedef@@define@@proto@ÿÿÿÿproc`@ÿÿÿÿÿÿÿÿÿÿÿÿÚª¿þÿufv"ë¿ýÿufv"9?þÿufv"1?þÿufv"ë?þÿufv"¤¿ýÿufv"¥¿ýÿufv"¥Ÿüÿufv"8€ufv"¡þÿufv"[ýÿufv"ºŸüÿufv"è¿ýÿssa<Íþÿytc<.€rid<$€mpd@_yek2 _yekŠ€snik;@tsal tfel3@tsil³?þÿgnol ewolq`atsl<€xnyl' niam"€ksam _xamD _xamS€cxam@hxam`bm‘?þÿunem" unemo€edom‡ edom„ edom4Àedom‰ edom† edomˆ eman+Àeman,ÀemanZ€emanH€f_on€i_on€eyonhýÿeyon~€c_kow€a_mo:@a_mo€a_mo5@i_mo€n_mo€nepo@nepo-@tpoÏßüÿitpoŸüÿrevo€revo$@revo€enap“?þÿhtap›?þÿhtap htapµþÿhtap±þÿhtap¯þÿsp×ýÿp_cr§?þÿdaer@laer1@rfer$Àrferœ@omerB@omerA@omer/@uqer6@eser#Àeser•@eser €hgir8@nur%@nurH@t_xr[ si_s:€si_s€evas5@yas•Àyas@1yas–À1yasŽ@1yas—À1yas@2yas˜À2yas@2yasœÀ2yas”@2yas™À2yas€@_yas‹@_yasgßüÿcyasšÀcyas’@_ees•?þÿdees'@dees‚¿þÿeees)@vees@les6À_les?¿þÿ_les Ÿüÿ_les=¿þÿoes- _tes„€_tes2@_tesŒ€_tes/À_tes—@_tesfßüÿ_tes-À_tes@_tes€_tes|þÿlehs‡?þÿlehs# lehs…?þÿlehs”ßüÿlehsƒ?þÿwohs€wohs#@wohs wohs\`wohsG`wohs% ezis7Àezis¾¿ýÿezisR@ezisC€ezis+@ezis0@ezisV@ezisA€ezisU@ezis@€ezis(@ezisW@ezisB€ezis/`ezis`tros tros tros ts5Àrats­?þÿtatsœ¿þÿtats}¿þÿovs( _gat¢Ÿüÿ_gat mgat~ýÿftÎ?þÿftØ?þÿftg¿þÿemit2`emit`emitÀ@emit¿@emit€emit€_pmt©?þÿggotƒ€eert eert eertM@eert:€eertJ@eertä¿þÿeertO@eertÚ¿þÿeertE@eert7€eert¬¿ýÿeertÄ¿ýÿeertL@eert8€eertP@eert@eertH@eert\€eertK@eert6€eertI@eert5€eertG@eert>€mirt?þÿepyt3Àh_pu"@t_puj@adpu*Àadpu¡@adpu´Àadpu®@_esu _esu resu™?þÿresu?þÿ_ufvÀÀ_ufv£@_ufv¿À_ufv²@_ufvR€_ufvf@_ufv^€_ufvL€_ufv.`_ufv`_ufv3`_ufv`_ufv,`_ufv`_ufv¼À_ufv±@_ufv@_ufv@_ufv½À_ufv¬@_ufv«À_ufv€_ufvD@_ufvZ€_ufvF@_ufv[€_ufvÀ_ufv¡À_ufv¤@_ufvÄÀ_ufv°@_ufv§À_ufv€_ufv€_ufv-@_ufv €_ufv!@_ufvY@_ufv>@_ufv®À_ufv€_ufv¢À_ufv©@_ufvd`_ufvM`_ufvc`_ufvL`_ufv¾À_ufv¯@_ufvxýÿ_ufvq _ufv? _ufv‘€_ufvºÀ_ufv€_ufv-€_ufv2@_ufv¦À_ufv¥@_ufv¥À_ufv“@_ufv1`_ufv`_ufv@_ufv @_ufvY€_ufvM€_ufv¬À_ufv€_ufv­À_ufv€_ufvS€_ufvF€_ufvC@_ufvî¿þÿ_ufv>`_ufv%`_ufv9`_ufv$`_ufvÁÀ_ufv €_ufv €_ufvÀ_ufv¢@_ufvžÀ_ufv§@_ufv5`_ufv`_ufv:`_ufv`_ufvÈŸüÿ_ufvãŸüÿ_ufv4`_ufv`_ufv<`_ufv"`_ufv;`_ufv `_ufv¸À_ufv!€_ufv›À_ufv‘@_ufvÅÀ_ufv€_ufv‰€_ufvýÿ_ufv–ýÿ_ufvh`_ufvR`_ufvl`_ufvV`_ufvk`_ufvU`_ufvf`_ufvT`_ufvi`_ufvO`_ufvm`_ufvS`_ufvg`_ufvQ`_ufvj`_ufvX`_ufvËßüÿ_ufvzýÿ_ufvE?þÿ_ufvŽ€_ufv_€_ufvG€_ufv–¿ýÿ_ufvÓÀ_ufvV€_ufv=€_ufvQ€_ufv`@_ufvÃÀ_ufv €_ufvU€_ufvh@_ufvW€_ufvE€_ufve`_ufvK`_ufvb`_ufvP`_ufv·À_ufv€_ufvP€_ufvd@_ufvŸÀ_ufvª@_ufv À_ufv¦@_ufv= _ufv€_ufv> _ufv€_ufv©À_ufv­@_ufv¤À_ufv«@_ufv]€_ufvK€_ufvÂÀ_ufv?`_ufv(`_ufv&`_ufv€_ufvp€_ufvc€_ufv¨À_ufv¨@_ufv¬€_ufv§€_ufv`_ufv¨€_ufv`_ufv©€_ufvªÀ_ufv€_ufv0`_ufv `_ufv+`_ufv`_ufv@_ufv@_ufv¶À_ufv €_ufvî_üÿ_ufvcßüÿ_ufv³À_ufv€_ufvB weiv0ÀweivŸ@weiv‹?þÿweiv?þÿa_mw?Àn_mw>Àkrow¿?þÿkrow½?þÿx À_paz ees~¿þÿees~¨¿þÿft~…Ÿüÿft~ŠŸüÿ€`ÿÿÿÿÿÿÿÿ•¿þÿèþÿû¿ýÿø¿ýÿð¿ýÿŠþÿ”þÿåþÿ¨¿ýÿ—¿ýÿ ýÿ™ýÿýÿnýÿÆßüÿ–ßüÿ…ßüÿaýÿVýÿúŸüÿÙŸüÿßüÿ©Ÿüÿ’Ÿüÿ @ÿÿÿÿÿÿÿÿÿÿÿÿÓŸüÿÝþÿ¬þÿÝŸüÿÑßüÿ5?þÿ„ßüÿóŸüÿ…¿þÿ|¿þÿ7?þÿÄ?þÿÅ?þÿèýÿóýÿÔßüÿÀ0ÿÿÿÿü­Ûº›wU0 éÇ¡}X5ï˧…_;õЭÿÿÿÿÀ#Ò®#ø§vfuview.hÀÀ%ÓøÏvfuview.cppÀÀ"Ò®#ø§vfuuti.hÀÀ$Ò)$˜:vfuuti.cppÀÀ$Ò®#ø§vfutools.hÀÀ&Ò®#ø§vfutools.cppÀÀ"Ò®#ø§vfusys.hÀÀ$Ò®#¤vfusys.cppÀÀ$Ò®#¤vfusetup.hÀÀ"Ó.'$ Nvfuopt.hÀÀ$Ó.'1`mvfuopt.cppÀÀ# Ò®#¤vfumenu.hÀÀ% Ò®#¤vfumenu.cppÀ À$ Ò®#¤vfufiles.hÀ À& Óñ&ÀÚvfufiles.cpp À À" Ò®#¤vfudir.h À À$Ó¸  @œvfudir.cpp À À#Ó4'*Ðvfucopy.h ÀÀ%Ó4')ØÖvfucopy.cpp ÀÀ"Ò®#¤vfuarc.hÀÀ$Òl,Єvfuarc.cppÀÀÓ.'$Xvfu.hÀÀ!Ó4'+Ïvfu.cppÀÿÿÿÿ!W4',esee.cppà0`üŒ ìíÞ±ÒǼ¨ž‘?l^I7,î ö¼ÞÔÈ“®¥œe…|nZQHŒ3& þöðÜÓǼ³©›ocUI=6+" ô7ÝÐÆº®š“ŒvpbSD%ùòéáØÏǾ°¢šÛ‚vf[NE8*ùâȽ°¤™†zla[PC5(2÷ìàÚÍÀ²©¡“vhZL=.# üòæÚ볪œ‡oh^6& øáÑÉ÷¨›“qh]TB8 ) ýõêâÒË¿¸®žŒxf]SK@ùêÛ̽®Ÿwh^O@1"úìÞÓǵ¦—ˆzl^PB4&*  ô å ¥ Ô Ä µ h • † w W K = ÷ $   ¯ à É ¶ v   ’ ‚ @ g Y L þ 3 ! Æ í ß Ò À· ¢ • € n X E 2 &   òàÏ©®‹|l[I8&ÿçÖŶùŠ~rjaXMB6, GëßÑÆ½³ªœ”‡}oh\P8)þõêâÔÇ»°¢•Š{m`M?2# þòæÛÐŽªŸ“ˆrg[OC90# ìtime_str_compact f_time gr_name st_gid getgrgid _grp group f_group pw_name sprintf st_uid getpwuid _pwd passwd f_owner f_modelong_name_viewopt sttype stsize sttime stgroup stowner stmoderefresh_view viewa_new_size set_sizedrop_viewget_item_color last_dotstr_rfindlast_slash strlen MODE_OFF_mode_str strcpy _is_dir _is_link_type_str_st memset NULL _ext_name_ext _name resetsay2centersay1center data str_mul str_lenslsaycenter errno strerrorstrsay2errno say2 a_str say1 con_cecon_max_y con_outcon_max_xstr_dot_reduce va_endres va_start vlist va_list ASSERT format attr linesay say_str say_bufdo_draw_status do_draw MAX_PATH_full_namefilename_atlfilename_ffrfilename_size_cachefilename_treefilename_historyfilename_conffilename_opthost_name_strgroup_id_struser_id_strshell_progshell_optionsshell_editorshell_browserext_colorsview_profileview_profilestrim_treembpanelizerssee_filters historyuser_externalspath_bookmarksfile_find_resultsdir_tree_filedir_tree_changed dir_treefiles_mask_arrayfiles_mask rc_path tmp_pathhome_pathstartup_pathfile_list_indexfs_block_size fs_total fs_free sel_sizesel_countfiles_size fsize_tfiles_countMAX_FILESfiles_listTFlist_panelizerexternal_panelizerarchive_extensions VArrayarchive_patharchive_namework_pathwork_mode "see.h""vfutools.h""vfuarc.h""vfusys.h""vfuuti.h""vfumenu.h""vfuview.h""vfudir.h""vfucopy.h""vfufiles.h""vfuopt.h" "vfu.h"KEY_ALT_9KEY_ALT_8KEY_ALT_7þ)ààààà à à à à ààààààààààààààààààà à!à"à#à$à%à'à(à)à*à+à,à-à.à/à0à1à2à3à4à5à6à7à8à=à>à?à@àAàBàCàDàEàFàGàIàJàKàLàMàNàOàQàRàSàTàUàVàWàXàYàZà[à\à]à^à_à`àaàbàcàdàeàfàgàhàiàjàkàlàmànàoàpàqàràsàuàyàzà{à|à}à~àà€àà‚àƒà„à…à†à‡àˆà‰àŠà‹àŒààŽààà‘à’à“à”à•à–à—à˜à™àšà›àœààžàŸà à¡à¢à£à¤à¥à¦à§à¨à©àªà«à¬à®à¯à°à³à´àµà¶à·à¸àºà»à¼à½à¾à¿àÀàÁàÂàÃàÄàÅàÆàÇàÈàÉàÊàËàÌàÍàÎàÏàÐàÑàÒàÓàÔàÕàÖà×àØàÙàÚàÛàÜàÝàÞàßàààãàäàåàæàçàèàéàêàëàìàíàîàïàðàñàòàóàôàõàöà÷àøàùàúàûàüàýàþàÿàááááááááá á á á4€5€6€7€8€9€:€;€<€=€>€?€@€A€B€C€D€E€F€G€H€I€J€K€L€M€N€O€P€Q€R€S€T€U€V€W€X€Y€Z€[€\€]€^€_€`€a€b€c€d€e€KEY_ALT_6KEY_ALT_5KEY_ALT_4KEY_ALT_3KEY_ALT_2KEY_ALT_1KEY_ALT_0KEY_CTRL_TKEY_CTRL_WKEY_CTRL_H_TARGET_GO32_ KEY_DEL KEY_F3KEY_ALT_GKEY_ALT_SKEY_ALT_FKEY_CTRL_D KEY_F2KEY_CTRL_SKEY_CTRL_YKEY_INSERTKEY_CTRL_A npageKEY_CTRL_V ppageKEY_CTRL_UKEY_CTRL_FKEY_CTRL_BKEY_CTRL_PKEY_CTRL_NKEY_CTRL_KKEY_CTRL_XKEY_CTRL_Coiocporpoyox pend pcloseEOF popen FILElast_pipe_cmdinsert_pipe_cmdstr_cut_rightremove_line floadfn kinsertncauto_indentins kenterkbsdelset nstr kdel right leftk fsaveremove_trails save insert fromdraw_linestr_countcrow real_colstr_ins_ch str_deljmapexpand_tabsset_cursorrequest_quit push F_OK accessinsert_fileremove_all countvamaxmodSeeEditorOptionsSeeEditor pagepossv SEEDROW colpage SEEDCOL tabsize fgetchandle_tabhandle_bs KEY_F con_csKEY_CTRL_LKEY_CTRL_EKEY_NPAGEKEY_PPAGEKEY_ALT_H KEY_F1KEY_BACKSPACEKEY_ALT_Xrun helpcon_chide con_puts str_findn toupper strchr KEY_END KEY_HOME KEY_UP KEY_DOWN KEY_LEFTKEY_RIGHT con_beep fwriter con_xycon_cshow bytepos epos editb editbs in_text hex_edit strcpyMAX_SEARCH_LENii find no_caselast_searchfind_next new_line atol hex2long str_upstr_cut_spc new_posTextInput go_totmpcon_getchcon_kbhit end2end home downres wrapup hex_mode draw chGREEN chREDstr_trim_left show_eolshow_rmarkshow_lmarkread_texty cpos draw_txtcnch grid dec_pos sprintf fread SEEK_SET fseekstri draw_hex str_tr size filtercs con_out str_padstr_sleft str_lenssssfile_size fopen xlat fclose a_fname openMAX_ESCAPE_KEYSzkeyescape_on closeSEE_VERSION help_str bsize buff cols status rowscon_max_y ymaxcon_max_x xmax ymin xminauto_size do_draw freezed fnameend_reachedcollast_line line NULLfescape_keys memsetopt a_optSeeViewerOptionsSeeViewerbgw_xlat_tablebg_xlat_table HEXCHARS fsize fpos CHKPOS assert ASSERT "see.h"@ÿÿÿÿ ¸àees"áees"Ïàufv" áufv"öàufv"ûàufv" ufv"- ufv"¡ufv"àufv"Aáufv"n@ufv"o@ufv"Aufv"*Aufv"áufv"¨àufv"áufv"­àufv"áufv"@ufv"áufv"¬àufv"áufv"Œ`ufv"/ ufv"àufv"x@ufv"áufv"ªàufv"áufv"‘`ufv". ufv"@ufv"+Aufv"áufv"áufv"“`ufv"2 ufv" ¡ufv"àufv"Eáufv"@ufv"v@ufv"áufv"«àufv"`ufv"0 ufv"¡ufv"àufv"u@ufv".Aufv"­Aufv" ufv"áufv" ufv"áufv"`ufv"Báufv"w@ufv",Aufv"áufv"@ufv"áufv"©àufv"`ufv"1¡ufv"àufv"Ñàufv"Dáufv"t@ufv"/Aufv"áufv"áufv"Ž`ufv"1 ufv" ¡ufv"àufv"@ufv"z@ufv"-Assa<àssa< ytc< rid<÷ampdarat_m`rat_ÿàrat_:`rat_ rat_árat_arat_z rat_àrat_árat_Fárat_@rat_‚@rat_CArat_  rat_`rat_  rat_Hàpyt_|ápyt_I diu_?`ufv_öaufv_õàufv_O`ufv_ ufv_å ufv_.¡ufv_Îàufv_Žáufv_]@ufv_ÿ@ufv_¬Aeiv_`eiv_à1a8á2a;áoc_a÷`oc_a}àaf_a4áaf_ax`cf_a3ácf_aw`nf_a4ànf_a›ànf_a˜`si_a `si_a àek_a“àil_ay@il_aAom_a0`om_aŠ`n_a‰àan_a `an_a àen_aö`en_a en_a†aen_a‡àen_a`en_aàen_a‰áen_aàen_a#`en_aàno_a)`no_a‰`po_aàpo_aø`po_a~àpo_a~@po_aAap_a``ap_awàap_a—`er_a°àer_a? er_aì ts_a `ts_a àts_aiáts_afàav_a™`hw_a…àroba[árobad`robaáca•aeccaµàeccaN`eccaCáecca­ ecca@eccak@tca¥àtca•€tca™€itcažaitcadáddaÙalla·alla§àllaHAlla€olla5àollaäàolla¹@ollaláolla @olla²@ollaAonoaráonoaoáonoaqáhcra áhcra+àhcra…àhcraáhcra(àhcra¸àhcraù`hcra\ hcra•@hcrasAhcraáhcra)àhcraµàhcraú`hcraš@hcratAcgraÞ`vgraß`icsaD€essaàessa\áessa? essaáessaô`essa] essaÀ@essa4Aessa àmitaFàmita áfota…aiotaÅàiota¿ iotanàiotag@lotapàrttaZárttacàrtta—àotuaÔàotua” otua7àotuaùàotuaàxa„áx_gb à_wgbàibÈaob¡koob‹àkoobÁ`koobˆàkoob¿`koobŒàkoobŠàdsb tesbaazisb+àfub6€fub¿@fubAffub)àetyb‚àetyb"`etyb„`etyb<àetybûàetybL`cÂàc\A1c7á2c9ád_bc€rabcHarabc:áalbcN€albcõaalbc1áalbcEAulbc[àulbc+álobcfAayccSaaycc]àaycc5áaycc=AergcYàergc>áhcRàhcU`hc{àhc$áhc´`hc¡hc@hc³@lbhc¥àlbhc«àychc¨àychc3áidhca`idhcÑàidhcaidhcš aehcQaaehc#áaehcQArghc]àrghc¦àpkhcàamhcªàomhc&aomhcóàomhcjáwohc´awohcjáerhc\àerhc§àerhc(áhwhc©àhwhc.áhwhcFAeyhc¬àeyhc*áfnicä`fnic“€fnic[afnic»àfnic)áfniclAfnic'áfnic—Apnicº`pnic,ápnic¹`pnic0ápilc‰€pilc›€pilc€pilc‡€pilc‚€pilcŒ€pilcš€pilcŽ€pilc²€pilc”€pilc˜€pilcÉ€pilcÈ€pilc…€pilc€€pilcÊ€pilcÄ€pilc´€pilc³€colc£`colc¢`colc¤`solc.àsolcasolcÂàsolc`solc©`c_mc¸`c_mcæàc_mc1`c_mcR`d_mcál_mc¹`l_mc3`l_mcT`m_mc5`m_mc¶`m_mc2`m_mcS`gamc\àgamc@ádmc}anemc¡nemc=ánemc¡nemc<ánemc¡nemc?ásemcgàsemcvásemcKasemc/áncSàncT`nc¡roncóaronc&áronc;AtncÞ@locàoloc!àoloc]Aploc¥àsloc(àmmocQàpmocZ€_noc‡à_nocò`_noc¥ _nocÊ@_nocôa_nocgá_nocIa_nocmA_noc“à_noca_noc×`_nocð@_nocžà_noc`_nocƒà_nocó`_noc¸`_nocñ@_noc3¡_nocì`_nocòa_nocÉa_nochà_noc3`_nocN`_nocÄ`_noc¦ _nocB@_nocž@_nocí`_nocgà_noc@_noc#à_nocdá_noc?á_noc¼`_noc÷@_nocLA_noc%à_nocfá_noc@á_nocÃ`_nocl _noc,¡_nocõ@_noc–A_noc!¡_nocAà_noceá_noc>á_nocPa_nocOA_noc’à_nocÝa_nocGa_noca_nocÿ`_nocâa_noc¡_noc„à_nocþ`_noc²`cnocM€cnoc-ácnocaAmnocÇaypocáypoc`ypocP`ypoc*`ypoc;àypocíàypoc>`ypoc6àypocèàypoc6áypocq`ypocD@ypociáypoc9àypocîàypoc%áypocY`ypocC@nuoc°ànuocç`nuocÇ€nuocÐ`nuocT nuoc-¡nuocMànuoc5@nuocÉ@pc€áalpc`alpc%áalpc‡AsopcUàa_rcqáa_rc\`o_rcZ`s_rcrás_rc[`dercXàderc9áscBàscascºàatscÜ`atscJaatsc4áatscAáatsc6ágatc7ágatcgAmitcYamitcDàmitcámitcÄ@rrucKArrucµArruc.`rruc]`rruc:árrucf`esuc rawc8árawc`AihwcO€ihwc^àihwc2áihwcbAxc…áleycZàd@an_d`an_d¤`atadG€atadcáatadïàatadTáatadaatadÄàatadj@atad“Aed`ed `_cedOàledÐàled†aledPàledà@sedÁacseduácsede`_vedyáived áivedj`ived#áivedo`id‰ápgidf@rid`rid`rid`ridš`_ridï`_rid @_rid9@_rid¯`_rida_rid0a_ridª@_rida_rid6á_ridEà_ridþ`_rid7á `ÿÿÿÿÿÿÿÿöÿÿü_þÿ‹þÿþÿþÿ»ŸýÿÛŸýÿû_ýÿÔ_ýÿM_ýÿý^ýÿÕ^ýÿóýÿmýÿìýÿÅýÿyýÿë¿üÿ“¿üÿ¿üÿ¿üÿÛ¾üÿ|þÿïüÿ@0`€üºÈ÷àÄ} 9—y>R à ¡oc>,å¹›} õIfû¸»¿¥¤> @É‚&÷]=¡õÜ»8†lSÅé-–oO¤ã¾ŒsWãÆrTªŽ ;' ` ¹. ßL.o̦ í ë×ò^>ŸKðîÕfÊ«ˆ«L+êÚ«—½ƒQ=© ǤDAÜÝ{¨ì‹w4m졧 û y\:iêÄœŸ ý Î ¶ _ 2 Ë ™  ` ? " ç É « ­ o R 6 ™ x d D 0  û Õ Á ­ I(†size_cache_compose_keyVStringconst char*s,fsize_t size? size_cache_cmpintconst char*s1,const char*s2%#SIZE_CACHE_OFFSET12€!@=Ýtree_draw_posvoidScrollPos&scroll,int opos€@5 Ätree_draw_pagevoidScrollPos&scroll€ @W">vfu_get_dir_nameintconst char*prompt,VString&target,int should_exist$€)@*@,@-@.@/@1@2@3@4@5@6@7@8@9@:@;@<@=@>@@@A@B@C@D@E@F@H@‚@ €) €‚@2Cstatusvoidconst char*format,...€) €}@/ÏSEEDROW(sv.pos()-sv.page()+1)€o@)Rfindintconst char*opts$€@@@@@@@@@@@ @"@#@$@%@?@Z@e@g@j@m@o@p@u@  *find_next_hexintint rev®end_txtvoid¨end_hexvoidŒdown_txtvoid„down_hexvoidTE€@@@ @ @ @ @@@@@@@@@@@@@@ @"@#@$@%@'@)@*@,@-@.@/@1@2@3@4@5@6@7@8@9@:@;@<@=@>@?@@@A@B@C@D@E@F@H@Z@e@g@j@m@o@p@u@}@‚@ €  ) iup_txtvoidaup_hexvoid€@e@/·filtervoidVString&s,int size€Z@2˜statusvoidconst char*format,...€ %MAXCOLS1024€œ€`€a@È@&Àfs_block_sizefsize_t€`@Æ@!¿fs_totalfsize_t€c@Ä@ ¾fs_freefsize_t€b@Â@!¼sel_sizefsize_t€]@½@»sel_countint€\@ @#ºfiles_sizefsize_t€T@_@ ¹files_countintîTIMECMP_D1íTIMECMP_DT0ëGSAME_TYPE11êGSAME_MODE10éGSAME_GROUP9èGSAME_OWNER8çGSAME_TIME17æGSAME_TIME6åGSAME_DATE5! äGSAME_DATETIME4ãGSAME_SIZE3âGSAME_EXT2áGSAME_NAME1V%Èvfu_cmp_files_crc32intconst char*src,const char*dst,const char*name&"„vfu_action_minusvoid-!Ivfu_action_plusvoidint key@ vfu_browsevoidconst char*fname,int no_filters/+ñvfu_browse_selected_filesvoid/Âvfu_editvoidconst char*fname#¥update_statusvoidIpvfu_shellvoidconst char*a_command,const char*a_options3(Svfu_toggle_view_fieldsvoidint ch(<vfu_signalvoidint sig&",vfu_reset_screenvoidvfu_donevoid2ûvfu_clivoidint argc,char*argv[]"ávfu_help_clivoidævfu_runvoid/Îvfu_exitintconst char*a_path5±vfu_exit_pathvoidconst char*a_path÷vfu_initvoidªvfu_helpvoidTupdate_statvoidconst struct stat*a_new_stat=NULL,int a_is_link=-1"$refresh_viewvoid!viewconst char*drop_viewvoid1 set_sizevoidfsize_t a_new_size4ðset_namevoidconst char*a_new_name.Ùfull_nameconst char*int fix€˜@ MÇTFconst char*a_name,const struct stat*a_stat,int a_is_link°resetvoid:¨say2centervoidconst char*a_str,int attr:£say1centervoidconst char*a_str,int attrB–saycentervoidint line,int attr,const char*a_strsay2errnovoid4Šsay2voidconst char*a_str,int attr4…say1voidconst char*a_str,int attrAysayvoidint line,int attr,const char*format,...#wsay_bufchar[1024]# odo_draw_statusintndo_drawint%Rview_profilesVArray!Ptrim_treeVArrayNmbVArray"LpanelizersVArray#Ksee_filtersVArrayJhistoryVArray& Iuser_externalsVArray)#Cfile_find_resultsVArray%"@dir_tree_changedint ?dir_treeVArray(";files_mask_arrayVArray&/fs_block_sizefsize_t!.fs_totalfsize_t -fs_freefsize_t!+sel_sizefsize_t*sel_countint#)files_sizefsize_t (files_countint*&files_listTF*[MAX_FILES]& $list_panelizerVArray*$!archive_extensionsVArraywork_modeint€@U@”€&"see.h"&"vfutools.h"&"vfuarc.h"&"vfusys.h"&"vfuuti.h"&"vfumenu.h"&"vfuview.h"&"vfudir.h"&"vfucopy.h"&"vfufiles.h"& "vfuopt.h"& "vfu.h"[runintRhelpvoid%=findintint no_casefind_nextint%!ñinsert_pipe_cmdvoid)Üremove_trailsvoidint n Ñremove_allvoid'»remove_linevoidint n/¯insert_filevoidconst char*fn$Žkinsertvoidint chekentervoidLkbsvoid2kdelvoid,go_tovoidendvoidhomevoidrightvoidîleftvoid!Êrequest_quitint¸saveint#¥drawvoidint from%‹draw_linevoidint n „set_cursorvoid%treal_colintint row3closevoid,openintconst char*a_fname'escape_onvoidint key2ÑSeeEditorSeeEditorOptions*a_opt(ÎSEEDCOL(col-colpage+1)'©read_textintint&cposðrunintçhelpvoidfhex_editvoidÎgo_tovoidÁend2void homevoidXdrawvoiddraw_txtvoidÁdraw_hexvoid,¯filtervoidchar*s,int sizeclosevoid,zopenintconst char*a_fname'jescape_onvoidint key2)SeeViewerSeeViewerOptions*a_opt+ bgw_xlat_tablechar[2][64]*bg_xlat_tablechar[2][64] HEXCHARSchar[];CHKPOSASSERT(fpos>=0);ASSERT(fpos<=fsize)ASSERTassert&"see.h"& & `0à üèÿòèÝÒÊ¿¶«€rj[PA’0% ôâÜÖÉõ©ž„sg[I3'þäʰŸ(„yh_V1! óéàÕË·¬ž“~m[I1 ÷áמ·°¥š‹€th^UB0% ìâ×ÊÄ·«ž…paK>6C îßÑÆ·ª™‹ykYL;/÷èÚÌ´¥}kVB5!÷áÒ»¥h]O=.(ÿ÷îÔÆ·¡“…gXO=/õâÖȼ°¢Ž€eWC5#ùëÝÏÁ³¥’„:. òâÑÆ«šŽ‚ypg\SH>- òéÞÑļ´Ÿ’„yp`RD5/$ ýòâ×ÌÁ·­}ti_S@3'ñéâÔÉÀº²¡—‡xk^O?6*ýñåÐȺ¯§ “ˆwiNF93øòæÎƾ¶®¡”…vhYF7(ø é Ú Ë ½ ¯   „ } v m d Z O 4 &  ý ö ï × Ñ Ã ³ £ œ ”  k ` K 3 õ è Ø Æ º ª ‡ x p i U ? 7 &   þ ð á Ö Ç ¿ ² ¤ ” ˆ t c R ; ,    ÿ ò ä × Ç º ­ ¡ š ‚ v i _ N F > ,  êß×Ê¿¹³©‘‰‚xpdWOH9/' ýîÔĽ¬šƒyj\K:/&úóçßÒŰ£š‰zk`UL9*ýôéÞÒǼ°¡[~m M>/  _VFU_H_ cBLACK con_bg cNORMAL con_fg NDEBUG main s_mask loops founddirectionstr_add_chstr_trim_right list ftwalk con_taHID_FFMASKHID_FFGREPvfu_hist_get menu con_putssize_str_compact size_str time_stradd strrchrpc FTWALK_Dvfu_break_opFTWALK_DX flag origin__ff_process__ff_pattern__ff_path__ff_masks fsavevfu_nav_update_posstr_trim_leftcon_full_boxbiConMenuInfovfu_file_find_resultsstr_get_chstr_set_ch str_insstrcasecmpdes linesKEY_CTRL_Uhkset str_word str_cutins floadvaall symlink is_link chowngu gr_gid getgrnamgrp pw_uid getpwnampwdregiduidHID_EE_OWNER utime st_mtime modtime st_atime actimetb utimbuf str2time new_timeHID_EE_TIME time2strMODE_MASK new_modeacone errstrvfu_sort_filessort_orderVFU_CHECK_LIST_POSdir_size_strvfu_dir_size dir_sizePS toupperstr_cut_spcHID_FMASK new_masktmpa_new_mask renamefile_existTextInputtag_mark_pos pageposyHID_COMMANDScmdvfu_tool_classifyvfu_tool_renamemserrHID_MKPATH#vfu_user_external_archive_execkey_by_name ext_strvfu_edit_attrMODE_STRING mode_strmode_str_tHID_GS_GREPpatvfu_get_dir_name targetvfu_expand_maskmask_auto_expandpopsmHID_GS_MASKvfu_get_strselactionmvfu_pack_files_listecstsame_fsize same_int same_strsame_modevfu_global_select_same strcmp ctime tmp2 tmp1t2t1 time_tvfu_time_cmpTIMECMP_T1TIMECMP_TTIMECMP_DTIMECMP_DTGSAME_TYPEGSAME_MODEGSAME_GROUPGSAME_OWNERGSAME_TIME1GSAME_TIMEGSAME_DATEGSAME_DATETIMEGSAME_SIZEGSAME_EXTGSAME_NAMEfile_crc32 stat_dst stat_srcfn2fn1dstsrcvfu_cmp_files_crc32 pathcmpn unsetenvstr_cut_rightvfu_browse_archive_filep type_strextvfu_user_external_findKEY_ENTERRX_TEMP_LIST setenv name_extfikey viewerSeeViewersvointernal_browser S_IWUSR S_IRUSR chmod vfu_tempstr_file_name_ext FNMATCH maskexpand_pathfull_fname tmp_name new_nameno_filtersstr_replace closerequest_quitrunr open editorSeeEditorcsseointernal_editor is_dir fname f_blocks f_bfree f_bavailshow_user_free f_bsize stafs statfs sizeupdate_statuscon_chidecon_restore stdin fgetc stdout fflush systemcon_suspend con_xy str_findvfu_update_shell_line statusoshell_linea_optionsa_commandf_time_type exit printfcon_cshow con_beepsigmaxmin con_init con_done unlink F_OKvfu_settings_savetree_save count vfu_donetree_rebuild cINFO optarg optc GETOPT temp argv argc vfu_cli cSTATUSvfu_help_clivfu_user_external_exec KEY_ICKEY_CTRL_F10KEY_CTRL_F1KEY_ALT_F10KEY_ALT_F1KEY_SH_F10KEY_SH_F1 KEY_F10 KEY_F1vfu_toolsvfu_edit_entryKEY_ALT_9KEY_ALT_8KEY_ALT_7KEY_ALT_6KEY_ALT_5KEY_ALT_4KEY_ALT_3KEY_ALT_2KEY_ALT_1bookmark_gotoKEY_ALT_0bookmark_hookupKEY_ALT_Jvfu_jump_to_mountpointKEY_ALT_Evfu_erase_filesKEY_ALT_L CM_LINK CM_COPYKEY_ALT_M CM_MOVEvfu_copy_files vfu_editvfu_commandvfu_rename_file_in_placeKEY_ALT_Nvfu_file_find namevfu_browsevfu_browse_selected_filesKEY_ALT_BKEY_ALT_Cvfu_extract_filesKEY_CTRL_ZKEY_ALT_Zvfu_directories_sizes randFGOCLOCKS_PER_SEC clock clock_tsKEY_CTRL_Tvfu_user_menuvfu_shell con_csvfu_edit_conf_filevfu_optionsvfu_global_selectvfu_arrange_filesvfu_drop_all_viewsKEY_ALT_EQvfu_chdir_historyKEY_ALT_Dvfu_chdirKEY_RIGHTlynx_navigation KEY_LEFTvfu_action_plusvfu_action_minusKEY_BACKSPACEvfu_nav_selectvfu_rescan_filesKEY_CTRL_Rvfu_read_files_menuKEY_ALT_Rtree_viewKEY_CTRL_DKEY_CTRL_Fvfu_change_file_maskvfu_nav_end KEY_ENDvfu_nav_home KEY_HOMEvfu_nav_npageKEY_NPAGEvfu_nav_ppageKEY_PPAGEvfu_nav_down KEY_DOWNvfu_nav_up KEY_UPKEY_ALT_XKEY_CTRL_Lvfu_inc_searchvfu_toggle_view_fields tolowercon_getchFLI show_posvfu_redraw_statusvfu_redrawvfu_reset_screen_TARGET_DESCRIPTION_ __DATE__ vfu_run vfu_beepz vfu_exit fclose fputsfile_set_mode_str fopenf FILE chdir a_pathvfu_exit_pathvfu_read_files time srand SIGQUIT SIGTERM SIGHUPvfu_signal SIGINT signalchcntimenu_box_info splitvfu_settings_load R_OK accessFILENAME_FFRFILENAME_HISTORYFILENAME_SIZE_CACHEFILENAME_TREEFILENAME_CONFFILENAME_OPTget_rc_directory str_trmake_path getenv getgid _gid gid_t getuid _uid uid_t__OPENDIR_FIND_HIDDEN__opendir_flagsgethostname_TARGET_GO32_ type wrapstr_fix_path getcwdWM_NORMAL vfu_initvfu_menu_boxFILENAME_CONF_GLOBAL2FILENAME_CONF_GLOBAL1FILENAME_CONF_GLOBAL0 push HEADER vfu_help st_sizefile_get_mode_strfile_type_str st_mode S_ISDIRfile_is_link memcpya_new_stat size_t str_padstr_sleftx readlinklt_TARGET_UNIX_name_view f_typestr_comma f_sizevfu_opt_timea_new_name strcatWM_ARCHIVEfixfull_nameupdate_stat set_namea_is_link a_stat stat a_namesel cPLAIN _color _view _size€0À üˆ™‹Ã®àþz@x寏W)é”`=)Ü4 m N"ùÕ§TrøSÁ5‰Ý@¥õu[Ã$ŒÜR¨qË5~û @ûb7w(ÛÇ®šÁcŒà­\xY+ûÜ$"Ò«Œ è hÔ L À þ'Ô¬ ‡ ê¤_ < 7  C .  Î ì¡ ÞŽ;Àÿ\H¯›PœI§€‰u`L*ോ*!Ãfile_list_indexScrollPos+$´external_panelizerVString%±archive_pathVString%°archive_nameVString"®work_pathVString qTF0‰~TF‡TFhHID_OMODE190 _VFU_H_€j€N©set_strintconst char*line,const char*keyword,VString&target& Epath_bookmarksVArray€ $ hclipboard_viewvoid$ ˆclipboard_viewvoidFâ__vfu_eraseintconst char*target,fsize_t*bytes_freed€e€K" __vfu_link_eraseintconst char*target,fsize_t*bytes_freedSÎ__vfu_symlinkintconst char*src,const char*dst,CopyInfo*copy_infoP¾__vfu_moveintconst char*src,const char*dst,CopyInfo*copy_infoP®__vfu_copyintconst char*src,const char*dst,CopyInfo*copy_info€‹€Kx__vfu_eraseintconst char*target,fsize_t*bytes_freed=NULL€‰€P"q__vfu_link_eraseintconst char*target,fsize_t*bytes_freed=NULL€‚€€€€€€Sw__vfu_symlinkintconst char*src,const char*dst,CopyInfo*copy_infoPv__vfu_moveintconst char*src,const char*dst,CopyInfo*copy_infoPu__vfu_copyintconst char*src,const char*dst,CopyInfo*copy_info?ok_countlong! CLIPBOARD_COPY1 !CB_DESCchar*[]-%$clipboard_copy_infoCopyInfo<#,device_free_spacefsize_tconst char*target€z€%!^clipboard_clearvoid4*€€€P€e€o€u€x€z€{€|€†€Œ€€@@@@@@@@@@@ @!@"@#@$@%@&@'@)@*@+@,@-@.@2@    #ClipboardVTrie€m€€& %!‡clipboard_clearvoidD8€^€a€m€w€€€€‚€‰€‹€€4@5@6@7@8@:@€€€€ € € €€€€€€€€€€€€€€€€ €!€"€$€%€'€(€*€+€-€      ! & ' €! €^€$EdescriptionVString€ € 4#€ @@!@(@+@0@?€W€X€Z€[€\€@0@;@=@>@.€/€0€2€3€4€5€6€7€8€9€:€>€@€A€B€C€D€€ €8Yexpand_tabsintVString&str,VString&mapĈ€@ @ @@'@(@}@´@µ@¶@·@¸@¹@º@»@¼@¾@¿@À@€€€:€<€@€A€B€C€D€E€F€H€J€L€M€N€U€V€a€€”€ÀÀÀÀÀ À À À À ÀÀÀÀÀÀÀÀ>À?À @"@4@5@6@7@8@:@?@€€€€ € € €€&€,€N€k€o€›€œ€¦€A B C D E F G H I J K L N P R T V X Y Z [ ] ^ _ ` a b c d e f g h i k v } „ † ‡ ˆ ``)`Y`y`|`    €R@=€W€@m  `B`Ïtree_loadvoid'#Ävfu_chdir_historyvoid4hvfu_chdirvoidconst char*a_new_dir&"vfufiles.h"&"vfusys.h"&"vfuuti.h"A Ldevice_is_sameintconst char*src,const char*dst?6file_is_sameintconst char*src,const char*dstWHID_GS_MASK20VHID_GREP10€R€S€‰ . Qmax_path_str_tchar[MAX_PATH]Pfsize_tdouble€L€N€!Mpathncmpstrncmp€J€M€Lpathcmpstrcmp%Jpathncmpstrncasecmp#Ipathcmpstrcasecmp;DFNMATCHfnmatch((p),(s),FNMATCH_FLAGS)p,s€A€D€# APATH_DELIMITER":"€@€H€@FNCASE1€C€F€ ?FNMATCH_FLAGS0# ;PATH_DELIMITER";":FNCASE0+9FNMATCH_FLAGSFNM_CASEFOLD7cuserid0x06lstatmemset(p,0,sizeof(p))n,p5S_ISSOCK0p4S_ISLNK0p&/"vfusys.h"&-"vfusetup.h"&*&(&$&"&!& &&€@2€&&&€@*€&&&&&&&&&.> mainintint argc,char*argv[]$  vfu_inc_searchvoid)%Õ vfu_read_files_menuvoid,ˆ vfu_file_findvoidint menunS __ff_processintconst char*origin,const char*fname,const struct stat*st,int is_link,int flag"N __ff_masksVArray+' vfu_file_find_resultsvoidÄ€@@I@J@K@L@M@N@O@P@Q@R@U@W@Y@[@\@]@^@_@`@a@b@c@h@i@l@n@q@r@s@t@v@w@x@y@€@Š@‹@@Ž@@@‘@’@“@”@•@—@˜@›@œ@@ž@Ÿ@¡@¢@£@¤@¥@¦@§@¨@©@ª@«@¬@­@®@¯@°@±@²@´@µ@¶@·@¸@¹@º@»@¼@¾@¿@À@€€€€ € € € €€€€€€€€€€€€€ €!€"€Y€ . ; Š Ž   ‘ ’ “ ” • – — ˜ œ ž   ¢ t`u``€``†`‡`ˆ`‰`Š`‹`Ž`` # #ç vfu_user_menuvoid4( vfu_jump_to_mountpointvoidint all$  vfu_edit_entryvoid1'Tvfu_directories_sizesvoidint n@&-vfu_change_file_maskvoidconst char*a_new_mask.* vfu_rename_file_in_placevoid!vfu_commandvoid%!ûbookmark_hookupvoid)Úbookmark_gotovoidint n¤vfu_toolsvoid4(‡vfu_user_external_execvoidint key'#Kvfu_global_selectvoid:( vfu_global_select_samevoidint same_modeIóvfu_time_cmpinttime_t t1,time_t t2,int type=TIMECMP_DTðTIMECMP_T13ïTIMECMP_T2 0àüJJ& ÆûïãÕŠ¸¤œHziZ<6)ü»êÙÎã©—‹pcSH<0óÖÔŶ§—†tfUF8%ÿí˼³£œ’„{rj\OC4&_mode_strmode_str_t _is_dir _is_link_type_str_st stat _ext_name_ext _nameTFfiles_count NULLfiles_list ASSERTVFU_CHECK_LIST_POSHID_SEQ_STARTHID_SEQ_DIGPOSHID_SEQ_SUFFIXHID_SEQ_PREFIXHID_CHDIRHID_GETDIRHID_COMMANDSHID_FMASKHID_SHELL_PARHID_EE_OWNERHID_EE_TIMEHID_FFGREPHID_FFPATHHID_FFMASKHID_MKPATHHID_GS_GREPHID_GS_MASK HID_GREP MAX_PATHmax_path_str_t fsize_t strncmp strcmpstrncasecmp pathncmpstrcasecmp pathcmp fnmatchs FNMATCH_TARGET_UNIX_PATH_DELIMITER FNCASEFNM_CASEFOLDFNMATCH_FLAGSx cuserid memsetn lstat S_ISSOCKp S_ISLNK_TARGET_GO32_"vfusys.h""vfusetup.h"BSD_TARGET_NETBSD_  øŠ‚ áááááááááááááááááá á!á"á#á$á%á&á'á(á)á*á+á,á-á/á0á1á2á3á4á5á6á7á8á9á:á;á<á=á>á?á@áAáBáCáDáEáFáGáHáIáJáKáLáMáNáOáPáQáRáSáTáUáVáWáXáYáZá[á\á]á^á_á`ábácádáeáfágáháiájákálámánáoápáqárásátáuáváwáxáyázá{á|á}á~áá€áá‚áƒá„á…á†á‡áˆá‰áŠá‹áŒááŽááá‘á’á“á”á•á–á—á˜á™ášá›áœáážáŸá á¡á¢á£á````` ` ` ` ` `````````````````` `!`"`#`$`%`&`'`(`)`*`+`,`.`/`0`1`2`3`4`5`6`7`8`:`;`<`=`>`?`@`A`B`C`D`E`F`G`H`I`J`K`L`M`N`O`P`Q`R`S`T`U`V`W`X`Y`Z`[`\`]`^`_```a`b`c`d`e`f`g`h`i`j`k`l`m`n`o`p`q`r`s`t`u`v`w`x`y`z`{`|`}`~``€``‚`ƒ`„`…`†`‡`ˆ`‰`Š`‹`Œ``Ž```‘`’`“`”`•`–`—`˜`™`š`›`œ``ž`Ÿ` `¡`¢`£`¤`¥`¦`§`¨`©`ª`«`¬`­`®`¯`°`±`²`³`´`µ`¶`·`¸`¹`º`»`¼`½`¾`¿`À`Á`Â`Ã`Ä`Å`Æ`Ç`È`É`Ê`Ë`Ì`Ñ`Ò`Ó`Ô`Õ`Ö`×`Ø`Ù`Ú`Û`Ü`Ý`Þ`ß`à`á`â`ã`ä`å`æ`ç`è`é`ê`ë`ì`í`î`ï`ñ`ò`ó`ô`õ`ö`÷`ø`ù`ú`û`ü`ý`þ`ÿ`aaaaaaaaa a a a a aaaaaaaaaaaaaaaaaaa a!a"a#a$a%a&a'a(a)a*a+a,a-a.a/a0a1a2a3a4a5a6a7a8a9a:a;aa?a@aAaBaCaDaEaFaGaHaIaJaKaLaMaNaOaPaQaRaSaTaUaVaWaXaYaZa[a\a]a^a_a`aaabacadaeafagahaiajakalamaqarasatauavawaxayaza{a|a}a~aa€aa‚aƒa„a…a†a‡aˆa‰aŠa‹aŒaaŽaaa‘a’a“a”a•a–a—a˜a™aša›aœaažaŸa a¡a¢a£a¤a¥a§a«a­a®a¯a°a±a²a³a´aµa¶a·a¸a¹aºa»a¼a½a¾a¿aÀaÁaÂaÃaÄaÅaÆaÇaÈaÉaÊaËaÌaÍaÎaÏaÑaÒaÓaÔaÕaÖa×aØaÙaÚaÛaÜaÝaÞaßaàaáaâaãaåaêaëaìaíaîaïaðañaòaóaôaõa€€€€#€$€%€&€'€(€)€*€+€,€-€.€/€0€1€2€3€²€·€Á€€ÀÀ0@€ü¯ÐíÝ¿¡ƒeF&æÅ¦ˆeBýmaçF&l˦ˆ%Q' ê0‰u êiÊ–uVåÀšL0û—;õغ¦’~j@,òÞ´ +ŒxDýÕÁ¡hTÝɪ–s_=)ûÚÆ¡yeQ=)íÙű‰uaE1ú¹|›? ÞúX:|ÝÀ¢ÏTðœS4A ç ¼ „  Ú ©  a + e ä · “ Y! ò Á ˜ r K ( ÿ Ô   „ p T 8 í ÿëÍ‘€—€€—€ €•€–€#À$À%À'À*À-À/À0À1À€£À@ €N@ÌÀ@a@.€y€ `<(vfu_read_archive_filesvoidint a_recursive&"vfufiles.h"€M@ÎÀ@ €&"vfucopy.h"&"vfudir.h"&"vfuopt.h"&"vfuuti.h"€O@ÆÀ& "vfuarc.h"4(Xvfu_jump_to_mountpointvoidint all+Vvfu_clipboardvoidint act)%Tvfu_read_files_menuvoid#Rvfu_sort_menuvoid'#Qvfu_global_selectvoid&"Pvfu_action_minusvoid)!Ovfu_action_plusvoidint1Mvfu_editvoidconst char*a_fname/+Lvfu_browse_selected_filesvoidDKvfu_browsevoidconst char*a_fname,int no_filters=0.*Ivfu_rename_file_in_placevoid$ Hvfu_edit_entryvoid-Gvfu_edit_attrintchar*attrs$ Avfu_inc_searchvoid#?vfu_user_menuvoid6(>vfu_user_external_execvoidint a_key#;update_statusvoid%!9bookmark_hookupvoid18bookmark_getconst char*int a_n<7bookmark_setvoidint a_n,const char*a_path+6bookmark_gotovoidint a_n@&4vfu_change_file_maskvoidconst char*a_new_mask;'2vfu_directories_sizesvoidint a_which_one+'1vfu_file_find_resultsvoid,0vfu_file_findvoidint menu!/vfu_commandvoid.vfu_toolsvoidI,vfu_shellvoidconst char*a_command,const char*a_options3('vfu_toggle_view_fieldsvoidint ch!%vfu_optionsvoid/#vfu_exitintconst char*a_path5"vfu_exit_pathvoidconst char*a_path(!vfu_signalvoidint sig&" vfu_reset_screenvoidvfu_donevoidvfu_clivoidvfu_runvoidvfu_initvoid"vfu_help_clivoidvfu_helpvoidCsay2centervoidconst char*a_str,int attr=cMESSAGECsay1centervoidconst char*a_str,int attr=cMESSAGEBsaycentervoidint line,int attr,const char*a_strsay2errnovoid= say2voidconst char*a_str,int attr=cMESSAGE= say1voidconst char*a_str,int attr=cMESSAGEA sayvoidint line,int attr,const char*format,...€Š@“À# do_draw_statusint€y@‘Àdo_drawint€—  €–  €•  €”   €“   €’   €‘   €   €  €Ž  €Š  €.  €  €®€`€­€Ž`€x@rÀ%èview_profilesVArray€w@pÀ!ætrim_treeVArray€v@nÀämbVArray€q@lÀ"âpanelizersVArray€t@jÀ#ásee_filtersVArray€s@hÀàhistoryVArray€r@fÀ& ßuser_externalsVArray€Y€“€€l@PÀ)#Øfile_find_resultsVArray€n@`À%"Ödir_tree_changedint€i@^À Õdir_treeVArray€h@\À("Ñfiles_mask_arrayVArray€‹€Š`€x€‰`€e€ˆ`€?€‡`€<€†`€^@NÀ*·files_listTF*[MAX_FILES]€Y@LÀ& µlist_panelizerVArray€›€€`€[@HÀ*$²archive_extensionsVArray€š€`€™€u`€˜€t`€W@@À­work_modeintªWM_ARCHIVE1©WM_NORMAL0¤xint€ÀÀÀÀÀÀÀÀÀÀ À!À"À6À£selint€•@—@˜@›@œ@@ž@Ÿ@¡@+À,À.À3À4À5À7À8À9À:À # € colorint€žis_dirint€is_linkint€›sizefsize_t1šset_sizevoidfsize_t a_new_size&€˜stconst struct stat*%€—mode_strconst char*%€–type_strconst char*L”update_statvoidconst struct stat*a_new_stat,int a_is_link’drop_viewvoid!‘viewconst char*4set_namevoidconst char*a_new_name €Žextconst char*%€name_extconst char*!€Œnameconst char*0‹full_nameconst char*int fix=0€•€'ÀMˆTFconst char*a_name,const struct stat*a_stat,int a_is_link"„refresh_viewvoidƒresetvoid* _full_namechar[MAX_PATH]}_colorint|_viewchar*{_sizefsize_t%z_mode_strmode_str_ty_is_dirintx_is_linkint"w_type_strchar[3] v_ststruct statu_extchar* t_name_extchar*s_namechar*`$jVFU_CHECK_LIST_POS{ASSERT(files_list[n]!=NULL);ASSERT(n>=0&&n&øåÝÔËÀ·­ —‰{l]P?2& øéÕ»°£“xqcUG9)ôÚʱ¢ˆwfR@%êàλ©ŸŒo`TE'ñÛɱŸ—|teVG8(Úüìã¬ÓÈ·†¦•Œ]|si#QB/ö ³åÚ¾„¦œšxoe^OG9+ú×ȸ¢Ž Œ†ynbZG;& óë— … w k a W L = 1 Ü  ú ä _ ¹ ® Ÿ k P  @ /  Ý ô æ ™ Æ º ¤ q “ † { 6 _ S G . &  Ý  ÷ ì ¹ Ô Ì Ä ‰ ® › ” ° } r d ^ W E 5 " û ç á Ï Æ ½ ñ¢ › ” | u f Z N @ 2 %   ÿ)äÖɼ¥˜…zrj^I;2M ðéß;±›ymeZwA7/üèÞÕǺ®ŸŠgZH</&ýöêÙÏ»„‚€*A+A,A-A.A/A0A1A2A3A4A5A7A8A9A:A;AA?A@ABACADAEAFAGAHAIAJAKALAMANAOAPAQARASATAUAVAWAXAYAZA[A\A]A^A_A`AaAbAcAdAeAfAgAhAiAjAkAlAmAnAoApAqArAsAtAuAvAwAxAyAzA{A|A}A~AA€AA‚AƒA„A…A†A‡AˆA‰AŠA‹AŒAAŽAAA‘A’A“A”A•A–A—A˜A™AšA›AœAAžAŸA A¡A¢A£A¤A¥A¦A§A¨A©AªA«A€"€ freadvfu_break_op abortedcpz fclose fopenf2f1 FILE dev_free no_infono_free_check cMESSAGEdescriptionstr_dot_reduce__vfu_file_erasefile_exist CR_SKIP CR_ABORTfile_size size errno__vfu_file_copy st_gid st_uid chowncopy_keep_modeopt utime modtime st_atime actimeutb utimbuffile_set_mode_str st_modefile_get_mode_str mode_strmode_str_tvfu_copy_mode abortecmenu_box_infovfu_menu_box vfu_beep say2 say1 datastr_commatime_str_compact st_sizes_ss_t sttimestr st_mtimeOM_ALWAYS_IF_MTIME stat_dst stat_srcOM_ALWAYS OM_NEVERover_mode F_OK accessover_if_exist cSTATUS2con_max_ycon_max_x con_out sprintffiles_sizea2current_sizec2a1c1copy_info CopyInfo a_fa a_fcshow_copy_posr_STAT_ROOT_TIME_STAT_DIRSIZE_STAT_EXEC_MAGIC_STAT_EXEC_EXT_STAT_INODE_djstat_flagsstsfast_stat strcat strrchr strcpychdevice_is_same st_ino st_devst2st1 statstrcasecmp ASSERT _fixpath_f2_f1_TARGET_GO32_dstsrcfile_is_same f_bfree f_bsizestr_file_path stafs statfs MAX_PATHt targetdevice_free_space fsize_tignore_copy_errors NULLcopy_buff CM_DESC"vfucopy.h""vfusys.h""vfuview.h""vfufiles.h""vfumenu.h""vfudir.h" "vfu.h" €õàöà÷àøàùàúàüàýàþàvfushell_line String#vfu_user_external_archive_execonevfu_extract_filesvfu_browse_archive_filevfu_read_archive_files "vfu.h"_VFUARC_H_ unlink chmod fsave tmpfilesay2errno data pushTL€¨à©àªà«à¬à­à®à¯à°à±à²à³à´àµà¶à·à¸à¹àºà»à¼à½à¾à¿àÀàÁàÂàÃàÄàÅàÆàÇàÈàÉàÊàËàÌàÍàÎàÏàÐàÑàÒàÓàÔàÕàÖà×àØàÙàÚàÛàÜàÝàÞàßàààáàâàãàäàåàæàçàèàéàêàëàìàíàïàðàñàòàóàôàselfiles_countzva VArray strcpyvfu_get_dir_name CM_COPYlast_copy_pathopt sprintf target MAX_PATHtsel_countonevfu_extract_filesstr_replaceshell_line#vfu_user_external_archive_exec__vfu_dir_erasevfu_browsevfu_shellwork_pathfull_nameFLIfiles_listfn chdir say1 S_IXUSR S_IWUSR S_IRUSR mkdir vfu_temp tmpdirvfu_browse_archive_file pclosevfu_add_file str_len atoi st_size S_IFDIR st_modestr_trim_rightstr_get_ch strncmp str_cut fgets say2 popenf FILEarchive_names Stringarchive_path memsetst stat linea_recursivevfu_read_archive_files"vfufiles.h""vfucopy.h""vfudir.h""vfuopt.h""vfuuti.h""vfuarc.h"allvfu_jump_to_mountpointactvfu_clipboardvfu_read_files_menuvfu_sort_menuvfu_global_selectvfu_action_minusvfu_action_plus vfu_editvfu_browse_selected_filesno_filters a_fnamevfu_browsevfu_rename_file_in_placevfu_edit_entry attrsvfu_edit_attrvfu_inc_searchvfu_user_menu a_keyvfu_user_external_execshell_line typekeyvfu_user_external_findupdate_statusbookmark_hookupbookmark_getbookmark_seta_nbookmark_gotoa_new_maskvfu_change_file_maska_which_onevfu_directories_sizesvfu_file_find_results menuvfu_file_findvfu_commandvfu_toolsa_optionsa_commandvfu_shellchvfu_toggle_view_fieldsvfu_options vfu_exit a_pathvfu_exit_pathsigû€öa÷aøaùaúaûaüaýaþaÿabb                                  ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M ààààà à à à à ààààààààààààààààààà à!à"à#à$à'à(à)à*à+à,à-à.à/à0à1à2à3à4à5à6à7à8à9à:à;à<à=à?à@àAàBàCàDàEàFàGàHàIàJàKàLàMàNàOàPàQàRàSàTàUàVàWàXàYàZà[à\à]à^à_à`àaàbàcàdàeàfàgàhàiàjàkàlàmànàoàpàqàràsàtàvàwàxàyàzà{à|à}à~àà€àà‚àƒà„à…à†à‡àˆà‰àŠà‹àŒààŽààà‘à’à“à”à•à–à—à˜à™àšà›àœààžàŸà à¡à¢à£à¤à¥à¦à§à€€¼€½€¾€¿€vfu_signalvfu_reset_screen vfu_done vfu_cli vfu_run vfu_initvfu_help_cli vfu_helpsay2centersay1centersaycentersay2errno say2 cMESSAGE a_str say1 format attr linesaydo_draw_status do_drawfilename_atlfilename_ffrfilename_size_cachefilename_treefilename_historyfilename_conffilename_opthost_name_strgroup_id_struser_id_strshell_progshell_editorshell_browserext_colorsview_profileview_profilestrim_treembpanelizerssee_filters historyuser_externalspath_bookmarksfile_find_resultsdir_tree_changed dir_treefiles_mask_arrayfiles_mask rc_path tmp_pathhome_pathstartup_pathFGO pagesizePS pageFLPposFLIfile_list_indexfs_block_size fs_total fs_free sel_sizesel_countfiles_sizeMAX_FILESlist_panelizerexternal_panelizerarchive_extensions VArrayarchive_patharchive_namework_pathwork_modeWM_ARCHIVEWM_NORMALsel color is_dir is_link sizea_new_size set_sizest mode_str type_stra_new_statupdate_statdrop_view viewa_new_name set_nameext name_ext namefixfull_namea_is_link a_stat a_namerefresh_view reset_full_name _color _view _size@À *êà_yekÚ`_yeköà_yek©`_yek|a_yekå`_yekþà_yekzà_yek{`_yekva_yekâ _yekà_yekƒ`_yekä`_yek2a_yekwà_yekŸà_yek˜à_yekÑ`_yekzà_yekÒ`_yekøà_yekýà_yekŒà_yek`_yekã`_yekÙ`_yekÒ`_yekvà_yekõà_yek‰à_yek‘`_yekà`_yektà_yeká_yek›à_yek`_yekæ`_yekî@_yekšà_yek}`_yekç`_yekï@_yekˆà_yek“`_yeká`_yekÓ`_yek}à_yekÔ`_yek‹à_yeky`_yekta_yekà syekž€wyekeàwyek ásnikÖàl`ly€lРl¡tsalåàtsal4`tsalÚàtsal…átsalàtsal[€tsalÜàtsalsàtsalƒátfelËànelö@ilÓ`enilàenilYáenilbàenil±àenildàenil áenilÀatsilåatsil"átsil-àtsild gnol“ágnol%àgnolãàgnol{Apoolîapoolpaewol€ewol)àewol€ewol€atsl atsl$axnyl’`xnyl/àxnyl÷àmJ€mcamFam¼ miàniamðaekamE`ekam`ekamâ`ekam<@pam¼àksam"aksam¸@ksamAksamiaksam4àksamòàxam®àxamï`xamRa_xam2à_xam%á_xam.à_xamZ _xam$á_xamCá_xam, _xamáà_xamá_xamÜ`_xamw _xam|á_xam'@_xam@_xamjA_xam+ _xamÙà_xam{àcxam4€hxamË@bm?ábmMàbmµ€bmabmØ bm%¡bm àbm+@bmæ@cmÑ`cmem$`cmem”àmmemR€smemàsmemzásmem smem´àsmem smem†àunemÞaunem‚àunem¡unem.àunemöàunemR`unemYáunemÚ unem¡unem2¡unem/@unem"¡unem àimÂ`dimÓ fdimÔ nimî`nimmaidkmÌàtskmý@dom¬à_domLá_dom@edom’€edomœ€edom3 edomé edommáedom—aedom•áedomáedomNáedom“áedomraedomàedom^áedom| edomqaedomL edom]áedom{ edomGáedom—áedomsaedomáedom}Aedom0€edom6 edomè edomIáedom@edomtáedom$`edom–átdom atdomfásmzagsm]€mitmEàmitmáxm»`nàn:an nanXAn€eman¯`emanàemanR eman7@eman…@eman>Aeman/aemanàeman8`emanJ@eman`eman¶ emanø cnÕàbednñaen €deen>€_wenqà_wenˆa_wencá_wen–a_wenhá_wena_wen#a_wenQ@_wenlà_wen_a_wenšatxen €txenµ 1fn c_onuàf_onaf_onœàf_onwáf_onb`i_onxái_on_`eyonàeyonÒàeyonàgapnóàgapns€rtsnÎàllunàllunyállunA llunállunu`llun6allun[ llunàllunpállun¶@llunvAoú`pcoçàsffoB€ioèàkoI€ko.€c_ko©€c_ko¨€dloß _dloE _dloŸA_dloC _dlo™A_dlofáa_moGáa_moV`a_moJáa_moU`a_mo?`a_moQ`i_moX`n_moFán_moW`eno”aenoÎàeno÷àeno£@eno Agapojanepo3ànepoanepo¾ànepo`nepo¡`sopo\€sopoUasopo! tpoàtpo’átpoäàtpohátpoü`tpoG tpo¡tpoàtpoátpoÈ@tpo9Aatpoã`ctpoâ`itpoàitpoÕàstpo_€giroÒagiroŠ proæàtuozátuo@tuo@revoBárevot`revo5árevoc`xoäàxo'€yoåàyo(€p6ap paegap©àegapaegap:àegap³`egap egap¢Aegap<àegapaegap Aenap>áenapLàenap„àssap–átaps`tap›`htapahtapP@htap:áhtapHàhtap¤àhtapÛàhtap htapràhtap;ahtap$ htap/ahtapÀ htap& htap:@cp×acpì`cp° olcpààolcpÈàolcp¯ dnepãàpophaepopÞàepop»àepopª sop¨àsop€asop8àsop®`sop´ sopWàsopí@sop&Agappñàgappr€ferpM@nirpô`morp«`morp morp±@morpAspŒasp;àspeasp[Asp€spŸ€spartspÜ@hsup·àhsup.`hsupÞàhsup–€hsup¨`hsupQ hsup'¡hsupkàhsup)@hsupÙ@n_wp›áu_wp®adwp«aqar…àrar1ár{€rÑ r¡r¿àrárø@ko_rO`dnar¦`dnarÝ p_cr/áp_crBàerH€er§aerhà1erº 2er» p_eržàs_eràu_er›àdaerWàdaer`daerž`daer`daer`laerÀàkferxàrfer‹árfer àomer³àomerÙàomerÈàaner…aaner `anerZ@uqer¸àuqerauqerÁàserbàser`áserª`ser;@eseruáeser àeser€eser^`eserˆàverX€hgirÌàidmr&`worÁàwor¡wor àswor"àswor=€sr@€elur`€nur•ànuranurÀàt_xr1at_xrás*às¡`s" s·às)ásm`s€as# s€@s!A1sa1s· 1sù 1s‰A2sa2s¸ 2sú 2sŠAda_sw€id_s_@fi_sÃàri_sXári_sWári_s'ari_sÍàri_sUási_s7 si_sQási_s< si_sRási_s&`si_s*asi_s: si_sKási_s= si_sOási_s[ási_s si_s&asi_sPási_s si_s> si_sTási_s^ási_s`áwi_sYáwi_s\áwi_s(awi_sÊàwi_sVáxi_s@ xi_sZáxi_s; xi_s]áxi_sÏàxi_sA xi_sSáam_sïaam_sqas_sPáis_sx€ts_s`@t_sOáemas_aemas^aemas\aemas]aevasÇàevasJ evas¦€yasXáyasaàyas„€1yashá1yaseà1yasÐà1yasEá1yas°`1yasY 1yas•à1yas*@1yas´@1yassá1yaskà2yasjá2yashà2yas¼à2yasVá2yas±`2yasp 2yasÆà2yasŸ@2yastá2yaslà2yaská2yasià2yasðà2yas`2yasa2yasA@_yasVá_yasWácyasoácyasjàorcsNaorcs orcs$€orcs¾€orcsl€_ees=á_eesKà_eessà_ees-àdees¤àdees¦àeeesªàeeesaeees¼àeees«àeeesþàkeesLàveesàvees+aveesàveesüàles`les"àlesíàlesB`lesP les6@les§@les_A_les)á_les0à_lesßà_les-`_lesM _les%@_lesŒA_les1A_les¯A_les*á_les1à_les _lesF@_lesAalesdaoesaoes‰àoesÿàtesÏàtes½atesa_tesSà_tesºà_tesmà_tesa€_tes+€_tesm€_tes€_tes `_tesà_tes[@_tes€_tesb€_tes,€_tesn€_tes€_tes€_tesba_tes á_tesˆá_tesà_tess _tes¬@_tesoà_teslà_tescaetes0antesÔ`lehsDálehsRàlehs™àlehs2àlehsóàlehsEálehsSàlehs˜àlehsù`lehs‘àlehsÛàlehsþàlehsFálehsGálehsTàfihs·€rohs‹@uohs­`uohs wohs2áwohsv`wohsJàwohs€wohsy wohs*àwohsçàwohsXàwohsq`wohs]awohsJAwohs´AwohsYàwohs awohs:àwohsõàisˆágisñ`gis5àhgisY`igisW`ngisV`qgis[`tgisZ`zisÆ@zisAezisDàezisaezisàezisoáezis"aezis* ezisÇ ezis“@ezisªAezis•`ezis  ezis´àezis‡aezis+ ezisu€ezisv€ezisYaezis$ ezis„ ezisaezis& ezist€ezis2aezis) ezisÛaezisÜaezisÅ@ezisAezis"`lspálsˆa1ls‹a2lsŒamsgatrosÖ`trosΠtros‹àtros×àtrosxAtros‘atrosÅ trosŠàtrosÖàtroswAtrosŒàtrosÔàcps_àilpsQ`ilpspàilpsásops^€sopszAirpsNàirpsšáirpsãàirps=áirpsairpsˆ irps?@irps’@irpsNAnars\`crs=acrsácrsi`crs{áss‚a1ss½ 2ss¾ acss1€sss=àts`atsàts³àts*átss`ts!atsu tsñ ts@àtsáts_á1tsá2ts áa_tsŸaa_tsUáa_tsÊ a_ts3àc_tsÉ c_tsAàd_tság_ts á @ÿÿÿÿÿÿÿÿÿÿÿÿ_ridFà_yekêàg_tsláÀ@0 Àü_gË è»uAöÝJ pA×¾¢…3 S6Ë ‚éÉ©HpF)Ù†HñœôŸJ7µÞÀY¦Œr=©•Z( óѽe1Ž ëÌ­ÔlN –j7³ Jæ h ÿ & í Ð Û ´ ‡ E  ˆ  ß { g €K@@^@0€1€z€¢€`C` @ €L@@_@2€f€v€•€o  ` @ €I@ @@@@Z@b€t€«€\ `*`@`€ @T€€ @Z@]@^@_@`@a@b@c@d@f@g@h@=€E€F€G€H€I€J€K€L€M€:& Ìvfu_read_local_filesvoidint a_recursiveo À__vfu_ftw_addintconst char*origin,const char*fname,const struct stat*st,int is_link,int flagS vfu_add_fileintconst char*fname,const struct stat*st,int is_link4  Wvfu_read_filesvoidint a_recursive6" 0vfu_rescan_filesvoidint a_recursiveB file_type_strconst char*mode_t mode,int is_link-& __file_stat_type_bufchar[3]& "vfudir.h"& "vfumenu.h"& "vfuview.h"& "vfuopt.h"€@X€ÑÀ @@£€A`& "vfufiles.h"& "vfu.h"2 5vfu_dir_sizefsize_tconst char*s3" 1size_cache_cleanvoidconst char*s€?@@@A@C@D@E@F@G@H@I@J@K@L@M@O@P@Q@R@S@U@V@W@Y@>  0size_cache_setvoidconst char*s,fsize_t size4  /size_cache_getfsize_tconst char*s2" .size_cache_indexintconst char*s€Q@S@5 ,tree_findintconst char*s,VArray*va3 )tree_findconst char*const char*s, (tree_indexintconst char*s> $tree_draw_posvoidTScrollPos&scroll,int opos6  #tree_draw_pagevoidTScrollPos&scrollD  "tree_draw_itemvoidint page,int index,int hilite=0 tree_fixvoid" tree_rebuildvoid tree_dropvoid tree_savevoid tree_loadvoid tree_viewvoid'# vfu_chdir_historyvoid4 vfu_chdirvoidconst char*a_new_dirX" vfu_get_dir_nameintconst char*prompt,String&target,int should_exist=1€A@3€" size_cacheVArray& "vfu.h" _VFUDIR_H_2pvfu_dir_sizefsize_tconst char*s;$8__dir_size_processfsize_tconst char*path€0@;@5"tree_findintconst char*s,VArray*va3 tree_findconst char*const char*s,átree_indexintconst char*s"OM_ALWAYS1!OM_ASK0CM_LINK2CM_MOVE1CM_COPY0+"COPY_BUFFER_SIZE1024*1024/!«vfu_erase_filesvoidint a_one9 vfu_copy_filesvoidint a_one,int a_modeE$ó__copy_calc_totalsvoidCopyInfo©_info,int a_oneK"Š__vfu_file_eraseintconst char*target,fsize_t*bytes_freedJ!3__vfu_dir_eraseintconst char*target,fsize_t*bytes_freedU!$__vfu_link_moveintconst char*src,const char*dst,CopyInfo*copy_infoU!__vfu_link_copyintconst char*src,const char*dst,CopyInfo*copy_infoT ê__vfu_dir_moveintconst char*src,const char*dst,CopyInfo*copy_infoT ‹__vfu_dir_copyintconst char*src,const char*dst,CopyInfo*copy_infoU!i__vfu_file_moveintconst char*src,const char*dst,CopyInfo*copy_infoU!÷__vfu_file_copyintconst char*src,const char*dst,CopyInfo*copy_info@Õvfu_copy_modeintconst char*src,const char*dstSžover_if_existintconst char*src,const char*dst,CopyInfo*copy_infoP€show_copy_posvoidfsize_t a_fc,fsize_t a_fa,CopyInfo*copy_infozfast_statstat:jfast_statintconst char*s,struct stat*st'$ignore_copy_errorsint copy_buffchar* CM_DESCchar*[]&"vfucopy.h"&"vfusys.h"&"vfuview.h"&"vfufiles.h"&"vfumenu.h"& "vfudir.h"& "vfu.h"F0vfu_user_external_archive_execvoidString&shell_line€ @ @ @@@@/#vfu_extract_filesvoidint one-)vfu_browse_archive_filevoid,(vfu_read_archive_filesvoid&"vfu.h" _VFUARC_H_/#’vfu_extract_filesvoidint one €ÆÀÈÀÊÀÌÀÎÀÑÀÓÀ@@ @F0ovfu_user_external_archive_execvoidString&shell_line-)Nvfu_browse_archive_filevoidÊ€T@ @½@Â@Ä@Æ@È@€$€%€&€'€(€)€*€+€,€-€.€0€1€2€4€5€6€7€8€9€:€;€<€=€@€A€B€C€D€E€F€H€J€L€M€N€R€S€U€V€€”€•€–€—€˜€™€š€›€œ€ÀÀÀÀÀ À À À À ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ À!À"À#À$À%À'À*À+À,À-À.À/À0À1À3À4À5À6À7À8À9À:À>À?À@ÀHÀLÀNÀPÀ\À^À`ÀfÀhÀjÀlÀnÀpÀrÀ‘À“À•À–À—À˜À™ÀšÀ›ÀœÀÀžÀŸÀ À¡À¢À£À¤À¥À¦À§À¨À©ÀªÀ«À¬À­À®À¯À°À±À²À³À´À¶À·À¸À¹ÀºÀ¼À½À¾À¿ÀÀÀÁÀÂÀÃÀÄÀÅÀ €€&€,€<€?€e€x€‹€“€­€®€y`|`                   `0à€üuyçÜѽ²|n`RD<4)" ÿôãÏ¿²Ÿ‹~jUE;)yîäÏ·§™‡ti]QE2" þéÙȵ¥‹€yrj\<üðÜȹ«›†WznbI<,å ÿò­ÛÏ¿t›ƒ<cW& ÓúçÙ£Êñ†‘ˆmYEÞÊŸq\I?4 ÃóäÓŠ³¨™of;SC0)çûï¬×ÎÁ}¡–…Vpg^“MF;."ýöèÙǹ­žÏ…wjYG;,& çÝÖÈ¿²©›Š{lfYI8)1öêßÑüª›†ueWK?` ùëÜ˺¬¤˜‹}vhs N:0$ ÿ ñ Þ È ¼ ²   ‹ } V f _ X R L > 8 2 *   ú é à Ù Ð Ã ¹ ­ ¡ • ‰ ~ r g ^ P B 6 ) !   ä Û Ê ¸ ¨ • € n Z G 4 *   õ å ß Ò É ¾ ² ¥ ’ ‡ { o c N D 2 )    ö ì ß Ñ Å ¶ ­ ž ‘ Š ‚ x q b Z L B 8 -    þñèß×È·¢œ•ŽzjaYD=1 úëäÍTH€O`P`Q`R`S`T`U`V`W`X`Y`Z`[`\`]`^`_```a`b`c`d`e`f`g`i`j`k`l`m`n`o`p`q`r`s`t`u`v`w`x`y`z`{`}`~`€``ƒ`„`†`‡`ˆ`‰`Š`‹`|€€€€‚€˜€™€š€œ€¨€ª€«€¬€°€³€Ä€È€__dir_size_processvastr_sright strlensl2sl1__tree_index_last_cache strncmpslsize_cache_cleandel atofstr_adler32fast_size_cachesspsssize_cache_indexvfu_dir_sizeKEY_CTRL_Zend home down KEY_DOWNup KEY_UP str1vfu_expand_mask s_mask loops founddirectionminstr_add_chin opagekeyPS set_str1set_range1 BSettree_index new_postree_view show_pos cINFOstr_commasize_cache_getsz str_tr opostree_draw_pos cCYANmax pagesize cHEADER con_out str_mul scrolltree_draw_page cMESSAGE cSTATUS con_ce cBAR con_putsmstr_replacetree_compactjstr_trim_right hilite indextree_draw_item_STAT_WRITEBIT_STAT_ROOT_TIME_STAT_DIRSIZE_STAT_EXEC_MAGIC_STAT_EXEC_EXT_STAT_INODE_djstat_flagstree_rebuild NULLstr_dot_reduce st_sizesize_cache_setins dir_size pathcmptrim_temptrim_tree trim strcat S_ISDIR is_dir dosstat st_mode S_ISLNK is_link lstat new_name sizest statvfu_break_op path__tree_rebuild_process fsize_tsetqpstr_countnis2s1 tree_fix fsavetree_savedir_tree_changedfilename_tree fload do_drawvfu_chdir_historyvfu_read_filestree_dropWM_NORMALsay2errno data sprintf chdirstr_reduce_path_TARGET_GO32_gettree_findmbtree_load dir_tree tree_cdoptwork_patharchive_patharchive_nameWM_ARCHIVEwork_modea_new_dirvfu_chdir ASSERTvfu_hist_addmake_path vfu_ask tolowerdir_existstr_cut_spcvfu_hist_getpcHID_CHDIRHID_GETDIRvfu_hist_menuzzKEY_PPAGEKEY_NPAGE KEY_DC KEY_END KEY_HOME KEY_ICKEY_RIGHT KEY_LEFTstr_ins_chstr_fix_pathexpand_path MAX_PATHtKEY_CTRL_XKEY_CTRL_Uvfu_menu_boxcon_chide sort vfu_beep setnlimimc countstr_rfind dtail dmainstr_get_chzKEY_CTRL_A str_delKEY_BACKSPACEtilde_expand str_findcon_getchcon_max_y con_xystr_set_ch str_padstr_sleftstr_trim_lefttarget_outcon_max_xmx cINPUT cINPUT2con_cshow str_len firsthit insertch pagepos say2 say1 dir_listresshould_exist target promptvfu_get_dir_name closedir pushfile_is_dirstr FNMATCH d_name strcmp readdir opendirde direntdirDIRpat a_vaa_fnpattern a_path__glob_gdnsize_cache VArray"vfumenu.h""vfuview.h""vfufiles.h""vfusys.h""vfuuti.h""vfuopt.h""vfudir.h"vfu_erase_files a_mode a_onevfu_copy_files__vfu_link_erase__vfu_file_erase NULLbytes_freed__vfu_dir_erase__vfu_link_move__vfu_link_copy__vfu_dir_move__vfu_dir_copy__vfu_file_move__vfu_file_copyvfu_copy_mode a_fa a_fcshow_copy_poscopy_infoover_if_existst statsfast_statdevice_is_samedstsrcfile_is_same targetdevice_free_spacedescription fsize_tcurrent_sizefiles_size abortover_modeno_free_checkcurrent_countfiles_count no_info reset CopyInfo CR_ABORT CR_SKIP CR_OKOM_ALWAYS_IF_MTIMEOM_IF_MTIME OM_NEVEROM_ALWAYS OM_ASK CM_LINK CM_MOVE CM_COPYCOPY_BUFFER_SIZE_VFUCOPY_H_con_getcherase_sizebytes_freed_ptrvfu_erase_files do_drawupdate_statusvfu_pack_files_listï€ûàááááááááá á á á á ááááááááááááááááááá á!á"á#á$á%á&á'á(á)á*á+á,á-á.á/á0á1á2á3á4á5á6á7á8á9á:á;á<á=á>á?á@áAáBáCáDáEáFáGáHáIáJáKáMáNáOáPáQáRáSáTáUáVáWáXáYáZá[á\á]á^á_á`áaábácádáeáfágáháiájákálámánáoápáqárásátáuáváwáxáyázá{á|á}á~áá€áá‚áƒá```` ` ` ` ``````````````````` `!`"`#`$`&`'`(`)`*`+`,`-`.`/`0`1`2`3`4`5`6`7`8`9`:`;`<`=`>`?`@`A`B`C`H`I`J`K`L`M`N`}€€„€…€‡€ˆ€‰€Š€Œ€Ž€€€‘€’€“€”€•€–€—€›€€ž€Ÿ€ €¡€¢€§€©€­€®€¯€±€´€µ€Å€Æ€Ç€É€Ê€full_nameselfiTF OM_ASKcopy_free_space_checkfile_existsstr_trim_rightstr_fix_pathexpand_pathvfu_get_dir_name name_extFLIfiles_listcm_mode_strlast_copy_path CM_LINK CM_MOVE CM_COPY a_modevfu_copy_filescurrent_countsel_countfiles_countvfu_update_sel_sizecopy_calc_totals a_one__copy_calc_totalstarget_size rmdirMODE_WRITE_ON fnamebytes_freed__vfu_link_erase__vfu_link_move readlink__vfu_dir_erase__vfu_dir_move closedirfile_is_dir__vfu_link_copyfile_is_link d_name strcmp readdir opendirde direntdirDIRsay2errnomake_pathfname_dstfname_src__vfu_dir_copy symlink rename__vfu_file_move unlink fwriteCOPY_BUFFER_SIZE€0@ÿÿÿÿü««á6áÞ†jMÙèÅ:¤\ŘÎx9ø¾kÛ†1„݉T4ß@@ؼ ƒÑfDïÐ2±“TðþÙ¡Ñ·Ÿk-úÎu@Ü´ˆd=ö´|Fóï·}P$7Æ‹cTìÃo@'Y –î­Ä°“xd \(Ô °  ç Ë Y ¯ v“ v Ø =  ú # · – ‚ \  ê Ö ‹ "b C SË w 8 õÍY-àçɵ“òÁ‰Qýà ¦ˆjVEåÀ—c,á'íext_colorsVString[16]%éview_profileVString& Úpath_bookmarksVArray#Ðfiles_maskVString Írc_pathVString!Ìtmp_pathVString"Ëhome_pathVString%Êstartup_pathVString€,€.ÇFGO(file_list_index.go(n))n€&€0ÆPS(file_list_index.pagesize())€€-ÅFLP(file_list_index.page())€ €,ÄFLI(file_list_index.pos())'#vfu_tool_classifyvoid&"vfu.h" _VFUTOOLS_H_ €•€ €¡€¢€£€¤€§€¨€©€P@)%Óvfu_tool_seq_renamevoid%!pvfu_tool_renamevoid'#)vfu_tool_classifyvoidJ$__get_classify_strvoidconst char*fname,char ch,char*tmp€P@¤€&"vfutools.h"&"vfufiles.h"&"vfuview.h"& "vfucopy.h"& "vfumenu.h"€€›€œ€€ž€} ~ € ‚ „ … † ‡ ˆ ‰ ‹  ¹À8/file_get_lfnintconst char*in,char*out8.file_get_sfnintconst char*in,char*out1+file_exist(access(d,F_OK)==0)d0*dir_exist(access(d,F_OK)==0)d€¹À€I'vfu_edit_attrintmode_str_t mod_str,int allow_masking=1€{€™€N`"FTIMETYPEchar*[]€}€—€NOYESchar*[]&"vfuuti.h"&"see.h"!Øvfu_optionsvoid€j€t€u€v€w€y€z€{€|€}€~€€€€€ƒ€„€…€‡€‰€Š€Œ€€Ž€€€‘€($µvfu_edit_conf_filevoid'#«vfu_settings_savevoid'#ævfu_settings_loadvoid4Êkey_by_nameintconst char*key_nameT¿set_splitterintconst char*line,const char*keyword,VArray&splitterJ´set_intintconst char*line,const char*keyword,int&targetMžset_arrintconst char*line,const char*keyword,VArray&target)%bvfu_load_dir_colorsvoidKXvfu_opt_timetime_ttime_t ctime,time_t mtime,time_t atime€€…€‡€9Svfu_opt_timetime_tconst struct stat*st9Kvfu_opt_timetime_tconst struct stat st&TogglesToggleEntry[]€€€€ !TAGMARKSchar*[]!TAGMARKSchar*[]"FTIMETYPEchar*[]%NOYESPRECOPYchar*[]NOYESchar*[]optOptions&"vfumenu.h"&"vfuview.h"&"vfudir.h"&"vfuuti.h"& "vfuopt.h"& "vfu.h"€m€r€P vfu_menu_boxintconst char*title,const char*menustr,int row=-1L vfu_menu_boxintint x,int y,const char*title,VArray*va=&mb€k€l€m€n€o€p€r€T  vfu_toggle_boxintint x,int y,const char*title,ToggleEntry*toggles4 menu_box_infocon_default_menu_info& "vfuuti.h"&  _VFUMENU_H_€h€i€M (vfu_menu_boxintconst char*title,const char*menustr,int rowH vfu_menu_boxintint x,int y,const char*title,VArray*vaT  vfu_toggle_boxintint x,int y,const char*title,ToggleEntry*toggles€1€\€b€c€d€f€h€i€& "vfuview.h"& "vfumenu.h"& "vfuopt.h"& "vfu.h"€9€\€l€& €N€O€P€Q€R€S€T€U€V€W€X€Y€Z€[€]€^€_€)% ,vfu_pack_files_listvoid'# *vfu_arrange_filesvoid$  )vfu_sort_filesvoid, (__vfu_sortvoidint l,int r( 'ficmpintint fn1,TF*f2; %namenumcmpintconst char*s1,const char*s2)% !vfu_file_entry_movevoid5! vfu_fmask_matchintconst char*fname,( vfu_read_pszlist_filesvoid-) vfu_read_external_filesvoid:& vfu_read_local_filesvoidint a_recursive<( vfu_read_archive_filesvoidint a_recursiveS vfu_add_fileintconst char*fname,const struct stat*st,int is_link6  vfu_read_filesvoidint a_recursive=08" vfu_rescan_filesvoidint a_recursive=0B file_type_strconst char*mode_t mode,int is_link _VFUFILES_H_)% 4vfu_file_entry_movevoid'# óvfu_arrange_filesvoid$  ßvfu_sort_filesvoid, ¿__vfu_sortvoidint l,int r( yficmpintint nf1,TF*f2; cnamenumcmpintconst char*s1,const char*s2)% >vfu_pack_files_listvoid5! 4vfu_fmask_matchintconst char*fname,( %vfu_read_pszlist_filesvoid-) ÿvfu_read_external_filesvoid,)à__tree_index_last_cacheint3"Ìsize_cache_cleanvoidconst char*s> Ãsize_cache_setvoidconst char*s,fsize_t size4 ¶size_cache_getfsize_tconst char*s2" size_cache_indexintconst char*sõtree_viewvoidB ytree_draw_itemvoidint page,int index,int hilite"_tree_rebuildvoid?(__tree_rebuild_processfsize_tconst char*pathótree_fixvoidétree_dropvoidÜtree_savevoidU__glob_gdnvoidconst char*a_path,const char*a_fnpattern,VArray&a_va"size_cacheVArray&"vfumenu.h"&"vfuview.h"& "vfuopt.h"& "vfudir.h"/!}vfu_erase_filesvoidint a_one9 |vfu_copy_filesvoidint a_one,int a_modeP"p__vfu_file_eraseintconst char*target,fsize_t*bytes_freed=NULLO!o__vfu_dir_eraseintconst char*target,fsize_t*bytes_freed=NULLU!k__vfu_link_moveintconst char*src,const char*dst,CopyInfo*copy_infoU!j__vfu_link_copyintconst char*src,const char*dst,CopyInfo*copy_infoT h__vfu_dir_moveintconst char*src,const char*dst,CopyInfo*copy_infoT g__vfu_dir_copyintconst char*src,const char*dst,CopyInfo*copy_infoU!e__vfu_file_moveintconst char*src,const char*dst,CopyInfo*copy_infoU!d__vfu_file_copyintconst char*src,const char*dst,CopyInfo*copy_info@Zvfu_copy_modeintconst char*src,const char*dstPVshow_copy_posvoidfsize_t a_fc,fsize_t a_fa,CopyInfo*copy_infoSSover_if_existintconst char*src,const char*dst,CopyInfo*copy_info:Rfast_statintconst char*s,struct stat*stA Qdevice_is_sameintconst char*src,const char*dst?Pfile_is_sameintconst char*src,const char*dst<#Ndevice_free_spacefsize_tconst char*target €^€w€€€€€€€€€CabortintBover_modeint"Ano_free_checkint#=current_countlong%<current_sizefsize_t!;files_countlong#:files_sizefsize_t8no_infoint€ € €2resetvoid+CR_ABORT255*CR_SKIP200)CR_OK0%$%OM_ALWAYS_IF_MTIME4$OM_IF_MTIME3#OM_NEVER2 0`àü,4KõæÚ ÏÀ«k•Šy+]G9ñþÀÞÕË­ž“UxicN9-þéøç©ØÈ¸j~s;^SG /"Ìýñܦƺ²ž‰An`P90' ùçÐǹ°Ÿ”†w\E7*íÔÀŒybZQE4Q!ñÛɺ­—‹wpi^q>0 ñæÝ̾«™|²bVD7'üïà×ÑÇ½Þ §šŒypfZMB9.' ö Ö Í ¾ · ° ¤ œ ” Ž † ~ u i _ W P I : 2 )    ÷ ì ß Ì ½ · ± « £ š „ { r k Z H A )    öéØÉ¸¦q›’†3aN=ï*#ŒÓ¸¤e}vo@]VO‡:4!oaUF6&í ýÀáÏÈ”¯¨›m‡€s/ZK:( ãýöîåÛÏÂî×ͽ¯a Žt[UK title y x vfu_toggle_box con_default_menu_info menu_box_info "vfuuti.h"  _VFUMENU_H_ count con_max_y push4(€¡¡¡¡ ¡ ¡ ¡ ¡ ¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡ ¡!¡"¡#¡$¡%¡&¡'¡(¡)¡*¡,¡-¡ str_word str_len str String zap mb t row menustr con_menu_box va VArray vfu_menu_box vfu_redraw con_toggle_box z cMENU_TI ti cMENU_CH ch cMENU_CN cn menu_borders opt bo menu_box_info toggles ToggleEntry title y x vfu_toggle_box "vfuview.h" "vfumenu.h" "vfuopt.h" "vfu.h"  vfu_pack_files_list vfu_arrange_files €å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ ¡¡¡¡ vfu_sort_files r l __vfu_sort f2 TF fn1 ficmp s2 s1 namenumcmp vfu_file_entry_move vfu_fmask_match vfu_read_pszlist_files vfu_read_external_files vfu_read_local_files vfu_read_archive_files st stat fname vfu_add_file vfu_read_files a_recursive vfu_rescan_files is_link mode mode_t file_type_str _VFUFILES_H_ vfu_redraw vfu_nav_down KEY_DOWN vfu_nav_up KEY_UP old key rand vfu_file_entry_move ec menu_box_info vfu_menu_box mb _rev _ord vfu_arrange_files midf mid j r l __vfu_sort sort_direction type_str st_gid st_uid st_atime st_ctime st_mtime size ext sort_order f1 f2 nf1 ficmp pathcmp atoi ss2 ss1 m re2 re1 VRegexp s2 s1 namenumcmp next pos vfu_pack_files_listÄ»€- . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g l m n o p q r s t u v w x y z { | } ~  €  ‚ ƒ „ … † ‡ ˆ ‰ Š ‹ Œ    ‘ ’ “ ” • – — ˜ ™ š › œ  ž Ÿ   ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ­ ® ¯ ° ² ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á  àÄ Å Æ Ç È É Ê Ë Ì Í ΠÏ РѠҠӠԠՠ֠נؠ٠ڠ۠ܠݠޠߠà á â ã ä €€€€€ €!€£€¤€¥€¦€ files_mask_array pc pclose F_OK access str_word str_cut popen tmp1 tmp unlink con_getch con_beep str_tr fclose fgets fopen f FILE files_size sel_size system err chdir work_path user_id_str tmp_path tmp_file_name FNMATCH auto_mount ftwalk file_is_link str_len str_trim_left str FTWALK_DX vfu_break_op flag origin __vfu_ftw_add sprintf str_fix_path expand_path full_name size_cache_get set_size is_dir fi TF vfu_fmask_match st_mode file_get_mode_str mode_str mode_str_t _TARGET_GO32_ show_hidden_files str_file_name_ext MAX_PATH t st stat fname vfu_add_file do_draw say2 FGO vfu_drop_all_views vfu_sort_files con_max_y file_list_index vfu_read_local_files vfu_read_pszlist_files list_panelizer vfu_read_external_files WM_NORMAL external_panelizer vfu_read_archive_files WM_ARCHIVE work_mode ASSERT archive_name NULL MAX_FILES say1 vfu_nav_update_pos update_status strcmp i count vfu_read_files name push sel files_list files_count sel_count keep_selection opt savea FLP old_flp FLI old_fli z a_recursive vfu_rescan_files S_IXUSR S_IXGRP S_IXOTH S_ISSOCK S_ISFIFO S_ISCHR S_ISBLK S_ISDIR strcpy is_link mode mode_t file_type_str __file_stat_type_buf "vfudir.h" "vfumenu.h" "vfuview.h" "vfuopt.h" "vfufiles.h" "vfu.h" vfu_dir_size4&€                                 ! " # $ % & ' ( ) * +  size_cache_clean size size_cache_set size_cache_get fsize_t size_cache_index va tree_find s tree_index opos tree_draw_pos scroll TScrollPos tree_draw_page hilite index page tree_draw_item tree_fix tree_rebuild tree_drop tree_save tree_load tree_view vfu_chdir_history a_new_dir vfu_chdir should_exist target String prompt vfu_get_dir_name size_cache VArray "vfu.h" _VFUDIR_H_ memsetþŒ``Ž```‘`’`“`”`•`—`˜`™`š`›``ž`Ÿ` `¡`¢`£`¤`¥`¦`§`¨`©`ª`«`¬`­`®`¯`°`±`²`³`´`µ`¶`·`¸`¹`º`»`¼`½`¾`¿`À`Á`Â`Ã`Ä`Å`Æ`Ç`È`É`Ê`Ë`Ì`Í`Ï`Ð`Ñ`Ò`Ó`Ô`Õ`Ö`×`Ø`Ù`Ú`Û`Ü`Ý`Þ`ß`à`á`â`ã`ä`å`æ`ç`è`é`ê`ë`ì`í`î`ï`ð`ñ`ò`ó`ô`õ`ö`÷`ø`ù`ú`û`ü`ý`þ`ÿ`aaaaaaaaa a a a a aaaaaaaaaaaaaaaaaaa a!a"a#a$a%a&a'a(a)a*a+a,a-a.a/a0a1a2a3a5a6a7a8a9a:a;aa?a@aAaBaCaDaEaFaGaHaIaJaKaLaNaOaPaQaRaSaTaUaVaWaYaZa[a]a^a_a`aaabacaeaiajakalamanaoapaqarasatauavawaza{a|a}aa€aa‚aƒa„a…a†a‡aˆa‰aŠa‹aŒaaŽaaa f€g€h€i€j€k€l€m€n€o€p€q€r€s€t€u€v€w€x€y€z€{€À@ÿÿÿÿ Llág_tsÌ i_ts"ám_ts'`m_ts¾àm_ts`ám_ts'am_ts~ m_tsdám_ts¡am_tsKám_tsÈ m_tsBàs_ts*`s_tsÄàs_tsQás_ts3au_ts™áu_tskáu_tsË fats afats áratsh@rats0árats?àrats˜@tats `tatsG tats®àtatsátatsr`tats atatst tatsð tats?àtatsátatsbátatsBatatsIátatsAatatsHátats atatsátats'àtatsû`idtsaodtsargtsŽáomtsŒáwotsártsIàrtslártsMárts¢`rts rts(¡rtsOàrtsÏ@rtsArts7A1rtssa2rts›a_rtsF€_rtsëa_rtsla_rts›@_rts„a_rtsj€_rts`_rtsSá_rtsZa_rtsA_rtsÃà_rtsa_rts©@_rts»a_rtsºà_rts« _rtsTà_rtsÚà_rts8a_rtsmà_rtsŠa_rtsî`_rtsò@_rts¾à_rtsÈ`_rtsSá_rtseá_rts5a_rtsuA_rts$@_rts@_rts@_rts$a_rts¢€_rtsi€_rtsx _rtsá_rtsh€_rtsS@_rts‘à_rtsý`_rtsÅ`_rtsRà_rtsGA_rtse€_rts6`_rts;`_rtsÞ`_rts‡ _rtsÅa_rtsÀà_rtsË`_rts?A_rtsÃa_rtsaà_rtsº@_rts¿à_rtsß`_rts>à_rtsqá_rtsÂà_rts·`_rts‘ _rts)¡_rtsUà_rtsó@_rtsyA_rts€_rtsjà_rtsT@_rtsBA_rtsrá_rtsOa_rts@à_rts!`_rtsÀ`_rtsÑ@_rts…A_rtsa_rtsa_rtsÜà_rtsEa_rts`à_rtsW@_rts»@_rts„á_rtsÏ`_rtsÄa_rtsÁ`_rtsPA_rts?à_rts `_rts¿`_rtsCà_rts!@_rts†A_rts&€_rts¹€_rtsX@_rtsŽa_rtsEà_rtsF`_rtsVa_rts¤ _rtsV@_rts‰@_rts[à_rtsÊa_rts¾`_rts _rtsêa_rtsÁà_rts<`_rtsBa_rtsnà_rtsU@_rts¼a_rts¬ _rts*¡crtsÂacrts% crtsácrts`crts'ácrts+acrts#@crtsŽàcrtsiácrtsµ@crtsZacrts( crts`crts£`crtsV crtsuàcrtsß@crts|àcrtsácrtsèàcrts!ácrts9 crtsMácrtsÃ@ertsmáirts²àirtsýàirts  irts#¡irtsO@irts|@irtsAlrts‚álrtsalrts£àlrtsálrts"@lrtsè@lrts„Anrts' nrts) nrts¿ànrts‰anrtsVànrtsÚ@rrtsØarrts&áistsáittsáittsNáytts‘ábusL€_busK€ffus^@vs§àovs*aovs‡àovsýàlmys¶almys `tsysatsysœ zsWatE€t`tààtátÛ`tv t$¡tàt>@tŽ@tMA1tUa2tVasbat£à_gat‚a_gat2A_gat®A_gat&à_gatïà_gateAmgatàmgatÐàmgatdAgratkagratâàgrat ágratk`grat¬`grat gratfàgrat ágratô@grat(Agrat½`grat'`btapmetà`txetkàtxetƒatxeté@ftáftC ft@`ft€ ftý ftG@ft¥@ft0Aft²AitS`it¡dlitÆ`mit¾@mit Aemit]`emitÂ@emit˜aemitÚaemit£áemitRáemit¼@emitAemitTaemit=àemitáemit½@emitAemitPaemitOaemitQaemitRaemitÁ@ltit¡ltit7¡ltitå@ltit"Alt(@mtJámt@pmtiàpmt‡apmt¨ pmt @pmt‹A1pmtWa1pmt© 2pmtXa_pmt– _pmta_pmt‘à_pmt2á_pmtAà_pmt— _pmtü@dpmtÆàfpmtñàggot ¡ggotàggotàggotsággotàggot¡ggotàolott`olotð`puotàpuot‹apuot—€puotp€puotyàeertý`eert0àeertåàeertDaeert+àeertààeert?aeert eertLaeert eertTaeert eert aeert eertaeert  eertaeert eert`aeert" eertÿ`eert eertå`eert7aeert eertè`eertaeert eertˆ`eert^aeert mirt,amirt.amirt@ámirtNàmirt-amirt­àrcst epyt8`epytàepyt5aepytàepytÍ epytIAu²adiu¤a_diu>`ednud€ednu%€ednuŠ€ednug€ednu!€ednuº€ilnuë`ilnuôàilnu`ilnu§ ilnuþ@esnu9apu`àpuuapu›Ah_puP€t_puQ€adpu`adpuàadpuaadpuàadpuI`adpuW adpu­@_esu#à_esuéà_esu:A_esu(à_esuêà_esuƒ@resu;áresuIàresu€àresuHáresuUàresu˜ resu’Abtucámituœamitubámitu¢amitugáav¯àav¸aavêàav€avaav% av ¡av àavKàe_av;€e_avbál_av7€l_av]ás_av9€s_av_áulavÝ@ulavArravárrav*àrravéàrrav‘€rrav”`rrav  rrav¡rravàrravJàrravá_ufv`_ufv à_ufv`_ufvŸà_ufvÇà_ufvr _ufvî _ufv™`_ufvÕ _ufvÿ _ufvñ`_ufv°@_ufvA_ufvj`_ufvWá_ufvÕ`_ufvÇ@_ufvA_ufvÕa_ufv‚á_ufva_ufvŒ _ufvœ@_ufvA_ufv®`_ufvšà_ufvØà_ufv7a_ufvÉà_ufvùà_ufv­`_ufvà_ufv…`_ufv†à_ufv”`_ufvõ`_ufv  _ufv–`_ufv a_ufv _ufva_ufv/ _ufvYA_ufvÝ`_ufvqà_ufv¤à_ufvà_ufvôà_ufv›`_ufvyà_ufvÇà_ufvá_ufvba_ufvH`_ufv£ _ufv¡_ufv¯à_ufvøà_ufv` _ufvò _ufvS _ufvô _ufv^`_ufv a_ufvO _ufví _ufvL@_ufvŠ`_ufv£à_ufvf _ufvï _ufve _ufvõ _ufvo`_ufvä _ufv¡_ufvÌà_ufv®@_ufviA_ufv€_ufvp`_ufvÍà_ufv¯@_ufvˆA_ufv €_ufv²`_ufv™à_ufvŒ`_ufv§€_ufvB _ufvç _ufvn`_ufvsà_ufvk`_ufvpà_ufvP`_ufv~à_ufvá_ufvé`_ufv¶à_ufvá_ufvž`_ufv|à_ufv×à_ufvÃà_ufvX`_ufvtà_ufv’a_ufvm _ufv¡_ufv¢à_ufv%a_ufvËà_ufvû@_ufv)A_ufvú@_ufvSa_ufv¡_ufv0¡_ufvÈà_ufvuá_ufvu`_ufvzà_ufv|a_ufv&@_ufvp@_ufv{a_ufv=@_ufvq@_ufvR@_ufvr@_ufvÌ`_ufvà_ufv+`_ufv¢@_ufv A_ufvü`_ufv{@_ufvA_ufvwa_ufvÚà_ufvüà_ufvÚ`_ufv’à_ufv3a_ufvŽà_ufvŸ`_ufv”à_ufvá_ufvqAweivŠáweivàweiv^AweivBáweivPàweivAáweivOàweiv,asilv8€silv^ágerv2€gerv¹ gervgàpnsv:€pnsvÀrtsv<€rtsv#€rtsv½€rtsv}€rtsv|€rtsvf€rtsv€rtsv¸€rtsvÀ€rtsv"€irtvˆ€irtv£€a_mw`a_mw$àa_mwø`a_mw_ a_mw†@a_mwoAn_mw4`n_mw#àn_mw an_mwb krowákrowàkrow÷`krow^ krow@krownAkrowákrow'àkrowÖàkrow¡€krowû`krow™ krow—@krowrAparwaàparw7`xA€x`x x ¡x5¡xƒáxã@x Atalx6àxamxànimx àyVàyay ¡y6¡yä@yAxamy$ànimy!àz1àzi`zëàzázÊ`zD z¡zIàznáz-@z¤@z@Apaz&¡paz,@pazç@_pazŽà_pazðàzzè`à0 @ü”ìàÏÄB½¶ª¢N3õ$Îéá×½¯]€ti0QF;ì  û”Ù¿©K€\ ?+ ôå˼©–ƒn^SB92%U÷íÕý²«¡—„|pcžI=1)  ÿòèÝÕŹªä•‰~rkeYPD8/ô×ÌÁ³§›qcMG4 êß×ÍŶ£‘lcYM9% ëàϽ¨‘†q_UJ7+ þðåØÊ¿§ye[D=3% òèÚÑż¬™eV@1%ñ þ±åÖÃmž‹x?bWK4$»ôàÊe¬™P=+ÔíßÜÁ°œzgWB:%øí¸ Ó̸®¢™‚l_I3È ª š Z } l H 0  « ð Ö ¼ z ’ † N p f Y C 6 * ñ  þ à å Û Î Ç ¶ ­ ¤ Ð º ­ ¢ • ˆ | m 1 ^ N < ú  ÊîãÖ™¾²¦hŒ€t8\PD, ßüïæÓ½­Ì…{iWLF:1% ùæÙá»´¬¤—yk`WQJC<èÚÓ嬛Œz=iZM/mode_str_tMODE_WRITE_ONMODE_MASKMODE_STRING MODE_OFF_VFUSYS_H_file_get_lfndosmemget flags__dpmi_intdisiesTL€AáBáCáDáEáFáGáHáIáJáKáLáMáNáOáPáQáRáSáTáUáVáWáXáYáZá[á\á]á^á_á`áaábácádáeáfágáháiájákálámánáoápáqárásátáuáváwáxáyázá{á|á}á~áá€áá‚áƒá„á…á†áˆá‰áŠá‹áŒáádscxaxx __tb strlendosmemputr__dpmi_regsdst MAX_PATHsrcoutinfile_get_sfn  vfu_toggle_boxmode_togglesToggleEntry AONOFF AONOFF2 NULL AONOFF1z mode_iallow_maskingvfu_edit_attr chmod strchr new_modenew_mod_strold_mod_strfile_set_mode_str st_modest stat filename S_ISVTX S_ISGID S_ISUID S_IXOTH S_IWOTH S_IROTH S_IXGRP S_IWGRP S_IRGRP S_IXUSR S_IWUSR S_IRUSR S_ISSOCK S_ISFIFO S_ISCHR S_ISBLK S_ISLNK S_ISDIR MODE_OFF strcpy mod_strmode_str_ttm mode_tfile_get_mode_str _TARGET_GO32_"vfumenu.h""vfuuti.h""vfusys.h" "vfu.h" cMAGENTA cMENU_TI cGREEN cMENU_CH cMENU_CN cTAG4+€ááááááááááá á!á"á#á$á%á&á'á(á)á*á+á,á-á.á/á0á1á2á3á4á5á6á7á8á9á:á<á=á>á?á@á cBAR cRED cWARNING chCYAN cSTATUS2 cCYAN cSTATUS cMESSAGE cWHITE cBLACK cINPUT2 cBLUE chWHITE CONCOLOR cINPUT cINFO2 chYELLOW cINFO chRED cHEADER cNORMAL cPLAINMAX_FILESRX_TEMP_LISTFILENAME_CONF_GLOBAL2FILENAME_CONF_GLOBAL1FILENAME_CONF_GLOBAL0FILENAME_FFRFILENAME_HISTORYFILENAME_SIZE_CACHEFILENAME_TREEFILENAME_CONFFILENAME_OPT_TARGET_GO32_ HEADERVFU_VERSION_SETUP_H_vfu_optionsTE€ÎàÏàÐàÑàÒàÓàÔàÕàÖà×àØàÙàÚàÛàÜàÝàÞàßàààáàâàãàäàåàæàçàèàéàêàìàíàîàïàðàñàòàóàôàõàöà÷àùàúàûàüàýàþàÿàááááááááá á á á á áááááá€À€vfu_edit_conf_filevfu_settings_savevfu_settings_load splitter VArray target keyword line set_set atime mtime ctimest statvfu_opt_time time_t key_namekey_by_nameoptseoSeeEditorOptionssvoSeeViewerOptionsbytes_freedkeep_selectionauto_mountlynx_navigationmenu_bordersshow_user_free zap_roshell_clsmask_auto_expandinternal_editorinternal_browsertag_mark_typecopy_keep_modecopy_calc_totalscopy_free_space_checkuse_dir_colorsuse_colorsallow_beepshow_hidden_filesfast_size_cache tree_cdtree_compactlong_name_viewf_time_type f_type f_owner f_group f_mode f_time f_sizepath_bookmarkslast_copy_pathmax_path_str_tsort_top_dirssort_directionsort_order Options TAGMARKSFTIMETYPE NOYES"vfuuti.h" "see.h"_VFUOPT_H_vfu_redraw_statusvfu_redrawvfu_drop_all_viewsvfu_toggle_boxvfu_options say2 do_draw datavfu_shell closerequest_quitrunr open editorSeeEditor cINFOcsvfu_edit_conf_file fsavefile_save_crc32vfu_settings_savefilename_size_cachesize_cache fclosetrim_tree chYELLOW chBLUEchMAGENTA chWHITE chCYAN chRED chGREEN chBLACKpath_bookmarks strlen fgetsfilename_conf fopen re_pan re_see re_uxshell_browsershell_editor getenvfilename_history say1 memcpyfilename_optĵ€ààààààààààààààààààà à!à"à#à$à%à&à'à(à)à*à+à,à.à/à0à1à2à3à4à5à6à7à8à9à:à;à<à=à>à?à@àAàBàCàDàEàFàGàHàIàJàKàLàMàOàPàQàRàSàTàUàVàWàXàYàZà[à\à]à^à_à`àaàbàcàdàeàfàgàhàiàjàkàlàmànàoàpàràsàtàuàvàwàxàyàzà{à|à}à~àà€à‚àƒà„à…à†à‡àˆà‰àŠà‹àŒàŽààà‘à’à”à•à–à—à˜à™à›ààžà à¡à¢à£à¤à¥à¦à§à¨à©àªà«à¬à­à²à´àµà¶à·à¸à¹àºà»à¼à½à¾à¿àÀàÁàÂàÃàÄàÅàÆàÇàÈàËàÌàÍ฀¹€º€»€file_load_crc32 tmp_opt fsett FILE zap_rosort_top_dirssort_directionsort_orderseo resetsvo memsetarchive_extensionspanelizerssee_filters historyuser_externalstvfu_settings_loadKEY_SH_F1KEY_CTRL_F1KEY_ALT_F1 KEY_F1 toupper reFKEYSKEY_ENTER KEY_IC strcmp key_namekey_by_namePATH_DELIMITER splitterset_splitter atoi set_int set_str push str_lowmre VRegexp target keyword line set_arrext_colors str_insstr_replacespc cWHITE cCYAN cMAGENTA cBLUE cYELLOW cGREEN cREDpos strncmp str_len str_cutstr_sleft str_find commentdelstr count floadva VArrayz_TARGET_UNIX_vfu_load_dir_colors atime mtime ctime st_atime st_mtime st_ctimest statvfu_opt_time time_tbytes_freedcopy_calc_totalsshow_user_freecopy_keep_modekeep_selectionauto_mountcopy_free_space_checkallow_beepmask_auto_expandlynx_navigationshell_clsfast_size_cache tree_cdtree_compactmenu_bordersinternal_editorinternal_browsershow_hidden_fileslower_case_ext_configuse_dir_colorsuse_colorstag_mark_typelong_name_viewf_time_type f_type f_size f_time f_group f_owner f_mode TogglesToggleEntry TAGMARKS_TARGET_GO32_FTIMETYPENOYESPRECOPY NULL NOYESopt Options"vfumenu.h""vfuview.h""vfudir.h""vfuuti.h""vfuopt.h" "vfu.h"€.¡/¡0¡1¡2¡3¡5¡6¡7¡àààà à à à àVAr row menustr mb va VArray vfu_menu_box toggles ToggleEntry@ ‡Fà_rida_rid8áeridìaeridnaerid`eridŸ`iamdÌ`d_odàd_odTád_od_àd_odJ`d_od ad_odq d_odÅàd_od\@d_odVAd_odUád_od`àd_od«AmsodŒámsod€ássod(anwodcànwodwanwodAnwodS€nwodT€ward^àwardFàwardÄàwardTàpord‡ápordàpordUAsd†átsd>atsdátsdn`tsd}áiatdÍ`ceaaceZáceÛ ce0@tide€àtideàtideatide½àdneeàdne{a2dnefà_dneU€_dneà_dneV€foeßàsopeàsareM`rreyarre› rreN@nrrenánrrenásrre“asewáacseàacse/àsixe¥€tixeõ`apxe!aapxe:`apxeÝ`apxe† apxe»àtxe4atxeàtxeÆ txe@txe _dihe@_dih< _dihc@_dih6 _dih‘@ilihAailih tsihÎ@tsihAtsihá@tsihÌ@tsih<átsihJàtsih‚àtsihÕ@kh¾aemohdàemohzaemoh1áemoh@àtsohJátsohWàtsoh•ArtshÐ@iGàiaiU i2@i}@ongi áiijànikaniyáni@t_ni~àedni@aedni edniØ@edniAsniÓàsniºasni1asniÖ@esniÆàesniµ`esni´àesniÛàetni)aetni'àetniìàetniaetni,àetniñàd_siad_si àd_si)ad_si‚ d_si1@d_si™@d_si8Al_siµal_siàl_si%al_si8 l_siê l_siI@l_si¨@j½àjCajÒ kŠàsbkÑàledkÍàpeek€peek¤€peekL peek8àpeekúàtnekÒàyek0àyek-ayekàyekiayekÞ yek @yek$A_yeká_yekÀ`_yeká_yekÂ`_yeká_yekÃ`_yeká_yekÄ`_yeká_yekÅ`_yeká_yekÆ`_yek á_yekÇ`_yekÊà_yekÈ`_yek á_yekÉ`_yek á_yekÊ`_yek¬`_yek«`_yek•`_yek¼`_yek—`_yekúà_yekÕ`_yek{à_yekÖ`_yeküà_yek™à_yek¾`_yekº`_yek·`_yek±`_yek‰`_yekûà_yek–à_yekx`_yekq€_yek¨`_yek—à_yekŽ`_yekÇ`_yekva_yekcà_yeká_yekôà_yek)€_yekÉ`_yekîà_yekéà_yekùà_yek‡`_yekœà_yek*€_yekïà_yek†`_yek×`_yek|à_yekØ`_yeká_yekëà_yekà_yekw`_yekìà_yekíà_yek‹`_yek÷à_yeká_yek `_yekðà_yek¿a_yekÙ`_yekòà_yeká 0@ü›ŸûFÛ¼™ùwËÞP§ pÌ-‡ðE¦hÓ]ŒöC± hÆ%ç¢Gƒ`@l"8õÙÅ‘X ÀuM´f>ß}ÿV.[Ø­†[G áÍžŠKG  ÑŒ¾ÜÞ{J‚öÖ´+S&ó_õþÀ¤‡oó %Ø Ä q : Ù ¿ ‡ C ÷Û¼¨ŠvZF 7÷Ð¥ÛêÖƒ·’lG!øÒ¦\<(ûïyT@€& 7 <  !Q __ff_optVString€  %P __ff_patternVString€ž "O __ff_pathVString€œ e(dvfu_user_external_findintint key,const char*ext,const char*type,VString*shell_line€˜  xsay_strVString%hfilename_atlVString%gfilename_ffrVString,%ffilename_size_cacheVString&efilename_treeVString)"dfilename_historyVString&cfilename_confVString%bfilename_optVString&`host_name_strVString%_group_id_strVString$^user_id_strVString#\shell_progVString€; &[shell_optionsVString%Zshell_editorVString&Yshell_browserVStringS#&file_set_mode_strintconst char*filename,const mode_str_t mod_str€… ‹ M#%file_get_mode_strintconst char*filename,mode_str_t&mod_strJ#$file_get_mode_strvoidconst mode_t tm,mode_str_t&mod_str$mode_str_tchar[12]+MODE_WRITE_ON"??w???????"'MODE_MASK"-?????????")MODE_STRING"drwxrwxrwx"&MODE_OFF"----------"€-€‚ &€(€€ &€&€~ & _VFUSYS_H_IJ€ @@!@+@0@€@@Ž@@@‘@’@“@”@¢@£@¤@¥@¦@§@¨@©@ª@«@¬@­@®@¯@°@±@²@€€ € € € €€€€€€€€€€€€€ €!€"€P€Z€[€\€e€j€o€x€z€{€†€Œ€€ÓÀ@@@ @@ @!@#@$@%@&@'@)@*@+@,@-@.@0@2@;@=@>@`@c@d@f@g@h@4€5€6€7€8€9€:€=€>€@€A€B€C€E€F€G€H€I€J€K€L€M€c€h€i€€„€…€‡€‰€Š€Œ€€Ž€€€‘€¡€§€¨€©€q r s u w z œ  ````````````` `"`$`%`(`G`J`K`L`M`O`P`Q`R`S`T`U`V`X`   8Òfile_get_lfnintconst char*in,char*out€\ m n o p q r s u v w x y z 8ºfile_get_sfnintconst char*in,char*out&¸&·Gqvfu_edit_attrintmode_str_t mod_str,int allow_masking7AONOFF(allow_masking?AONOFF1:AONOFF2)S#Cfile_set_mode_strintconst char*filename,const mode_str_t mod_str€r s M#8file_get_mode_strintconst char*filename,mode_str_t&mod_strJ#file_get_mode_strvoidconst mode_t tm,mode_str_t&mod_str&&"vfumenu.h"&"vfuuti.h"& "vfusys.h"& "vfu.h"6McMENU_TI(CONCOLOR(chWHITE,cMAGENTA))4LcMENU_CH(CONCOLOR(chWHITE,cGREEN))$#€A B C D E F G H I J K L N P R T V X Y Z [ ] ^ _ ` a b c d e f g h i k 3KcMENU_CN(CONCOLOR(chWHITE,cBLUE))-IcTAG(CONCOLOR(cRED,cWHITE))/HcBAR(CONCOLOR(chWHITE,cBLUE))2FcWARNING(CONCOLOR(chWHITE,cRED))"EcSTATUS2(chCYAN) DcSTATUS(cCYAN)"CcMESSAGE(cWHITE)2BcINPUT2(CONCOLOR(cBLACK,cWHITE))1AcINPUT(CONCOLOR(chWHITE,cBLUE))"@cINFO2(chYELLOW)!?cINFO(chYELLOW) >cHEADER(chRED)!=cPLAIN(cNORMAL) 9MAX_FILES64000,7RX_TEMP_LIST"RX_TEMP_LIST"A'4FILENAME_CONF_GLOBAL2"/usr/local/"FILENAME_CONFE'0FILENAME_CONF_GLOBAL1"/usr/local/etc/"FILENAME_CONF;',FILENAME_CONF_GLOBAL0"/etc/"FILENAME_CONF€K V '(FILENAME_FFR"vfu.ffr"€J L /"'FILENAME_HISTORY"vfu.history"€I R /%&FILENAME_SIZE_CACHE"vfu.size"€H P )%FILENAME_TREE"vfu.tree"€F N )$FILENAME_CONF"vfu.conf"€E G +#FILENAME_OPT"vfu.options"'!FILENAME_FFR"vfu.ffr"+" FILENAME_HISTORY"vfu.hst".%FILENAME_SIZE_CACHE"vfu.siz"(FILENAME_TREE"vfu.tre"(FILENAME_CONF"vfu.cfg"'FILENAME_OPT"vfu.opt"bHEADER"VF/U v"VFU_VERSION" by (c) Vladi Belperchinov-Shabanski `Cade' 1996-2002"#VFU_VERSION"3.04" _SETUP_H_!avfu_optionsvoid($`vfu_edit_conf_filevoid'#^vfu_settings_savevoid'#]vfu_settings_loadvoidO[set_setintconst char*line,const char*keyword,VArray&splitterJZset_setintconst char*line,const char*keyword,int&targetD:€”€–€—€™€                            ! " # % & ' ( ) * + - 0 2 3 4 6 7 < = > ? @ q`   KXset_setintconst char*line,const char*keyword,char*targetKVvfu_opt_timetime_ttime_t ctime,time_t mtime,time_t atime€3 4 6 9Uvfu_opt_timetime_tconst struct stat*st9Tvfu_opt_timetime_tconst struct stat st4Rkey_by_nameintconst char*key_name€|€0 PoptOptions€ ! %MseoSeeEditorOptions%LsvoSeeViewerOptions4&€                           ! " # % ' ( ) * + - q` Jbytes_freedint# Hkeep_selectionintGauto_mountint$!Elynx_navigationint!Cmenu_bordersint# Bshow_user_freeint@zap_roint>shell_clsint%"=mask_auto_expandint$!;internal_editorint%":internal_browserint"8tag_mark_typeint# 6copy_keep_modeint%"5copy_calc_totalsint*'4copy_free_space_checkint# 1use_dir_colorsint0use_colorsint.allow_beepint&#,show_hidden_filesint$!*fast_size_cacheint)tree_cdint!(tree_compactint# 'long_name_viewint %f_time_typeint$f_typeint#f_ownerint"f_groupint!f_modeint f_timeintf_sizeint2 path_bookmarksmax_path_str_t[10]1 last_copy_pathmax_path_str_t[3]"sort_top_dirsint# sort_directionintsort_orderint!TAGMARKSchar*[]@0àÿÿÿÿü¯²»æÛÔÈs¥“JmbY¤8' ¬“ƒs*cRAÿ Êô騒´§ q‰‚zA`NG;+ì ö»ß×É쵩¡“…xj[NG@4'äÙÐ뙂wgWH=0$²õåÒ¿¬š†|tk`Wæ4|d@%è÷¨Ø¾³†š’ŒJthX;,$â þíµÜϽ~© 9i[J|(úìãÛÏ·¯©¢›“‡¨o^Q?0÷ðçÜÓ¿¶æœŒwld\QE<1' ýõÙÍ¿®¢š‘…r^K?7&oþõëãØÐº¨¢œ’‹ƒxy^D,$úìÜÐÅ·¯¡›‡cVI=2#Ù ý ò ç ¥ È ¼ ± e ™ y 4 \ G <  ,  Ì ñ å Ý ’  ¯ ¥ ` ~ l f \ V > 6 b T D 9 ,  Ò ÿ ð á – Á ° q | C i Z N  9 0 ! Û ó á ¨ Ð Ä · } › Ž … Q w k _ ŒE .    õèâËü¶¬£›Âtl_MC:,÷ìÞÏÞ²¤“‚ofWD8/õéÎø­¡“ˆrkd\N@4' ùéàϽ¯¤•‰un]TB6+ ûóÜ̹­§ž‹{l[J70) curr show_posfiTFget_item_colorsel_mark_postag_mark_pos"vfuopt.h"_VFUVIEW_H_do_draw_status sizef fsize_tvfu_nav_selectvfu_nav_endvfu_nav_update_posFGOvfu_nav_home pagedownvfu_nav_npage pageup old_flivfu_nav_ppage downvfu_nav_downupfile_list_index old_flpvfu_nav_up cINFO2con_max_yhost_name_strgroup_id_str datauser_id_strfs_block_size sel_sizefiles_size fs_total fs_freestr_commasel_counttmps2s1vfu_redraw_status cPLAINstr_sleft str_pad strlen f_type f_sizef_time_type f_time f_group f_ownerMODE_STRING f_modelong_name_view spos str_lensort_directionsort_order NULLstr_dot_reducearchive_patharchive_namework_pathVFU_VERSION cWARNINGWM_ARCHIVEwork_mode con_ce cINFOfiles_mask MAX_PATHvfu_redrawFTIMETYPE cTAG cBOLDtag_mark_type TAGMARKSFLI cWHITE CONCOLORstr_set_chsel view colorcPSFLPVFU_CHECK_LIST_POSn vfu_draw do_drawdrop_viewfiles_listfiles_countvfu_drop_all_views cHEADERcon_max_x con_out sprintftall curr show_pos type_strext_colors str_find chWHITE cBLACKz_TARGET_GO32_ str_lowextstr_get_ch name cCYAN is_dir cNORMALuse_colorsopt ASSERTstrfiTFget_item_colortag_mark_possel_mark_pos"vfusys.h""vfuuti.h""vfuopt.h""vfuview.h""vfufiles.h" "vfu.h" vfu_temp targetvfu_get_strposs4*€ÿ@AAAAAAAAA A A A A AAAAAAAAAAAAAAAAAAA A!A"A#A$A&A'A(A)Akeyvfu_get_str_history titleyxvfu_hist_menuvfu_hist_removevfu_hist_count valuevfu_hist_index indexvfu_hist_getstr hist_idvfu_hist_addsizsize_str_compact vfu_beepbuftim time_ttime_str_compact maskvfu_expand_maskonevfu_update_sel_size fsize_t allowed prompt vfu_askvfu_break_opa_options a_line Stringvfu_update_shell_line "vfu.h"_VFUUTI_H_ unlink mkstemp tmp_path vfu_tempvfu_temp_filenameTextInputÄ‹€o@t@u@v@w@x@y@z@{@|@}@~@@€@@‚@ƒ@„@…@†@‡@ˆ@‰@Š@‹@Œ@@Ž@@@‘@’@“@”@•@–@—@˜@™@š@›@œ@@ž@Ÿ@ @¡@¢@£@¤@¥@¦@§@¨@©@ª@«@¬@­@®@¯@°@±@²@³@´@µ@¶@·@¸@¹@º@»@¼@½@¾@¿@À@Á@Â@Ã@Ä@Å@Æ@Ç@È@É@Ê@Ë@Ì@Í@Î@Ï@Ð@Ñ@Ò@Ó@Ô@Õ@Ö@×@Ø@Ù@Ú@Û@Ü@Ý@Þ@ß@à@á@â@ã@ä@å@æ@ç@è@é@ê@ë@ì@í@î@ï@ð@ñ@ò@ó@ô@õ@ö@÷@ø@ú@û@ü@ý@þ@rcon_max_xlencon_max_y target str_lenstr_cut_spccon_cshowcon_chideKEY_PPAGEKEY_NPAGEposvfu_get_str_history__vfu_get_str_hist_idvfu_menu_box push strlenzapmb titleyxvfu_hist_menuhist_menu_hotkeysdel strcmpcnt value pstrget strncmp count indexvfu_hist_getins historyvfu_hist_countvfu_hist_removevfu_hist_index str_pad hstrstr hist_idvfu_hist_addHISTIDPAD MAXHIST con_beepallow_beepopt vfu_beepsizsize_str_compact ctime strcpy time timenow ASSERTbuftim time_ttime_str_compactstr_replace str_insstr_count maskvfu_expand_mask NULL strchr say1ch allowed prompt vfu_askvfu_redraw_statusvfu_redrawupdate_status set_sizevfu_dir_size dir_size is_dir is_linkselfiTFzonevfu_update_sel_size fsize_tkey say2con_getchcon_kbhitvfu_break_opstr_add_charchive_patharchive_namestartup_pathwork_pathvfu_get_dir_nameHID_SHELL_PARvfu_get_str size sprintfextstr_file_name MAX_PATHt str_trfile_get_sfnshort_namefull_name nameFLIfiles_listWM_ARCHIVEwork_modefiles_count use_SFN_TARGET_GO32_isouta_options a_line Stringvfu_update_shell_line"vfuview.h""vfuopt.h""vfudir.h""vfusys.h""vfumenu.h""vfuuti.h" "vfu.h"€]@n@p@q@r@"vfvfu_tool_seq_renamevfu_tool_renamevfu_tool_classify "vfu.h"_VFUTOOLS_H_dU€@@@@@@@@@ @!@"@#@$@%@&@'@(@)@*@+@,@-@.@/@0@1@2@3@4@5@6@7@8@9@:@;@<@=@>@?@@@A@B@C@D@E@F@G@H@I@J@K@L@M@N@O@P@Q@R@S@T@U@V@W@X@Y@Z@[@\@^@_@`@a@b@c@d@e@f@g@h@i@j@k@l@do_ F_OK access datafmt start atoi digposHID_SEQ_STARTHID_SEQ_DIGPOSHID_SEQ_SUFFIXHID_SEQ_PREFIXvfu_get_str s_start s_digpos suffix prefix do_draw set_name renamefile_existstr_squeezestr_replace str_tr str_up str_lowstr_file_pathvfu_tool_seq_rename new_name path Stringerrvfu_tool_renamevfu_read_files__vfu_file_move name_ext is_linkfiTF sel_sizefiles_sizecopy_info CopyInfocon_getchsay2errnoget sprintftdir_existmake_pathres pathncmp count found namesel is_dirfiles_listfiles_countizecmenu_box_infovfu_menu_box pushzapmb say1sel_counttl MAX_PATHvfu_tool_classifystr_sleftstr_file_ext strcat strlenstr_file_nametmpch fname__get_classify_str"vfutools.h""vfufiles.h""vfuview.h""vfucopy.h""vfumenu.h"file_get_lfnout€Žááá‘á’á“á•á–á—á@@@@@ @ @ @ @ @@@@@@@@@infile_get_sfn_TARGET_GO32_file_exist F_OK accessddir_existallow_maskingvfu_edit_attrfile_set_mode_str filename mod_strtm mode_tfile_get_mode_str`0@üƒŒ~×®ŠqU8U,óª‰]àŸË?$ÇŒJ6öîŒc‹¬T#ŸfJ1èdzri> É«U,ë©• &ë   L ¬ ‡ n P « 3  û Ç  Š i @ ƒ é Å £ ÷ \ <  Ô ² ‘ - áĨt²S? áŠfF—ÿݺ´uT0Ü vbN)N:éÕ&„Ù¯pŠhG'ÞÊ¥~'Wext_colorsVString[16]%Sview_profileVString€‹`&Adir_tree_fileVString#:files_maskVString 7rc_pathVString!6tmp_pathVString"5home_pathVString%4startup_pathVString*!1file_list_indexScrollPos+$#external_panelizerVString% archive_pathVString%archive_nameVString"work_pathVString€|`QFFNMATCH_OCfnmatch((p),(s),(n)?FNM_CASEFOLD:FNMATCH_FLAGS)p,s,n€y`=EFNMATCH_NCfnmatch((p),(s),FNM_CASEFOLD)p,s€–€€€€# € *'2lower_case_ext_configint€ ($&vfu_nav_update_posvoid€Y`Z`\`]`_`a`b`c`d`e`f`g`h`i`j`k`l`m`$ %vfu_nav_selectvoid!$vfu_nav_endvoid"#vfu_nav_homevoid#"vfu_nav_npagevoid#!vfu_nav_ppagevoid" vfu_nav_downvoid vfu_nav_upvoid'#vfu_redraw_statusvoid vfu_redrawvoid$vfu_drawvoidint n($vfu_drop_all_viewsvoid/show_posvoidint curr,int all) get_item_colorintTF*fi€H`_`!sel_mark_posint€I`]`!tag_mark_posint €J@ÊÀ]@/€d€u€`D`Z`&&"vfuopt.h" _VFUVIEW_H_($•vfu_nav_update_posvoid$ xvfu_nav_selectvoid€@`A`B`C`D`E`G`H`I`J`K`L`M`N`O`P`Q`R`S`T`U`V`X`!mvfu_nav_endvoid"bvfu_nav_homevoid#Ovfu_nav_npagevoid#<vfu_nav_ppagevoid"*vfu_nav_downvoid vfu_nav_upvoid'#Üvfu_redraw_statusvoid {vfu_redrawvoid"zFTIMETYPEchar*[]$]vfu_drawvoidint n($Tvfu_drop_all_viewsvoid/Kshow_posvoidint curr,int all) get_item_colorintTF*fi!tag_mark_posint!sel_mark_posint&"vfusys.h" €Q@?€ÈÀn€w€–€n `E`&&"vfuuti.h"&"vfuopt.h"&"vfuview.h"& "vfufiles.h"& "vfu.h"%+vfu_tempconst char*^)vfu_get_strintconst char*prompt,String&target,int hist_id,int x=-1,int y=-1B%(vfu_get_str_historyvoidint key,String&s,int&pos€)`*`+`,`.`/`0`1`2`3`4`5`6`7`9`:`;`<`>`?`K&vfu_hist_menuintint x,int y,const char*title,int hist_id;!%vfu_hist_removevoidint hist_id,int index/ $vfu_hist_countintint hist_id@ #vfu_hist_indexintint hist_id,const char*value€6`7`B"vfu_hist_getchar*int hist_id,int index,char*strA!vfu_hist_getconst char*int hist_id,int index=0= vfu_hist_addvoidint hist_id,const char*strB"size_str_compactchar*const fsize_t siz,char*bufvfu_beepvoidA"time_str_compactchar*const time_t tim,char*buf4!vfu_expand_maskString&String&mask4%vfu_update_sel_sizefsize_tint oneAvfu_askintconst char*prompt,const char*allowedÄ«€m€€€€‚€‰€‹€€•À–À—À˜À™ÀšÀ›ÀœÀÀžÀŸÀ À¡À¢À£À¤À¥À¦À§À¨À©ÀªÀ«À¬À­À®À¯À°À±À²À³À´À¶À·À¸À¹ÀºÀ¼À½À¾À¿ÀÀÀÁÀÂÀÃÀÄÀÅÀ @@@@C@D@E@F@G@H@I@J@K@L@M@O@P@Q@R@S@U@V@W@Y@€€€€€€€€ €!€"€$€%€'€(€*€+€-€O€P€Q€R€S€T€U€V€W€X€Y€Z€[€]€^€_€m€p€r€€ž€¬€& 2 3 4 6 7 < = > ? @ … ‹  ``+`,`.`/`0`1`2`3`4`5`6`7`9`:`;`<`>`?`\`a`b`c`d`e`f`g`h`i`j`k`l`m`    & ' !vfu_break_opintI'vfu_update_shell_lineintString&a_line,String&a_options&"vfu.h" _VFUUTI_H_%¢vfu_tempconst char*ÄŒ€ @ @@T@W@Y@[@\@]@^@_@`@a@b@c@h@i@l@n@q@r@s@t@v@w@x@y@Š@‹@ @½@Â@Ä@Æ@È@€€Y€u€|€˜€™€š€›€œ€@ÀHÀLÀNÀPÀ\À^À`ÀfÀhÀjÀlÀnÀpÀrÀ‘À“À@@@A@b@3€<€?€D€e€x€{€|€}€~€€€€ƒ€‹€“€—€™€­€®€  . 0 ; Š Ž   ‘ ’ “ ” • – — ˜ ž   ¢ `!`&`H`I`N`]`_`t`u``€``†`‡`ˆ`‰`Š`‹`Ž``                   €`` ` ` ` `````````````````` `!`"`$`%`&`(`1#¡vfu_temp_filenamechar[MAX_PATH]Xƒvfu_get_strintconst char*prompt,String&target,int hist_id,int x,int yB%tvfu_get_str_historyvoidint key,String&s,int&pos*'s__vfu_get_str_hist_idintK^vfu_hist_menuintint x,int y,const char*title,int hist_id)#]hist_menu_hotkeyschar[];!Mvfu_hist_removevoidint hist_id,int index/ @vfu_hist_countintint hist_id@ 6vfu_hist_indexintint hist_id,const char*value€``B-vfu_hist_getchar*int hist_id,int index,char*str?vfu_hist_getconst char*int hist_id,int index= vfu_hist_addvoidint hist_id,const char*strHISTIDPAD8MAXHIST14ÿvfu_beepvoidB"òsize_str_compactchar*const fsize_t siz,char*bufA"átime_str_compactchar*const time_t tim,char*buf4!Övfu_expand_maskString&String&maskAÌvfu_askintconst char*prompt,const char*allowed4%¨vfu_update_sel_sizefsize_tint one!˜vfu_break_opintI'vfu_update_shell_lineintString&a_line,String&a_options&"vfuview.h"&"vfuopt.h"to€@@@@I@J@K@L@M@N@O@P@Q@R@U@$€%€&€'€(€)€*€+€,€-€.€0€1€2€4€5€6€7€8€9€;€=€?€W€X€ÆÀÈÀÊÀÌÀÎÀÑÀ @ @@@@@@@@@@Z@]@^@_@a@.€/€0€1€2€\€b€d€f€l€n€t€u€v€w€y€z€”€•€–€ €¢€£€¤€«€\ m n o p x y ~ € ‚ `` ` ` ```*`@`A`B`C`D`E`Z`&"vfudir.h"&"vfusys.h"&"vfumenu.h"& "vfuuti.h"& "vfu.h"€¦€«€¬€``I@)%vfu_tool_seq_renamevoid%!vfu_tool_renamevoid€0`ÿÿÿÿüÁǤ»ôÝÐÊs¥–…ÉaP@ܲ˜~o`Q7+üìÛÏȾ²¦˜Ž€yrcTD3üñåØÌÁ¹­£–ˆ}qg]PIC8," ýöðåÝÐź¯¤˜‹~rfTL:1$ ÷çÖÏű¥›‰sf_QA0)ûåÒ·« š”Ž‚v±b¤N©:&ñÙÏÆx½Ÿld[O<4ŒßƒqhaXJ4*!ñä×ȹ§˜‰wgW!D1* üíßÓž²ª£•ñ̶clipboard_addCLIPBOARD_SYMLINKCLIPBOARD_MOVEclipboard_addCLIPBOARD_MOVE count fsize fcntclipboard_menuactclipboard_menu toupper pushactclipboard_menuCLIPBOARD_SYMLINKvsnprintfpsget VStringgoScrollPos VStringHID_OMODEhandle_tab undefstr_split VString shiftmbclipboard_viewclipboard_view__vfu_erase__vfu_erase__vfu_symlink__vfu_move__vfu_copy__vfu_symlink__vfu_move__vfu_copy ok_count ok_countvfu_rescan_files savea_count exists keep VTriestr_file_name_extwork_path nextps keysva VArray modeCLIPBOARD_COPY cINFOsay CB_DESC mode keep resetclipboard_copy_infoCLIPBOARD_COPY undefClipboard VTrieclipboard_clearclipboard_pasteclipboard_clearclipboard_paste VString VStringrhl s_size s_adlersize_cache_compose_keysize_cache_cmpSIZE_CACHE_OFFSET npage ppageKEY_ALT_X touppergoset_pagesizeset_min_maxScrollPosfi str_chopstr_file_name_extstr_file_path undef VStringstr_find_regexp undefgoset_pagesizeset_min_max ruler opts sposmsg opos last_opt compfind_next_txtrevfind_next_hex end_txt end_hex down_txt down_hex memmove up_txt up_hex cWHITE cBLACK CONCOLORsub sub_spmokre datastr_add_cht ascii hexdump offsetxrs hex_cols needw rowsz VString va_endvsnprintf va_start vlist va_listbuf format MAXCOLS __ff_opt VRegexp sscanf mode_tHID_OMODEokfile_string_searchset_pagesizeset_min_maxKEY_CTRL_EKEY_CTRL_Aoyoxstr_split undefScrollPos VString VString undef ne VString set_pagesize set_min_max set_pos set_pageshow_hidden_files str_lowlower_case_ext_configFNMATCH_OCFNMATCH_OCFNMATCH_NClower_case_ext_configlower_case_ext_configvfu_nav_update_posvfu_nav_select€¬A­A®A¯A°A²A³A´AµA€€€€€ € € € € €€€€€vfu_nav_endvfu_nav_homevfu_nav_npagevfu_nav_ppagevfu_nav_downvfu_nav_upvfu_redraw_statusvfu_redrawn vfu_drawvfu_drop_all_viewsall 0€ÿÿÿÿü$&ÎÖ±ŽjEúÔ«…Y4ª–za*þÆïv¬ÃH[%—’FãoêÎ ~SeeEditor€ , find_next_txtc intint rev `~SeeViewer Ð~TFÀTF#…clipboard_addvoid/CopyInfo€1CopyInfo _VFUCOPY_H_.!†clipboard_pastevoidint mode€ #clipboard_addvoid.!(clipboard_pastevoidint mode! CLIPBOARD_MOVE2, ‰clipboard_menuvoidint act, sclipboard_menuvoidint act$#CLIPBOARD_SYMLINK3NYset_setintconst char*line,const char*keyword,VString&targetOptions _VFUOPT_H_€ e(=vfu_user_external_findintint key,const char*ext,const char*type,VString*shell_line%ýfilename_atlVString%üfilename_ffrVString,%ûfilename_size_cacheVString&úfilename_treeVString)"ùfilename_historyVString&øfilename_confVString%÷filename_optVString&õhost_name_strVString%ôgroup_id_strVString$óuser_id_strVString#ñshell_progVString%ðshell_editorVString&ïshell_browserVStringvfu-4.10/vfu/vfuarc.h0000644000175000001440000000103511005727265013314 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vfuarc.h,v 1.6 2003/01/26 21:48:42 cade Exp $ * */ #ifndef _VFUARC_H_ #define _VFUARC_H_ #include "vfu.h" void vfu_read_archive_files(); void vfu_browse_archive_file(); void vfu_extract_files( int one ); void vfu_user_external_archive_exec( VString &shell_line ); #endif /* _VFUARC_H_ */ /* eof vfuarc.h */ vfu-4.10/vfu/vfudir.h0000644000175000001440000000326211005727265013331 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vfudir.h,v 1.11 2007/12/16 13:44:10 cade Exp $ * */ #ifndef _VFUDIR_H_ #define _VFUDIR_H_ #include "vfu.h" extern VArray size_cache; /*###########################################################################*/ int vfu_get_dir_name( const char *prompt, VString &target, int should_exist = 1 ); void vfu_chdir( const char *a_new_dir ); void vfu_chdir_history(); /*###########################################################################*/ void tree_view(); void tree_load(); void tree_save(); void tree_drop(); void tree_rebuild(); void tree_fix(); void tree_draw_item( int page, int index, int hilite = 0 ); void tree_draw_page( ScrollPos &scroll ); void tree_draw_pos( ScrollPos &scroll, int opos ); /*###########################################################################*/ int tree_index( const char *s ); const char* tree_find( const char *s ); /* return full path by dirname */ /* return count of found dirnames and stores them to sc */ int tree_find( const char *s, VArray *va ); VString size_cache_compose_key( const char *s, fsize_t size ); int size_cache_index( const char *s ); fsize_t size_cache_get( const char *s ); void size_cache_set( const char *s, fsize_t size, int sort = 1 ); void size_cache_append( const char *s, fsize_t size ); void size_cache_clean( const char *s ); void size_cache_sort(); /*###########################################################################*/ fsize_t vfu_dir_size( const char *s, int sort = 1 ); #endif //_VFUDRI_H_ vfu-4.10/vfu/vfuopt.h0000644000175000001440000000444411172604201013345 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vfuopt.h,v 1.9 2005/06/07 22:33:48 cade Exp $ * */ #ifndef _VFUOPT_H_ #define _VFUOPT_H_ #include "see.h" #include "vfuuti.h" extern const char *NOYES[]; extern const char *FTIMETYPE[]; extern const char *TAGMARKS[]; struct Options { int sort_order; int sort_direction; int sort_top_dirs; max_path_str_t last_copy_path[3]; max_path_str_t path_bookmarks[10]; int f_size; int f_time; int f_mode; int f_group; int f_owner; int f_type; int f_time_type; int long_name_view; int tree_compact; int tree_cd; int show_hidden_files; /* `dot' files in UNIX, `HS' files in dos */ int allow_beep; int use_colors; int use_dir_colors; /* /etc/DIR_COLORS */ int lower_case_ext_config; int copy_free_space_check; int copy_calc_totals; int copy_keep_mode; /* preserve mode, owner, group on copy ? */ int tag_mark_type; int internal_browser; int internal_editor; int mask_auto_expand; int shell_cls; int zap_ro; /* zap/erase read-only files */ int show_user_free; /* ...space instead of real fs free */ int menu_borders; int lynx_navigation; /* should <- == - and -> == + */ int default_copy_to_cwd; /* default copy dir always points to CWD */ int auto_mount; int keep_selection; /* on rescan files */ int bytes_freed; /* calc/show bytes freed on erase */ SeeViewerOptions svo; SeeEditorOptions seo; }; extern Options opt; int key_by_name( const char* key_name ); time_t vfu_opt_time( const struct stat st ); time_t vfu_opt_time( const struct stat* st ); time_t vfu_opt_time( time_t ctime, time_t mtime, time_t atime ); int set_set( const char *line, const char *keyword, char *target ); int set_set( const char *line, const char *keyword, VString &target ); int set_set( const char *line, const char *keyword, int &target ); int set_set( const char *line, const char *keyword, VArray &splitter ); void vfu_settings_load(); void vfu_settings_save(); void vfu_edit_conf_file(); void vfu_options(); #endif /* _VFUOPT_H_ */ vfu-4.10/vfu/vfusys.h0000644000175000001440000000354311005727265013373 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vfusys.h,v 1.6 2005/06/05 22:00:10 cade Exp $ * */ #ifndef _VFUSYS_H_ #define _VFUSYS_H_ #include #include #include /* following defines are taken from coreutils-5.2.1 Copyright (C) 1989, 1991-2004 Free Software Foundation, Inc. to address the file size problem when file is larger than 2GB */ #ifndef CHAR_BIT # define CHAR_BIT 8 #endif #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) #define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0)) #define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t))) /* VFU specific defines */ #define MODE_OFF "----------" #define MODE_STRING "drwxrwxrwx" #define MODE_MASK "-?????????" #define MODE_WRITE_ON "??w???????" /* allow WRITE mask */ typedef char mode_str_t[12]; /* these functions set/get file's attributes/mode from/to string with this format: for Linux/UNIX: drwxrwxrwx for DOS: DV----RHSA it is supposed that all attribs count is 10 */ /* FIXME: these functions cannot handle symlink flag yet */ void file_get_mode_str( const mode_t tm, mode_str_t &mod_str ); int file_get_mode_str( const char *filename, mode_str_t &mod_str ); int file_set_mode_str( const char *filename, const mode_str_t mod_str ); int vfu_edit_attr( mode_str_t mod_str, int allow_masking = 1 ); /* FIXME: dir_exist should check if directory really */ #define dir_exist( d ) ( access( d, F_OK ) == 0) #define file_exist( d ) ( access( d, F_OK ) == 0) #ifdef _TARGET_GO32_ int file_get_sfn( const char *in, char *out ); int file_get_lfn( const char *in, char *out ); #endif #endif /* _VFUSYS_H_ */ /* eof vfusys.h */ vfu-4.10/vfu/vfuuti.cpp0000644000175000001440000003047211310550160013675 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vfuuti.cpp,v 1.19 2007/12/16 13:52:50 cade Exp $ * */ #include "vfu.h" #include "vfuuti.h" #include "vfumenu.h" #include "vfusys.h" #include "vfudir.h" #include "vfuopt.h" #include "vfuview.h" /*---------------------------------------------------------------------------*/ fsize_t file_st_size( struct stat* st ) { return st->st_size + ( st->st_size < 0 ) * ((uintmax_t)TYPE_MAXIMUM(off_t) - TYPE_MINIMUM(off_t) + 1); } VString vfu_readlink( const char* fname ) { char t[MAX_PATH+1]; t[0] = 0; int l = readlink( fname, t, MAX_PATH ); if (l != -1) t[l] = 0; VString res = t; return res; } /*---------------------------------------------------------------------------*/ int vfu_update_shell_line( VString &a_line, VString &a_options ) { VString out; VString s; int i = 0; int one = 0; int full = 0; // toggles #ifdef _TARGET_GO32_ int use_SFN = 0; #endif while( a_line[i] ) if ( a_line[i] == '%' ) { switch( a_line[i+1] ) { #ifdef _TARGET_GO32_ case '_' : use_SFN = 1; break; #endif case 'r' : /* rescan files after */ case 'R' : a_options += "r"; break; // refresh all files after (readdir) case 'f' : /* file name */ case 'F' : case 'g' : case 'G' : one = 0; if ( a_line[i+1] == 'f' ) one = 1; if ( a_line[i+1] == 'F' ) one = 1; full = 0; if ( a_line[i+1] == 'F' ) full = 1; if ( a_line[i+1] == 'G' ) full = 1; // FIXME: 'one' is used to merge F and G options in the future int z; for( z = 0; z < files_count; z++ ) { TF *fi = files_list[z]; if ( one && z != FLI ) continue; /* if one and not current -- skip */ if ( !one && !fi->sel ) continue; /* if not one and not selected -- skip */ if( work_mode == WM_ARCHIVE ) { s = files_list[z]->name(); } else if( full ) { files_list[z]->full_name(); } else { s = files_list[z]->name(); } if( !one ) { // need to list files, quote them... // FIXME: this should be optional for all one and !one if ( str_find( s, "'" ) == -1 ) { s = "'" + s +"' "; } else if ( str_find( s, "\"" ) == -1 ) { s = "\"" + s +"\" "; } else { s = ""; } } out += s; } break; case 'e' : /* name only */ case 'E' : /* extension only */ if ( a_line[i+1] == 'e' ) s = str_file_name( s ); else s = files_list[FLI]->ext(); out += s; break; case 's' : /* current file size */ sprintf( s, "%.0f", files_list[FLI]->size() ); out += s; break; case '?' : /* prompt user for argument */ if (vfu_get_str( "Enter parameter:", s, HID_SHELL_PAR )) out += s; else return 3; break; case 'd' : /* prompt user for directory */ s = ""; if (vfu_get_dir_name( "Enter directory:", s, 0 )) out += s; else return 3; break; case 'c' : /* current path */ s = work_path; #ifdef _TARGET_GO32_ str_tr( s, "/", "\\" ); #endif out += s; break; case 'C' : /* startup dir */ s = startup_path; #ifdef _TARGET_GO32_ str_tr( s, "/", "\\" ); #endif out += s; break; case 'a' : /* Archive name */ out += archive_name; break; case 'A' : /* Archive path */ s = archive_path; #ifdef _TARGET_GO32_ str_tr( s, "/", "\\" ); #endif out += s; break; case 'w' : case 'W' : a_options += "w"; break; case 'i' : a_options += "i"; break; case 'n' : a_options += "n"; break; case '!' : a_options += "!"; break; default : /* chars not recognized are accepted "as is" */ str_add_ch( out, a_line[i+1] ); break; } i += 2; } else { str_add_ch( out, a_line[i] ); i++; } a_line = out; return 0; } /*---------------------------------------------------------------------------*/ int vfu_break_op() { if (con_kbhit()) if (con_getch() == 27) { say2( "Press ENTER to cancel or other key to continue..." ); int key = con_getch(); say2( "" ); if ( key == 13 ) return 1; } return 0; } /*---------------------------------------------------------------------------*/ fsize_t vfu_update_sel_size( int one ) // used before copy/move to calc estimated size { fsize_t size = 0; int z; int need_size_cache_sort = 0; for( z = 0; z < files_count; z++ ) { TF *fi = files_list[z]; if ( one && z != FLI ) continue; /* if one and not current -- skip */ if ( !one && !fi->sel ) continue; /* if not one and not selected -- skip */ if ( fi->is_link() ) continue; /* links does not have own size -- skip */ if ( fi->is_dir() ) { /* this is directory */ fsize_t dir_size = vfu_dir_size( fi->name(), 0 ); need_size_cache_sort = 1; if ( dir_size == -1 ) { /* dir size calculation has been canceled */ size = -1; break; } fi->set_size( dir_size ); size += dir_size; } else { /* this is regular file */ size += fi->size(); } } /* for */ if( need_size_cache_sort ) size_cache_sort(); update_status(); /* */ vfu_redraw(); /* just to redraw before copy/move/etc... */ vfu_redraw_status(); /* just to redraw before copy/move/etc... */ return size; } /*---------------------------------------------------------------------------*/ int vfu_ask( const char *prompt, const char *allowed ) { int ch = 1; say1( prompt ); while ( strchr( allowed, ch ) == NULL ) ch = con_getch(); return ch; } /*---------------------------------------------------------------------------*/ VString& vfu_expand_mask( VString& mask ) { if ( str_count( mask, "*?" ) > 0 ) return mask; mask += "*"; if ( mask[0] == '.' ) str_ins( mask, 0, "*" ); str_replace( mask, "**", "*" ); return mask; } /*---------------------------------------------------------------------------*/ char* time_str_compact( const time_t tim, char* buf ) { ASSERT( buf ); time_t timenow = time( NULL ); strcpy(buf, ctime(&tim)); if (timenow > tim + 6L * 30L * 24L * 60L * 60L /* old */ || timenow < tim - 60L * 60L) /* in the future */ strcpy (buf + 11, buf + 19); buf[16] = 0; strcpy(buf, buf+4); if (buf[4] == ' ') buf[4] = '0'; return buf; } /*---------------------------------------------------------------------------*/ char* size_str_compact( const fsize_t siz, char* buf ) { if ( siz < 1024 ) sprintf( buf, "%.0fb", siz ); else if ( siz < 1024*1024 ) sprintf( buf, "%.0fk", siz/1024 ); else sprintf( buf, "%.0fm", siz/(1024*1024) ); return buf; } /*---------------------------------------------------------------------------*/ void vfu_beep() { if ( opt.allow_beep ) { con_beep(); } } /*###########################################################################*/ #define MAXHIST 14 // max history items per id #define HISTIDPAD 8 void vfu_hist_add( int hist_id, const char* str ) { VString hstr = hist_id; str_pad( hstr, HISTIDPAD ); hstr += ","; hstr += str; int z; z = vfu_hist_index( hist_id, str ); if ( z != -1 ) vfu_hist_remove( hist_id, z ); z = vfu_hist_count( hist_id ); while (z >= MAXHIST) { z--; vfu_hist_remove( hist_id, z ); } if (z) z++; history.ins( 0, hstr ); } const char* vfu_hist_get( int hist_id, int index ) { VString hstr = hist_id; str_pad( hstr, HISTIDPAD ); hstr += ","; int i = 0; int z; for ( z = 0; z < history.count(); z++ ) if ( strncmp( hstr, history[z], HISTIDPAD+1 ) == 0 ) { if ( index == -1 || index == i ) return history.get( z ) + HISTIDPAD+1; i++; } return NULL; } char* vfu_hist_get( int hist_id, int index, char* str ) { str[0] = 0; const char* pstr = vfu_hist_get( hist_id, index ); if ( pstr ) strcpy( str, pstr ); return str; } int vfu_hist_index( int hist_id, const char* value ) { int z; int cnt = vfu_hist_count( hist_id ); for ( z = 0; z < cnt; z++ ) if ( strcmp( value, vfu_hist_get( hist_id, z ) ) == 0 ) return z; return -1; } int vfu_hist_count( int hist_id ) { VString hstr = hist_id; str_pad( hstr, HISTIDPAD ); hstr += ","; int cnt = 0; int z; for ( z = 0; z < history.count(); z++ ) cnt += ( strncmp( hstr, history[z], HISTIDPAD+1 ) == 0 ); return cnt; } // use hist_id=-1 and/or index=-1 to remove all void vfu_hist_remove( int hist_id, int index ) { VString hstr = hist_id; str_pad( hstr, HISTIDPAD ); hstr += ","; int i = 0; int z = 0; while( z < history.count() ) { if ( hist_id != -1 && strncmp( hstr, history[z], HISTIDPAD+1 ) != 0 ) { z++; continue; } if ( index != -1 && index != i ) { z++; i++; continue; } history.del( z ); if ( index != -1 ) break; } } static char hist_menu_hotkeys[] = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"; int vfu_hist_menu( int x, int y, const char* title, int hist_id ) { VString str; mb.undef(); int z; int cnt = vfu_hist_count( hist_id ); if ( cnt < 1 ) return -1; for ( z = 0; z < cnt; z++ ) { ASSERT( z < str_len( hist_menu_hotkeys ) ); str = ""; str_add_ch( str, hist_menu_hotkeys[z] ); str = str + " " + vfu_hist_get( hist_id, z ); mb.push( str ); } return vfu_menu_box( x, y, title ); } /*---------------------------------------------------------------------------*/ int __vfu_get_str_hist_id; /* used to keep history id passed here... */ void vfu_get_str_history( int key, VString &s, int &pos ) { if ( __vfu_get_str_hist_id <= 0 ) return; if ( key != KEY_NPAGE && key != KEY_PPAGE ) return; con_chide(); int z = vfu_hist_menu( 5, 5, "Line History", __vfu_get_str_hist_id ); con_cshow(); if ( z == -1 ) return; s = mb.get(z) + 2; str_cut_spc( s ); pos = str_len( s ); } int vfu_get_str( const char *prompt, VString& target, int hist_id, int x, int y ) { if ( x == -1 ) x = 1; if ( y == -1 ) y = con_max_y(); int len = con_max_x() - 3 - x; /* FIXME: this is not correct if x and y are specified */ if ( prompt && prompt[0] ) say1( prompt ); say2( "" ); __vfu_get_str_hist_id = hist_id; if ( strcmp( target, "" ) == 0 && vfu_hist_get( hist_id, 0 ) ) target = vfu_hist_get( hist_id, 0 ); char t[1024]; /* FIXME: can be overflowed? */ strcpy( t, target ); int r = TextInput( x, y, "", len, len, t, vfu_get_str_history ); target = t; say1( "" ); say2( "" ); __vfu_get_str_hist_id = 0; if( r ) vfu_hist_add( hist_id, target ); return ( r != 0 ); } /*---------------------------------------------------------------------------*/ /* to fool gcc warning that mktemp() is not safe, I don't really care :/ still there is no mkstemp for directories :)) */ char vfu_temp_filename[MAX_PATH]; const char* vfu_temp() { strcpy( vfu_temp_filename, tmp_path + "vfu.XXXXXX" ); mkstemp( vfu_temp_filename ); unlink( vfu_temp_filename ); return vfu_temp_filename; } /*###########################################################################*/ /* eof vfuuti.cpp */ vfu-4.10/vfu/vfuuti.h0000644000175000001440000000337611005727265013362 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vfuuti.h,v 1.9 2005/08/28 14:02:19 cade Exp $ * */ #ifndef _VFUUTI_H_ #define _VFUUTI_H_ #include "vfu.h" /*###########################################################################*/ fsize_t file_st_size( struct stat* st ); VString vfu_readlink( const char* fname ); /*###########################################################################*/ int vfu_update_shell_line( VString &a_line, VString &a_options ); int vfu_break_op(); /* return != 0 if ESC pressed, non blocking */ int vfu_ask( const char *prompt, const char *allowed ); /* blocking */ /* used before copy/move to calc estimated size */ fsize_t vfu_update_sel_size( int one ); VString& vfu_expand_mask( VString& mask ); char* time_str_compact( const time_t tim, char* buf ); void vfu_beep(); char* size_str_compact( const fsize_t siz, char* buf ); /*###########################################################################*/ void vfu_hist_add( int hist_id, const char* str ); const char* vfu_hist_get( int hist_id, int index = 0 ); char* vfu_hist_get( int hist_id, int index, char* str ); int vfu_hist_index( int hist_id, const char* value ); int vfu_hist_count( int hist_id ); void vfu_hist_remove( int hist_id, int index ); int vfu_hist_menu( int x, int y, const char* title, int hist_id ); void vfu_get_str_history( int key, VString &s, int &pos ); /* internal! */ int vfu_get_str( const char *prompt, VString& target, int hist_id, int x = -1, int y = -1 ); const char* vfu_temp(); /*###########################################################################*/ #endif//_VFUUTI_H_ vfu-4.10/vfu/vfucopy.h0000644000175000001440000001073511005727265013530 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vfucopy.h,v 1.7 2003/04/28 17:17:01 cade Exp $ * */ #ifndef _VFUCOPY_H_ #define _VFUCOPY_H_ #ifndef COPY_BUFFER_SIZE #define COPY_BUFFER_SIZE 1024*1024 /* 1M */ #endif /* copy modes **************************************************************/ #define CM_COPY 0 // copy #define CM_MOVE 1 // move #define CM_LINK 2 // symlink /* clipboard modes *********************************************************/ #define CLIPBOARD_COPY 1 #define CLIPBOARD_MOVE 2 #define CLIPBOARD_SYMLINK 3 /* overwrite modes *********************************************************/ #define OM_ASK 0 /* ask before overwrite */ #define OM_ALWAYS 1 /* always overwrite */ #define OM_NEVER 2 /* never overwrite */ #define OM_IF_MTIME 3 /* if newer modify time*/ #define OM_ALWAYS_IF_MTIME 4 /* always if newer modify time*/ /* copy results ************************************************************/ #define CR_OK 0 #define CR_SKIP 200 #define CR_ABORT 255 /* run-time copy info structure ********************************************/ struct CopyInfo { CopyInfo() { reset(); }; void reset() { no_info = files_count = current_count = ok_count = no_free_check = over_mode = abort = 0; files_size = current_size = 0; }; int no_info; fsize_t files_size; long files_count; /* not used */ fsize_t current_size; long current_count; /* not used */ long ok_count; /* files copied ok */ int no_free_check; /* if 1 -- don't check for destination free space */ int over_mode; /* what to do if dest exist? see OM_XXX defines */ int abort; /* if != 0 -- abort and return */ VString description; }; /*************************************************************************** ** ** utilities ** ****************************************************************************/ fsize_t device_free_space( const char *target ); /* user free space, NOT real! */ int file_is_same( const char *src, const char *dst ); int device_is_same( const char *src, const char *dst ); int fast_stat( const char* s, struct stat *st ); int over_if_exist( const char* src, const char *dst, CopyInfo* copy_info ); void show_copy_pos( fsize_t a_fc, /* file under copy current pos */ fsize_t a_fa, /* file under copy all size */ CopyInfo *copy_info ); /* totals info */ int vfu_copy_mode( const char* src, const char* dst ); /*************************************************************************** ** ** COPY/MOVE/SYMLINK ** ****************************************************************************/ /* copy/move ***************************************************************/ int __vfu_file_copy( const char* src, const char* dst, CopyInfo* copy_info ); int __vfu_file_move( const char* src, const char* dst, CopyInfo* copy_info ); int __vfu_dir_copy( const char* src, const char* dst, CopyInfo* copy_info ); int __vfu_dir_move( const char* src, const char* dst, CopyInfo* copy_info ); int __vfu_link_copy( const char* src, const char* dst, CopyInfo* copy_info ); int __vfu_link_move( const char* src, const char* dst, CopyInfo* copy_info ); /* erase *******************************************************************/ int __vfu_dir_erase( const char* target, fsize_t* bytes_freed = NULL ); int __vfu_file_erase( const char* target, fsize_t* bytes_freed = NULL ); int __vfu_link_erase( const char* target, fsize_t* bytes_freed = NULL ); /* shells, call __*_*_*() above ********************************************/ int __vfu_copy( const char* src, const char* dst, CopyInfo* copy_info ); int __vfu_move( const char* src, const char* dst, CopyInfo* copy_info ); int __vfu_symlink( const char* src, const char* dst, CopyInfo* copy_info ); int __vfu_erase( const char* target, fsize_t* bytes_freed = NULL ); /* high-level interface functions ******************************************/ void vfu_copy_files( int a_one, int a_mode ); void vfu_erase_files( int a_one ); /*************************************************************************** ** ** CLIPBOARD ** ****************************************************************************/ void clipboard_add(); void clipboard_paste( int mode ); void clipboard_clear(); void clipboard_view(); void clipboard_menu( int act ); #endif //_VFUCOPY_H_ vfu-4.10/vfu/vfutools.cpp0000644000175000001440000002056511310550143014237 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vfutools.cpp,v 1.16 2006/03/19 20:14:48 cade Exp $ * */ #include "vfumenu.h" #include "vfucopy.h" #include "vfuview.h" #include "vfufiles.h" #include "vfutools.h" /*------------------------------------------------------------------------*/ void __get_classify_str( const char *fname, char ch, char *tmp ) { tmp[0] = 0; if (ch == 'N') { strcpy( tmp, str_file_name( fname ) ); if (strlen(fname) == strlen(tmp)) strcat( tmp, ".---" ); } else if (ch == 'E') { strcpy( tmp, str_file_ext( fname ) ); if (strlen(tmp) == 0) strcat( tmp, "---" ); } else { strcpy( tmp, str_file_name( fname ) ); str_sleft( tmp, ch - '0' ); if (strlen(fname) == strlen(tmp)) strcat( tmp, ".---" ); } } void vfu_tool_classify() { /* FIXME: how this will handle files with path in the list? */ char tmp[MAX_PATH]; int tl; // tmplen if ( sel_count == 0 ) { say1( "Classify function works only on already selected files..." ); return; } mb.undef(); mb.push("N Name"); mb.push("E Ext"); mb.push("1 First 1 letter"); mb.push("2 First 2 letters"); mb.push("3 First 3 letters"); mb.push("4 First 4 letters"); mb.push("5 First 5 letters"); mb.push("6 First 6 letters"); mb.push("7 First 7 letters"); mb.push("8 First 8 letters"); mb.push("9 First 9 letter"); if ( vfu_menu_box( 50, 5, "Classify files by") == -1 ) return; char ch = menu_box_info.ec; mb.undef(); int z; int i; for ( z = 0; z < files_count; z++ ) { if ( files_list[z]->is_dir() ) continue; if ( !files_list[z]->sel ) continue; __get_classify_str( files_list[z]->name(), ch, tmp ); tl = strlen( tmp ); int found = 0; for ( i = 0; i < mb.count(); i++ ) if ( pathncmp( tmp, mb[i], tl ) == 0 ) { found = 1; break; } if (!found) mb.push(tmp); } for ( i = 0; i < mb.count(); i++ ) { int res = make_path( mb[i] ); if ( res && !dir_exist( mb[i] ) ) { char t[MAX_PATH]; sprintf( t, "Cannot create directory: %s, (press a key for cancel)", mb.get(i) ); say1( t ); say2errno(); con_getch(); return; } } CopyInfo copy_info; copy_info.files_size = sel_size; copy_info.files_count = sel_count; for ( z = 0; z < files_count; z++ ) { TF *fi = files_list[z]; if ( fi->is_dir() ) continue; if ( fi->is_link() ) continue; if ( !fi->sel ) continue; __get_classify_str( fi->name(), ch, tmp ); strcat( tmp, "/" ); strcat( tmp, fi->name_ext()); if ( __vfu_file_move( fi->name(), tmp, ©_info ) == 255 ) break; } vfu_read_files( 0 ); } /*------------------------------------------------------------------------*/ void vfu_tool_rename() { int z; int err; VString path; VString new_name; VString t; if ( files_count < 1 ) { say1( "No files to rename... (Empty directory)" ); return; }; if ( sel_count < 1 ) { say1( "No files to rename... (You have to select required files)" ); return; }; mb.undef(); mb.push( "1 README.TXT => readme.txt" ); mb.push( "2 README.TXT => readme.TXT" ); mb.push( "3 README.TXT => README.txt" ); mb.push( "4 readme.txt => README.TXT" ); mb.push( "5 readme.txt => README.txt" ); mb.push( "6 readme.txt => readme.TXT" ); mb.push( "_ Replace spaces with _" ); mb.push( "Y Simplify name (RTFM)" ); mb.push( "S Sequential rename" ); mb.push( "W Swap SymLink w.Original" ); mb.push( "R Replace S.Link w.Original" ); if (vfu_menu_box( 50, 5, "Rename Tools" ) == -1) return; switch( menu_box_info.ec ) { case 'S' : vfu_tool_seq_rename(); break; case 'R' : vfu_tool_replace_sym_org(0); break; case 'W' : vfu_tool_replace_sym_org(1); break; case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '_' : case 'Y' : err = 0; for ( z = 0; z < files_count; z++ ) { TF* fi = files_list[z]; // if ( fi->is_dir() ) continue; // why not? ;) if ( !fi->sel ) continue; path = str_file_path( fi->name() ); new_name = ""; t = str_file_name( fi->name() ); if (menu_box_info.ec == '1' || menu_box_info.ec == '2') str_low( t ); if (menu_box_info.ec == '4' || menu_box_info.ec == '5') str_up( t ); new_name += t; t = str_file_ext( fi->name() ); if (menu_box_info.ec == '1' || menu_box_info.ec == '3') str_low( t ); if (menu_box_info.ec == '4' || menu_box_info.ec == '6') str_up( t ); if (strlen(t) > 0) { new_name += "."; new_name += t; } if (menu_box_info.ec == '_') str_tr( new_name, " ", "_" ); if (menu_box_info.ec == 'Y') { str_replace( new_name, "%20", "_" ); str_tr( new_name, " `'&\"\\/,()!", "___________" ); str_tr( new_name, "âáëéèêàíîïùúóô", "aaeeeeaiiiuuoo" ); str_squeeze( new_name, "_" ); str_replace( new_name, "_-_", "-" ); } new_name = path + new_name; if ( !file_exist( new_name) ) { if (rename( fi->name(), new_name ) == 0) /* FIXME: full name ? */ { fi->set_name( new_name ); do_draw = 2; /* FIXME: this should be optimized? */ } else err++; } else err++; } sprintf( t, "Rename complete (errors: %d)", err ); say1( t ); break; } } /*------------------------------------------------------------------------*/ void vfu_tool_seq_rename() { VString prefix; VString suffix; VString s_digpos; VString s_start; if(!vfu_get_str( "Enter filename prefix: ", prefix, HID_SEQ_PREFIX )) return; if(!vfu_get_str( "Enter filename suffix: ", suffix, HID_SEQ_SUFFIX )) return; if(!vfu_get_str( "Enter digit places: (digits only) ", s_digpos, HID_SEQ_DIGPOS )) return; if(!vfu_get_str( "Enter start number: (digits only) ", s_start, HID_SEQ_START )) return; int digpos = atoi( s_digpos ); int start = atoi( s_start ); if (digpos < 1 || digpos > 20) digpos = 1; if (start < 0) start = 0; VString new_name; VString t; VString fmt; sprintf( fmt, "%%s%%0%dd%%s", digpos ); int err = 0; int z; for ( z = 0; z < files_count; z++ ) { TF* fi = files_list[z]; if ( fi->is_dir() ) continue; if ( !fi->sel ) continue; sprintf( new_name, fmt, prefix.data(), start, suffix.data() ); t = str_file_path( fi->name() ); /* FIXME: full name? */ new_name = t + new_name; if (access( new_name, F_OK ) == 0) { err++; continue; } if (rename( fi->name(), new_name )) { err++; continue; } fi->set_name( new_name ); do_draw = 2; /* FIXME: this should be optimized? */ start++; } sprintf( t, "Rename complete (errors: %d)", err ); say1( t ); } /*------------------------------------------------------------------------*/ // replaces symlink entry with original one: // rm symlink // mv original symlink void vfu_tool_replace_sym_org( int swap ) { int err = 0; int z; for ( z = 0; z < files_count; z++ ) { TF* fi = files_list[z]; if ( fi->is_dir() ) continue; // FIXME: dali? if ( !fi->sel ) continue; if ( !fi->is_link() ) continue; VString sym = fi->full_name(); VString org = vfu_readlink( sym ); if (access( org, F_OK )) { err++; continue; } if (unlink( sym )) { err++; continue; } if (rename( org, sym )) { err++; continue; } if (swap) { symlink( sym, org ); } fi->update_stat(); do_draw = 2; /* FIXME: this should be optimized? */ } char t[256]; sprintf( t, "Replace complete (errors: %d)", err ); say1( t ); } /*------------------------------------------------------------------------*/ /* eof vfutools.cpp */ vfu-4.10/vfu/vfuarc.cpp0000644000175000001440000001240311310547712013644 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vfuarc.cpp,v 1.12 2003/01/26 21:48:42 cade Exp $ * */ #include "vfuarc.h" #include "vfuuti.h" #include "vfuopt.h" #include "vfudir.h" #include "vfucopy.h" #include "vfufiles.h" /*---------------------------------------------------------------------------*/ void vfu_read_archive_files( int a_recursive ) { char line[2048] = ""; struct stat st; memset( &st, 0, sizeof(st)); if ( a_recursive ) archive_path = ""; /* cannot have path when recursing archive */ VString s; s = "/usr/lib/vfu/rx_auto "; s += ( a_recursive ) ? "v" : "l"; s += " '" + archive_name + "' "; s += " '" + archive_path + "' "; s += " 2> /dev/null"; /* NOTE: calling rx_* should be safe and result should be proper all bugs must be traced outside VFU ... */ FILE *f = popen( s, "r" ); s = ""; if ( !f ) { say2( "Archive cannot be recognized or cannot be read" ); } else while( fgets(line, 2048-1, f) ) { str_cut( line, "\n\r" ); if ( strncmp( line, "NAME:", 5 ) == 0 ) { s = line+5; if ( str_get_ch( s, -1 ) == '/' ) /* i.e. last char */ { str_trim_right( s, 1 ); st.st_mode |= S_IFDIR; } /* FIXME: my man page for stat() says S_IFDIR is not POSIX?! */ } else if ( strncmp( line, "SIZE:", 5 ) == 0 ) { st.st_size = atoi( line+5 ); } else if ( strncmp( line, "TIME:", 5 ) == 0 ) { struct tm t; memset( &t, 0, sizeof(t) ); VRegexp r( "^(....)(..)(..)(..)(..)(..)?" ); r.m( line + 5 ); t.tm_year = atoi( r[0] ) - 1900; t.tm_mon = atoi( r[1] ); t.tm_mday = atoi( r[2] ); t.tm_hour = atoi( r[3] ); t.tm_min = atoi( r[4] ); t.tm_sec = atoi( r[5] ); st.st_mtime = st.st_ctime = st.st_atime = mktime( &t ); } else if ( line[0] == 0 ) { if ( str_len( s ) > 0 ) vfu_add_file( s, &st, 0 ); /* FIXME: there's no links for now */ s = ""; memset( &st, 0, sizeof(st) ); } } pclose( f ); } /*---------------------------------------------------------------------------*/ void vfu_browse_archive_file() { VString tmpdir = vfu_temp(); if(mkdir( tmpdir, S_IRUSR|S_IWUSR|S_IXUSR /*|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH*/ )) { say1( "error: cannot create temp directory" ); say2( tmpdir ); return; } chdir( tmpdir ); VString fn = files_list[FLI]->full_name(); VString s; s = "/usr/lib/vfu/rx_auto x \""; s += work_path; s += archive_name; s += "\" "; s += fn; s += " 2> /dev/null"; vfu_shell( s, "" ); chdir( tmpdir ); /* FIXME: a little hack -- vfu_shell() changes current path */ vfu_browse( fn ); chdir( work_path ); __vfu_dir_erase( tmpdir ); say1( "" ); } /*---------------------------------------------------------------------------*/ void vfu_user_external_archive_exec( VString &shell_line ) { VString tmpdir = vfu_temp(); if(mkdir( tmpdir, S_IRUSR|S_IWUSR|S_IXUSR /*|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH*/ )) { say1( "error: cannot create temp directory" ); say2( tmpdir ); return; } chdir( tmpdir ); VString fn = files_list[FLI]->full_name(); VString s; s = "/usr/lib/vfu/rx_auto x \""; s += work_path; s += archive_name; s += "\" "; s += fn; s += " 2> /dev/null"; vfu_shell( s, "" ); chdir( tmpdir ); /* FIXME: a little hack -- vfu_shell() changes current path */ str_replace( shell_line, "%f", fn ); str_replace( shell_line, "%F", fn ); vfu_shell( shell_line, "" ); chdir( work_path ); __vfu_dir_erase( tmpdir ); say1( "" ); } /*---------------------------------------------------------------------------*/ void vfu_extract_files( int one ) { if ( sel_count == 0 && one == 0 ) one = 1; char t[MAX_PATH]; VString target; if ( one == 0 ) sprintf( t, "EXTRACT SELECTION to: " ); else sprintf( t, "EXTRACT `%s' to:", files_list[FLI]->full_name() ); target = opt.last_copy_path[ CM_COPY ]; if ( !vfu_get_dir_name( t, target ) ) return; strcpy( opt.last_copy_path[ CM_COPY ], target ); VArray va; int z; for( z = 0; z < files_count; z++ ) if ((files_list[z]->sel && one == 0) || (z == FLI && one != 0)) va.push( files_list[z]->full_name() ); if (chdir(target)) { sprintf( t, "Cannot chdir to: %s", target.data() ); say1( t ); say2errno(); return; } VString tmpfile = vfu_temp(); if (va.fsave( tmpfile )) { sprintf( t, "Error writing list file: %s", tmpfile.data() ); say1( t ); return; } chmod( tmpfile, S_IRUSR|S_IWUSR ); VString s; s = "/usr/lib/vfu/rx_auto x \""; s += work_path; s += archive_name; s += "\" @"; s += tmpfile; s += " 2> /dev/null"; vfu_shell( s, "" ); if (unlink( tmpfile )) { /* sprintf( t, "Cannot unlink/erase temp file: %s", tmpfile ); say2( t ); */ } if (chdir(work_path)) { sprintf( t, "Cannot chdir back to to: %s", work_path.data() ); say1( t ); say2errno(); return; } say1( "EXTRACT ok." ); } /*---------------------------------------------------------------------------*/ /* eof vfuarc.cpp */ vfu-4.10/vfu/vfuopt.cpp0000644000175000001440000003517611310550124013704 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vfuopt.cpp,v 1.18 2008/01/18 18:40:30 cade Exp $ * */ #include "vfu.h" #include "vfuopt.h" #include "vfuuti.h" #include "vfudir.h" #include "vfuview.h" #include "vfumenu.h" Options opt; const char *NOYES[] = { " - ", "YES", NULL }; const char *NOYESPRECOPY[] = { " - ", "YES", "PRELIM", NULL }; const char *FTIMETYPE[] = { "CHANGE", "MODIFY", "ACCESS", NULL }; #ifdef _TARGET_GO32_ const char *TAGMARKS[] = { ">>", "=>", "->", "Í", "Ä", " ¯", "¯¯", NULL }; #else const char *TAGMARKS[] = { ">>", "=>", "->", NULL }; #endif ToggleEntry Toggles[] = { // { "[a] 1234567890123456", &(opt.some) }, { 0 , "--screen--", NULL, NULL }, { '1', "Show Mode field", &(opt.f_mode), NOYES }, { '2', "Show Owner field", &(opt.f_owner), NOYES }, { '3', "Show Group field", &(opt.f_group), NOYES }, { '4', "Show Time field", &(opt.f_time), NOYES }, { '5', "Show Size field", &(opt.f_size), NOYES }, { '6', "Show Type field", &(opt.f_type), NOYES }, { '7', " Time Type ", &(opt.f_time_type), FTIMETYPE }, { '8', "Long name view ", &(opt.long_name_view), NOYES }, { ' ', "TagMark type ", &(opt.tag_mark_type), TAGMARKS }, { ' ', "Use colors ", &(opt.use_colors), NOYES }, { ' ', "Use /etc/DIR_COLORS", &(opt.use_dir_colors), NOYES }, { ' ', "Lowercase extensions for configs", &(opt.lower_case_ext_config), NOYES }, { '.', "Show hidden files", &(opt.show_hidden_files), NOYES }, { 0 , "--navigation--", NULL, NULL }, { 'i', "Use internal viewer", &(opt.internal_browser), NOYES }, { 'I', "Use internal editor", &(opt.internal_editor), NOYES }, { ' ', "Use menu borders", &(opt.menu_borders), NOYES }, { 0 , "--trees/dirs-- " , NULL, NULL }, { ' ', "Compact DirTree", &(opt.tree_compact), NOYES }, { ' ', "CDTree (cdpath) ", &(opt.tree_cd), NOYES }, { 0 , "--troubleshooting--", NULL, NULL }, { ' ', "Clear screen on shell", &(opt.shell_cls), NOYES }, { 0 , "--compatibility--", NULL, NULL }, { ' ', "Lynx style navigation", &(opt.lynx_navigation), NOYES }, { ' ', "Mask auto expand", &(opt.mask_auto_expand), NOYES }, { ' ', "Use CWD as target for COPY/MOVE", &(opt.default_copy_to_cwd), NOYES }, { 0 , "--other--", NULL, NULL }, /* { ' ', "Can Zap/Erase READ-ONLY Files?!", &(opt.zap_ro), NOYES }, ? */ { 'b', "Allow beep!", &(opt.allow_beep), NOYES }, { 's', "Free space check on copy", &(opt.copy_free_space_check), NOYES }, { ' ', "Auto mount on change dir", &(opt.auto_mount), NOYES}, { ' ', "Preserve selection (after rescan)", &(opt.keep_selection), NOYES}, { ' ', "Preserve ownership/mode on copy?", &(opt.copy_keep_mode), NOYES }, { ' ', "Show user's free space", &(opt.show_user_free), NOYES }, { ' ', "Calc/Show bytes on copy", &(opt.copy_calc_totals), NOYESPRECOPY }, { ' ', "Calc/Show bytes freed on erase", &(opt.bytes_freed), NOYES }, { -1, "---", NULL } }; /*---------------------------------------------------------------------------*/ time_t vfu_opt_time( const struct stat st ) { if (opt.f_time_type == 0) return st.st_ctime; else if (opt.f_time_type == 1) return st.st_mtime; else if (opt.f_time_type == 2) return st.st_atime; else return 0; } time_t vfu_opt_time( const struct stat* st ) { return vfu_opt_time( *st ); } time_t vfu_opt_time( time_t ctime, time_t mtime, time_t atime ) { if (opt.f_time_type == 0) return ctime; else if (opt.f_time_type == 1) return mtime; else if (opt.f_time_type == 2) return atime; else return 0; } /*---------------------------------------------------------------------------*/ void vfu_load_dir_colors() { #ifdef _TARGET_UNIX_ VArray va; va.fload( "/etc/DIR_COLORS" ); if (va.count() == 0) return; while( va.count() ) { VString str = va[0]; va.del( 0 ); int comment = str_find( str, '#' ); if ( comment != -1 ) str_sleft( str, comment ); str_cut( str, " \t" ); if ( str_len( str ) == 0 ) continue; if ( strncmp( str, "TERM " , 5 ) == 0 ) continue; if ( strncmp( str, "COLOR " , 6 ) == 0 ) continue; if ( strncmp( str, "OPTIONS ", 8 ) == 0 ) continue; int pos = -1; if ( str_find( str, "31" ) != -1 ) pos = cRED; else if ( str_find( str, "32" ) != -1 ) pos = cGREEN; else if ( str_find( str, "33" ) != -1 ) pos = cYELLOW; else if ( str_find( str, "34" ) != -1 ) pos = cBLUE; else if ( str_find( str, "35" ) != -1 ) pos = cMAGENTA; else if ( str_find( str, "36" ) != -1 ) pos = cCYAN; else if ( str_find( str, "37" ) != -1 ) pos = cWHITE; else ; int spc = str_find( str, ' ' ); if ( spc == -1 || pos == -1 ) continue; str_sleft( str, spc ); str_replace( str, "DIR", ".[].<>" ); str_replace( str, "LINK", ".->" ); str_replace( str, "FIFO", ".()" ); str_replace( str, "SOCK", ".##" ); str_replace( str, "BLK", ".==" ); str_replace( str, "CHR", ".++" ); str_replace( str, "EXEC", ".**" ); str_ins( ext_colors[pos], 0, str ); }; for ( int z = 0; z < 16; z++ ) if( str_len( ext_colors[z] ) > 0 ) { ext_colors[z] += "."; if ( opt.lower_case_ext_config ) str_low( ext_colors[z] ); } #endif /* _TARGET_UNIX_ */ } /*---------------------------------------------------------------------------*/ int set_arr( const char *line, const char *keyword, VArray &target ) { VRegexp re("^[ \011]*([a-zA-Z0-9]+)[ \011]*=[ \011]*(.+)"); if ( ! re.m( line ) ) return 0; if ( str_low( re[1] ) != keyword ) return 0; target.push( re[2] ); return 1; } /*---------------------------------------------------------------------------*/ int set_str( const char *line, const char *keyword, VString &target ) { VRegexp re("^[ \011]*([a-zA-Z0-9]+)[ \011]*=[ \011]*(.+)"); if ( ! re.m( line ) ) return 0; if ( str_low( re[1] ) != keyword ) return 0; target = re[2]; return 1; } /*---------------------------------------------------------------------------*/ int set_int( const char *line, const char *keyword, int &target ) { VRegexp re("^[ \011]*([a-zA-Z0-9]+)[ \011]*=[ \011]*([0123456789]+)"); if ( ! re.m( line ) ) return 0; if ( str_low( re[1] ) != keyword ) return 0; target = atoi( re[2] ); return 1; } /*---------------------------------------------------------------------------*/ int set_splitter( const char *line, const char *keyword, VArray &splitter ) { VRegexp re("^[ \011]*([a-zA-Z0-9]+)[ \011]*=[ \011]*(.+)"); if ( ! re.m( line ) ) return 0; if ( str_low( re[1] ) != keyword ) return 0; splitter = str_split( PATH_DELIMITER, re[2] ); return 1; } /*---------------------------------------------------------------------------*/ int key_by_name( const char* key_name ) { if (strcmp (key_name, "IC" ) == 0) return KEY_IC; if (strcmp (key_name, "INS" ) == 0) return KEY_IC; if (strcmp (key_name, "INSERT") == 0) return KEY_IC; if (strcmp (key_name, "ENTER" ) == 0) return KEY_ENTER; if (strcmp (key_name, "RETURN") == 0) return KEY_ENTER; /* if (strcmp (key_name, "MENU" ) == 0) ux.key = - menucount; */ VRegexp reFKEYS( "[\\@\\^\\#]?[fF][01234567890]+" ); if ( reFKEYS.m( key_name ) ) { if ( toupper(key_name[0]) == 'F' ) return KEY_F1 + atoi( key_name + 1 ) - 1; else if ( toupper(key_name[0]) == '@' ) return KEY_ALT_F1 + atoi( key_name + 2 ) - 1; else if ( toupper(key_name[0]) == '^' ) return KEY_CTRL_F1 + atoi( key_name + 2 ) - 1; else if ( toupper(key_name[0]) == '#' ) return KEY_SH_F1 + atoi( key_name + 2 ) - 1; } return 0; } /*---------------------------------------------------------------------------*/ void vfu_settings_load() { VString str; user_externals.undef(); history.undef(); see_filters.undef(); panelizers.undef(); archive_extensions.undef(); path_bookmarks.undef(); /***** LOAD DEFAULTS *******/ memset( &opt, 0, sizeof( opt ) ); opt.svo.reset(); opt.seo.reset(); opt.seo.handle_tab = 1; opt.sort_order = 'N'; opt.sort_direction = 'A'; opt.sort_top_dirs = 1; opt.f_size = 1; opt.f_time = 1; opt.f_mode = 1; opt.f_group = 1; opt.f_owner = 1; opt.f_type = 1; opt.f_time_type = 1; opt.long_name_view = 0; opt.tree_compact = 0; opt.tree_cd = 1; opt.show_hidden_files = 1; opt.allow_beep = 1; opt.use_colors = 1; opt.use_dir_colors = 1; opt.lower_case_ext_config = 1; opt.copy_free_space_check = 1; opt.copy_calc_totals = 1; opt.copy_keep_mode = 1; opt.tag_mark_type = 0; opt.internal_browser = 1; opt.internal_editor = 1; opt.mask_auto_expand = 1; opt.shell_cls = 1; opt.zap_ro = 0; opt.show_user_free = 1; opt.menu_borders = 0; opt.lynx_navigation = 0; opt.auto_mount = 1; opt.keep_selection = 1; opt.bytes_freed = 1; /***** LOAD DEFAULTS END ***/ FILE *fsett; Options tmp_opt; memset( &tmp_opt, 0, sizeof( tmp_opt ) ); if ( file_load_crc32( filename_opt, &tmp_opt, sizeof( tmp_opt ) ) == 0 ) memcpy( &opt, &tmp_opt, sizeof(Options) ); else say1( "warning: bad vfu.options file, loading defaults..." ); history.fload( filename_history ); if (getenv("EDITOR")) { shell_editor = getenv("EDITOR"); shell_editor += " %f"; } if (getenv("PAGER") ) { shell_browser = getenv("PAGER"); shell_browser += " %f"; } else if (getenv("BROWSER") ) { shell_browser = getenv("BROWSER"); shell_browser += " %f"; } else if (getenv("VIEWER") ) { shell_browser = getenv("VIEWER"); shell_browser += " %f"; } VRegexp re_ux("^\\s*u?x\\s*=\\s*([^,]*)[ \011]*,\\s*([^, \011]*)\\s*,\\s*([^, \011]*)\\s*,(.*)$", "i"); VRegexp re_see( "^\\s*see\\s*=\\s*([^, \011]*)\\s*,(.*)$", "i" ); VRegexp re_pan( "^\\s*panelize\\s*=\\s*([^,]*)\\s*,(.*)$", "i" ); char line[1024]; if ( (fsett = fopen( filename_conf, "r")) ) { while(fgets(line, 1024, fsett)) { if ( line[0] == '#' ) continue; if ( line[0] == ';' ) continue; str_cut( line, "\n\r" ); if ( strlen( line ) == 0 ) continue; if(set_str( line, "browser", shell_browser))continue; if(set_str( line, "pager", shell_browser))continue; if(set_str( line, "viewer", shell_browser))continue; if(set_arr( line, "archive", archive_extensions))continue; if(set_str( line, "editor", shell_editor))continue; if(set_str( line, "diff", shell_diff))continue; if(set_arr( line, "bookmark", path_bookmarks))continue; // follow 10 are deprecated /* if(set_arr( line, "bookmark1", path_bookmarks))continue; if(set_arr( line, "bookmark2", path_bookmarks))continue; if(set_arr( line, "bookmark3", path_bookmarks))continue; if(set_arr( line, "bookmark4", path_bookmarks))continue; if(set_arr( line, "bookmark5", path_bookmarks))continue; if(set_arr( line, "bookmark6", path_bookmarks))continue; if(set_arr( line, "bookmark7", path_bookmarks))continue; if(set_arr( line, "bookmark8", path_bookmarks))continue; if(set_arr( line, "bookmark9", path_bookmarks))continue; */ /* if(set_str( line, "cblack" , ext_colors[0]); */ if(set_str( line, "cgreen" , ext_colors[cGREEN]))continue; if(set_str( line, "cred" , ext_colors[cRED]))continue; if(set_str( line, "ccyan" , ext_colors[cCYAN]))continue; if(set_str( line, "cwhite" , ext_colors[cWHITE]))continue; if(set_str( line, "cmagenta" , ext_colors[cMAGENTA]))continue; if(set_str( line, "cblue" , ext_colors[cBLUE]))continue; if(set_str( line, "cyellow" , ext_colors[cYELLOW]))continue; if(set_str( line, "chblack" , ext_colors[chBLACK]))continue; if(set_str( line, "chgreen" , ext_colors[chGREEN]))continue; if(set_str( line, "chred" , ext_colors[chRED]))continue; if(set_str( line, "chcyan" , ext_colors[chCYAN]))continue; if(set_str( line, "chwhite" , ext_colors[chWHITE]))continue; if(set_str( line, "chmagenta", ext_colors[chMAGENTA]))continue; if(set_str( line, "chblue" , ext_colors[chBLUE]))continue; if(set_str( line, "chyellow" , ext_colors[chYELLOW]))continue; if(set_splitter( line, "trimtree", trim_tree ))continue; /* following code is used to clean input data */ if( re_ux.m( line ) ) { str = ""; str = str + re_ux[1] + ","; /* get description */ str = str + re_ux[2] + ","; /* get key name */ VString t = re_ux[3]; /* get extensions */ if ( t != "*" && t[-1] != '.' ) t += "."; str = str + t + ","; str += re_ux[4]; /* get shell line */ user_externals.push( str ); continue; } else if( re_see.m( line ) ) { str = ""; see_filters.push( str + re_see[1] + "," + re_see[2] ); continue; } else if( re_pan.m( line ) ) { str = ""; panelizers.push( str + re_see[1] + "," + re_see[2] ); continue; } } fclose(fsett); } #ifdef _TARGET_GO32_ int z; for ( z = 0; z < 16; z++ ) str_low( ext_colors[z] ); #endif if (opt.use_dir_colors) vfu_load_dir_colors(); // if (file_load_crc32( filename_size_cache, &size_cache, sizeof(size_cache))) // memset( &size_cache, 0, sizeof(size_cache) ); size_cache.undef(); size_cache.fload( filename_size_cache ); } /*---------------------------------------------------------------------------*/ void vfu_settings_save() { file_save_crc32( filename_opt, &opt, sizeof(opt)); // file_save_crc32( filename_size_cache, &size_cache, sizeof(size_cache)); history.fsave( filename_history ); size_cache.fsave( filename_size_cache ); } /*---------------------------------------------------------------------------*/ void vfu_edit_conf_file() { if (opt.internal_editor) { opt.seo.cs = cINFO; SeeEditor editor( &opt.seo ); if( editor.open( filename_conf ) == 0 ) { int r = 1; while ( r ) { editor.run(); r = editor.request_quit(); } } else say1( "Error loading file..." ); editor.close(); } else { VString line = shell_editor; str_replace( line, "%f", filename_conf ); str_replace( line, "%F", filename_conf ); vfu_shell( line.data(), 0 ); } vfu_settings_save(); vfu_settings_load(); do_draw = 2; say1(""); say2(""); } /*---------------------------------------------------------------------------*/ void vfu_options() { say1("press SPACE to toggle, ENTER or ESC to exit"); say2(""); vfu_toggle_box( 30, 5, "Options/Toggles (scroll down, SPACE selects)", Toggles ); vfu_settings_save(); vfu_settings_load(); vfu_drop_all_views(); vfu_redraw(); vfu_redraw_status(); say1(""); say2(""); } vfu-4.10/vfu/vfumenu.h0000644000175000001440000000123511005727265013515 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vfumenu.h,v 1.5 2003/01/26 21:48:42 cade Exp $ * */ #ifndef _VFUMENU_H_ #define _VFUMENU_H_ #include #include "vfuuti.h" #define menu_box_info con_default_menu_info int vfu_toggle_box( int x, int y, const char *title, ToggleEntry* toggles ); int vfu_menu_box( int x, int y, const char *title, VArray *va = &mb ); int vfu_menu_box( const char* title, const char* menustr, int row = -1 ); #endif /* _VFUMENU_H_ */ /* eof vfumenu.h */ vfu-4.10/vfu/vfuview.h0000644000175000001440000000160111005727265013520 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vfuview.h,v 1.6 2003/11/22 03:26:48 cade Exp $ * */ #ifndef _VFUVIEW_H_ #define _VFUVIEW_H_ #include "vfuopt.h" extern int tag_mark_pos; extern int sel_mark_pos; int get_item_color( TF* fi ); VString fsize_fmt( fsize_t fs ); /* return commified number */ void show_pos( int curr, int all ); void vfu_drop_all_views(); void vfu_draw(int n); void vfu_redraw(); /* redraw file list and header */ void vfu_redraw_status(); /* redraw bottom status, total,free,selected... */ void vfu_nav_up(); void vfu_nav_down(); void vfu_nav_ppage(); void vfu_nav_npage(); void vfu_nav_home(); void vfu_nav_end(); void vfu_nav_select(); void vfu_nav_update_pos(); #endif //_VFUVIEW_H_ vfu-4.10/vfu/vfuview.cpp0000644000175000001440000002361011103062611014041 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1996-2003 * http://soul.datamax.bg/~cade * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vfuview.cpp,v 1.17 2005/06/01 23:13:08 cade Exp $ * */ #include "vfu.h" #include "vfufiles.h" #include "vfuview.h" #include "vfuopt.h" #include "vfuuti.h" #include "vfusys.h" int sel_mark_pos; int tag_mark_pos; int get_item_color( TF *fi ) { VString str; ASSERT( fi ); if (!opt.use_colors) return cNORMAL; /* don't use colors -- option */ if ( fi->is_dir() ) return cCYAN; // dirs are cCYAN by default str = fi->name(); if ( str_get_ch( str, 0 ) == '.' ) str = ".dotfiles"; else { str = fi->ext(); if ( str == "" ) str = "."; } str += "."; if ( opt.lower_case_ext_config ) str_low( str ); // lowercase extension #ifdef _TARGET_GO32_ /* under dos/windows file names are not case sensitive */ str_low( str ); #endif int z; if ( str != ".." ) { for ( z = cBLACK; z <= chWHITE; z++ ) if (str_find( ext_colors[z], str ) != -1) return z; } /* extension not found -- try type string */ str = fi->type_str(); str = "." + str + "."; if ( str != ".." ) { for ( z = cBLACK; z <= chWHITE; z++ ) if (str_find( ext_colors[z], str ) != -1) return z; } /* type string not found too return std color */ return cNORMAL; } /*-----------------------------------------------------------------------*/ VString fsize_fmt( fsize_t fs ) /* return commified number */ { VString str; if( fs > 99999999999.0 ) // 99_999_999_999 11 positions + 3 comma = 14 chars { str.fi( int( fs / ( 1024*1024 ) ) ); str_comma( str ); str += " MiB"; } else { str.fi( fs ); str_comma( str ); } return str; } /*-----------------------------------------------------------------------*/ void show_pos( int curr, int all ) { char t[64]; sprintf( t, "%5d of %5d", curr, all ); con_out( con_max_x() - 13, 3, t, cHEADER ); } /*#######################################################################*/ void vfu_drop_all_views() { int z = 0; for( z = 0; z < files_count; z++ ) files_list[z]->drop_view(); do_draw += 1; } /*#######################################################################*/ void vfu_draw( int n ) { VFU_CHECK_LIST_POS( n ); if ( n < FLP || n > FLP + PS ) return; /* we are out of screen -- don't draw */ TF* fi = files_list[n]; int c = fi->color(); /* color to be used */ VString view = fi->view(); if ( fi->sel ) { str_set_ch( view, sel_mark_pos, '#' ); c = CONCOLOR(cBLACK,cWHITE); } if ( n == FLI ) { str_set_ch( view, tag_mark_pos , TAGMARKS[opt.tag_mark_type][0] ); str_set_ch( view, tag_mark_pos+1, TAGMARKS[opt.tag_mark_type][1] ); c += cBOLD; /* this is a hack, can be removed w/o warning :) -- more visibility */ if ( c == 120 ) c = cTAG; // 116; // 123; // 63; // 123 } con_out( 1, n - FLP + 4, view, c ); // con_ce( c ); } /*#######################################################################*/ extern const char *FTIMETYPE[]; /* in vfuopt.cpp */ void vfu_redraw() /* redraw file list and header */ { char t[MAX_PATH]; VString str; str = "Mask: "; str += files_mask; con_out(1,1,str,cINFO); con_ce(cINFO); if ( work_mode == WM_ARCHIVE ) con_out( con_max_x()-34, 1, " [-ARCHIVE-] ", cWARNING ); con_out(con_max_x()-17,1,"Press H for help",cINFO); con_out(con_max_x()-20,1,"VFU " VFU_VERSION " for help",cINFO); str = "Path: "; str += work_path; if ( work_mode == WM_ARCHIVE ) { str += "["; str += archive_name; str += "]/"; /* NOTE: to simulate root dir visually */ str += archive_path; } str = str_dot_reduce( str, con_max_x()-1 ); con_out(1,2,str,cINFO); con_ce(cINFO); str = ""; if ( opt.sort_order == 'N' ) str = "NAME"; if ( opt.sort_order == 'M' ) str = "NAME#"; if ( opt.sort_order == 'E' ) str = "EXT"; if ( opt.sort_order == 'A' ) str = "MODE"; if ( opt.sort_order == 'O' ) str = "OWNER"; if ( opt.sort_order == 'G' ) str = "GROUP"; if ( opt.sort_order == 'T' ) str = "MTIME"; if ( opt.sort_order == 'H' ) str = "CTIME"; if ( opt.sort_order == 'C' ) str = "ATIME"; if ( opt.sort_order == 'S' ) str = "SIZE"; if ( opt.sort_order == 'Y' ) str = "TYPE"; str += opt.sort_direction == 'A' ? "+" : "-"; str = "(SORT:" + str + ")"; con_out( con_max_x() - str_len( str ) + 1, 2, str, cHEADER ); str = ""; t[0] = 0; char *spos = t; if (opt.sort_order == 'D') opt.sort_order = 'T'; /* hack anyway */ if (!opt.long_name_view) { if (opt.f_mode ) spos += sprintf( spos, "%10s ", MODE_STRING ); if (opt.f_owner ) spos += sprintf( spos, " OWNER " ); if (opt.f_group ) spos += sprintf( spos, " GROUP " ); if (opt.f_time ) spos += sprintf( spos, "%s TiME ", FTIMETYPE[opt.f_time_type] ); if (opt.f_size ) spos += sprintf( spos, " SiZE " ); }; if ( opt.f_mode + opt.f_owner + opt.f_group + opt.f_time + opt.f_size + opt.f_type == 0 ) opt.f_type = 1; /* a hack really :) if all fields are off -- turn on type one */ if (opt.f_type || opt.long_name_view) spos += sprintf( spos, "TP" ); tag_mark_pos = strlen( t ); sel_mark_pos = tag_mark_pos + 2; spos += sprintf( spos, " #NAME %s", opt.long_name_view ? "( long name view )" : "" ); str_pad( t, - con_max_x() ); str_sleft( t, con_max_x() ); con_out(1,3, t, cHEADER ); show_pos( FLI+1, files_count ); int z; for ( z = 0; z < PS; z++ ) { ASSERT( FLP + z >= 0 ); if ( FLP + z >= files_count ) { con_out( 1, z+4, "~", cPLAIN ); con_ce( cPLAIN ); } else if ( files_list[FLP+z] == NULL ) /* FIXME: if NULL?! */ { con_out( 1, z+4, "~", cPLAIN ); con_ce( cPLAIN ); } else vfu_draw( FLP + z ); } if ( files_count <= 0 ) con_out( ( con_max_x() - 20 ) / 2, 10, " *** No files found *** ", cHEADER); } /*-----------------------------------------------------------------------*/ void vfu_redraw_status() /* redraw bottom status, total,free,selected... */ { VString s1; VString s2; VString tmp; /* first line here */ s1 = "Select:"; tmp = sel_count; str_comma(tmp); str_pad(tmp,14); s1 += tmp; s1 += " Free: "; tmp = fsize_fmt( fs_free ); str_pad(tmp,14); s1 += tmp; if (fs_total == 0 || fs_free > fs_total) tmp = " n/a%"; else sprintf( 64, tmp, "%5.1f%%", (double)100 * ((double)fs_free / (double)fs_total)); s1 += " " + tmp + " FSize:"; tmp = fsize_fmt( files_size ); str_pad(tmp,14); s1 += tmp; if (fs_total == 0 || files_size > fs_total) tmp = " n/a%"; else sprintf(tmp,"%4.1f%%", (double)100 * ((double)files_size / (double)fs_total)); s1 += " " + tmp; /* second line here */ s2 = "S.Size:"; tmp = fsize_fmt( sel_size ); str_pad(tmp,14); s2 += tmp; s2 += " Total:"; tmp = fsize_fmt( fs_total ); str_pad(tmp,14); s2 += tmp; tmp = fs_block_size; str_pad( tmp,5 ); s2 += " [" + tmp + "]"; sprintf( tmp," %s.%s@%s ", user_id_str.data(), group_id_str.data(), host_name_str.data() ); s2 += tmp; str_pad( s1, - con_max_x() ); str_pad( s2, - con_max_x() ); con_out( 1, con_max_y()-3, s1, cINFO2 ); con_out( 1, con_max_y()-2, s2, cINFO2 ); } /*#######################################################################*/ void vfu_nav_up() { if ( files_count == 0) return; if ( FLI == 0 ) return; int old_flp = FLP; file_list_index.up(); if ( old_flp != FLP ) do_draw = 1; else { vfu_draw(FLI+1); vfu_draw(FLI); } } /*-----------------------------------------------------------------------*/ void vfu_nav_down() { if ( files_count == 0 ) return; if ( FLI == files_count - 1 ) return; int old_flp = FLP; file_list_index.down(); if ( old_flp != FLP ) do_draw = 1; else { vfu_draw( FLI-1 ); vfu_draw( FLI ); } } /*-----------------------------------------------------------------------*/ void vfu_nav_ppage() { if ( files_count == 0 ) return; if ( FLP == 0 && FLI == 0 ) return; int old_fli = FLI; int old_flp = FLP; file_list_index.pageup(); if ( old_flp != FLP ) do_draw = 1; else { vfu_draw( old_fli ); vfu_draw( FLI ); } } /*-----------------------------------------------------------------------*/ void vfu_nav_npage() { if ( files_count == 0 ) return; if ( FLP >= files_count - PS && FLI == files_count - 1 ) return; int old_fli = FLI; int old_flp = FLP; file_list_index.pagedown(); if ( old_flp != FLP ) do_draw = 1; else { vfu_draw( old_fli ); vfu_draw( FLI ); } } /*-----------------------------------------------------------------------*/ void vfu_nav_home() { if ( files_count == 0 ) return; if ( FLI == 0 ) return; FGO( 0 ); vfu_nav_update_pos(); do_draw = 1; } /*-----------------------------------------------------------------------*/ void vfu_nav_end() { if ( files_count == 0 ) return; if ( FLI >= files_count - 1 ) return; FGO( files_count - 1 ); vfu_nav_update_pos(); do_draw = 1; } /*-----------------------------------------------------------------------*/ void vfu_nav_select() { if ( files_count == 0 ) return; TF *fi = files_list[FLI]; fsize_t f = fi->size(); if ( f < 0 ) f = 0; /* dirs w/o size i.e. -1 */ if ( fi->sel ) { /* unselect */ sel_count --; sel_size -= f; } else { /* select */ sel_count ++; sel_size += f; } fi->sel = - ( fi->sel - 1 ); /* I know -- !!(fi->sel) ... :) */ vfu_draw( FLI ); vfu_nav_down(); vfu_draw( FLI ); do_draw_status = 1; } /*-----------------------------------------------------------------------*/ void vfu_nav_update_pos() { ASSERT( files_count >= 0 ); if ( FLI < 0 ) FGO( 0 ); if ( files_count == 0 ) FGO( 0 ); if ( files_count > 0 && FLI > files_count - 1 ) FGO( files_count - 1 ); } /* eof vfuview.cpp */ vfu-4.10/TODO0000644000175000001440000000076111172607454011554 0ustar cadeusers MOST IMPORTANT (LONG TERM?) TODO NOTES: -- clean up all the documentation and build/install scripts mess :( -- fix makemake.pl to handle install/uninstall targets -- write rx_* tools for different archives/storages (HELP WANTED!) -- mount in JumpToMountpoints menu -- build tree from local file systems only (option) -- edit symlink reference to use get_dir_name() instead of get_text()... -- check if source exist when move/copy/symlink (warning really) -- save/load selection with key vfu-4.10/NOTES0000644000175000001440000000221411172606420011662 0ustar cadeusers This file contains some misc notes... -- If you try to compile vfu under NetBSD: try to use `build.netbsd'... If you fail to compile it try one of: 1. get newer vfu version at http://soul.datamax.bg/~cade/vfu 2. mailto: Hubert Feyrer Hubert Feyrer is official VFU maintainer for NetBSD platform. 3. mailto: Vladi Belperchinov-Shabanski -- If you want to compile vfu static binary: 1. cd vfu 2. make LDDEF=-static voila! :) -- How to compile VFU for other UNIX platform? You have to edit vslib/target.h file and to add these lines just before `#ifndef _TARGET_DESCRIPTION_' line: (I'll give example as if the new target is RS6000) ---cut--- #ifdef _TARGET_UNKNOWN_ #if defined(__RS6000__) #define _TARGET_RS6000_ #define _TARGET_DESCRIPTION_ "UNIX/RS6000" #undef _TARGET_UNKNOWN_ #endif #endif ---cut--- and start make: make CCDEF=-D__RS6000__ in both vslib and vfu directories VFU should compile without big problems on any UNIX (hope so:)) P! Vladi. Vladi Belperchinov-Shabanski vfu-4.10/build0000755000175000001440000000044511172606420012100 0ustar cadeusers#!/bin/sh echo "Compiling VSLIB..." cd vslib make if [ -e libvslib.a ]; then echo "VSLIB compiled ok." else echo "VSLIB compilation failed..." fi cd .. echo "Compiling VFU..." cd vfu make if [ -e vfu ]; then echo "VFU compiled ok." else echo "VFU compilation failed..." fi cd .. vfu-4.10/extra/0000755000175000001440000000000011172606426012201 5ustar cadeusersvfu-4.10/extra/Rxvt0000644000175000001440000000025111172606420013057 0ustar cadeusers*font: vga *boldFont: vga *saveLines: 500 *foreground: #cccccc *background: #444444 *cursorColor: green *scrollBar: False *title: Term *keysym.16: "\b" *keysym.6f: "^?" vfu-4.10/extra/README0000644000175000001440000000137611172606420013062 0ustar cadeusers This directory contains some extra files, not (directly) related to the VFU project Xmodmap is a modmap file that enables keypad keys as arrows/home/end etc... vga.pcf is my favorite font for rxvt (xterm) Rxvt is my configuration for rxvt (/var/X11R6/lib/app-defaults/Rxvt) OBSOLETE: see Xdefaults vfu-bash is a bash function that enables vfu to change working directory on exit, to merge with your current environment you have to: . ./vfu-bash note the leading dot! Xdefaults contains some fixes to allow easier VFU usage under X (mostly rxvt issues) Vladi. vfu-4.10/extra/terminfo/0000755000175000001440000000000011172606427014025 5ustar cadeusersvfu-4.10/extra/terminfo/linux-c2.terminfo.src0000644000175000001440000000432711172606420020020 0ustar cadeusers# Reconstructed via infocmp from file: /usr/share/terminfo/l/linux-c # Changed by to avoid all `ESC[0c' and similar cursor state # sequences to be used with rxvt and most xterm-compatible terminal-emulators linux-c2|linux console 1.3.6+ (rev2) with private palette for each virtual console, am, bce, ccc, eo, mir, msgr, xenl, xon, colors#8, it#8, ncv#2, pairs#64, acsc=+\020\,\021-\030.^Y0\333`\004a\261f\370g\361h\260i\316j\331k\277l\332m\300n\305o~p\304q\304r\304s_t\303u\264v\301w\302x\263y\363z\362{\343|\330}\234~\376, bel=^G, blink=\E[5m, bold=\E[1m, civis=\E[?25l, clear=\E[H\E[J, cnorm=\E[?25h, cr=^M, csr=\E[%i%p1%d;%p2%dr, cub1=^H, cud1=^J, cuf1=\E[C, cup=\E[%i%p1%d;%p2%dH, cuu1=\E[A, cvvis=\E[?25h, dch=\E[%p1%dP, dch1=\E[P, dim=\E[2m, dl=\E[%p1%dM, dl1=\E[M, ech=\E[%p1%dX, ed=\E[J, el=\E[K, el1=\E[1K, flash=\E[?5h\E[?5l$<200/>, home=\E[H, hpa=\E[%i%p1%dG, ht=^I, hts=\EH, ich=\E[%p1%d@, ich1=\E[@, il=\E[%p1%dL, il1=\E[L, ind=^J, initc=\E]P%?%p1%{9}%>%t%p1%{10}%-%'a'%+%c%e%p1%d%;%p2%{255}%&%Pr%gr%{16}%/%Px%?%gx%{9}%>%t%gx%{10}%-%'A'%+%c%e%gx%d%;%gr%{15}%&%Px%?%gx%{9}%>%t%gx%{10}%-%'A'%+%c%e%gx%d%;%p3%{255}%&%Pr%gr%{16}%/%Px%?%gx%{9}%>%t%gx%{10}%-%'A'%+%c%e%gx%d%;%gr%{15}%&%Px%?%gx%{9}%>%t%gx%{10}%-%'A'%+%c%e%gx%d%;%p4%{255}%&%Pr%gr%{16}%/%Px%?%gx%{9}%>%t%gx%{10}%-%'A'%+%c%e%gx%d%;%gr%{15}%&%Px%?%gx%{9}%>%t%gx%{10}%-%'A'%+%c%e%gx%d%;, invis=\E[8m, kb2=\E[G, kbs=\177, kcbt=\E[Z, kcub1=\E[D, kcud1=\E[B, kcuf1=\E[C, kcuu1=\E[A, kdch1=\E[3~, kend=\E[4~, kf1=\E[[A, kf10=\E[21~, kf11=\E[23~, kf12=\E[24~, kf13=\E[25~, kf14=\E[26~, kf15=\E[28~, kf16=\E[29~, kf17=\E[31~, kf18=\E[32~, kf19=\E[33~, kf2=\E[[B, kf20=\E[34~, kf3=\E[[C, kf4=\E[[D, kf5=\E[[E, kf6=\E[17~, kf7=\E[18~, kf8=\E[19~, kf9=\E[20~, khome=\E[1~, kich1=\E[2~, knp=\E[6~, kpp=\E[5~, kspd=^Z, nel=^M^J, oc=\E]R, op=\E[39;49m, rc=\E8, rev=\E[7m, ri=\EM, rmacs=\E[10m, rmir=\E[4l, rmpch=\E[10m, rmso=\E[27m, rmul=\E[24m, rs1=\Ec\E]R, sc=\E7, setab=\E[4%p1%dm, setaf=\E[3%p1%dm, sgr=\E[0;10%?%p1%t;7%;%?%p2%t;4%;%?%p3%t;7%;%?%p4%t;5%;%?%p5%t;2%;%?%p6%t;1%;%?%p7%t;8%;%?%p9%t;11%;m, sgr0=\E[0;10m, smacs=\E[11m, smir=\E[4h, smpch=\E[11m, smso=\E[7m, smul=\E[4m, tbc=\E[3g, u6=\E[%i%d;%dR, u7=\E[6n, u8=\E[?6c, u9=\E[c, vpa=\E[%i%p1%dd, vfu-4.10/extra/terminfo/README0000644000175000001440000000136411172606420014702 0ustar cadeusers NOTE: THIS IS OPTIONAL, YOU SHOULD USE THIS ONLY IF YOU HAVE PROBLEMS WITH STANDARD TERMINFO ENTRIES (linux,linux*,rxvt...) If you want to use this terminfo/termcap definition: 1. copy `linux-c2' file to /usr/share/terminof/l/ 2. export TERM=linux-c2 (for bash) 3. run vfu or 1. compile linux-c2.terminfo.src: tic linux-c2.terminfo.src -o . 2. you should got linux-c2 file in ./l/ directory 3. proceed as above This works fine with linux console and rxvt (xterm works also). If you have found bugs in linux-c2 or you have any notes about this file, feel free to contact me I'll be glad to help you or to fix/update linux-c2. vfu home page is: http://cade.datamax.bg/vfu vfu-4.10/extra/terminfo/linux-c20000644000175000001440000000375711172606420015416 0ustar cadeusersS}Ylinux-c2|linux console 1.3.6+ (rev2) with private palette for each virtual consoleÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿ!%)ÿÿ4EGKRÿÿT[ÿÿ_cjnÿÿÿÿrx}ÿÿÿÿ‚‡Œÿÿ‘–› ©¯ÿÿÿÿ·¼ÂÈÿÿÿÿÿÿÿÿÿÿÿÿÚÞÿÿâÿÿÿÿÿÿäÿÿéÿÿÿÿÿÿÿÿíòøý $)ÿÿ.ÿÿ27<ÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿDÿÿGPÿÿYÿÿbÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿkÿÿÿÿÿÿqt‚„‡èÿÿëÿÿÿÿÿÿÿÿÿÿÿÿíÿÿÿÿÿÿÿÿñÿÿ2ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ6ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ;ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ=CIOU[agmsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿyÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ~‰Ž”˜¡¥ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ9CÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿMS [%i%p1%d;%p2%dr[%i%p1%dG[%i%p1%d;%p2%dH [?25l[?25h[?25h[%p1%dX[?5h[?5l$<200/>[@[3~[[A[21~[[B[[C[[D[[E[17~[18~[19~[20~[1~[2~[6~[5~ [%p1%dP[%p1%dM[%p1%d@[%p1%dLc]R8[%i%p1%dd7 M[0;10%?%p1%t;7%;%?%p2%t;4%;%?%p3%t;7%;%?%p4%t;5%;%?%p5%t;2%;%?%p6%t;1%;%?%p7%t;8%;%?%p9%t;11%;mH +,-.0Û`a±føgñh°iÎjÙk¿lÚmÀnÅo~pÄqÄrÄs_tÃu´vÁwÂx³yózò{ã|Ø}œ~þ[4~[23~[24~[25~[26~[28~[29~[31~[32~[33~[34~[%i%d;%dR[?6c]R]P%?%p1%{9}%>%t%p1%{10}%-%'a'%+%c%e%p1%d%;%p2%{255}%&%Pr%gr%{16}%/%Px%?%gx%{9}%>%t%gx%{10}%-%'A'%+%c%e%gx%d%;%gr%{15}%&%Px%?%gx%{9}%>%t%gx%{10}%-%'A'%+%c%e%gx%d%;%p3%{255}%&%Pr%gr%{16}%/%Px%?%gx%{9}%>%t%gx%{10}%-%'A'%+%c%e%gx%d%;%gr%{15}%&%Px%?%gx%{9}%>%t%gx%{10}%-%'A'%+%c%e%gx%d%;%p4%{255}%&%Pr%gr%{16}%/%Px%?%gx%{9}%>%t%gx%{10}%-%'A'%+%c%e%gx%d%;%gr%{15}%&%Px%?%gx%{9}%>%t%gx%{10}%-%'A'%+%c%e%gx%d%;[3%p1%dm[4%p1%dmvfu-4.10/extra/Xmodmap0000644000175000001440000000057411172606420013531 0ustar cadeuserskeycode 22 = BackSpace osfBackSpace keycode 63 = asterisk keycode 112 = slash keycode 108 = Return keycode 79 = Home keycode 80 = Up keycode 81 = Page_Up keycode 82 = minus keycode 83 = Left keycode 85 = Right keycode 86 = plus keycode 87 = End keycode 88 = Down keycode 89 = Page_Down keycode 90 = Insert keycode 91 = Delete vfu-4.10/extra/vfu-bash0000644000175000001440000000016211172606420013630 0ustar cadeusersfunction vfu() { /usr/local/bin/vfu $*; cd "`cat /tmp/vfu.exit.$USER`"; rm -f /tmp/vfu.exit.$USER; }vfu-4.10/extra/vga.pcf0000644000175000001440000006007011172606420013445 0ustar cadeusersfcp ¨˜d@¤D¬ÄJ ÌO@ÜQ€ äUdð_   g&K3K@ÿÿÿÿITPOINT_SIZEFONTvgaWEIGHTRESOLUTIONRESOLUTION_XRESOLUTION_YX_HEIGHTQUAD_WIDTH   ÿÿ÷ÿ €ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„€ˆˆŒ„@€À@€À@€À@€À@€À@€À@€À@€À@€À @ € À @ € À @ € À @ € À @ € À @€À@€À@€À@€À@€À@€À@€À@€À@€À@€À@€À@€À@€À@€À@€À@€À@€À@€À @ € À !@!€!À!"@"€"À"#@#€#À#$@$€$À$%@%€%À%&@&€&À&'@'€'À'(@(€(À()@)€)À)*@*€*À*+@+€+À+,@,€,À,-@-€-À-.@.€.À./@/€/À/0@0€0À01@1€1À12@2€2À23@3€3À34@4€4À45@5€5À56@6€6À67@7€7À78@8€8À89@9€9À9:@:€:À:;@;€;À;<@<€<À<=@=€=À=>@>€>À>?@?€?À? @€>cc{{{;>~¥¥™~~ÿÛÿÿÛçÿÿ~6>>><<ççç<<~ÿÿ~<<<ÿÿÿÿÿÿçÃÃçÿÿÿÿÿÿ<fBBf<ÿÿÿÿÿÙ½½™Ãÿÿÿÿÿx`pX3333<ffff<~üÌü þÆþÆÆÆÆæçgÛ<ç<Û@`px||xp`@<~~<fffffffffþÛÛÛÞØØØØØ>c6cc60c><~~<~<~~<00  66>>>><<<fff$6666666>cC>``ac>Cc0 ca66n;333n 0 0 000000 f<ÿ<f~ @`0 6cckkcc6~>c`0 c>c``<```c>08<63000x?```c>?cccc>c``0 >ccc>cccc>>ccc~```0 `0  0`~~ 0`0 >cc0>cc{{{;>6cccccc?fff>ffff?<fCCf<6ffffff6fFFffF<fC{ccf\ccccccccc<<x00000333gff66ffgFfcwkccccccgo{scccc>cccccccc>?fff>>cccccck{>0p?fff>6fffg>cc0`cc>~~Z<ccccccccc>ccccccc6cccckkkw6cc6>>6ccffff<<ca0 Cc< <8p`@<00000000<6cÿ 0>333n6ffff>>cc>800<63333n>cc>6&n33333>036nffffg<``p``````ff<f66fg<7kkkkc;ffffff>ccccc>;fffff>n33333>00x;nf>c0c> ? l8333333nfffff<cckkk6c66ccccccc~`03 cpppn;6ccc<fCCf<0`>3333333n0 >cc>60>333n30>333n 0>333n60>333n<ff<0`<6>cc>c>cc> >cc>f<<f< <c6ccccc66ccccc f>f3nl~v|6333333s6>ccccc>c>ccccc> >ccccc> 3333333n 333333nccccccc~`0c>ccccccc>ccccccccc><ff<6&g?ff<~~33#3{333cpØ~ 0>333n0 < >ccccc> 333333nn;;ffffffn;cgo{sccc<66|~66> cc>````Cc3 ;a0|Cc3 fsy|``<<<l66l6l6ˆ"ˆ"ˆ"ˆ"ˆ"ˆ"ˆ"ˆ"ªUªUªUªUªUªUªUªU»î»î»î»î»î»î»î»îlllllllolllllllllllllllllllllo`ollllllllllllllllllllllll`olllllllllllllo`llllllløÿÿøÿÿøølllllllìlllllllllllllì üü ìlllllllllllllïÿÿïlllllllllllllì ìllllllllÿÿlllllïïllllllllÿÿlllllllÿÿÿÿlllllllllllllllüøøøøülllllllllllllllÿllllllllÿÿøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿððððððððððððððððÿÿÿÿÿÿÿn;;n3333ccc3cc6666666c  c~fffff>n;~<fff<~6cccc66ccc6666wx 0|ffff<~ÛÛÛ~À`~ÛÛÏ~8 > 8>cccccccc~ÿ 0`0 ~0  0~pØØ~n;n;66ð00000766<866666 >>>>>>>€‡ˆ‰€€ˆˆŠ€€ˆˆŠ€€‡ˆˆ€€‡ˆˆ€ˆˆ‰€€ˆˆ‰€‚†ˆ†~€ˆˆŒ„‡ˆ‡€ˆˆŒ„€‡ˆŠ€‡ˆŠ€€ˆˆŠ€€ˆˆŠ€ˆˆ‰€€‡ˆ‹€€‡ˆ‹€‡ˆŠ‡ˆŠ€€ˆˆŠ€€‡ˆ‹€‡ˆ„€‡ˆŠ€‡ˆŠ€‡ˆŠ€€‡ˆ‡~€‡ˆ‡~€‡ˆ†~€‡ˆ‡~€‡ˆˆ€‡ˆˆ€€ˆ€€‚†ˆŠ€‡ˆ‹y€‡ˆ‰€€‡ˆŒ‚€‡ˆˆ€€‡ˆŠ€„ˆ‹y‚†ˆŠ€‚†ˆŠ€€ˆˆ‡~‡ˆ‡~‚…ˆƒ€‡ˆ…|ƒ…ˆ‚€€‡ˆˆ€€‡ˆŠ€‡ˆŠ€€‡ˆŠ€€‡ˆŠ€€‡ˆŠ€€‡ˆŠ€€‡ˆŠ€€‡ˆŠ€€‡ˆŠ€€‡ˆŠ€ƒ…ˆˆ‚…ˆˆ€‡ˆ‰€‡ˆ‡}‡ˆ‰€€‡ˆŠ€€‡ˆ‰€€‡ˆŠ€€‡ˆŠ€€‡ˆŠ€€‡ˆŠ€€‡ˆŠ€€‡ˆŠ€€‡ˆŠ€€‡ˆŠ€‚†ˆŠ€€‡ˆŠ€€‡ˆŠ€€‡ˆŠ€€‡ˆŠ€€‡ˆŠ€€‡ˆŠ€€‡ˆŠ€€‡ˆŠ‚€‡ˆŠ€€‡ˆŠ€‡ˆŠ€€‡ˆŠ€€‡ˆŠ€€‡ˆŠ€€‡ˆŠ€‡ˆŠ€€‡ˆŠ€‚†ˆŠ€€‡ˆ‰€‚†ˆŠ€€‡ˆŒx€ˆˆ‚‚…ˆŒw€‡ˆ‡€€‡ˆŠ€€‡ˆ‡€€‡ˆŠ€€‡ˆ‡€€†ˆŠ€€‡ˆ‡ƒ€‡ˆŠ€‚†ˆŠ€‡ˆŠƒ€‡ˆŠ€‚†ˆŠ€€‡ˆ‡€€‡ˆ‡€€‡ˆ‡€€‡ˆ‡ƒ€‡ˆ‡ƒ€‡ˆ‡€€‡ˆ‡€€‡ˆŠ€€‡ˆ‡€‡ˆ‡€€‡ˆ‡€€‡ˆ‡€€‡ˆ‡ƒ€‡ˆ‡€‡ˆŠ€ƒ…ˆŠ€‡ˆŠ€€‡ˆŠx€‡ˆˆ€‡ˆŠ‚€‡ˆŠ€€‡ˆ‹€€‡ˆ‹€€‡ˆŠ€€‡ˆ‹€€‡ˆ‹€‡ˆˆ€‡ˆ‹€€‡ˆŠ€€‡ˆ‹€‡ˆŠ€‡ˆ‹€†ˆ‹€€‡ˆ‹€€‡ˆŒ€€‡ˆŒ€€‡ˆ‡€€‡ˆŠ€€‡ˆ‹€€‡ˆŠ€€‡ˆ‹€€‡ˆ‹€€‡ˆ‹€€‡ˆŠƒ€‡ˆ‹€€‡ˆ‹€‡ˆ‹€€‡ˆ‹€‡ˆŠ€€‡ˆ‹€€ˆˆ‹‚€‡ˆ‹€‚†ˆ‹€€‡ˆ‹€€‡ˆ‹€€‡ˆŠ€€‡ˆŒ€‡ˆ‹{†ˆ‹{€‡ˆŠ€€‡ˆ†€‡ˆ†€‡ˆ‹‚€‡ˆ‹‚‚†ˆŠ€€‡ˆ‡~€‡ˆ‡~ˆˆŒ„€ˆˆŒ„€ˆˆŒ„ƒ…ˆŒ„€…ˆŒ„€…ˆŒ„€‡ˆŒ„€‡ˆ…„€…ˆ‡„€‡ˆŒ„‚‡ˆŒ„€‡ˆ‡„€‡ˆŒ|€‡ˆŒ|€…ˆŒ|€…ˆ…„ƒˆˆŒ|€ˆˆŒ|€ˆˆ…„ƒˆˆŒ„€ˆˆ…|€ˆˆŒ„ƒˆˆŒ„‚ˆˆŒ„‚ˆˆŒ|‚ˆˆ‡„€ˆˆŒ|€ˆˆ‡„‚ˆˆŒ„€ˆˆ‡|€ˆˆŒ„€ˆˆŒ|€ˆˆŒ|€ˆˆ‡„€ˆˆ…„‚ˆˆŒ|ƒˆˆŒ|ƒˆˆ‡„‚ˆˆ…„€ˆˆŒ„€ˆˆŒ„€…ˆŒ|ƒˆˆ…„€ˆˆŒ„€ˆˆ…„€„ˆŒ„„ˆˆŒ„€ˆˆŒ{€‡ˆ‡€€‡ˆŠ€€‡ˆŠ€€‡ˆˆ€€‡ˆ‰€€‡ˆ‡€€‡ˆˆ€‡ˆˆ€‡ˆ‰€€‡ˆ‰€€‡ˆŠ€‡ˆŠ€€ˆˆ‡~€ˆˆ‰€†ˆŠ€€‡ˆ‰€€‡ˆˆ€ˆˆˆ€‡ˆ‰€‡ˆ‰€ƒˆˆŠ„€…ˆŒ€‡ˆˆ€‡ˆ‡~†ˆ‹yƒ…ˆ…}ƒ…ˆ„}€ˆˆ‹€€†ˆ‹{€…ˆ‹{†ˆˆ€€ˆ€€ÿ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿšššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššššš $*06<BHNTZ`flrx~„Š–œ¢¨®´ºÀÆÌÒØÞäêðöü &,28>DJPV\bhntz€†Œ’˜ž¤ª°¶¼ÂÈÎÔÚàæìòøþ "(.4:@FLRX^djpv|‚ˆŽ”𠦬²¸¾ÄÊÐÖÜâèîôú $*06<BHNTZ`flrx~„Š–œ¢¨®´ºÀÆÌÒØÞäêðöü &,28>DJPV\bhntz€†Œ’˜ž¤ª°¶¼ÂÈÎÔÚàæìòøþ "(.4:@FLRX^djpv|‚ˆŽ”𠦬²¸¾ÄÊÐÖÜâèîôúC0000C0001C0002C0003C0004C0005C0006C0007C0008C0009C000aC000bC000cC000dC000eC000fC0010C0011C0012C0013C0014C0015C0016C0017C0018C0019C001aC001bC001cC001dC001eC001fC0020C0021C0022C0023C0024C0025C0026C0027C0028C0029C002aC002bC002cC002dC002eC002fC0030C0031C0032C0033C0034C0035C0036C0037C0038C0039C003aC003bC003cC003dC003eC003fC0040C0041C0042C0043C0044C0045C0046C0047C0048C0049C004aC004bC004cC004dC004eC004fC0050C0051C0052C0053C0054C0055C0056C0057C0058C0059C005aC005bC005cC005dC005eC005fC0060C0061C0062C0063C0064C0065C0066C0067C0068C0069C006aC006bC006cC006dC006eC006fC0070C0071C0072C0073C0074C0075C0076C0077C0078C0079C007aC007bC007cC007dC007eC007fC0080C0081C0082C0083C0084C0085C0086C0087C0088C0089C008aC008bC008cC008dC008eC008fC0090C0091C0092C0093C0094C0095C0096C0097C0098C0099C009aC009bC009cC009dC009eC009fC00a0C00a1C00a2C00a3C00a4C00a5C00a6C00a7C00a8C00a9C00aaC00abC00acC00adC00aeC00afC00b0C00b1C00b2C00b3C00b4C00b5C00b6C00b7C00b8C00b9C00baC00bbC00bcC00bdC00beC00bfC00c0C00c1C00c2C00c3C00c4C00c5C00c6C00c7C00c8C00c9C00caC00cbC00ccC00cdC00ceC00cfC00d0C00d1C00d2C00d3C00d4C00d5C00d6C00d7C00d8C00d9C00daC00dbC00dcC00ddC00deC00dfC00e0C00e1C00e2C00e3C00e4C00e5C00e6C00e7C00e8C00e9C00eaC00ebC00ecC00edC00eeC00efC00f0C00f1C00f2C00f3C00f4C00f5C00f6C00f7C00f8C00f9C00faC00fbC00fcC00fdC00feC00ff   ÿÿ÷ÿ vfu-4.10/extra/Xdefaults0000644000175000001440000000037411172606420014061 0ustar cadeusersRxvt*font: vga Rxvt*boldFont: vga Rxvt*saveLines: 500 Rxvt*foreground: #cccccc Rxvt*background: #444444 Rxvt*cursorColor: green Rxvt*scrollBar: False Rxvt*title: Term Rxvt*keysym.16: "\b" Rxvt*keysym.6f: "^?" Rxvt*backspacekey: ^H Rxvt*modifier: mod1 vfu-4.10/vfu.10000644000175000001440000001734711172611246011750 0ustar cadeusers.\" Automatically generated by Pod::Man version 1.15 .\" Mon Apr 28 20:27:08 2003 .\" .\" Standard preamble: .\" ====================================================================== .de Sh \" Subsection heading .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. | will give a .\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used .\" to do unbreakable dashes and therefore won't be available. \*(C` and .\" \*(C' expand to `' in nroff, nothing in troff, for use with C<> .tr \(*W-|\(bv\*(Tr .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' 'br\} .\" .\" If the F register is turned on, we'll generate index entries on stderr .\" for titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and .\" index entries marked with X<> in POD. Of course, you'll have to process .\" the output yourself in some meaningful fashion. .if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .\" .\" For nroff, turn off justification. Always turn off hyphenation; it .\" makes way too many mistakes in technical documents. .hy 0 .if n .na .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. .bd B 3 . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ====================================================================== .\" .IX Title "VFU 1" .TH VFU 1 "Version 4.00" "2002-11-27" "VFU File Manager" .UC .SH "NAME" vfu \- \s-1VFU\s0 is console (text-mode) file manager for UNIX/Linux .SH "SYNOPSIS" .IX Header "SYNOPSIS" vfu [options] .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\fBvfu\fR has following features: .PP .Vb 11 \& - Fast one-key commands \& - Extended completition and wildcard expansion \& - Directory tree with sizes (incl. sizes cache) \& - File-type colorization (extension and type) \& - Archives support (TAR, TGZ, BZ2, and many more) \& - Simple FTP support through archive-like interface \& - Internal text/hex file viewer and editor (optional) \& - Extensive user-defined external support/utils \& - Regular expressions selection and search \& - Multiple file masks \& - and much more... .Ve .SH "OPTIONS" .IX Header "OPTIONS" .Vb 2 \& -h \&prints help for command line options .Ve .Vb 2 \& -i \&runs vfu in interactive mode (can be used with \e-d) .Ve .Vb 2 \& -d path \&changes working directory to `path' .Ve .Vb 2 \& -r \&rebuild directory tree .Ve .Vb 2 \& -t \&view directory tree only .Ve These options are for using vfu in partial non-interactive mode. .PP .Vb 1 \& example: vfu -d /usr/local -i .Ve .SH "CONFIGURATION" .IX Header "CONFIGURATION" \&\fBvfu\fR configuration is divided in two parts (files): .PP \&\fBvfu.conf\fR .PP This file contains configuration for external editor and pager, favorite directories, file-type colorization. This is plain text file which format is described below. vfu only reads vfu.conf, it never writes in it! .PP \&\fBvfu.options\fR .PP This file contains all Options/Toggles which can be changed from inside vfu \*(-- Options menu. vfu.options is binary file and is overwritten on vfu exit or on change option event! Deleting this file will reset vfu toggles to default values. vfu.options is not portable between vfu versions! .Sh "Location of vfu.conf" .IX Subsection "Location of vfu.conf" \&\fBvfu.conf\fR can be placed as any of: .PP .Vb 1 \& $HOME/.vfu/vfu.conf .Ve .Vb 1 \& $HOME/$RC_PREFIX/vfu/vfu.conf (if $RC_PREFIX is exported) .Ve .Vb 1 \& /etc/vfu.conf .Ve .Vb 1 \& /usr/local/etc/vfu.conf .Ve .Vb 1 \& /usr/local/vfu.conf .Ve .Sh "Other files location" .IX Subsection "Other files location" All other files including vfu.options are placed in: .PP .Vb 1 \& $HOME/.vfu/ .Ve .Vb 1 \& $HOME/$RC_PREFIX/vfu/ .Ve What is \fB\f(CB\*(C`$RC_PREFIX\*(C'\fB\fR and why to use it? Some more information for this can be found in the \fB\s-1CONFIG\s0\fR file which is supplied with \&\fBvfu\fR package. .SH "VFU.CONF" .IX Header "VFU.CONF" This is a sample copy of vfu.conf with appropriate comments: .SH "DISTRIBUTION" .IX Header "DISTRIBUTION" It is supposed that only source packages will be distributed. However sometimes binary packages will be released, but not often. \&\s-1VFU\s0 packages are named in this way: .PP .Vb 1 \& vfu-X.xx.src.tgz .Ve source package for version X.xx .PP .Vb 1 \& vfu-X.xx.bin.platform.tgz .Ve binary package for version X.xx for `platform' platform .PP examples: .PP .Vb 1 \& vfu-4.00.src.tgz .Ve .Vb 1 \& vfu-4.00.bin.linux.glibc.tgz .Ve .Vb 1 \& vfu-4.00.bin.linux.libc5.tgz .Ve .Vb 1 \& vfu-4.00.bin.dos.tgz .Ve All packages are \s-1TAR+GZIP\s0 .tgz, bz2 and zip are available on request. .PP \&\fB\s-1NOTE\s0\fR: Always check \s-1HISTORY\s0 document \*(-- it often contains some usefull notes! .SH "FILES" .IX Header "FILES" .Vb 1 \& $HOME/$RC_PREFIX/vfu/vfu.conf .Ve configuration, explained above .PP .Vb 1 \& $HOME/$RC_PREFIX/vfu/vfu.options .Ve options, explained above .PP .Vb 1 \& $HOME/$RC_PREFIX/vfu/vfu.history .Ve contains history lines .PP .Vb 1 \& $HOME/$RC_PREFIX/vfu/vfu.tree .Ve contains directory tree .PP If you don't set \f(CW$RC_PREFIX\fR configuration files are: .PP .Vb 4 \& $HOME/.vfu/vfu.conf \& $HOME/.vfu/vfu.options \& $HOME/.vfu/vfu.history \& $HOME/.vfu/vfu.tree .Ve .SH "TODO" .IX Header "TODO" see the \s-1TODO\s0 file .SH "BUGS" .IX Header "BUGS" unknown .SH "AUTHOR" .IX Header "AUTHOR" .Vb 4 \& Vladi Belperchinov-Shabanski "Cade" \& \& http://cade.datamax.bg/ \& http://cade.datamax.bg/vfu/ .Ve vfu-4.10/vslib/0000755000175000001440000000000011312262432012164 5ustar cadeusersvfu-4.10/vslib/pcre/0000755000175000001440000000000011231160251013111 5ustar cadeusersvfu-4.10/vslib/pcre/internal.h0000644000175000001440000003771011005727400015112 0ustar cadeusers/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* This is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. See the file Tech.Notes for some information on the internals. Written by: Philip Hazel Copyright (c) 1997-2001 University of Cambridge ----------------------------------------------------------------------------- Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: 1. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. If PCRE is embedded in any software that is released under the GNU General Purpose Licence (GPL), then the terms of that licence shall supersede any condition above with which it is incompatible. ----------------------------------------------------------------------------- */ /* This header contains definitions that are shared between the different modules, but which are not relevant to the outside. */ /* Get the definitions provided by running "configure" */ #include "config.h" /* To cope with SunOS4 and other systems that lack memmove() but have bcopy(), define a macro for memmove() if HAVE_MEMMOVE is false, provided that HAVE_BCOPY is set. Otherwise, include an emulating function for those systems that have neither (there some non-Unix environments where this is the case). This assumes that all calls to memmove are moving strings upwards in store, which is the case in PCRE. */ #if ! HAVE_MEMMOVE #undef memmove /* some systems may have a macro */ #if HAVE_BCOPY #define memmove(a, b, c) bcopy(b, a, c) #else void * pcre_memmove(unsigned char *dest, const unsigned char *src, size_t n) { int i; dest += n; src += n; for (i = 0; i < n; ++i) *(--dest) = *(--src); } #define memmove(a, b, c) pcre_memmove(a, b, c) #endif #endif /* Standard C headers plus the external interface definition */ #include #include #include #include #include #include #include "pcre.h" /* In case there is no definition of offsetof() provided - though any proper Standard C system should have one. */ #ifndef offsetof #define offsetof(p_type,field) ((size_t)&(((p_type *)0)->field)) #endif /* These are the public options that can change during matching. */ #define PCRE_IMS (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL) /* Private options flags start at the most significant end of the four bytes, but skip the top bit so we can use ints for convenience without getting tangled with negative values. The public options defined in pcre.h start at the least significant end. Make sure they don't overlap, though now that we have expanded to four bytes there is plenty of space. */ #define PCRE_FIRSTSET 0x40000000 /* first_char is set */ #define PCRE_REQCHSET 0x20000000 /* req_char is set */ #define PCRE_STARTLINE 0x10000000 /* start after \n for multiline */ #define PCRE_INGROUP 0x08000000 /* compiling inside a group */ #define PCRE_ICHANGED 0x04000000 /* i option changes within regex */ /* Options for the "extra" block produced by pcre_study(). */ #define PCRE_STUDY_MAPPED 0x01 /* a map of starting chars exists */ /* Masks for identifying the public options which are permitted at compile time, run time or study time, respectively. */ #define PUBLIC_OPTIONS \ (PCRE_CASELESS|PCRE_EXTENDED|PCRE_ANCHORED|PCRE_MULTILINE| \ PCRE_DOTALL|PCRE_DOLLAR_ENDONLY|PCRE_EXTRA|PCRE_UNGREEDY|PCRE_UTF8) #define PUBLIC_EXEC_OPTIONS \ (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY) #define PUBLIC_STUDY_OPTIONS 0 /* None defined */ /* Magic number to provide a small check against being handed junk. */ #define MAGIC_NUMBER 0x50435245UL /* 'PCRE' */ /* Miscellaneous definitions */ typedef int BOOL; #define FALSE 0 #define TRUE 1 /* Escape items that are just an encoding of a particular data value. Note that ESC_N is defined as yet another macro, which is set in config.h to either \n (the default) or \r (which some people want). */ #ifndef ESC_E #define ESC_E 27 #endif #ifndef ESC_F #define ESC_F '\f' #endif #ifndef ESC_N #define ESC_N NEWLINE #endif #ifndef ESC_R #define ESC_R '\r' #endif #ifndef ESC_T #define ESC_T '\t' #endif /* These are escaped items that aren't just an encoding of a particular data value such as \n. They must have non-zero values, as check_escape() returns their negation. Also, they must appear in the same order as in the opcode definitions below, up to ESC_z. The final one must be ESC_REF as subsequent values are used for \1, \2, \3, etc. There is a test in the code for an escape greater than ESC_b and less than ESC_Z to detect the types that may be repeated. If any new escapes are put in-between that don't consume a character, that code will have to change. */ enum { ESC_A = 1, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_W, ESC_w, ESC_Z, ESC_z, ESC_REF }; /* Opcode table: OP_BRA must be last, as all values >= it are used for brackets that extract substrings. Starting from 1 (i.e. after OP_END), the values up to OP_EOD must correspond in order to the list of escapes immediately above. */ enum { OP_END, /* End of pattern */ /* Values corresponding to backslashed metacharacters */ OP_SOD, /* Start of data: \A */ OP_NOT_WORD_BOUNDARY, /* \B */ OP_WORD_BOUNDARY, /* \b */ OP_NOT_DIGIT, /* \D */ OP_DIGIT, /* \d */ OP_NOT_WHITESPACE, /* \S */ OP_WHITESPACE, /* \s */ OP_NOT_WORDCHAR, /* \W */ OP_WORDCHAR, /* \w */ OP_EODN, /* End of data or \n at end of data: \Z. */ OP_EOD, /* End of data: \z */ OP_OPT, /* Set runtime options */ OP_CIRC, /* Start of line - varies with multiline switch */ OP_DOLL, /* End of line - varies with multiline switch */ OP_ANY, /* Match any character */ OP_CHARS, /* Match string of characters */ OP_NOT, /* Match anything but the following char */ OP_STAR, /* The maximizing and minimizing versions of */ OP_MINSTAR, /* all these opcodes must come in pairs, with */ OP_PLUS, /* the minimizing one second. */ OP_MINPLUS, /* This first set applies to single characters */ OP_QUERY, OP_MINQUERY, OP_UPTO, /* From 0 to n matches */ OP_MINUPTO, OP_EXACT, /* Exactly n matches */ OP_NOTSTAR, /* The maximizing and minimizing versions of */ OP_NOTMINSTAR, /* all these opcodes must come in pairs, with */ OP_NOTPLUS, /* the minimizing one second. */ OP_NOTMINPLUS, /* This first set applies to "not" single characters */ OP_NOTQUERY, OP_NOTMINQUERY, OP_NOTUPTO, /* From 0 to n matches */ OP_NOTMINUPTO, OP_NOTEXACT, /* Exactly n matches */ OP_TYPESTAR, /* The maximizing and minimizing versions of */ OP_TYPEMINSTAR, /* all these opcodes must come in pairs, with */ OP_TYPEPLUS, /* the minimizing one second. These codes must */ OP_TYPEMINPLUS, /* be in exactly the same order as those above. */ OP_TYPEQUERY, /* This set applies to character types such as \d */ OP_TYPEMINQUERY, OP_TYPEUPTO, /* From 0 to n matches */ OP_TYPEMINUPTO, OP_TYPEEXACT, /* Exactly n matches */ OP_CRSTAR, /* The maximizing and minimizing versions of */ OP_CRMINSTAR, /* all these opcodes must come in pairs, with */ OP_CRPLUS, /* the minimizing one second. These codes must */ OP_CRMINPLUS, /* be in exactly the same order as those above. */ OP_CRQUERY, /* These are for character classes and back refs */ OP_CRMINQUERY, OP_CRRANGE, /* These are different to the three seta above. */ OP_CRMINRANGE, OP_CLASS, /* Match a character class */ OP_REF, /* Match a back reference */ OP_RECURSE, /* Match this pattern recursively */ OP_ALT, /* Start of alternation */ OP_KET, /* End of group that doesn't have an unbounded repeat */ OP_KETRMAX, /* These two must remain together and in this */ OP_KETRMIN, /* order. They are for groups the repeat for ever. */ /* The assertions must come before ONCE and COND */ OP_ASSERT, /* Positive lookahead */ OP_ASSERT_NOT, /* Negative lookahead */ OP_ASSERTBACK, /* Positive lookbehind */ OP_ASSERTBACK_NOT, /* Negative lookbehind */ OP_REVERSE, /* Move pointer back - used in lookbehind assertions */ /* ONCE and COND must come after the assertions, with ONCE first, as there's a test for >= ONCE for a subpattern that isn't an assertion. */ OP_ONCE, /* Once matched, don't back up into the subpattern */ OP_COND, /* Conditional group */ OP_CREF, /* Used to hold an extraction string number (cond ref) */ OP_BRAZERO, /* These two must remain together and in this */ OP_BRAMINZERO, /* order. */ OP_BRANUMBER, /* Used for extracting brackets whose number is greater than can fit into an opcode. */ OP_BRA /* This and greater values are used for brackets that extract substrings up to a basic limit. After that, use is made of OP_BRANUMBER. */ }; /* The highest extraction number before we have to start using additional bytes. (Originally PCRE didn't have support for extraction counts highter than this number.) The value is limited by the number of opcodes left after OP_BRA, i.e. 255 - OP_BRA. We actually set it a bit lower to leave room for additional opcodes. */ #define EXTRACT_BASIC_MAX 150 /* The texts of compile-time error messages are defined as macros here so that they can be accessed by the POSIX wrapper and converted into error codes. Yes, I could have used error codes in the first place, but didn't feel like changing just to accommodate the POSIX wrapper. */ #define ERR1 "\\ at end of pattern" #define ERR2 "\\c at end of pattern" #define ERR3 "unrecognized character follows \\" #define ERR4 "numbers out of order in {} quantifier" #define ERR5 "number too big in {} quantifier" #define ERR6 "missing terminating ] for character class" #define ERR7 "invalid escape sequence in character class" #define ERR8 "range out of order in character class" #define ERR9 "nothing to repeat" #define ERR10 "operand of unlimited repeat could match the empty string" #define ERR11 "internal error: unexpected repeat" #define ERR12 "unrecognized character after (?" #define ERR13 "unused error" #define ERR14 "missing )" #define ERR15 "back reference to non-existent subpattern" #define ERR16 "erroffset passed as NULL" #define ERR17 "unknown option bit(s) set" #define ERR18 "missing ) after comment" #define ERR19 "parentheses nested too deeply" #define ERR20 "regular expression too large" #define ERR21 "failed to get memory" #define ERR22 "unmatched parentheses" #define ERR23 "internal error: code overflow" #define ERR24 "unrecognized character after (?<" #define ERR25 "lookbehind assertion is not fixed length" #define ERR26 "malformed number after (?(" #define ERR27 "conditional group contains more than two branches" #define ERR28 "assertion expected after (?(" #define ERR29 "(?p must be followed by )" #define ERR30 "unknown POSIX class name" #define ERR31 "POSIX collating elements are not supported" #define ERR32 "this version of PCRE is not compiled with PCRE_UTF8 support" #define ERR33 "characters with values > 255 are not yet supported in classes" #define ERR34 "character value in \\x{...} sequence is too large" #define ERR35 "invalid condition (?(0)" /* All character handling must be done as unsigned characters. Otherwise there are problems with top-bit-set characters and functions such as isspace(). However, we leave the interface to the outside world as char *, because that should make things easier for callers. We define a short type for unsigned char to save lots of typing. I tried "uchar", but it causes problems on Digital Unix, where it is defined in sys/types, so use "uschar" instead. */ typedef unsigned char uschar; /* The real format of the start of the pcre block; the actual code vector runs on as long as necessary after the end. */ typedef struct real_pcre { unsigned long int magic_number; size_t size; const unsigned char *tables; unsigned long int options; unsigned short int top_bracket; unsigned short int top_backref; uschar first_char; uschar req_char; uschar code[1]; } real_pcre; /* The real format of the extra block returned by pcre_study(). */ typedef struct real_pcre_extra { uschar options; uschar start_bits[32]; } real_pcre_extra; /* Structure for passing "static" information around between the functions doing the compiling, so that they are thread-safe. */ typedef struct compile_data { const uschar *lcc; /* Points to lower casing table */ const uschar *fcc; /* Points to case-flipping table */ const uschar *cbits; /* Points to character type table */ const uschar *ctypes; /* Points to table of type maps */ } compile_data; /* Structure for passing "static" information around between the functions doing the matching, so that they are thread-safe. */ typedef struct match_data { int errorcode; /* As it says */ int *offset_vector; /* Offset vector */ int offset_end; /* One past the end */ int offset_max; /* The maximum usable for return data */ const uschar *lcc; /* Points to lower casing table */ const uschar *ctypes; /* Points to table of type maps */ BOOL offset_overflow; /* Set if too many extractions */ BOOL notbol; /* NOTBOL flag */ BOOL noteol; /* NOTEOL flag */ BOOL utf8; /* UTF8 flag */ BOOL endonly; /* Dollar not before final \n */ BOOL notempty; /* Empty string match not wanted */ const uschar *start_pattern; /* For use when recursing */ const uschar *start_subject; /* Start of the subject string */ const uschar *end_subject; /* End of the subject string */ const uschar *start_match; /* Start of this match attempt */ const uschar *end_match_ptr; /* Subject position at end match */ int end_offset_top; /* Highwater mark at end of match */ } match_data; /* Bit definitions for entries in the pcre_ctypes table. */ #define ctype_space 0x01 #define ctype_letter 0x02 #define ctype_digit 0x04 #define ctype_xdigit 0x08 #define ctype_word 0x10 /* alphameric or '_' */ #define ctype_meta 0x80 /* regexp meta char or zero (end pattern) */ /* Offsets for the bitmap tables in pcre_cbits. Each table contains a set of bits for a class map. Some classes are built by combining these tables. */ #define cbit_space 0 /* [:space:] or \s */ #define cbit_xdigit 32 /* [:xdigit:] */ #define cbit_digit 64 /* [:digit:] or \d */ #define cbit_upper 96 /* [:upper:] */ #define cbit_lower 128 /* [:lower:] */ #define cbit_word 160 /* [:word:] or \w */ #define cbit_graph 192 /* [:graph:] */ #define cbit_print 224 /* [:print:] */ #define cbit_punct 256 /* [:punct:] */ #define cbit_cntrl 288 /* [:cntrl:] */ #define cbit_length 320 /* Length of the cbits table */ /* Offsets of the various tables from the base tables pointer, and total length. */ #define lcc_offset 0 #define fcc_offset 256 #define cbits_offset 512 #define ctypes_offset (cbits_offset + cbit_length) #define tables_length (ctypes_offset + 256) /* End of internal.h */ vfu-4.10/vslib/pcre/pcreposix.c0000644000175000001440000002162511005727400015303 0ustar cadeusers/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* This is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. See the file Tech.Notes for some information on the internals. This module is a wrapper that provides a POSIX API to the underlying PCRE functions. Written by: Philip Hazel Copyright (c) 1997-2001 University of Cambridge ----------------------------------------------------------------------------- Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: 1. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. If PCRE is embedded in any software that is released under the GNU General Purpose Licence (GPL), then the terms of that licence shall supersede any condition above with which it is incompatible. ----------------------------------------------------------------------------- */ #include "internal.h" #include "pcreposix.h" #include "stdlib.h" /* Corresponding tables of PCRE error messages and POSIX error codes. */ static const char *estring[] = { ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, ERR10, ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17, ERR18, ERR19, ERR20, ERR21, ERR22, ERR23, ERR24, ERR25, ERR26, ERR27, ERR29, ERR29, ERR30, ERR31 }; static int eint[] = { REG_EESCAPE, /* "\\ at end of pattern" */ REG_EESCAPE, /* "\\c at end of pattern" */ REG_EESCAPE, /* "unrecognized character follows \\" */ REG_BADBR, /* "numbers out of order in {} quantifier" */ REG_BADBR, /* "number too big in {} quantifier" */ REG_EBRACK, /* "missing terminating ] for character class" */ REG_ECTYPE, /* "invalid escape sequence in character class" */ REG_ERANGE, /* "range out of order in character class" */ REG_BADRPT, /* "nothing to repeat" */ REG_BADRPT, /* "operand of unlimited repeat could match the empty string" */ REG_ASSERT, /* "internal error: unexpected repeat" */ REG_BADPAT, /* "unrecognized character after (?" */ REG_ASSERT, /* "unused error" */ REG_EPAREN, /* "missing )" */ REG_ESUBREG, /* "back reference to non-existent subpattern" */ REG_INVARG, /* "erroffset passed as NULL" */ REG_INVARG, /* "unknown option bit(s) set" */ REG_EPAREN, /* "missing ) after comment" */ REG_ESIZE, /* "parentheses nested too deeply" */ REG_ESIZE, /* "regular expression too large" */ REG_ESPACE, /* "failed to get memory" */ REG_EPAREN, /* "unmatched brackets" */ REG_ASSERT, /* "internal error: code overflow" */ REG_BADPAT, /* "unrecognized character after (?<" */ REG_BADPAT, /* "lookbehind assertion is not fixed length" */ REG_BADPAT, /* "malformed number after (?(" */ REG_BADPAT, /* "conditional group containe more than two branches" */ REG_BADPAT, /* "assertion expected after (?(" */ REG_BADPAT, /* "(?p must be followed by )" */ REG_ECTYPE, /* "unknown POSIX class name" */ REG_BADPAT, /* "POSIX collating elements are not supported" */ REG_INVARG, /* "this version of PCRE is not compiled with PCRE_UTF8 support" */ REG_BADPAT, /* "characters with values > 255 are not yet supported in classes" */ REG_BADPAT, /* "character value in \x{...} sequence is too large" */ REG_BADPAT /* "invalid condition (?(0)" */ }; /* Table of texts corresponding to POSIX error codes */ static const char *pstring[] = { "", /* Dummy for value 0 */ "internal error", /* REG_ASSERT */ "invalid repeat counts in {}", /* BADBR */ "pattern error", /* BADPAT */ "? * + invalid", /* BADRPT */ "unbalanced {}", /* EBRACE */ "unbalanced []", /* EBRACK */ "collation error - not relevant", /* ECOLLATE */ "bad class", /* ECTYPE */ "bad escape sequence", /* EESCAPE */ "empty expression", /* EMPTY */ "unbalanced ()", /* EPAREN */ "bad range inside []", /* ERANGE */ "expression too big", /* ESIZE */ "failed to get memory", /* ESPACE */ "bad back reference", /* ESUBREG */ "bad argument", /* INVARG */ "match failed" /* NOMATCH */ }; /************************************************* * Translate PCRE text code to int * *************************************************/ /* PCRE compile-time errors are given as strings defined as macros. We can just look them up in a table to turn them into POSIX-style error codes. */ static int pcre_posix_error_code(const char *s) { size_t i; for (i = 0; i < sizeof(estring)/sizeof(char *); i++) if (strcmp(s, estring[i]) == 0) return eint[i]; return REG_ASSERT; } /************************************************* * Translate error code to string * *************************************************/ size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size) { const char *message, *addmessage; size_t length, addlength; message = (errcode >= (int)(sizeof(pstring)/sizeof(char *)))? "unknown error code" : pstring[errcode]; length = strlen(message) + 1; addmessage = " at offset "; addlength = (preg != NULL && (int)preg->re_erroffset != -1)? strlen(addmessage) + 6 : 0; if (errbuf_size > 0) { if (addlength > 0 && errbuf_size >= length + addlength) sprintf(errbuf, "%s%s%-6d", message, addmessage, (int)preg->re_erroffset); else { strncpy(errbuf, message, errbuf_size - 1); errbuf[errbuf_size-1] = 0; } } return length + addlength; } /************************************************* * Free store held by a regex * *************************************************/ void regfree(regex_t *preg) { (pcre_free)(preg->re_pcre); } /************************************************* * Compile a regular expression * *************************************************/ /* Arguments: preg points to a structure for recording the compiled expression pattern the pattern to compile cflags compilation flags Returns: 0 on success various non-zero codes on failure */ int regcomp(regex_t *preg, const char *pattern, int cflags) { const char *errorptr; int erroffset; int options = 0; if ((cflags & REG_ICASE) != 0) options |= PCRE_CASELESS; if ((cflags & REG_NEWLINE) != 0) options |= PCRE_MULTILINE; preg->re_pcre = pcre_compile(pattern, options, &errorptr, &erroffset, NULL); preg->re_erroffset = erroffset; if (preg->re_pcre == NULL) return pcre_posix_error_code(errorptr); preg->re_nsub = pcre_info(preg->re_pcre, NULL, NULL); return 0; } /************************************************* * Match a regular expression * *************************************************/ /* Unfortunately, PCRE requires 3 ints of working space for each captured substring, so we have to get and release working store instead of just using the POSIX structures as was done in earlier releases when PCRE needed only 2 ints. */ int regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags) { int rc; int options = 0; int *ovector = NULL; if ((eflags & REG_NOTBOL) != 0) options |= PCRE_NOTBOL; if ((eflags & REG_NOTEOL) != 0) options |= PCRE_NOTEOL; preg->re_erroffset = (size_t)(-1); /* Only has meaning after compile */ if (nmatch > 0) { ovector = (int *)malloc(sizeof(int) * nmatch * 3); if (ovector == NULL) return REG_ESPACE; } rc = pcre_exec(preg->re_pcre, NULL, string, (int)strlen(string), 0, options, ovector, nmatch * 3); if (rc == 0) rc = nmatch; /* All captured slots were filled in */ if (rc >= 0) { size_t i; for (i = 0; i < rc; i++) { pmatch[i].rm_so = ovector[i*2]; pmatch[i].rm_eo = ovector[i*2+1]; } if (ovector != NULL) free(ovector); for (; i < nmatch; i++) pmatch[i].rm_so = pmatch[i].rm_eo = -1; return 0; } else { if (ovector != NULL) free(ovector); switch(rc) { case PCRE_ERROR_NOMATCH: return REG_NOMATCH; case PCRE_ERROR_NULL: return REG_INVARG; case PCRE_ERROR_BADOPTION: return REG_INVARG; case PCRE_ERROR_BADMAGIC: return REG_INVARG; case PCRE_ERROR_UNKNOWN_NODE: return REG_ASSERT; case PCRE_ERROR_NOMEMORY: return REG_ESPACE; default: return REG_ASSERT; } } } /* End of pcreposix.c */ vfu-4.10/vslib/pcre/pcreposix.h0000644000175000001440000000444511005727400015311 0ustar cadeusers/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* Copyright (c) 1997-2001 University of Cambridge */ #ifndef _PCREPOSIX_H #define _PCREPOSIX_H /* This is the header for the POSIX wrapper interface to the PCRE Perl- Compatible Regular Expression library. It defines the things POSIX says should be there. I hope. */ /* Have to include stdlib.h in order to ensure that size_t is defined. */ #include /* Allow for C++ users */ #ifdef __cplusplus extern "C" { #endif /* Options defined by POSIX. */ #define REG_ICASE 0x01 #define REG_NEWLINE 0x02 #define REG_NOTBOL 0x04 #define REG_NOTEOL 0x08 /* These are not used by PCRE, but by defining them we make it easier to slot PCRE into existing programs that make POSIX calls. */ #define REG_EXTENDED 0 #define REG_NOSUB 0 /* Error values. Not all these are relevant or used by the wrapper. */ enum { REG_ASSERT = 1, /* internal error ? */ REG_BADBR, /* invalid repeat counts in {} */ REG_BADPAT, /* pattern error */ REG_BADRPT, /* ? * + invalid */ REG_EBRACE, /* unbalanced {} */ REG_EBRACK, /* unbalanced [] */ REG_ECOLLATE, /* collation error - not relevant */ REG_ECTYPE, /* bad class */ REG_EESCAPE, /* bad escape sequence */ REG_EMPTY, /* empty expression */ REG_EPAREN, /* unbalanced () */ REG_ERANGE, /* bad range inside [] */ REG_ESIZE, /* expression too big */ REG_ESPACE, /* failed to get memory */ REG_ESUBREG, /* bad back reference */ REG_INVARG, /* bad argument */ REG_NOMATCH /* match failed */ }; /* The structure representing a compiled regular expression. */ typedef struct { void *re_pcre; size_t re_nsub; size_t re_erroffset; } regex_t; /* The structure in which a captured offset is returned. */ typedef int regoff_t; typedef struct { regoff_t rm_so; regoff_t rm_eo; } regmatch_t; /* The functions */ extern int regcomp(regex_t *, const char *, int); extern int regexec(regex_t *, const char *, size_t, regmatch_t *, int); extern size_t regerror(int, const regex_t *, char *, size_t); extern void regfree(regex_t *); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* End of pcreposix.h */ vfu-4.10/vslib/pcre/LICENCE0000644000175000001440000000363011005727400014104 0ustar cadeusersPCRE LICENCE ------------ PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by: Philip Hazel University of Cambridge Computing Service, Cambridge, England. Phone: +44 1223 334714. Copyright (c) 1997-2001 University of Cambridge Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: 1. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. In practice, this means that if you use PCRE in software which you distribute to others, commercially or otherwise, you must put a sentence like this Regular expression support is provided by the PCRE library package, which is open source software, written by Philip Hazel, and copyright by the University of Cambridge, England. somewhere reasonably visible in your documentation and in any relevant files or online help data or similar. A reference to the ftp site for the source, that is, to ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/ should also be given in the documentation. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. If PCRE is embedded in any software that is released under the GNU General Purpose Licence (GPL), or Lesser General Purpose Licence (LGPL), then the terms of that licence shall supersede any condition above with which it is incompatible. The documentation for PCRE, supplied in the "doc" directory, is distributed under the same terms as the software itself. End vfu-4.10/vslib/pcre/get.c0000644000175000001440000001640111005727400014042 0ustar cadeusers/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* This is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. See the file Tech.Notes for some information on the internals. Written by: Philip Hazel Copyright (c) 1997-2001 University of Cambridge ----------------------------------------------------------------------------- Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: 1. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. If PCRE is embedded in any software that is released under the GNU General Purpose Licence (GPL), then the terms of that licence shall supersede any condition above with which it is incompatible. ----------------------------------------------------------------------------- */ /* This module contains some convenience functions for extracting substrings from the subject string after a regex match has succeeded. The original idea for these functions came from Scott Wimer . */ /* Include the internals header, which itself includes Standard C headers plus the external pcre header. */ #include "internal.h" /************************************************* * Copy captured string to given buffer * *************************************************/ /* This function copies a single captured substring into a given buffer. Note that we use memcpy() rather than strncpy() in case there are binary zeros in the string. Arguments: subject the subject string that was matched ovector pointer to the offsets table stringcount the number of substrings that were captured (i.e. the yield of the pcre_exec call, unless that was zero, in which case it should be 1/3 of the offset table size) stringnumber the number of the required substring buffer where to put the substring size the size of the buffer Returns: if successful: the length of the copied string, not including the zero that is put on the end; can be zero if not successful: PCRE_ERROR_NOMEMORY (-6) buffer too small PCRE_ERROR_NOSUBSTRING (-7) no such captured substring */ int pcre_copy_substring(const char *subject, int *ovector, int stringcount, int stringnumber, char *buffer, int size) { int yield; if (stringnumber < 0 || stringnumber >= stringcount) return PCRE_ERROR_NOSUBSTRING; stringnumber *= 2; yield = ovector[stringnumber+1] - ovector[stringnumber]; if (size < yield + 1) return PCRE_ERROR_NOMEMORY; memcpy(buffer, subject + ovector[stringnumber], yield); buffer[yield] = 0; return yield; } /************************************************* * Copy all captured strings to new store * *************************************************/ /* This function gets one chunk of store and builds a list of pointers and all of the captured substrings in it. A NULL pointer is put on the end of the list. Arguments: subject the subject string that was matched ovector pointer to the offsets table stringcount the number of substrings that were captured (i.e. the yield of the pcre_exec call, unless that was zero, in which case it should be 1/3 of the offset table size) listptr set to point to the list of pointers Returns: if successful: 0 if not successful: PCRE_ERROR_NOMEMORY (-6) failed to get store */ int pcre_get_substring_list(const char *subject, int *ovector, int stringcount, const char ***listptr) { int i; int size = sizeof(char *); int double_count = stringcount * 2; char **stringlist; char *p; for (i = 0; i < double_count; i += 2) size += sizeof(char *) + ovector[i+1] - ovector[i] + 1; stringlist = (char **)(pcre_malloc)(size); if (stringlist == NULL) return PCRE_ERROR_NOMEMORY; *listptr = (const char **)stringlist; p = (char *)(stringlist + stringcount + 1); for (i = 0; i < double_count; i += 2) { int len = ovector[i+1] - ovector[i]; memcpy(p, subject + ovector[i], len); *stringlist++ = p; p += len; *p++ = 0; } *stringlist = NULL; return 0; } /************************************************* * Free store obtained by get_substring_list * *************************************************/ /* This function exists for the benefit of people calling PCRE from non-C programs that can call its functions, but not free() or (pcre_free)() directly. Argument: the result of a previous pcre_get_substring_list() Returns: nothing */ void pcre_free_substring_list(const char **pointer) { (pcre_free)((void *)pointer); } /************************************************* * Copy captured string to new store * *************************************************/ /* This function copies a single captured substring into a piece of new store Arguments: subject the subject string that was matched ovector pointer to the offsets table stringcount the number of substrings that were captured (i.e. the yield of the pcre_exec call, unless that was zero, in which case it should be 1/3 of the offset table size) stringnumber the number of the required substring stringptr where to put a pointer to the substring Returns: if successful: the length of the string, not including the zero that is put on the end; can be zero if not successful: PCRE_ERROR_NOMEMORY (-6) failed to get store PCRE_ERROR_NOSUBSTRING (-7) substring not present */ int pcre_get_substring(const char *subject, int *ovector, int stringcount, int stringnumber, const char **stringptr) { int yield; char *substring; if (stringnumber < 0 || stringnumber >= stringcount) return PCRE_ERROR_NOSUBSTRING; stringnumber *= 2; yield = ovector[stringnumber+1] - ovector[stringnumber]; substring = (char *)(pcre_malloc)(yield + 1); if (substring == NULL) return PCRE_ERROR_NOMEMORY; memcpy(substring, subject + ovector[stringnumber], yield); substring[yield] = 0; *stringptr = substring; return yield; } /************************************************* * Free store obtained by get_substring * *************************************************/ /* This function exists for the benefit of people calling PCRE from non-C programs that can call its functions, but not free() or (pcre_free)() directly. Argument: the result of a previous pcre_get_substring() Returns: nothing */ void pcre_free_substring(const char *pointer) { (pcre_free)((void *)pointer); } /* End of get.c */ vfu-4.10/vslib/pcre/README0000644000175000001440000003364711005727400014012 0ustar cadeusersREADME file for PCRE (Perl-compatible regular expression library) ----------------------------------------------------------------- The latest release of PCRE is always available from ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-xxx.tar.gz Please read the NEWS file if you are upgrading from a previous release. PCRE has its own native API, but a set of "wrapper" functions that are based on the POSIX API are also supplied in the library libpcreposix. Note that this just provides a POSIX calling interface to PCRE: the regular expressions themselves still follow Perl syntax and semantics. The header file for the POSIX-style functions is called pcreposix.h. The official POSIX name is regex.h, but I didn't want to risk possible problems with existing files of that name by distributing it that way. To use it with an existing program that uses the POSIX API, it will have to be renamed or pointed at by a link. Contributions by users of PCRE ------------------------------ You can find contributions from PCRE users in the directory ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/Contrib where there is also a README file giving brief descriptions of what they are. Several of them provide support for compiling PCRE on various flavours of Windows systems (I myself do not use Windows). Some are complete in themselves; others are pointers to URLs containing relevant files. Building PCRE on a Unix system ------------------------------ To build PCRE on a Unix system, first run the "configure" command from the PCRE distribution directory, with your current directory set to the directory where you want the files to be created. This command is a standard GNU "autoconf" configuration script, for which generic instructions are supplied in INSTALL. Most commonly, people build PCRE within its own distribution directory, and in this case, on many systems, just running "./configure" is sufficient, but the usual methods of changing standard defaults are available. For example, CFLAGS='-O2 -Wall' ./configure --prefix=/opt/local specifies that the C compiler should be run with the flags '-O2 -Wall' instead of the default, and that "make install" should install PCRE under /opt/local instead of the default /usr/local. If you want to build in a different directory, just run "configure" with that directory as current. For example, suppose you have unpacked the PCRE source into /source/pcre/pcre-xxx, but you want to build it in /build/pcre/pcre-xxx: cd /build/pcre/pcre-xxx /source/pcre/pcre-xxx/configure If you want to make use of the experimential, incomplete support for UTF-8 character strings in PCRE, you must add --enable-utf8 to the "configure" command. Without it, the code for handling UTF-8 is not included in the library. (Even when included, it still has to be enabled by an option at run time.) The "configure" script builds five files: . libtool is a script that builds shared and/or static libraries . Makefile is built by copying Makefile.in and making substitutions. . config.h is built by copying config.in and making substitutions. . pcre-config is built by copying pcre-config.in and making substitutions. . RunTest is a script for running tests Once "configure" has run, you can run "make". It builds two libraries called libpcre and libpcreposix, a test program called pcretest, and the pcregrep command. You can use "make install" to copy these, the public header files pcre.h and pcreposix.h, and the man pages to appropriate live directories on your system, in the normal way. Running "make install" also installs the command pcre-config, which can be used to recall information about the PCRE configuration and installation. For example, pcre-config --version prints the version number, and pcre-config --libs outputs information about where the library is installed. This command can be included in makefiles for programs that use PCRE, saving the programmer from having to remember too many details. There is one esoteric feature that is controlled by "configure". It concerns the character value used for "newline", and is something that you probably do not want to change on a Unix system. The default is to use whatever value your compiler gives to '\n'. By using --enable-newline-is-cr or --enable-newline-is-lf you can force the value to be CR (13) or LF (10) if you really want to. Shared libraries on Unix systems -------------------------------- The default distribution builds PCRE as two shared libraries and two static libraries, as long as the operating system supports shared libraries. Shared library support relies on the "libtool" script which is built as part of the "configure" process. The libtool script is used to compile and link both shared and static libraries. They are placed in a subdirectory called .libs when they are newly built. The programs pcretest and pcregrep are built to use these uninstalled libraries (by means of wrapper scripts in the case of shared libraries). When you use "make install" to install shared libraries, pcregrep and pcretest are automatically re-built to use the newly installed shared libraries before being installed themselves. However, the versions left in the source directory still use the uninstalled libraries. To build PCRE using static libraries only you must use --disable-shared when configuring it. For example ./configure --prefix=/usr/gnu --disable-shared Then run "make" in the usual way. Similarly, you can use --disable-static to build only shared libraries. Building on non-Unix systems ---------------------------- For a non-Unix system, read the comments in the file NON-UNIX-USE. PCRE has been compiled on Windows systems and on Macintoshes, but I don't know the details because I don't use those systems. It should be straightforward to build PCRE on any system that has a Standard C compiler, because it uses only Standard C functions. Testing PCRE ------------ To test PCRE on a Unix system, run the RunTest script that is created by the configuring process. (This can also be run by "make runtest", "make check", or "make test".) For other systems, see the instruction in NON-UNIX-USE. The script runs the pcretest test program (which is documented in the doc directory) on each of the testinput files (in the testdata directory) in turn, and compares the output with the contents of the corresponding testoutput file. A file called testtry is used to hold the output from pcretest. To run pcretest on just one of the test files, give its number as an argument to RunTest, for example: RunTest 3 The first and third test files can also be fed directly into the perltest script to check that Perl gives the same results. The third file requires the additional features of release 5.005, which is why it is kept separate from the main test input, which needs only Perl 5.004. In the long run, when 5.005 (or higher) is widespread, these two test files may get amalgamated. The second set of tests check pcre_fullinfo(), pcre_info(), pcre_study(), pcre_copy_substring(), pcre_get_substring(), pcre_get_substring_list(), error detection, and run-time flags that are specific to PCRE, as well as the POSIX wrapper API. It also uses the debugging flag to check some of the internals of pcre_compile(). If you build PCRE with a locale setting that is not the standard C locale, the character tables may be different (see next paragraph). In some cases, this may cause failures in the second set of tests. For example, in a locale where the isprint() function yields TRUE for characters in the range 128-255, the use of [:isascii:] inside a character class defines a different set of characters, and this shows up in this test as a difference in the compiled code, which is being listed for checking. Where the comparison test output contains [\x00-\x7f] the test will contain [\x00-\xff], and similarly in some other cases. This is not a bug in PCRE. The fourth set of tests checks pcre_maketables(), the facility for building a set of character tables for a specific locale and using them instead of the default tables. The tests make use of the "fr" (French) locale. Before running the test, the script checks for the presence of this locale by running the "locale" command. If that command fails, or if it doesn't include "fr" in the list of available locales, the fourth test cannot be run, and a comment is output to say why. If running this test produces instances of the error ** Failed to set locale "fr" in the comparison output, it means that locale is not available on your system, despite being listed by "locale". This does not mean that PCRE is broken. The fifth test checks the experimental, incomplete UTF-8 support. It is not run automatically unless PCRE is built with UTF-8 support. This file can be fed directly to the perltest8 script, which requires Perl 5.6 or higher. The sixth file tests internal UTF-8 features of PCRE that are not relevant to Perl. Character tables ---------------- PCRE uses four tables for manipulating and identifying characters. The final argument of the pcre_compile() function is a pointer to a block of memory containing the concatenated tables. A call to pcre_maketables() can be used to generate a set of tables in the current locale. If the final argument for pcre_compile() is passed as NULL, a set of default tables that is built into the binary is used. The source file called chartables.c contains the default set of tables. This is not supplied in the distribution, but is built by the program dftables (compiled from dftables.c), which uses the ANSI C character handling functions such as isalnum(), isalpha(), isupper(), islower(), etc. to build the table sources. This means that the default C locale which is set for your system will control the contents of these default tables. You can change the default tables by editing chartables.c and then re-building PCRE. If you do this, you should probably also edit Makefile to ensure that the file doesn't ever get re-generated. The first two 256-byte tables provide lower casing and case flipping functions, respectively. The next table consists of three 32-byte bit maps which identify digits, "word" characters, and white space, respectively. These are used when building 32-byte bit maps that represent character classes. The final 256-byte table has bits indicating various character types, as follows: 1 white space character 2 letter 4 decimal digit 8 hexadecimal digit 16 alphanumeric or '_' 128 regular expression metacharacter or binary zero You should not alter the set of characters that contain the 128 bit, as that will cause PCRE to malfunction. Manifest -------- The distribution should contain the following files: (A) The actual source files of the PCRE library functions and their headers: dftables.c auxiliary program for building chartables.c get.c ) maketables.c ) study.c ) source of pcre.c ) the functions pcreposix.c ) pcre.in "source" for the header for the external API; pcre.h is built from this by "configure" pcreposix.h header for the external POSIX wrapper API internal.h header for internal use config.in template for config.h, which is built by configure (B) Auxiliary files: AUTHORS information about the author of PCRE ChangeLog log of changes to the code INSTALL generic installation instructions LICENCE conditions for the use of PCRE COPYING the same, using GNU's standard name Makefile.in template for Unix Makefile, which is built by configure NEWS important changes in this release NON-UNIX-USE notes on building PCRE on non-Unix systems README this file RunTest.in template for a Unix shell script for running tests config.guess ) files used by libtool, config.sub ) used only when building a shared library configure a configuring shell script (built by autoconf) configure.in the autoconf input used to build configure doc/Tech.Notes notes on the encoding doc/pcre.3 man page source for the PCRE functions doc/pcre.html HTML version doc/pcre.txt plain text version doc/pcreposix.3 man page source for the POSIX wrapper API doc/pcreposix.html HTML version doc/pcreposix.txt plain text version doc/pcretest.txt documentation of test program doc/perltest.txt documentation of Perl test program doc/pcregrep.1 man page source for the pcregrep utility doc/pcregrep.html HTML version doc/pcregrep.txt plain text version install-sh a shell script for installing files ltmain.sh file used to build a libtool script pcretest.c comprehensive test program pcredemo.c simple demonstration of coding calls to PCRE perltest Perl test program perltest8 Perl test program for UTF-8 tests pcregrep.c source of a grep utility that uses PCRE pcre-config.in source of script which retains PCRE information testdata/testinput1 test data, compatible with Perl 5.004 and 5.005 testdata/testinput2 test data for error messages and non-Perl things testdata/testinput3 test data, compatible with Perl 5.005 testdata/testinput4 test data for locale-specific tests testdata/testinput5 test data for UTF-8 tests compatible with Perl 5.6 testdata/testinput6 test data for other UTF-8 tests testdata/testoutput1 test results corresponding to testinput1 testdata/testoutput2 test results corresponding to testinput2 testdata/testoutput3 test results corresponding to testinput3 testdata/testoutput4 test results corresponding to testinput4 testdata/testoutput5 test results corresponding to testinput5 testdata/testoutput6 test results corresponding to testinput6 (C) Auxiliary files for Win32 DLL dll.mk pcre.def Philip Hazel August 2001 vfu-4.10/vslib/pcre/chartables.c0000644000175000001440000001555511005727400015404 0ustar cadeusers/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* This file is automatically written by the dftables auxiliary program. If you edit it by hand, you might like to edit the Makefile to prevent its ever being regenerated. This file is #included in the compilation of pcre.c to build the default character tables which are used when no tables are passed to the compile function. */ static unsigned char pcre_default_tables[] = { /* This table is a lower casing table. */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103, 104,105,106,107,108,109,110,111, 112,113,114,115,116,117,118,119, 120,121,122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103, 104,105,106,107,108,109,110,111, 112,113,114,115,116,117,118,119, 120,121,122,123,124,125,126,127, 128,129,130,131,132,133,134,135, 136,137,138,139,140,141,142,143, 144,145,146,147,148,149,150,151, 152,153,154,155,156,157,158,159, 160,161,162,163,164,165,166,167, 168,169,170,171,172,173,174,175, 176,177,178,179,180,181,182,183, 184,185,186,187,188,189,190,191, 192,193,194,195,196,197,198,199, 200,201,202,203,204,205,206,207, 208,209,210,211,212,213,214,215, 216,217,218,219,220,221,222,223, 224,225,226,227,228,229,230,231, 232,233,234,235,236,237,238,239, 240,241,242,243,244,245,246,247, 248,249,250,251,252,253,254,255, /* This table is a case flipping table. */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103, 104,105,106,107,108,109,110,111, 112,113,114,115,116,117,118,119, 120,121,122, 91, 92, 93, 94, 95, 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,123,124,125,126,127, 128,129,130,131,132,133,134,135, 136,137,138,139,140,141,142,143, 144,145,146,147,148,149,150,151, 152,153,154,155,156,157,158,159, 160,161,162,163,164,165,166,167, 168,169,170,171,172,173,174,175, 176,177,178,179,180,181,182,183, 184,185,186,187,188,189,190,191, 192,193,194,195,196,197,198,199, 200,201,202,203,204,205,206,207, 208,209,210,211,212,213,214,215, 216,217,218,219,220,221,222,223, 224,225,226,227,228,229,230,231, 232,233,234,235,236,237,238,239, 240,241,242,243,244,245,246,247, 248,249,250,251,252,253,254,255, /* This table contains bit maps for various character classes. Each map is 32 bytes long and the bits run from the least significant end of each byte. The classes that have their own maps are: space, xdigit, digit, upper, lower, word, graph print, punct, and cntrl. Other classes are built from combinations. */ 0x00,0x3e,0x00,0x00,0x01,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, 0x7e,0x00,0x00,0x00,0x7e,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfe,0xff,0xff,0x07,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0x07, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, 0xfe,0xff,0xff,0x87,0xfe,0xff,0xff,0x07, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfe,0xff,0x00,0xfc, 0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x78, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* This table identifies various classes of character by individual bits: 0x01 white space character 0x02 letter 0x04 decimal digit 0x08 hexadecimal digit 0x10 alphanumeric or '_' 0x80 regular expression metacharacter or binary zero */ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */ 0x00,0x01,0x01,0x01,0x01,0x01,0x00,0x00, /* 8- 15 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */ 0x01,0x00,0x00,0x00,0x80,0x00,0x00,0x00, /* - ' */ 0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x00, /* ( - / */ 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /* 0 - 7 */ 0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x80, /* 8 - ? */ 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* @ - G */ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* H - O */ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* P - W */ 0x12,0x12,0x12,0x80,0x00,0x00,0x80,0x10, /* X - _ */ 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* ` - g */ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* h - o */ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* p - w */ 0x12,0x12,0x12,0x80,0x80,0x00,0x00,0x00, /* x -127 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */ /* End of chartables.c */ vfu-4.10/vslib/pcre/makefile0000644000175000001440000000517711005727400014627 0ustar cadeusers ### MAKEMAKE STARTS HERE ####################################################### ### Created by makemake.pl on Wed Dec 29 04:47:29 2004 ######################### ### GLOBAL TARGETS ############################################################# default: all re: rebuild li: link all: libpcre.a clean: clean-libpcre.a rebuild: rebuild-libpcre.a link: link-libpcre.a ### GLOBAL (AND USER) DEFS ##################################################### AR = ar rv CC = gcc LD = gcc MKDIR = mkdir -p RANLIB = ranlib RMDIR = rm -rf RMFILE = rm -f SRC = *.c *.cpp *.cc *.cxx ### TARGET 1: libpcre.a ######################################################## CC_1 = gcc LD_1 = gcc AR_1 = ar rv RANLIB_1 = ranlib CCFLAGS_1 = -I. -O2 $(CCDEF) LDFLAGS_1 = $(LDDEF) DEPFLAGS_1 = ARFLAGS_1 = TARGET_1 = libpcre.a ### SOURCES FOR TARGET 1: libpcre.a ############################################ SRC_1= \ chartables.c \ get.c \ pcre.c \ pcreposix.c \ study.c \ #### OBJECTS FOR TARGET 1: libpcre.a ########################################### OBJ_1= \ .OBJ.libpcre.a/chartables.o \ .OBJ.libpcre.a/get.o \ .OBJ.libpcre.a/pcre.o \ .OBJ.libpcre.a/pcreposix.o \ .OBJ.libpcre.a/study.o \ ### TARGET DEFINITION FOR TARGET 1: libpcre.a ################################## .OBJ.libpcre.a: $(MKDIR) .OBJ.libpcre.a libpcre.a: .OBJ.libpcre.a $(OBJ_1) $(AR_1) $(ARFLAGS_1) $(TARGET_1) $(OBJ_1) $(RANLIB_1) $(TARGET_1) clean-libpcre.a: $(RMFILE) $(TARGET_1) $(RMDIR) .OBJ.libpcre.a rebuild-libpcre.a: clean-libpcre.a libpcre.a link-libpcre.a: .OBJ.libpcre.a $(OBJ_1) $(RMFILE) libpcre.a $(AR_1) $(ARFLAGS_1) $(TARGET_1) $(OBJ_1) $(RANLIB_1) $(TARGET_1) ### TARGET OBJECTS FOR TARGET 1: libpcre.a ##################################### .OBJ.libpcre.a/chartables.o: chartables.c chartables.c $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c chartables.c -o .OBJ.libpcre.a/chartables.o .OBJ.libpcre.a/get.o: get.c get.c internal.h config.h pcre.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c get.c -o .OBJ.libpcre.a/get.o .OBJ.libpcre.a/pcre.o: pcre.c pcre.c internal.h config.h pcre.h chartables.c $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c pcre.c -o .OBJ.libpcre.a/pcre.o .OBJ.libpcre.a/pcreposix.o: pcreposix.c pcreposix.c internal.h config.h pcre.h pcreposix.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c pcreposix.c -o .OBJ.libpcre.a/pcreposix.o .OBJ.libpcre.a/study.o: study.c study.c internal.h config.h pcre.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c study.c -o .OBJ.libpcre.a/study.o ### MAKEMAKE ENDS HERE ######################################################### vfu-4.10/vslib/pcre/mm.conf0000644000175000001440000000037411005727400014401 0ustar cadeusers# # $Id: mm.conf,v 1.3 2003/01/04 18:29:58 cade Exp $ # CC = gcc LD = gcc ############################################################################ # make pcre library [libpcre.a] CCFLAGS = -I. -O2 $(CCDEF) LDFLAGS = $(LDDEF) SRC = *.c vfu-4.10/vslib/pcre/study.c0000644000175000001440000002534211005727400014437 0ustar cadeusers/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* This is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. See the file Tech.Notes for some information on the internals. Written by: Philip Hazel Copyright (c) 1997-2001 University of Cambridge ----------------------------------------------------------------------------- Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: 1. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. If PCRE is embedded in any software that is released under the GNU General Purpose Licence (GPL), then the terms of that licence shall supersede any condition above with which it is incompatible. ----------------------------------------------------------------------------- */ /* Include the internals header, which itself includes Standard C headers plus the external pcre header. */ #include "internal.h" /************************************************* * Set a bit and maybe its alternate case * *************************************************/ /* Given a character, set its bit in the table, and also the bit for the other version of a letter if we are caseless. Arguments: start_bits points to the bit map c is the character caseless the caseless flag cd the block with char table pointers Returns: nothing */ static void set_bit(uschar *start_bits, int c, BOOL caseless, compile_data *cd) { start_bits[c/8] |= (1 << (c&7)); if (caseless && (cd->ctypes[c] & ctype_letter) != 0) start_bits[cd->fcc[c]/8] |= (1 << (cd->fcc[c]&7)); } /************************************************* * Create bitmap of starting chars * *************************************************/ /* This function scans a compiled unanchored expression and attempts to build a bitmap of the set of initial characters. If it can't, it returns FALSE. As time goes by, we may be able to get more clever at doing this. Arguments: code points to an expression start_bits points to a 32-byte table, initialized to 0 caseless the current state of the caseless flag cd the block with char table pointers Returns: TRUE if table built, FALSE otherwise */ static BOOL set_start_bits(const uschar *code, uschar *start_bits, BOOL caseless, compile_data *cd) { register int c; /* This next statement and the later reference to dummy are here in order to trick the optimizer of the IBM C compiler for OS/2 into generating correct code. Apparently IBM isn't going to fix the problem, and we would rather not disable optimization (in this module it actually makes a big difference, and the pcre module can use all the optimization it can get). */ volatile int dummy; do { const uschar *tcode = code + 3; BOOL try_next = TRUE; while (try_next) { /* If a branch starts with a bracket or a positive lookahead assertion, recurse to set bits from within them. That's all for this branch. */ if ((int)*tcode >= OP_BRA || *tcode == OP_ASSERT) { if (!set_start_bits(tcode, start_bits, caseless, cd)) return FALSE; try_next = FALSE; } else switch(*tcode) { default: return FALSE; /* Skip over extended extraction bracket number */ case OP_BRANUMBER: tcode += 3; break; /* Skip over lookbehind and negative lookahead assertions */ case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: do tcode += (tcode[1] << 8) + tcode[2]; while (*tcode == OP_ALT); tcode += 3; break; /* Skip over an option setting, changing the caseless flag */ case OP_OPT: caseless = (tcode[1] & PCRE_CASELESS) != 0; tcode += 2; break; /* BRAZERO does the bracket, but carries on. */ case OP_BRAZERO: case OP_BRAMINZERO: if (!set_start_bits(++tcode, start_bits, caseless, cd)) return FALSE; dummy = 1; do tcode += (tcode[1] << 8) + tcode[2]; while (*tcode == OP_ALT); tcode += 3; break; /* Single-char * or ? sets the bit and tries the next item */ case OP_STAR: case OP_MINSTAR: case OP_QUERY: case OP_MINQUERY: set_bit(start_bits, tcode[1], caseless, cd); tcode += 2; break; /* Single-char upto sets the bit and tries the next */ case OP_UPTO: case OP_MINUPTO: set_bit(start_bits, tcode[3], caseless, cd); tcode += 4; break; /* At least one single char sets the bit and stops */ case OP_EXACT: /* Fall through */ tcode++; case OP_CHARS: /* Fall through */ tcode++; case OP_PLUS: case OP_MINPLUS: set_bit(start_bits, tcode[1], caseless, cd); try_next = FALSE; break; /* Single character type sets the bits and stops */ case OP_NOT_DIGIT: for (c = 0; c < 32; c++) start_bits[c] |= ~cd->cbits[c+cbit_digit]; try_next = FALSE; break; case OP_DIGIT: for (c = 0; c < 32; c++) start_bits[c] |= cd->cbits[c+cbit_digit]; try_next = FALSE; break; case OP_NOT_WHITESPACE: for (c = 0; c < 32; c++) start_bits[c] |= ~cd->cbits[c+cbit_space]; try_next = FALSE; break; case OP_WHITESPACE: for (c = 0; c < 32; c++) start_bits[c] |= cd->cbits[c+cbit_space]; try_next = FALSE; break; case OP_NOT_WORDCHAR: for (c = 0; c < 32; c++) start_bits[c] |= ~cd->cbits[c+cbit_word]; try_next = FALSE; break; case OP_WORDCHAR: for (c = 0; c < 32; c++) start_bits[c] |= cd->cbits[c+cbit_word]; try_next = FALSE; break; /* One or more character type fudges the pointer and restarts, knowing it will hit a single character type and stop there. */ case OP_TYPEPLUS: case OP_TYPEMINPLUS: tcode++; break; case OP_TYPEEXACT: tcode += 3; break; /* Zero or more repeats of character types set the bits and then try again. */ case OP_TYPEUPTO: case OP_TYPEMINUPTO: tcode += 2; /* Fall through */ case OP_TYPESTAR: case OP_TYPEMINSTAR: case OP_TYPEQUERY: case OP_TYPEMINQUERY: switch(tcode[1]) { case OP_NOT_DIGIT: for (c = 0; c < 32; c++) start_bits[c] |= ~cd->cbits[c+cbit_digit]; break; case OP_DIGIT: for (c = 0; c < 32; c++) start_bits[c] |= cd->cbits[c+cbit_digit]; break; case OP_NOT_WHITESPACE: for (c = 0; c < 32; c++) start_bits[c] |= ~cd->cbits[c+cbit_space]; break; case OP_WHITESPACE: for (c = 0; c < 32; c++) start_bits[c] |= cd->cbits[c+cbit_space]; break; case OP_NOT_WORDCHAR: for (c = 0; c < 32; c++) start_bits[c] |= ~cd->cbits[c+cbit_word]; break; case OP_WORDCHAR: for (c = 0; c < 32; c++) start_bits[c] |= cd->cbits[c+cbit_word]; break; } tcode += 2; break; /* Character class: set the bits and either carry on or not, according to the repeat count. */ case OP_CLASS: { tcode++; for (c = 0; c < 32; c++) start_bits[c] |= tcode[c]; tcode += 32; switch (*tcode) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRQUERY: case OP_CRMINQUERY: tcode++; break; case OP_CRRANGE: case OP_CRMINRANGE: if (((tcode[1] << 8) + tcode[2]) == 0) tcode += 5; else try_next = FALSE; break; default: try_next = FALSE; break; } } break; /* End of class handling */ } /* End of switch */ } /* End of try_next loop */ code += (code[1] << 8) + code[2]; /* Advance to next branch */ } while (*code == OP_ALT); return TRUE; } /************************************************* * Study a compiled expression * *************************************************/ /* This function is handed a compiled expression that it must study to produce information that will speed up the matching. It returns a pcre_extra block which then gets handed back to pcre_exec(). Arguments: re points to the compiled expression options contains option bits errorptr points to where to place error messages; set NULL unless error Returns: pointer to a pcre_extra block, NULL on error or if no optimization possible */ pcre_extra * pcre_study(const pcre *external_re, int options, const char **errorptr) { uschar start_bits[32]; real_pcre_extra *extra; const real_pcre *re = (const real_pcre *)external_re; compile_data compile_block; *errorptr = NULL; if (re == NULL || re->magic_number != MAGIC_NUMBER) { *errorptr = "argument is not a compiled regular expression"; return NULL; } if ((options & ~PUBLIC_STUDY_OPTIONS) != 0) { *errorptr = "unknown or incorrect option bit(s) set"; return NULL; } /* For an anchored pattern, or an unchored pattern that has a first char, or a multiline pattern that matches only at "line starts", no further processing at present. */ if ((re->options & (PCRE_ANCHORED|PCRE_FIRSTSET|PCRE_STARTLINE)) != 0) return NULL; /* Set the character tables in the block which is passed around */ compile_block.lcc = re->tables + lcc_offset; compile_block.fcc = re->tables + fcc_offset; compile_block.cbits = re->tables + cbits_offset; compile_block.ctypes = re->tables + ctypes_offset; /* See if we can find a fixed set of initial characters for the pattern. */ memset(start_bits, 0, 32 * sizeof(uschar)); if (!set_start_bits(re->code, start_bits, (re->options & PCRE_CASELESS) != 0, &compile_block)) return NULL; /* Get an "extra" block and put the information therein. */ extra = (real_pcre_extra *)(pcre_malloc)(sizeof(real_pcre_extra)); if (extra == NULL) { *errorptr = "failed to get memory"; return NULL; } extra->options = PCRE_STUDY_MAPPED; memcpy(extra->start_bits, start_bits, sizeof(start_bits)); return (pcre_extra *)extra; } /* End of study.c */ vfu-4.10/vslib/pcre/config.h0000644000175000001440000000363211005727400014537 0ustar cadeusers/* config.h. Generated automatically by configure. */ /* On Unix systems config.in is converted by configure into config.h. PCRE is written in Standard C, but there are a few non-standard things it can cope with, allowing it to run on SunOS4 and other "close to standard" systems. On a non-Unix system you should just copy this file into config.h, and set up the macros the way you need them. You should normally change the definitions of HAVE_STRERROR and HAVE_MEMMOVE to 1. Unfortunately, because of the way autoconf works, these cannot be made the defaults. If your system has bcopy() and not memmove(), change the definition of HAVE_BCOPY instead of HAVE_MEMMOVE. If your system has neither bcopy() nor memmove(), leave them both as 0; an emulation function will be used. */ /* Define to empty if the keyword does not work. */ /* #undef const */ /* Define to `unsigned' if doesn't define size_t. */ /* #undef size_t */ /* The following two definitions are mainly for the benefit of SunOS4, which doesn't have the strerror() or memmove() functions that should be present in all Standard C libraries. The macros HAVE_STRERROR and HAVE_MEMMOVE should normally be defined with the value 1 for other systems, but unfortunately we can't make this the default because "configure" files generated by autoconf will only change 0 to 1; they won't change 1 to 0 if the functions are not found. */ #define HAVE_STRERROR 1 #define HAVE_MEMMOVE 1 /* There are some non-Unix systems that don't even have bcopy(). If this macro is false, an emulation is used. If HAVE_MEMMOVE is set to 1, the value of HAVE_BCOPY is not relevant. */ #define HAVE_BCOPY 1 /* The value of NEWLINE determines the newline character. The default is to leave it up to the compiler, but some sites want to force a particular value. On Unix systems, "configure" can be used to override this default. */ #ifndef NEWLINE #define NEWLINE '\n' #endif /* End */ vfu-4.10/vslib/pcre/pcre.c0000644000175000001440000045313411005727400014224 0ustar cadeusers/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* This is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. See the file Tech.Notes for some information on the internals. Written by: Philip Hazel Copyright (c) 1997-2001 University of Cambridge ----------------------------------------------------------------------------- Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: 1. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. If PCRE is embedded in any software that is released under the GNU General Purpose Licence (GPL), then the terms of that licence shall supersede any condition above with which it is incompatible. ----------------------------------------------------------------------------- */ /* Define DEBUG to get debugging output on stdout. */ /* #define DEBUG */ /* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef inline, and there are *still* stupid compilers about that don't like indented pre-processor statements. I suppose it's only been 10 years... */ #ifdef DEBUG #define DPRINTF(p) printf p #else #define DPRINTF(p) /*nothing*/ #endif /* Include the internals header, which itself includes Standard C headers plus the external pcre header. */ #include "internal.h" /* Allow compilation as C++ source code, should anybody want to do that. */ #ifdef __cplusplus #define class pcre_class #endif /* Maximum number of items on the nested bracket stacks at compile time. This applies to the nesting of all kinds of parentheses. It does not limit un-nested, non-capturing parentheses. This number can be made bigger if necessary - it is used to dimension one int and one unsigned char vector at compile time. */ #define BRASTACK_SIZE 200 /* The number of bytes in a literal character string above which we can't add any more is different when UTF-8 characters may be encountered. */ #ifdef SUPPORT_UTF8 #define MAXLIT 250 #else #define MAXLIT 255 #endif /* Min and max values for the common repeats; for the maxima, 0 => infinity */ static const char rep_min[] = { 0, 0, 1, 1, 0, 0 }; static const char rep_max[] = { 0, 0, 0, 0, 1, 1 }; /* Text forms of OP_ values and things, for debugging (not all used) */ #ifdef DEBUG static const char *OP_names[] = { "End", "\\A", "\\B", "\\b", "\\D", "\\d", "\\S", "\\s", "\\W", "\\w", "\\Z", "\\z", "Opt", "^", "$", "Any", "chars", "not", "*", "*?", "+", "+?", "?", "??", "{", "{", "{", "*", "*?", "+", "+?", "?", "??", "{", "{", "{", "*", "*?", "+", "+?", "?", "??", "{", "{", "{", "*", "*?", "+", "+?", "?", "??", "{", "{", "class", "Ref", "Recurse", "Alt", "Ket", "KetRmax", "KetRmin", "Assert", "Assert not", "AssertB", "AssertB not", "Reverse", "Once", "Cond", "Cref", "Brazero", "Braminzero", "Branumber", "Bra" }; #endif /* Table for handling escaped characters in the range '0'-'z'. Positive returns are simple data values; negative values are for special things like \d and so on. Zero means further processing is needed (for things like \x), or the escape is invalid. */ static const short int escapes[] = { 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 7 */ 0, 0, ':', ';', '<', '=', '>', '?', /* 8 - ? */ '@', -ESC_A, -ESC_B, 0, -ESC_D, 0, 0, 0, /* @ - G */ 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ 0, 0, 0, -ESC_S, 0, 0, 0, -ESC_W, /* P - W */ 0, 0, -ESC_Z, '[', '\\', ']', '^', '_', /* X - _ */ '`', 7, -ESC_b, 0, -ESC_d, ESC_E, ESC_F, 0, /* ` - g */ 0, 0, 0, 0, 0, 0, ESC_N, 0, /* h - o */ 0, 0, ESC_R, -ESC_s, ESC_T, 0, 0, -ESC_w, /* p - w */ 0, 0, -ESC_z /* x - z */ }; /* Tables of names of POSIX character classes and their lengths. The list is terminated by a zero length entry. The first three must be alpha, upper, lower, as this is assumed for handling case independence. */ static const char *posix_names[] = { "alpha", "lower", "upper", "alnum", "ascii", "cntrl", "digit", "graph", "print", "punct", "space", "word", "xdigit" }; static const uschar posix_name_lengths[] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 }; /* Table of class bit maps for each POSIX class; up to three may be combined to form the class. */ static const int posix_class_maps[] = { cbit_lower, cbit_upper, -1, /* alpha */ cbit_lower, -1, -1, /* lower */ cbit_upper, -1, -1, /* upper */ cbit_digit, cbit_lower, cbit_upper, /* alnum */ cbit_print, cbit_cntrl, -1, /* ascii */ cbit_cntrl, -1, -1, /* cntrl */ cbit_digit, -1, -1, /* digit */ cbit_graph, -1, -1, /* graph */ cbit_print, -1, -1, /* print */ cbit_punct, -1, -1, /* punct */ cbit_space, -1, -1, /* space */ cbit_word, -1, -1, /* word */ cbit_xdigit,-1, -1 /* xdigit */ }; /* Definition to allow mutual recursion */ static BOOL compile_regex(int, int, int *, uschar **, const uschar **, const char **, BOOL, int, int *, int *, compile_data *); /* Structure for building a chain of data that actually lives on the stack, for holding the values of the subject pointer at the start of each subpattern, so as to detect when an empty string has been matched by a subpattern - to break infinite loops. */ typedef struct eptrblock { struct eptrblock *prev; const uschar *saved_eptr; } eptrblock; /* Flag bits for the match() function */ #define match_condassert 0x01 /* Called to check a condition assertion */ #define match_isgroup 0x02 /* Set if start of bracketed group */ /************************************************* * Global variables * *************************************************/ /* PCRE is thread-clean and doesn't use any global variables in the normal sense. However, it calls memory allocation and free functions via the two indirections below, which are can be changed by the caller, but are shared between all threads. */ void *(*pcre_malloc)(size_t) = malloc; void (*pcre_free)(void *) = free; /************************************************* * Macros and tables for character handling * *************************************************/ /* When UTF-8 encoding is being used, a character is no longer just a single byte. The macros for character handling generate simple sequences when used in byte-mode, and more complicated ones for UTF-8 characters. */ #ifndef SUPPORT_UTF8 #define GETCHARINC(c, eptr) c = *eptr++; #define GETCHARLEN(c, eptr, len) c = *eptr; #define BACKCHAR(eptr) #else /* SUPPORT_UTF8 */ /* Get the next UTF-8 character, advancing the pointer */ #define GETCHARINC(c, eptr) \ c = *eptr++; \ if (md->utf8 && (c & 0xc0) == 0xc0) \ { \ int a = utf8_table4[c & 0x3f]; /* Number of additional bytes */ \ int s = 6*a; \ c = (c & utf8_table3[a]) << s; \ while (a-- > 0) \ { \ s -= 6; \ c |= (*eptr++ & 0x3f) << s; \ } \ } /* Get the next UTF-8 character, not advancing the pointer, setting length */ #define GETCHARLEN(c, eptr, len) \ c = *eptr; \ len = 1; \ if (md->utf8 && (c & 0xc0) == 0xc0) \ { \ int i; \ int a = utf8_table4[c & 0x3f]; /* Number of additional bytes */ \ int s = 6*a; \ c = (c & utf8_table3[a]) << s; \ for (i = 1; i <= a; i++) \ { \ s -= 6; \ c |= (eptr[i] & 0x3f) << s; \ } \ len += a; \ } /* If the pointer is not at the start of a character, move it back until it is. */ #define BACKCHAR(eptr) while((*eptr & 0xc0) == 0x80) eptr--; #endif /************************************************* * Default character tables * *************************************************/ /* A default set of character tables is included in the PCRE binary. Its source is built by the maketables auxiliary program, which uses the default C ctypes functions, and put in the file chartables.c. These tables are used by PCRE whenever the caller of pcre_compile() does not provide an alternate set of tables. */ #include "chartables.c" #ifdef SUPPORT_UTF8 /************************************************* * Tables for UTF-8 support * *************************************************/ /* These are the breakpoints for different numbers of bytes in a UTF-8 character. */ static int utf8_table1[] = { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff}; /* These are the indicator bits and the mask for the data bits to set in the first byte of a character, indexed by the number of additional bytes. */ static int utf8_table2[] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc}; static int utf8_table3[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01}; /* Table of the number of extra characters, indexed by the first character masked with 0x3f. The highest number for a valid UTF-8 character is in fact 0x3d. */ static uschar utf8_table4[] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; /************************************************* * Convert character value to UTF-8 * *************************************************/ /* This function takes an integer value in the range 0 - 0x7fffffff and encodes it as a UTF-8 character in 0 to 6 bytes. Arguments: cvalue the character value buffer pointer to buffer for result - at least 6 bytes long Returns: number of characters placed in the buffer */ static int ord2utf8(int cvalue, uschar *buffer) { register int i, j; for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++) if (cvalue <= utf8_table1[i]) break; buffer += i; for (j = i; j > 0; j--) { *buffer-- = 0x80 | (cvalue & 0x3f); cvalue >>= 6; } *buffer = utf8_table2[i] | cvalue; return i + 1; } #endif /************************************************* * Return version string * *************************************************/ #define STRING(a) # a #define XSTRING(s) STRING(s) const char * pcre_version(void) { return XSTRING(PCRE_MAJOR) "." XSTRING(PCRE_MINOR) " " XSTRING(PCRE_DATE); } /************************************************* * (Obsolete) Return info about compiled pattern * *************************************************/ /* This is the original "info" function. It picks potentially useful data out of the private structure, but its interface was too rigid. It remains for backwards compatibility. The public options are passed back in an int - though the re->options field has been expanded to a long int, all the public options at the low end of it, and so even on 16-bit systems this will still be OK. Therefore, I haven't changed the API for pcre_info(). Arguments: external_re points to compiled code optptr where to pass back the options first_char where to pass back the first character, or -1 if multiline and all branches start ^, or -2 otherwise Returns: number of capturing subpatterns or negative values on error */ int pcre_info(const pcre *external_re, int *optptr, int *first_char) { const real_pcre *re = (const real_pcre *)external_re; if (re == NULL) return PCRE_ERROR_NULL; if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC; if (optptr != NULL) *optptr = (int)(re->options & PUBLIC_OPTIONS); if (first_char != NULL) *first_char = ((re->options & PCRE_FIRSTSET) != 0)? re->first_char : ((re->options & PCRE_STARTLINE) != 0)? -1 : -2; return re->top_bracket; } /************************************************* * Return info about compiled pattern * *************************************************/ /* This is a newer "info" function which has an extensible interface so that additional items can be added compatibly. Arguments: external_re points to compiled code external_study points to study data, or NULL what what information is required where where to put the information Returns: 0 if data returned, negative on error */ int pcre_fullinfo(const pcre *external_re, const pcre_extra *study_data, int what, void *where) { const real_pcre *re = (const real_pcre *)external_re; const real_pcre_extra *study = (const real_pcre_extra *)study_data; if (re == NULL || where == NULL) return PCRE_ERROR_NULL; if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC; switch (what) { case PCRE_INFO_OPTIONS: *((unsigned long int *)where) = re->options & PUBLIC_OPTIONS; break; case PCRE_INFO_SIZE: *((size_t *)where) = re->size; break; case PCRE_INFO_CAPTURECOUNT: *((int *)where) = re->top_bracket; break; case PCRE_INFO_BACKREFMAX: *((int *)where) = re->top_backref; break; case PCRE_INFO_FIRSTCHAR: *((int *)where) = ((re->options & PCRE_FIRSTSET) != 0)? re->first_char : ((re->options & PCRE_STARTLINE) != 0)? -1 : -2; break; case PCRE_INFO_FIRSTTABLE: *((const uschar **)where) = (study != NULL && (study->options & PCRE_STUDY_MAPPED) != 0)? study->start_bits : NULL; break; case PCRE_INFO_LASTLITERAL: *((int *)where) = ((re->options & PCRE_REQCHSET) != 0)? re->req_char : -1; break; default: return PCRE_ERROR_BADOPTION; } return 0; } #ifdef DEBUG /************************************************* * Debugging function to print chars * *************************************************/ /* Print a sequence of chars in printable format, stopping at the end of the subject if the requested. Arguments: p points to characters length number to print is_subject TRUE if printing from within md->start_subject md pointer to matching data block, if is_subject is TRUE Returns: nothing */ static void pchars(const uschar *p, int length, BOOL is_subject, match_data *md) { int c; if (is_subject && length > md->end_subject - p) length = md->end_subject - p; while (length-- > 0) if (isprint(c = *(p++))) printf("%c", c); else printf("\\x%02x", c); } #endif /************************************************* * Handle escapes * *************************************************/ /* This function is called when a \ has been encountered. It either returns a positive value for a simple escape such as \n, or a negative value which encodes one of the more complicated things such as \d. When UTF-8 is enabled, a positive value greater than 255 may be returned. On entry, ptr is pointing at the \. On exit, it is on the final character of the escape sequence. Arguments: ptrptr points to the pattern position pointer errorptr points to the pointer to the error message bracount number of previous extracting brackets options the options bits isclass TRUE if inside a character class cd pointer to char tables block Returns: zero or positive => a data character negative => a special escape sequence on error, errorptr is set */ static int check_escape(const uschar **ptrptr, const char **errorptr, int bracount, int options, BOOL isclass, compile_data *cd) { const uschar *ptr = *ptrptr; int c, i; /* If backslash is at the end of the pattern, it's an error. */ c = *(++ptr); if (c == 0) *errorptr = ERR1; /* Digits or letters may have special meaning; all others are literals. */ else if (c < '0' || c > 'z') {} /* Do an initial lookup in a table. A non-zero result is something that can be returned immediately. Otherwise further processing may be required. */ else if ((i = escapes[c - '0']) != 0) c = i; /* Escapes that need further processing, or are illegal. */ else { const uschar *oldptr; switch (c) { /* The handling of escape sequences consisting of a string of digits starting with one that is not zero is not straightforward. By experiment, the way Perl works seems to be as follows: Outside a character class, the digits are read as a decimal number. If the number is less than 10, or if there are that many previous extracting left brackets, then it is a back reference. Otherwise, up to three octal digits are read to form an escaped byte. Thus \123 is likely to be octal 123 (cf \0123, which is octal 012 followed by the literal 3). If the octal value is greater than 377, the least significant 8 bits are taken. Inside a character class, \ followed by a digit is always an octal number. */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (!isclass) { oldptr = ptr; c -= '0'; while ((cd->ctypes[ptr[1]] & ctype_digit) != 0) c = c * 10 + *(++ptr) - '0'; if (c < 10 || c <= bracount) { c = -(ESC_REF + c); break; } ptr = oldptr; /* Put the pointer back and fall through */ } /* Handle an octal number following \. If the first digit is 8 or 9, Perl generates a binary zero byte and treats the digit as a following literal. Thus we have to pull back the pointer by one. */ if ((c = *ptr) >= '8') { ptr--; c = 0; break; } /* \0 always starts an octal number, but we may drop through to here with a larger first octal digit. */ case '0': c -= '0'; while(i++ < 2 && (cd->ctypes[ptr[1]] & ctype_digit) != 0 && ptr[1] != '8' && ptr[1] != '9') c = c * 8 + *(++ptr) - '0'; c &= 255; /* Take least significant 8 bits */ break; /* \x is complicated when UTF-8 is enabled. \x{ddd} is a character number which can be greater than 0xff, but only if the ddd are hex digits. */ case 'x': #ifdef SUPPORT_UTF8 if (ptr[1] == '{' && (options & PCRE_UTF8) != 0) { const uschar *pt = ptr + 2; register int count = 0; c = 0; while ((cd->ctypes[*pt] & ctype_xdigit) != 0) { count++; c = c * 16 + cd->lcc[*pt] - (((cd->ctypes[*pt] & ctype_digit) != 0)? '0' : 'W'); pt++; } if (*pt == '}') { if (c < 0 || count > 8) *errorptr = ERR34; ptr = pt; break; } /* If the sequence of hex digits does not end with '}', then we don't recognize this construct; fall through to the normal \x handling. */ } #endif /* Read just a single hex char */ c = 0; while (i++ < 2 && (cd->ctypes[ptr[1]] & ctype_xdigit) != 0) { ptr++; c = c * 16 + cd->lcc[*ptr] - (((cd->ctypes[*ptr] & ctype_digit) != 0)? '0' : 'W'); } break; /* Other special escapes not starting with a digit are straightforward */ case 'c': c = *(++ptr); if (c == 0) { *errorptr = ERR2; return 0; } /* A letter is upper-cased; then the 0x40 bit is flipped */ if (c >= 'a' && c <= 'z') c = cd->fcc[c]; c ^= 0x40; break; /* PCRE_EXTRA enables extensions to Perl in the matter of escapes. Any other alphameric following \ is an error if PCRE_EXTRA was set; otherwise, for Perl compatibility, it is a literal. This code looks a bit odd, but there used to be some cases other than the default, and there may be again in future, so I haven't "optimized" it. */ default: if ((options & PCRE_EXTRA) != 0) switch(c) { default: *errorptr = ERR3; break; } break; } } *ptrptr = ptr; return c; } /************************************************* * Check for counted repeat * *************************************************/ /* This function is called when a '{' is encountered in a place where it might start a quantifier. It looks ahead to see if it really is a quantifier or not. It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd} where the ddds are digits. Arguments: p pointer to the first char after '{' cd pointer to char tables block Returns: TRUE or FALSE */ static BOOL is_counted_repeat(const uschar *p, compile_data *cd) { if ((cd->ctypes[*p++] & ctype_digit) == 0) return FALSE; while ((cd->ctypes[*p] & ctype_digit) != 0) p++; if (*p == '}') return TRUE; if (*p++ != ',') return FALSE; if (*p == '}') return TRUE; if ((cd->ctypes[*p++] & ctype_digit) == 0) return FALSE; while ((cd->ctypes[*p] & ctype_digit) != 0) p++; return (*p == '}'); } /************************************************* * Read repeat counts * *************************************************/ /* Read an item of the form {n,m} and return the values. This is called only after is_counted_repeat() has confirmed that a repeat-count quantifier exists, so the syntax is guaranteed to be correct, but we need to check the values. Arguments: p pointer to first char after '{' minp pointer to int for min maxp pointer to int for max returned as -1 if no max errorptr points to pointer to error message cd pointer to character tables clock Returns: pointer to '}' on success; current ptr on error, with errorptr set */ static const uschar * read_repeat_counts(const uschar *p, int *minp, int *maxp, const char **errorptr, compile_data *cd) { int min = 0; int max = -1; while ((cd->ctypes[*p] & ctype_digit) != 0) min = min * 10 + *p++ - '0'; if (*p == '}') max = min; else { if (*(++p) != '}') { max = 0; while((cd->ctypes[*p] & ctype_digit) != 0) max = max * 10 + *p++ - '0'; if (max < min) { *errorptr = ERR4; return p; } } } /* Do paranoid checks, then fill in the required variables, and pass back the pointer to the terminating '}'. */ if (min > 65535 || max > 65535) *errorptr = ERR5; else { *minp = min; *maxp = max; } return p; } /************************************************* * Find the fixed length of a pattern * *************************************************/ /* Scan a pattern and compute the fixed length of subject that will match it, if the length is fixed. This is needed for dealing with backward assertions. Arguments: code points to the start of the pattern (the bracket) options the compiling options Returns: the fixed length, or -1 if there is no fixed length */ static int find_fixedlength(uschar *code, int options) { int length = -1; register int branchlength = 0; register uschar *cc = code + 3; /* Scan along the opcodes for this branch. If we get to the end of the branch, check the length against that of the other branches. */ for (;;) { int d; register int op = *cc; if (op >= OP_BRA) op = OP_BRA; switch (op) { case OP_BRA: case OP_ONCE: case OP_COND: d = find_fixedlength(cc, options); if (d < 0) return -1; branchlength += d; do cc += (cc[1] << 8) + cc[2]; while (*cc == OP_ALT); cc += 3; break; /* Reached end of a branch; if it's a ket it is the end of a nested call. If it's ALT it is an alternation in a nested call. If it is END it's the end of the outer call. All can be handled by the same code. */ case OP_ALT: case OP_KET: case OP_KETRMAX: case OP_KETRMIN: case OP_END: if (length < 0) length = branchlength; else if (length != branchlength) return -1; if (*cc != OP_ALT) return length; cc += 3; branchlength = 0; break; /* Skip over assertive subpatterns */ case OP_ASSERT: case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: do cc += (cc[1] << 8) + cc[2]; while (*cc == OP_ALT); cc += 3; break; /* Skip over things that don't match chars */ case OP_REVERSE: case OP_BRANUMBER: case OP_CREF: cc++; /* Fall through */ case OP_OPT: cc++; /* Fall through */ case OP_SOD: case OP_EOD: case OP_EODN: case OP_CIRC: case OP_DOLL: case OP_NOT_WORD_BOUNDARY: case OP_WORD_BOUNDARY: cc++; break; /* Handle char strings. In UTF-8 mode we must count characters, not bytes. This requires a scan of the string, unfortunately. We assume valid UTF-8 strings, so all we do is reduce the length by one for byte whose bits are 10xxxxxx. */ case OP_CHARS: branchlength += *(++cc); #ifdef SUPPORT_UTF8 for (d = 1; d <= *cc; d++) if ((cc[d] & 0xc0) == 0x80) branchlength--; #endif cc += *cc + 1; break; /* Handle exact repetitions */ case OP_EXACT: case OP_TYPEEXACT: branchlength += (cc[1] << 8) + cc[2]; cc += 4; break; /* Handle single-char matchers */ case OP_NOT_DIGIT: case OP_DIGIT: case OP_NOT_WHITESPACE: case OP_WHITESPACE: case OP_NOT_WORDCHAR: case OP_WORDCHAR: case OP_ANY: branchlength++; cc++; break; /* Check a class for variable quantification */ case OP_CLASS: cc += 33; switch (*cc) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRQUERY: case OP_CRMINQUERY: return -1; case OP_CRRANGE: case OP_CRMINRANGE: if ((cc[1] << 8) + cc[2] != (cc[3] << 8) + cc[4]) return -1; branchlength += (cc[1] << 8) + cc[2]; cc += 5; break; default: branchlength++; } break; /* Anything else is variable length */ default: return -1; } } /* Control never gets here */ } /************************************************* * Check for POSIX class syntax * *************************************************/ /* This function is called when the sequence "[:" or "[." or "[=" is encountered in a character class. It checks whether this is followed by an optional ^ and then a sequence of letters, terminated by a matching ":]" or ".]" or "=]". Argument: ptr pointer to the initial [ endptr where to return the end pointer cd pointer to compile data Returns: TRUE or FALSE */ static BOOL check_posix_syntax(const uschar *ptr, const uschar **endptr, compile_data *cd) { int terminator; /* Don't combine these lines; the Solaris cc */ terminator = *(++ptr); /* compiler warns about "non-constant" initializer. */ if (*(++ptr) == '^') ptr++; while ((cd->ctypes[*ptr] & ctype_letter) != 0) ptr++; if (*ptr == terminator && ptr[1] == ']') { *endptr = ptr; return TRUE; } return FALSE; } /************************************************* * Check POSIX class name * *************************************************/ /* This function is called to check the name given in a POSIX-style class entry such as [:alnum:]. Arguments: ptr points to the first letter len the length of the name Returns: a value representing the name, or -1 if unknown */ static int check_posix_name(const uschar *ptr, int len) { register int yield = 0; while (posix_name_lengths[yield] != 0) { if (len == posix_name_lengths[yield] && strncmp((const char *)ptr, posix_names[yield], len) == 0) return yield; yield++; } return -1; } /************************************************* * Compile one branch * *************************************************/ /* Scan the pattern, compiling it into the code vector. Arguments: options the option bits brackets points to number of extracting brackets used code points to the pointer to the current code point ptrptr points to the current pattern pointer errorptr points to pointer to error message optchanged set to the value of the last OP_OPT item compiled reqchar set to the last literal character required, else -1 countlits set to count of mandatory literal characters cd contains pointers to tables Returns: TRUE on success FALSE, with *errorptr set on error */ static BOOL compile_branch(int options, int *brackets, uschar **codeptr, const uschar **ptrptr, const char **errorptr, int *optchanged, int *reqchar, int *countlits, compile_data *cd) { int repeat_type, op_type; int repeat_min, repeat_max; int bravalue, length; int greedy_default, greedy_non_default; int prevreqchar; int condcount = 0; int subcountlits = 0; register int c; register uschar *code = *codeptr; uschar *tempcode; const uschar *ptr = *ptrptr; const uschar *tempptr; uschar *previous = NULL; uschar class[32]; /* Set up the default and non-default settings for greediness */ greedy_default = ((options & PCRE_UNGREEDY) != 0); greedy_non_default = greedy_default ^ 1; /* Initialize no required char, and count of literals */ *reqchar = prevreqchar = -1; *countlits = 0; /* Switch on next character until the end of the branch */ for (;; ptr++) { BOOL negate_class; int class_charcount; int class_lastchar; int newoptions; int skipbytes; int subreqchar; c = *ptr; if ((options & PCRE_EXTENDED) != 0) { if ((cd->ctypes[c] & ctype_space) != 0) continue; if (c == '#') { /* The space before the ; is to avoid a warning on a silly compiler on the Macintosh. */ while ((c = *(++ptr)) != 0 && c != NEWLINE) ; continue; } } switch(c) { /* The branch terminates at end of string, |, or ). */ case 0: case '|': case ')': *codeptr = code; *ptrptr = ptr; return TRUE; /* Handle single-character metacharacters */ case '^': previous = NULL; *code++ = OP_CIRC; break; case '$': previous = NULL; *code++ = OP_DOLL; break; case '.': previous = code; *code++ = OP_ANY; break; /* Character classes. These always build a 32-byte bitmap of the permitted characters, except in the special case where there is only one character. For negated classes, we build the map as usual, then invert it at the end. */ case '[': previous = code; *code++ = OP_CLASS; /* If the first character is '^', set the negation flag and skip it. */ if ((c = *(++ptr)) == '^') { negate_class = TRUE; c = *(++ptr); } else negate_class = FALSE; /* Keep a count of chars so that we can optimize the case of just a single character. */ class_charcount = 0; class_lastchar = -1; /* Initialize the 32-char bit map to all zeros. We have to build the map in a temporary bit of store, in case the class contains only 1 character, because in that case the compiled code doesn't use the bit map. */ memset(class, 0, 32 * sizeof(uschar)); /* Process characters until ] is reached. By writing this as a "do" it means that an initial ] is taken as a data character. */ do { if (c == 0) { *errorptr = ERR6; goto FAILED; } /* Handle POSIX class names. Perl allows a negation extension of the form [:^name]. A square bracket that doesn't match the syntax is treated as a literal. We also recognize the POSIX constructions [.ch.] and [=ch=] ("collating elements") and fault them, as Perl 5.6 does. */ if (c == '[' && (ptr[1] == ':' || ptr[1] == '.' || ptr[1] == '=') && check_posix_syntax(ptr, &tempptr, cd)) { BOOL local_negate = FALSE; int posix_class, i; register const uschar *cbits = cd->cbits; if (ptr[1] != ':') { *errorptr = ERR31; goto FAILED; } ptr += 2; if (*ptr == '^') { local_negate = TRUE; ptr++; } posix_class = check_posix_name(ptr, tempptr - ptr); if (posix_class < 0) { *errorptr = ERR30; goto FAILED; } /* If matching is caseless, upper and lower are converted to alpha. This relies on the fact that the class table starts with alpha, lower, upper as the first 3 entries. */ if ((options & PCRE_CASELESS) != 0 && posix_class <= 2) posix_class = 0; /* Or into the map we are building up to 3 of the static class tables, or their negations. */ posix_class *= 3; for (i = 0; i < 3; i++) { int taboffset = posix_class_maps[posix_class + i]; if (taboffset < 0) break; if (local_negate) for (c = 0; c < 32; c++) class[c] |= ~cbits[c+taboffset]; else for (c = 0; c < 32; c++) class[c] |= cbits[c+taboffset]; } ptr = tempptr + 1; class_charcount = 10; /* Set > 1; assumes more than 1 per class */ continue; } /* Backslash may introduce a single character, or it may introduce one of the specials, which just set a flag. Escaped items are checked for validity in the pre-compiling pass. The sequence \b is a special case. Inside a class (and only there) it is treated as backspace. Elsewhere it marks a word boundary. Other escapes have preset maps ready to or into the one we are building. We assume they have more than one character in them, so set class_count bigger than one. */ if (c == '\\') { c = check_escape(&ptr, errorptr, *brackets, options, TRUE, cd); if (-c == ESC_b) c = '\b'; else if (c < 0) { register const uschar *cbits = cd->cbits; class_charcount = 10; switch (-c) { case ESC_d: for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_digit]; continue; case ESC_D: for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_digit]; continue; case ESC_w: for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_word]; continue; case ESC_W: for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_word]; continue; case ESC_s: for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_space]; continue; case ESC_S: for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_space]; continue; default: *errorptr = ERR7; goto FAILED; } } /* Fall through if single character, but don't at present allow chars > 255 in UTF-8 mode. */ #ifdef SUPPORT_UTF8 if (c > 255) { *errorptr = ERR33; goto FAILED; } #endif } /* A single character may be followed by '-' to form a range. However, Perl does not permit ']' to be the end of the range. A '-' character here is treated as a literal. */ if (ptr[1] == '-' && ptr[2] != ']') { int d; ptr += 2; d = *ptr; if (d == 0) { *errorptr = ERR6; goto FAILED; } /* The second part of a range can be a single-character escape, but not any of the other escapes. Perl 5.6 treats a hyphen as a literal in such circumstances. */ if (d == '\\') { const uschar *oldptr = ptr; d = check_escape(&ptr, errorptr, *brackets, options, TRUE, cd); #ifdef SUPPORT_UTF8 if (d > 255) { *errorptr = ERR33; goto FAILED; } #endif /* \b is backslash; any other special means the '-' was literal */ if (d < 0) { if (d == -ESC_b) d = '\b'; else { ptr = oldptr - 2; goto SINGLE_CHARACTER; /* A few lines below */ } } } if (d < c) { *errorptr = ERR8; goto FAILED; } for (; c <= d; c++) { class[c/8] |= (1 << (c&7)); if ((options & PCRE_CASELESS) != 0) { int uc = cd->fcc[c]; /* flip case */ class[uc/8] |= (1 << (uc&7)); } class_charcount++; /* in case a one-char range */ class_lastchar = c; } continue; /* Go get the next char in the class */ } /* Handle a lone single character - we can get here for a normal non-escape char, or after \ that introduces a single character. */ SINGLE_CHARACTER: class [c/8] |= (1 << (c&7)); if ((options & PCRE_CASELESS) != 0) { c = cd->fcc[c]; /* flip case */ class[c/8] |= (1 << (c&7)); } class_charcount++; class_lastchar = c; } /* Loop until ']' reached; the check for end of string happens inside the loop. This "while" is the end of the "do" above. */ while ((c = *(++ptr)) != ']'); /* If class_charcount is 1 and class_lastchar is not negative, we saw precisely one character. This doesn't need the whole 32-byte bit map. We turn it into a 1-character OP_CHAR if it's positive, or OP_NOT if it's negative. */ if (class_charcount == 1 && class_lastchar >= 0) { if (negate_class) { code[-1] = OP_NOT; } else { code[-1] = OP_CHARS; *code++ = 1; } *code++ = class_lastchar; } /* Otherwise, negate the 32-byte map if necessary, and copy it into the code vector. */ else { if (negate_class) for (c = 0; c < 32; c++) code[c] = ~class[c]; else memcpy(code, class, 32); code += 32; } break; /* Various kinds of repeat */ case '{': if (!is_counted_repeat(ptr+1, cd)) goto NORMAL_CHAR; ptr = read_repeat_counts(ptr+1, &repeat_min, &repeat_max, errorptr, cd); if (*errorptr != NULL) goto FAILED; goto REPEAT; case '*': repeat_min = 0; repeat_max = -1; goto REPEAT; case '+': repeat_min = 1; repeat_max = -1; goto REPEAT; case '?': repeat_min = 0; repeat_max = 1; REPEAT: if (previous == NULL) { *errorptr = ERR9; goto FAILED; } /* If the next character is '?' this is a minimizing repeat, by default, but if PCRE_UNGREEDY is set, it works the other way round. Advance to the next character. */ if (ptr[1] == '?') { repeat_type = greedy_non_default; ptr++; } else repeat_type = greedy_default; /* If previous was a string of characters, chop off the last one and use it as the subject of the repeat. If there was only one character, we can abolish the previous item altogether. A repeat with a zero minimum wipes out any reqchar setting, backing up to the previous value. We must also adjust the countlits value. */ if (*previous == OP_CHARS) { int len = previous[1]; if (repeat_min == 0) *reqchar = prevreqchar; *countlits += repeat_min - 1; if (len == 1) { c = previous[2]; code = previous; } else { c = previous[len+1]; previous[1]--; code--; } op_type = 0; /* Use single-char op codes */ goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */ } /* If previous was a single negated character ([^a] or similar), we use one of the special opcodes, replacing it. The code is shared with single- character repeats by adding a suitable offset into repeat_type. */ else if ((int)*previous == OP_NOT) { op_type = OP_NOTSTAR - OP_STAR; /* Use "not" opcodes */ c = previous[1]; code = previous; goto OUTPUT_SINGLE_REPEAT; } /* If previous was a character type match (\d or similar), abolish it and create a suitable repeat item. The code is shared with single-character repeats by adding a suitable offset into repeat_type. */ else if ((int)*previous < OP_EODN || *previous == OP_ANY) { op_type = OP_TYPESTAR - OP_STAR; /* Use type opcodes */ c = *previous; code = previous; OUTPUT_SINGLE_REPEAT: /* If the maximum is zero then the minimum must also be zero; Perl allows this case, so we do too - by simply omitting the item altogether. */ if (repeat_max == 0) goto END_REPEAT; /* Combine the op_type with the repeat_type */ repeat_type += op_type; /* A minimum of zero is handled either as the special case * or ?, or as an UPTO, with the maximum given. */ if (repeat_min == 0) { if (repeat_max == -1) *code++ = OP_STAR + repeat_type; else if (repeat_max == 1) *code++ = OP_QUERY + repeat_type; else { *code++ = OP_UPTO + repeat_type; *code++ = repeat_max >> 8; *code++ = (repeat_max & 255); } } /* The case {1,} is handled as the special case + */ else if (repeat_min == 1 && repeat_max == -1) *code++ = OP_PLUS + repeat_type; /* The case {n,n} is just an EXACT, while the general case {n,m} is handled as an EXACT followed by an UPTO. An EXACT of 1 is optimized. */ else { if (repeat_min != 1) { *code++ = OP_EXACT + op_type; /* NB EXACT doesn't have repeat_type */ *code++ = repeat_min >> 8; *code++ = (repeat_min & 255); } /* If the mininum is 1 and the previous item was a character string, we either have to put back the item that got cancelled if the string length was 1, or add the character back onto the end of a longer string. For a character type nothing need be done; it will just get put back naturally. Note that the final character is always going to get added below. */ else if (*previous == OP_CHARS) { if (code == previous) code += 2; else previous[1]++; } /* For a single negated character we also have to put back the item that got cancelled. */ else if (*previous == OP_NOT) code++; /* If the maximum is unlimited, insert an OP_STAR. */ if (repeat_max < 0) { *code++ = c; *code++ = OP_STAR + repeat_type; } /* Else insert an UPTO if the max is greater than the min. */ else if (repeat_max != repeat_min) { *code++ = c; repeat_max -= repeat_min; *code++ = OP_UPTO + repeat_type; *code++ = repeat_max >> 8; *code++ = (repeat_max & 255); } } /* The character or character type itself comes last in all cases. */ *code++ = c; } /* If previous was a character class or a back reference, we put the repeat stuff after it, but just skip the item if the repeat was {0,0}. */ else if (*previous == OP_CLASS || *previous == OP_REF) { if (repeat_max == 0) { code = previous; goto END_REPEAT; } if (repeat_min == 0 && repeat_max == -1) *code++ = OP_CRSTAR + repeat_type; else if (repeat_min == 1 && repeat_max == -1) *code++ = OP_CRPLUS + repeat_type; else if (repeat_min == 0 && repeat_max == 1) *code++ = OP_CRQUERY + repeat_type; else { *code++ = OP_CRRANGE + repeat_type; *code++ = repeat_min >> 8; *code++ = repeat_min & 255; if (repeat_max == -1) repeat_max = 0; /* 2-byte encoding for max */ *code++ = repeat_max >> 8; *code++ = repeat_max & 255; } } /* If previous was a bracket group, we may have to replicate it in certain cases. */ else if ((int)*previous >= OP_BRA || (int)*previous == OP_ONCE || (int)*previous == OP_COND) { register int i; int ketoffset = 0; int len = code - previous; uschar *bralink = NULL; /* If the maximum repeat count is unlimited, find the end of the bracket by scanning through from the start, and compute the offset back to it from the current code pointer. There may be an OP_OPT setting following the final KET, so we can't find the end just by going back from the code pointer. */ if (repeat_max == -1) { register uschar *ket = previous; do ket += (ket[1] << 8) + ket[2]; while (*ket != OP_KET); ketoffset = code - ket; } /* The case of a zero minimum is special because of the need to stick OP_BRAZERO in front of it, and because the group appears once in the data, whereas in other cases it appears the minimum number of times. For this reason, it is simplest to treat this case separately, as otherwise the code gets far too messy. There are several special subcases when the minimum is zero. */ if (repeat_min == 0) { /* If we set up a required char from the bracket, we must back off to the previous value and reset the countlits value too. */ if (subcountlits > 0) { *reqchar = prevreqchar; *countlits -= subcountlits; } /* If the maximum is also zero, we just omit the group from the output altogether. */ if (repeat_max == 0) { code = previous; goto END_REPEAT; } /* If the maximum is 1 or unlimited, we just have to stick in the BRAZERO and do no more at this point. */ if (repeat_max <= 1) { memmove(previous+1, previous, len); code++; *previous++ = OP_BRAZERO + repeat_type; } /* If the maximum is greater than 1 and limited, we have to replicate in a nested fashion, sticking OP_BRAZERO before each set of brackets. The first one has to be handled carefully because it's the original copy, which has to be moved up. The remainder can be handled by code that is common with the non-zero minimum case below. We just have to adjust the value or repeat_max, since one less copy is required. */ else { int offset; memmove(previous+4, previous, len); code += 4; *previous++ = OP_BRAZERO + repeat_type; *previous++ = OP_BRA; /* We chain together the bracket offset fields that have to be filled in later when the ends of the brackets are reached. */ offset = (bralink == NULL)? 0 : previous - bralink; bralink = previous; *previous++ = offset >> 8; *previous++ = offset & 255; } repeat_max--; } /* If the minimum is greater than zero, replicate the group as many times as necessary, and adjust the maximum to the number of subsequent copies that we need. */ else { for (i = 1; i < repeat_min; i++) { memcpy(code, previous, len); code += len; } if (repeat_max > 0) repeat_max -= repeat_min; } /* This code is common to both the zero and non-zero minimum cases. If the maximum is limited, it replicates the group in a nested fashion, remembering the bracket starts on a stack. In the case of a zero minimum, the first one was set up above. In all cases the repeat_max now specifies the number of additional copies needed. */ if (repeat_max >= 0) { for (i = repeat_max - 1; i >= 0; i--) { *code++ = OP_BRAZERO + repeat_type; /* All but the final copy start a new nesting, maintaining the chain of brackets outstanding. */ if (i != 0) { int offset; *code++ = OP_BRA; offset = (bralink == NULL)? 0 : code - bralink; bralink = code; *code++ = offset >> 8; *code++ = offset & 255; } memcpy(code, previous, len); code += len; } /* Now chain through the pending brackets, and fill in their length fields (which are holding the chain links pro tem). */ while (bralink != NULL) { int oldlinkoffset; int offset = code - bralink + 1; uschar *bra = code - offset; oldlinkoffset = (bra[1] << 8) + bra[2]; bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset; *code++ = OP_KET; *code++ = bra[1] = offset >> 8; *code++ = bra[2] = (offset & 255); } } /* If the maximum is unlimited, set a repeater in the final copy. We can't just offset backwards from the current code point, because we don't know if there's been an options resetting after the ket. The correct offset was computed above. */ else code[-ketoffset] = OP_KETRMAX + repeat_type; } /* Else there's some kind of shambles */ else { *errorptr = ERR11; goto FAILED; } /* In all case we no longer have a previous item. */ END_REPEAT: previous = NULL; break; /* Start of nested bracket sub-expression, or comment or lookahead or lookbehind or option setting or condition. First deal with special things that can come after a bracket; all are introduced by ?, and the appearance of any of them means that this is not a referencing group. They were checked for validity in the first pass over the string, so we don't have to check for syntax errors here. */ case '(': newoptions = options; skipbytes = 0; if (*(++ptr) == '?') { int set, unset; int *optset; switch (*(++ptr)) { case '#': /* Comment; skip to ket */ ptr++; while (*ptr != ')') ptr++; continue; case ':': /* Non-extracting bracket */ bravalue = OP_BRA; ptr++; break; case '(': bravalue = OP_COND; /* Conditional group */ if ((cd->ctypes[*(++ptr)] & ctype_digit) != 0) { int condref = *ptr - '0'; while (*(++ptr) != ')') condref = condref*10 + *ptr - '0'; if (condref == 0) { *errorptr = ERR35; goto FAILED; } ptr++; code[3] = OP_CREF; code[4] = condref >> 8; code[5] = condref & 255; skipbytes = 3; } else ptr--; break; case '=': /* Positive lookahead */ bravalue = OP_ASSERT; ptr++; break; case '!': /* Negative lookahead */ bravalue = OP_ASSERT_NOT; ptr++; break; case '<': /* Lookbehinds */ switch (*(++ptr)) { case '=': /* Positive lookbehind */ bravalue = OP_ASSERTBACK; ptr++; break; case '!': /* Negative lookbehind */ bravalue = OP_ASSERTBACK_NOT; ptr++; break; default: /* Syntax error */ *errorptr = ERR24; goto FAILED; } break; case '>': /* One-time brackets */ bravalue = OP_ONCE; ptr++; break; case 'R': /* Pattern recursion */ *code++ = OP_RECURSE; ptr++; continue; default: /* Option setting */ set = unset = 0; optset = &set; while (*ptr != ')' && *ptr != ':') { switch (*ptr++) { case '-': optset = &unset; break; case 'i': *optset |= PCRE_CASELESS; break; case 'm': *optset |= PCRE_MULTILINE; break; case 's': *optset |= PCRE_DOTALL; break; case 'x': *optset |= PCRE_EXTENDED; break; case 'U': *optset |= PCRE_UNGREEDY; break; case 'X': *optset |= PCRE_EXTRA; break; default: *errorptr = ERR12; goto FAILED; } } /* Set up the changed option bits, but don't change anything yet. */ newoptions = (options | set) & (~unset); /* If the options ended with ')' this is not the start of a nested group with option changes, so the options change at this level. At top level there is nothing else to be done (the options will in fact have been set from the start of compiling as a result of the first pass) but at an inner level we must compile code to change the ims options if necessary, and pass the new setting back so that it can be put at the start of any following branches, and when this group ends, a resetting item can be compiled. */ if (*ptr == ')') { if ((options & PCRE_INGROUP) != 0 && (options & PCRE_IMS) != (newoptions & PCRE_IMS)) { *code++ = OP_OPT; *code++ = *optchanged = newoptions & PCRE_IMS; } options = newoptions; /* Change options at this level */ previous = NULL; /* This item can't be repeated */ continue; /* It is complete */ } /* If the options ended with ':' we are heading into a nested group with possible change of options. Such groups are non-capturing and are not assertions of any kind. All we need to do is skip over the ':'; the newoptions value is handled below. */ bravalue = OP_BRA; ptr++; } } /* Else we have a referencing group; adjust the opcode. If the bracket number is greater than EXTRACT_BASIC_MAX, we set the opcode one higher, and arrange for the true number to follow later, in an OP_BRANUMBER item. */ else { if (++(*brackets) > EXTRACT_BASIC_MAX) { bravalue = OP_BRA + EXTRACT_BASIC_MAX + 1; code[3] = OP_BRANUMBER; code[4] = *brackets >> 8; code[5] = *brackets & 255; skipbytes = 3; } else bravalue = OP_BRA + *brackets; } /* Process nested bracketed re. Assertions may not be repeated, but other kinds can be. We copy code into a non-register variable in order to be able to pass its address because some compilers complain otherwise. Pass in a new setting for the ims options if they have changed. */ previous = (bravalue >= OP_ONCE)? code : NULL; *code = bravalue; tempcode = code; if (!compile_regex( options | PCRE_INGROUP, /* Set for all nested groups */ ((options & PCRE_IMS) != (newoptions & PCRE_IMS))? newoptions & PCRE_IMS : -1, /* Pass ims options if changed */ brackets, /* Extracting bracket count */ &tempcode, /* Where to put code (updated) */ &ptr, /* Input pointer (updated) */ errorptr, /* Where to put an error message */ (bravalue == OP_ASSERTBACK || bravalue == OP_ASSERTBACK_NOT), /* TRUE if back assert */ skipbytes, /* Skip over OP_COND/OP_BRANUMBER */ &subreqchar, /* For possible last char */ &subcountlits, /* For literal count */ cd)) /* Tables block */ goto FAILED; /* At the end of compiling, code is still pointing to the start of the group, while tempcode has been updated to point past the end of the group and any option resetting that may follow it. The pattern pointer (ptr) is on the bracket. */ /* If this is a conditional bracket, check that there are no more than two branches in the group. */ else if (bravalue == OP_COND) { uschar *tc = code; condcount = 0; do { condcount++; tc += (tc[1] << 8) | tc[2]; } while (*tc != OP_KET); if (condcount > 2) { *errorptr = ERR27; goto FAILED; } } /* Handle updating of the required character. If the subpattern didn't set one, leave it as it was. Otherwise, update it for normal brackets of all kinds, forward assertions, and conditions with two branches. Don't update the literal count for forward assertions, however. If the bracket is followed by a quantifier with zero repeat, we have to back off. Hence the definition of prevreqchar and subcountlits outside the main loop so that they can be accessed for the back off. */ if (subreqchar > 0 && (bravalue >= OP_BRA || bravalue == OP_ONCE || bravalue == OP_ASSERT || (bravalue == OP_COND && condcount == 2))) { prevreqchar = *reqchar; *reqchar = subreqchar; if (bravalue != OP_ASSERT) *countlits += subcountlits; } /* Now update the main code pointer to the end of the group. */ code = tempcode; /* Error if hit end of pattern */ if (*ptr != ')') { *errorptr = ERR14; goto FAILED; } break; /* Check \ for being a real metacharacter; if not, fall through and handle it as a data character at the start of a string. Escape items are checked for validity in the pre-compiling pass. */ case '\\': tempptr = ptr; c = check_escape(&ptr, errorptr, *brackets, options, FALSE, cd); /* Handle metacharacters introduced by \. For ones like \d, the ESC_ values are arranged to be the negation of the corresponding OP_values. For the back references, the values are ESC_REF plus the reference number. Only back references and those types that consume a character may be repeated. We can test for values between ESC_b and ESC_Z for the latter; this may have to change if any new ones are ever created. */ if (c < 0) { if (-c >= ESC_REF) { int number = -c - ESC_REF; previous = code; *code++ = OP_REF; *code++ = number >> 8; *code++ = number & 255; } else { previous = (-c > ESC_b && -c < ESC_Z)? code : NULL; *code++ = -c; } continue; } /* Data character: reset and fall through */ ptr = tempptr; c = '\\'; /* Handle a run of data characters until a metacharacter is encountered. The first character is guaranteed not to be whitespace or # when the extended flag is set. */ NORMAL_CHAR: default: previous = code; *code = OP_CHARS; code += 2; length = 0; do { if ((options & PCRE_EXTENDED) != 0) { if ((cd->ctypes[c] & ctype_space) != 0) continue; if (c == '#') { /* The space before the ; is to avoid a warning on a silly compiler on the Macintosh. */ while ((c = *(++ptr)) != 0 && c != NEWLINE) ; if (c == 0) break; continue; } } /* Backslash may introduce a data char or a metacharacter. Escaped items are checked for validity in the pre-compiling pass. Stop the string before a metaitem. */ if (c == '\\') { tempptr = ptr; c = check_escape(&ptr, errorptr, *brackets, options, FALSE, cd); if (c < 0) { ptr = tempptr; break; } /* If a character is > 127 in UTF-8 mode, we have to turn it into two or more characters in the UTF-8 encoding. */ #ifdef SUPPORT_UTF8 if (c > 127 && (options & PCRE_UTF8) != 0) { uschar buffer[8]; int len = ord2utf8(c, buffer); for (c = 0; c < len; c++) *code++ = buffer[c]; length += len; continue; } #endif } /* Ordinary character or single-char escape */ *code++ = c; length++; } /* This "while" is the end of the "do" above. */ while (length < MAXLIT && (cd->ctypes[c = *(++ptr)] & ctype_meta) == 0); /* Update the last character and the count of literals */ prevreqchar = (length > 1)? code[-2] : *reqchar; *reqchar = code[-1]; *countlits += length; /* Compute the length and set it in the data vector, and advance to the next state. */ previous[1] = length; if (length < MAXLIT) ptr--; break; } } /* end of big loop */ /* Control never reaches here by falling through, only by a goto for all the error states. Pass back the position in the pattern so that it can be displayed to the user for diagnosing the error. */ FAILED: *ptrptr = ptr; return FALSE; } /************************************************* * Compile sequence of alternatives * *************************************************/ /* On entry, ptr is pointing past the bracket character, but on return it points to the closing bracket, or vertical bar, or end of string. The code variable is pointing at the byte into which the BRA operator has been stored. If the ims options are changed at the start (for a (?ims: group) or during any branch, we need to insert an OP_OPT item at the start of every following branch to ensure they get set correctly at run time, and also pass the new options into every subsequent branch compile. Argument: options the option bits optchanged new ims options to set as if (?ims) were at the start, or -1 for no change brackets -> int containing the number of extracting brackets used codeptr -> the address of the current code pointer ptrptr -> the address of the current pattern pointer errorptr -> pointer to error message lookbehind TRUE if this is a lookbehind assertion skipbytes skip this many bytes at start (for OP_COND, OP_BRANUMBER) reqchar -> place to put the last required character, or a negative number countlits -> place to put the shortest literal count of any branch cd points to the data block with tables pointers Returns: TRUE on success */ static BOOL compile_regex(int options, int optchanged, int *brackets, uschar **codeptr, const uschar **ptrptr, const char **errorptr, BOOL lookbehind, int skipbytes, int *reqchar, int *countlits, compile_data *cd) { const uschar *ptr = *ptrptr; uschar *code = *codeptr; uschar *last_branch = code; uschar *start_bracket = code; uschar *reverse_count = NULL; int oldoptions = options & PCRE_IMS; int branchreqchar, branchcountlits; *reqchar = -1; *countlits = INT_MAX; code += 3 + skipbytes; /* Loop for each alternative branch */ for (;;) { int length; /* Handle change of options */ if (optchanged >= 0) { *code++ = OP_OPT; *code++ = optchanged; options = (options & ~PCRE_IMS) | optchanged; } /* Set up dummy OP_REVERSE if lookbehind assertion */ if (lookbehind) { *code++ = OP_REVERSE; reverse_count = code; *code++ = 0; *code++ = 0; } /* Now compile the branch */ if (!compile_branch(options, brackets, &code, &ptr, errorptr, &optchanged, &branchreqchar, &branchcountlits, cd)) { *ptrptr = ptr; return FALSE; } /* Fill in the length of the last branch */ length = code - last_branch; last_branch[1] = length >> 8; last_branch[2] = length & 255; /* Save the last required character if all branches have the same; a current value of -1 means unset, while -2 means "previous branch had no last required char". */ if (*reqchar != -2) { if (branchreqchar >= 0) { if (*reqchar == -1) *reqchar = branchreqchar; else if (*reqchar != branchreqchar) *reqchar = -2; } else *reqchar = -2; } /* Keep the shortest literal count */ if (branchcountlits < *countlits) *countlits = branchcountlits; DPRINTF(("literal count = %d min=%d\n", branchcountlits, *countlits)); /* If lookbehind, check that this branch matches a fixed-length string, and put the length into the OP_REVERSE item. Temporarily mark the end of the branch with OP_END. */ if (lookbehind) { *code = OP_END; length = find_fixedlength(last_branch, options); DPRINTF(("fixed length = %d\n", length)); if (length < 0) { *errorptr = ERR25; *ptrptr = ptr; return FALSE; } reverse_count[0] = (length >> 8); reverse_count[1] = length & 255; } /* Reached end of expression, either ')' or end of pattern. Insert a terminating ket and the length of the whole bracketed item, and return, leaving the pointer at the terminating char. If any of the ims options were changed inside the group, compile a resetting op-code following. */ if (*ptr != '|') { length = code - start_bracket; *code++ = OP_KET; *code++ = length >> 8; *code++ = length & 255; if (optchanged >= 0) { *code++ = OP_OPT; *code++ = oldoptions; } *codeptr = code; *ptrptr = ptr; return TRUE; } /* Another branch follows; insert an "or" node and advance the pointer. */ *code = OP_ALT; last_branch = code; code += 3; ptr++; } /* Control never reaches here */ } /************************************************* * Find first significant op code * *************************************************/ /* This is called by several functions that scan a compiled expression looking for a fixed first character, or an anchoring op code etc. It skips over things that do not influence this. For one application, a change of caseless option is important. Arguments: code pointer to the start of the group options pointer to external options optbit the option bit whose changing is significant, or zero if none are optstop TRUE to return on option change, otherwise change the options value and continue Returns: pointer to the first significant opcode */ static const uschar* first_significant_code(const uschar *code, int *options, int optbit, BOOL optstop) { for (;;) { switch ((int)*code) { case OP_OPT: if (optbit > 0 && ((int)code[1] & optbit) != (*options & optbit)) { if (optstop) return code; *options = (int)code[1]; } code += 2; break; case OP_CREF: case OP_BRANUMBER: code += 3; break; case OP_WORD_BOUNDARY: case OP_NOT_WORD_BOUNDARY: code++; break; case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: do code += (code[1] << 8) + code[2]; while (*code == OP_ALT); code += 3; break; default: return code; } } /* Control never reaches here */ } /************************************************* * Check for anchored expression * *************************************************/ /* Try to find out if this is an anchored regular expression. Consider each alternative branch. If they all start with OP_SOD or OP_CIRC, or with a bracket all of whose alternatives start with OP_SOD or OP_CIRC (recurse ad lib), then it's anchored. However, if this is a multiline pattern, then only OP_SOD counts, since OP_CIRC can match in the middle. A branch is also implicitly anchored if it starts with .* and DOTALL is set, because that will try the rest of the pattern at all possible matching points, so there is no point trying them again. Arguments: code points to start of expression (the bracket) options points to the options setting Returns: TRUE or FALSE */ static BOOL is_anchored(register const uschar *code, int *options) { do { const uschar *scode = first_significant_code(code + 3, options, PCRE_MULTILINE, FALSE); register int op = *scode; if (op >= OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND) { if (!is_anchored(scode, options)) return FALSE; } else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR) && (*options & PCRE_DOTALL) != 0) { if (scode[1] != OP_ANY) return FALSE; } else if (op != OP_SOD && ((*options & PCRE_MULTILINE) != 0 || op != OP_CIRC)) return FALSE; code += (code[1] << 8) + code[2]; } while (*code == OP_ALT); return TRUE; } /************************************************* * Check for starting with ^ or .* * *************************************************/ /* This is called to find out if every branch starts with ^ or .* so that "first char" processing can be done to speed things up in multiline matching and for non-DOTALL patterns that start with .* (which must start at the beginning or after \n). Argument: points to start of expression (the bracket) Returns: TRUE or FALSE */ static BOOL is_startline(const uschar *code) { do { const uschar *scode = first_significant_code(code + 3, NULL, 0, FALSE); register int op = *scode; if (op >= OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND) { if (!is_startline(scode)) return FALSE; } else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR) { if (scode[1] != OP_ANY) return FALSE; } else if (op != OP_CIRC) return FALSE; code += (code[1] << 8) + code[2]; } while (*code == OP_ALT); return TRUE; } /************************************************* * Check for fixed first char * *************************************************/ /* Try to find out if there is a fixed first character. This is called for unanchored expressions, as it speeds up their processing quite considerably. Consider each alternative branch. If they all start with the same char, or with a bracket all of whose alternatives start with the same char (recurse ad lib), then we return that char, otherwise -1. Arguments: code points to start of expression (the bracket) options pointer to the options (used to check casing changes) Returns: -1 or the fixed first char */ static int find_firstchar(const uschar *code, int *options) { register int c = -1; do { int d; const uschar *scode = first_significant_code(code + 3, options, PCRE_CASELESS, TRUE); register int op = *scode; if (op >= OP_BRA) op = OP_BRA; switch(op) { default: return -1; case OP_BRA: case OP_ASSERT: case OP_ONCE: case OP_COND: if ((d = find_firstchar(scode, options)) < 0) return -1; if (c < 0) c = d; else if (c != d) return -1; break; case OP_EXACT: /* Fall through */ scode++; case OP_CHARS: /* Fall through */ scode++; case OP_PLUS: case OP_MINPLUS: if (c < 0) c = scode[1]; else if (c != scode[1]) return -1; break; } code += (code[1] << 8) + code[2]; } while (*code == OP_ALT); return c; } /************************************************* * Compile a Regular Expression * *************************************************/ /* This function takes a string and returns a pointer to a block of store holding a compiled version of the expression. Arguments: pattern the regular expression options various option bits errorptr pointer to pointer to error text erroroffset ptr offset in pattern where error was detected tables pointer to character tables or NULL Returns: pointer to compiled data block, or NULL on error, with errorptr and erroroffset set */ pcre * pcre_compile(const char *pattern, int options, const char **errorptr, int *erroroffset, const unsigned char *tables) { real_pcre *re; int length = 3; /* For initial BRA plus length */ int runlength; int c, reqchar, countlits; int bracount = 0; int top_backref = 0; int branch_extra = 0; int branch_newextra; unsigned int brastackptr = 0; size_t size; uschar *code; const uschar *ptr; compile_data compile_block; int brastack[BRASTACK_SIZE]; uschar bralenstack[BRASTACK_SIZE]; #ifdef DEBUG uschar *code_base, *code_end; #endif /* Can't support UTF8 unless PCRE has been compiled to include the code. */ #ifndef SUPPORT_UTF8 if ((options & PCRE_UTF8) != 0) { *errorptr = ERR32; return NULL; } #endif /* We can't pass back an error message if errorptr is NULL; I guess the best we can do is just return NULL. */ if (errorptr == NULL) return NULL; *errorptr = NULL; /* However, we can give a message for this error */ if (erroroffset == NULL) { *errorptr = ERR16; return NULL; } *erroroffset = 0; if ((options & ~PUBLIC_OPTIONS) != 0) { *errorptr = ERR17; return NULL; } /* Set up pointers to the individual character tables */ if (tables == NULL) tables = pcre_default_tables; compile_block.lcc = tables + lcc_offset; compile_block.fcc = tables + fcc_offset; compile_block.cbits = tables + cbits_offset; compile_block.ctypes = tables + ctypes_offset; /* Reflect pattern for debugging output */ DPRINTF(("------------------------------------------------------------------\n")); DPRINTF(("%s\n", pattern)); /* The first thing to do is to make a pass over the pattern to compute the amount of store required to hold the compiled code. This does not have to be perfect as long as errors are overestimates. At the same time we can detect any internal flag settings. Make an attempt to correct for any counted white space if an "extended" flag setting appears late in the pattern. We can't be so clever for #-comments. */ ptr = (const uschar *)(pattern - 1); while ((c = *(++ptr)) != 0) { int min, max; int class_charcount; int bracket_length; if ((options & PCRE_EXTENDED) != 0) { if ((compile_block.ctypes[c] & ctype_space) != 0) continue; if (c == '#') { /* The space before the ; is to avoid a warning on a silly compiler on the Macintosh. */ while ((c = *(++ptr)) != 0 && c != NEWLINE) ; continue; } } switch(c) { /* A backslashed item may be an escaped "normal" character or a character type. For a "normal" character, put the pointers and character back so that tests for whitespace etc. in the input are done correctly. */ case '\\': { const uschar *save_ptr = ptr; c = check_escape(&ptr, errorptr, bracount, options, FALSE, &compile_block); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; if (c >= 0) { ptr = save_ptr; c = '\\'; goto NORMAL_CHAR; } } length++; /* A back reference needs an additional 2 bytes, plus either one or 5 bytes for a repeat. We also need to keep the value of the highest back reference. */ if (c <= -ESC_REF) { int refnum = -c - ESC_REF; if (refnum > top_backref) top_backref = refnum; length += 2; /* For single back reference */ if (ptr[1] == '{' && is_counted_repeat(ptr+2, &compile_block)) { ptr = read_repeat_counts(ptr+2, &min, &max, errorptr, &compile_block); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; if ((min == 0 && (max == 1 || max == -1)) || (min == 1 && max == -1)) length++; else length += 5; if (ptr[1] == '?') ptr++; } } continue; case '^': case '.': case '$': case '*': /* These repeats won't be after brackets; */ case '+': /* those are handled separately */ case '?': length++; continue; /* This covers the cases of repeats after a single char, metachar, class, or back reference. */ case '{': if (!is_counted_repeat(ptr+1, &compile_block)) goto NORMAL_CHAR; ptr = read_repeat_counts(ptr+1, &min, &max, errorptr, &compile_block); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; if ((min == 0 && (max == 1 || max == -1)) || (min == 1 && max == -1)) length++; else { length--; /* Uncount the original char or metachar */ if (min == 1) length++; else if (min > 0) length += 4; if (max > 0) length += 4; else length += 2; } if (ptr[1] == '?') ptr++; continue; /* An alternation contains an offset to the next branch or ket. If any ims options changed in the previous branch(es), and/or if we are in a lookbehind assertion, extra space will be needed at the start of the branch. This is handled by branch_extra. */ case '|': length += 3 + branch_extra; continue; /* A character class uses 33 characters. Don't worry about character types that aren't allowed in classes - they'll get picked up during the compile. A character class that contains only one character uses 2 or 3 bytes, depending on whether it is negated or not. Notice this where we can. */ case '[': class_charcount = 0; if (*(++ptr) == '^') ptr++; do { if (*ptr == '\\') { int ch = check_escape(&ptr, errorptr, bracount, options, TRUE, &compile_block); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; if (-ch == ESC_b) class_charcount++; else class_charcount = 10; } else class_charcount++; ptr++; } while (*ptr != 0 && *ptr != ']'); /* Repeats for negated single chars are handled by the general code */ if (class_charcount == 1) length += 3; else { length += 33; /* A repeat needs either 1 or 5 bytes. */ if (*ptr != 0 && ptr[1] == '{' && is_counted_repeat(ptr+2, &compile_block)) { ptr = read_repeat_counts(ptr+2, &min, &max, errorptr, &compile_block); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; if ((min == 0 && (max == 1 || max == -1)) || (min == 1 && max == -1)) length++; else length += 5; if (ptr[1] == '?') ptr++; } } continue; /* Brackets may be genuine groups or special things */ case '(': branch_newextra = 0; bracket_length = 3; /* Handle special forms of bracket, which all start (? */ if (ptr[1] == '?') { int set, unset; int *optset; switch (c = ptr[2]) { /* Skip over comments entirely */ case '#': ptr += 3; while (*ptr != 0 && *ptr != ')') ptr++; if (*ptr == 0) { *errorptr = ERR18; goto PCRE_ERROR_RETURN; } continue; /* Non-referencing groups and lookaheads just move the pointer on, and then behave like a non-special bracket, except that they don't increment the count of extracting brackets. Ditto for the "once only" bracket, which is in Perl from version 5.005. */ case ':': case '=': case '!': case '>': ptr += 2; break; /* A recursive call to the regex is an extension, to provide the facility which can be obtained by $(?p{perl-code}) in Perl 5.6. */ case 'R': if (ptr[3] != ')') { *errorptr = ERR29; goto PCRE_ERROR_RETURN; } ptr += 3; length += 1; break; /* Lookbehinds are in Perl from version 5.005 */ case '<': if (ptr[3] == '=' || ptr[3] == '!') { ptr += 3; branch_newextra = 3; length += 3; /* For the first branch */ break; } *errorptr = ERR24; goto PCRE_ERROR_RETURN; /* Conditionals are in Perl from version 5.005. The bracket must either be followed by a number (for bracket reference) or by an assertion group. */ case '(': if ((compile_block.ctypes[ptr[3]] & ctype_digit) != 0) { ptr += 4; length += 3; while ((compile_block.ctypes[*ptr] & ctype_digit) != 0) ptr++; if (*ptr != ')') { *errorptr = ERR26; goto PCRE_ERROR_RETURN; } } else /* An assertion must follow */ { ptr++; /* Can treat like ':' as far as spacing is concerned */ if (ptr[2] != '?' || (ptr[3] != '=' && ptr[3] != '!' && ptr[3] != '<') ) { ptr += 2; /* To get right offset in message */ *errorptr = ERR28; goto PCRE_ERROR_RETURN; } } break; /* Else loop checking valid options until ) is met. Anything else is an error. If we are without any brackets, i.e. at top level, the settings act as if specified in the options, so massage the options immediately. This is for backward compatibility with Perl 5.004. */ default: set = unset = 0; optset = &set; ptr += 2; for (;; ptr++) { c = *ptr; switch (c) { case 'i': *optset |= PCRE_CASELESS; continue; case 'm': *optset |= PCRE_MULTILINE; continue; case 's': *optset |= PCRE_DOTALL; continue; case 'x': *optset |= PCRE_EXTENDED; continue; case 'X': *optset |= PCRE_EXTRA; continue; case 'U': *optset |= PCRE_UNGREEDY; continue; case '-': optset = &unset; continue; /* A termination by ')' indicates an options-setting-only item; this is global at top level; otherwise nothing is done here and it is handled during the compiling process on a per-bracket-group basis. */ case ')': if (brastackptr == 0) { options = (options | set) & (~unset); set = unset = 0; /* To save length */ } /* Fall through */ /* A termination by ':' indicates the start of a nested group with the given options set. This is again handled at compile time, but we must allow for compiled space if any of the ims options are set. We also have to allow for resetting space at the end of the group, which is why 4 is added to the length and not just 2. If there are several changes of options within the same group, this will lead to an over-estimate on the length, but this shouldn't matter very much. We also have to allow for resetting options at the start of any alternations, which we do by setting branch_newextra to 2. Finally, we record whether the case-dependent flag ever changes within the regex. This is used by the "required character" code. */ case ':': if (((set|unset) & PCRE_IMS) != 0) { length += 4; branch_newextra = 2; if (((set|unset) & PCRE_CASELESS) != 0) options |= PCRE_ICHANGED; } goto END_OPTIONS; /* Unrecognized option character */ default: *errorptr = ERR12; goto PCRE_ERROR_RETURN; } } /* If we hit a closing bracket, that's it - this is a freestanding option-setting. We need to ensure that branch_extra is updated if necessary. The only values branch_newextra can have here are 0 or 2. If the value is 2, then branch_extra must either be 2 or 5, depending on whether this is a lookbehind group or not. */ END_OPTIONS: if (c == ')') { if (branch_newextra == 2 && (branch_extra == 0 || branch_extra == 3)) branch_extra += branch_newextra; continue; } /* If options were terminated by ':' control comes here. Fall through to handle the group below. */ } } /* Extracting brackets must be counted so we can process escapes in a Perlish way. If the number exceeds EXTRACT_BASIC_MAX we are going to need an additional 3 bytes of store per extracting bracket. */ else { bracount++; if (bracount > EXTRACT_BASIC_MAX) bracket_length += 3; } /* Save length for computing whole length at end if there's a repeat that requires duplication of the group. Also save the current value of branch_extra, and start the new group with the new value. If non-zero, this will either be 2 for a (?imsx: group, or 3 for a lookbehind assertion. */ if (brastackptr >= sizeof(brastack)/sizeof(int)) { *errorptr = ERR19; goto PCRE_ERROR_RETURN; } bralenstack[brastackptr] = branch_extra; branch_extra = branch_newextra; brastack[brastackptr++] = length; length += bracket_length; continue; /* Handle ket. Look for subsequent max/min; for certain sets of values we have to replicate this bracket up to that many times. If brastackptr is 0 this is an unmatched bracket which will generate an error, but take care not to try to access brastack[-1] when computing the length and restoring the branch_extra value. */ case ')': length += 3; { int minval = 1; int maxval = 1; int duplength; if (brastackptr > 0) { duplength = length - brastack[--brastackptr]; branch_extra = bralenstack[brastackptr]; } else duplength = 0; /* Leave ptr at the final char; for read_repeat_counts this happens automatically; for the others we need an increment. */ if ((c = ptr[1]) == '{' && is_counted_repeat(ptr+2, &compile_block)) { ptr = read_repeat_counts(ptr+2, &minval, &maxval, errorptr, &compile_block); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; } else if (c == '*') { minval = 0; maxval = -1; ptr++; } else if (c == '+') { maxval = -1; ptr++; } else if (c == '?') { minval = 0; ptr++; } /* If the minimum is zero, we have to allow for an OP_BRAZERO before the group, and if the maximum is greater than zero, we have to replicate maxval-1 times; each replication acquires an OP_BRAZERO plus a nesting bracket set - hence the 7. */ if (minval == 0) { length++; if (maxval > 0) length += (maxval - 1) * (duplength + 7); } /* When the minimum is greater than zero, 1 we have to replicate up to minval-1 times, with no additions required in the copies. Then, if there is a limited maximum we have to replicate up to maxval-1 times allowing for a BRAZERO item before each optional copy and nesting brackets for all but one of the optional copies. */ else { length += (minval - 1) * duplength; if (maxval > minval) /* Need this test as maxval=-1 means no limit */ length += (maxval - minval) * (duplength + 7) - 6; } } continue; /* Non-special character. For a run of such characters the length required is the number of characters + 2, except that the maximum run length is 255. We won't get a skipped space or a non-data escape or the start of a # comment as the first character, so the length can't be zero. */ NORMAL_CHAR: default: length += 2; runlength = 0; do { if ((options & PCRE_EXTENDED) != 0) { if ((compile_block.ctypes[c] & ctype_space) != 0) continue; if (c == '#') { /* The space before the ; is to avoid a warning on a silly compiler on the Macintosh. */ while ((c = *(++ptr)) != 0 && c != NEWLINE) ; continue; } } /* Backslash may introduce a data char or a metacharacter; stop the string before the latter. */ if (c == '\\') { const uschar *saveptr = ptr; c = check_escape(&ptr, errorptr, bracount, options, FALSE, &compile_block); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; if (c < 0) { ptr = saveptr; break; } #ifdef SUPPORT_UTF8 if (c > 127 && (options & PCRE_UTF8) != 0) { int i; for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++) if (c <= utf8_table1[i]) break; runlength += i; } #endif } /* Ordinary character or single-char escape */ runlength++; } /* This "while" is the end of the "do" above. */ while (runlength < MAXLIT && (compile_block.ctypes[c = *(++ptr)] & ctype_meta) == 0); ptr--; length += runlength; continue; } } length += 4; /* For final KET and END */ if (length > 65539) { *errorptr = ERR20; return NULL; } /* Compute the size of data block needed and get it, either from malloc or externally provided function. We specify "code[0]" in the offsetof() expression rather than just "code", because it has been reported that one broken compiler fails on "code" because it is also an independent variable. It should make no difference to the value of the offsetof(). */ size = length + offsetof(real_pcre, code[0]); re = (real_pcre *)(pcre_malloc)(size); if (re == NULL) { *errorptr = ERR21; return NULL; } /* Put in the magic number, and save the size, options, and table pointer */ re->magic_number = MAGIC_NUMBER; re->size = size; re->options = options; re->tables = tables; /* Set up a starting, non-extracting bracket, then compile the expression. On error, *errorptr will be set non-NULL, so we don't need to look at the result of the function here. */ ptr = (const uschar *)pattern; code = re->code; *code = OP_BRA; bracount = 0; (void)compile_regex(options, -1, &bracount, &code, &ptr, errorptr, FALSE, 0, &reqchar, &countlits, &compile_block); re->top_bracket = bracount; re->top_backref = top_backref; /* If not reached end of pattern on success, there's an excess bracket. */ if (*errorptr == NULL && *ptr != 0) *errorptr = ERR22; /* Fill in the terminating state and check for disastrous overflow, but if debugging, leave the test till after things are printed out. */ *code++ = OP_END; #ifndef DEBUG if (code - re->code > length) *errorptr = ERR23; #endif /* Give an error if there's back reference to a non-existent capturing subpattern. */ if (top_backref > re->top_bracket) *errorptr = ERR15; /* Failed to compile */ if (*errorptr != NULL) { (pcre_free)(re); PCRE_ERROR_RETURN: *erroroffset = ptr - (const uschar *)pattern; return NULL; } /* If the anchored option was not passed, set flag if we can determine that the pattern is anchored by virtue of ^ characters or \A or anything else (such as starting with .* when DOTALL is set). Otherwise, see if we can determine what the first character has to be, because that speeds up unanchored matches no end. If not, see if we can set the PCRE_STARTLINE flag. This is helpful for multiline matches when all branches start with ^. and also when all branches start with .* for non-DOTALL matches. */ if ((options & PCRE_ANCHORED) == 0) { int temp_options = options; if (is_anchored(re->code, &temp_options)) re->options |= PCRE_ANCHORED; else { int ch = find_firstchar(re->code, &temp_options); if (ch >= 0) { re->first_char = ch; re->options |= PCRE_FIRSTSET; } else if (is_startline(re->code)) re->options |= PCRE_STARTLINE; } } /* Save the last required character if there are at least two literal characters on all paths, or if there is no first character setting. */ if (reqchar >= 0 && (countlits > 1 || (re->options & PCRE_FIRSTSET) == 0)) { re->req_char = reqchar; re->options |= PCRE_REQCHSET; } /* Print out the compiled data for debugging */ #ifdef DEBUG printf("Length = %d top_bracket = %d top_backref = %d\n", length, re->top_bracket, re->top_backref); if (re->options != 0) { printf("%s%s%s%s%s%s%s%s%s\n", ((re->options & PCRE_ANCHORED) != 0)? "anchored " : "", ((re->options & PCRE_CASELESS) != 0)? "caseless " : "", ((re->options & PCRE_ICHANGED) != 0)? "case state changed " : "", ((re->options & PCRE_EXTENDED) != 0)? "extended " : "", ((re->options & PCRE_MULTILINE) != 0)? "multiline " : "", ((re->options & PCRE_DOTALL) != 0)? "dotall " : "", ((re->options & PCRE_DOLLAR_ENDONLY) != 0)? "endonly " : "", ((re->options & PCRE_EXTRA) != 0)? "extra " : "", ((re->options & PCRE_UNGREEDY) != 0)? "ungreedy " : ""); } if ((re->options & PCRE_FIRSTSET) != 0) { if (isprint(re->first_char)) printf("First char = %c\n", re->first_char); else printf("First char = \\x%02x\n", re->first_char); } if ((re->options & PCRE_REQCHSET) != 0) { if (isprint(re->req_char)) printf("Req char = %c\n", re->req_char); else printf("Req char = \\x%02x\n", re->req_char); } code_end = code; code_base = code = re->code; while (code < code_end) { int charlength; printf("%3d ", code - code_base); if (*code >= OP_BRA) { if (*code - OP_BRA > EXTRACT_BASIC_MAX) printf("%3d Bra extra", (code[1] << 8) + code[2]); else printf("%3d Bra %d", (code[1] << 8) + code[2], *code - OP_BRA); code += 2; } else switch(*code) { case OP_OPT: printf(" %.2x %s", code[1], OP_names[*code]); code++; break; case OP_CHARS: charlength = *(++code); printf("%3d ", charlength); while (charlength-- > 0) if (isprint(c = *(++code))) printf("%c", c); else printf("\\x%02x", c); break; case OP_KETRMAX: case OP_KETRMIN: case OP_ALT: case OP_KET: case OP_ASSERT: case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: case OP_ONCE: case OP_REVERSE: case OP_BRANUMBER: case OP_COND: case OP_CREF: printf("%3d %s", (code[1] << 8) + code[2], OP_names[*code]); code += 2; break; case OP_STAR: case OP_MINSTAR: case OP_PLUS: case OP_MINPLUS: case OP_QUERY: case OP_MINQUERY: case OP_TYPESTAR: case OP_TYPEMINSTAR: case OP_TYPEPLUS: case OP_TYPEMINPLUS: case OP_TYPEQUERY: case OP_TYPEMINQUERY: if (*code >= OP_TYPESTAR) printf(" %s", OP_names[code[1]]); else if (isprint(c = code[1])) printf(" %c", c); else printf(" \\x%02x", c); printf("%s", OP_names[*code++]); break; case OP_EXACT: case OP_UPTO: case OP_MINUPTO: if (isprint(c = code[3])) printf(" %c{", c); else printf(" \\x%02x{", c); if (*code != OP_EXACT) printf("0,"); printf("%d}", (code[1] << 8) + code[2]); if (*code == OP_MINUPTO) printf("?"); code += 3; break; case OP_TYPEEXACT: case OP_TYPEUPTO: case OP_TYPEMINUPTO: printf(" %s{", OP_names[code[3]]); if (*code != OP_TYPEEXACT) printf(","); printf("%d}", (code[1] << 8) + code[2]); if (*code == OP_TYPEMINUPTO) printf("?"); code += 3; break; case OP_NOT: if (isprint(c = *(++code))) printf(" [^%c]", c); else printf(" [^\\x%02x]", c); break; case OP_NOTSTAR: case OP_NOTMINSTAR: case OP_NOTPLUS: case OP_NOTMINPLUS: case OP_NOTQUERY: case OP_NOTMINQUERY: if (isprint(c = code[1])) printf(" [^%c]", c); else printf(" [^\\x%02x]", c); printf("%s", OP_names[*code++]); break; case OP_NOTEXACT: case OP_NOTUPTO: case OP_NOTMINUPTO: if (isprint(c = code[3])) printf(" [^%c]{", c); else printf(" [^\\x%02x]{", c); if (*code != OP_NOTEXACT) printf(","); printf("%d}", (code[1] << 8) + code[2]); if (*code == OP_NOTMINUPTO) printf("?"); code += 3; break; case OP_REF: printf(" \\%d", (code[1] << 8) | code[2]); code += 3; goto CLASS_REF_REPEAT; case OP_CLASS: { int i, min, max; code++; printf(" ["); for (i = 0; i < 256; i++) { if ((code[i/8] & (1 << (i&7))) != 0) { int j; for (j = i+1; j < 256; j++) if ((code[j/8] & (1 << (j&7))) == 0) break; if (i == '-' || i == ']') printf("\\"); if (isprint(i)) printf("%c", i); else printf("\\x%02x", i); if (--j > i) { printf("-"); if (j == '-' || j == ']') printf("\\"); if (isprint(j)) printf("%c", j); else printf("\\x%02x", j); } i = j; } } printf("]"); code += 32; CLASS_REF_REPEAT: switch(*code) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRPLUS: case OP_CRMINPLUS: case OP_CRQUERY: case OP_CRMINQUERY: printf("%s", OP_names[*code]); break; case OP_CRRANGE: case OP_CRMINRANGE: min = (code[1] << 8) + code[2]; max = (code[3] << 8) + code[4]; if (max == 0) printf("{%d,}", min); else printf("{%d,%d}", min, max); if (*code == OP_CRMINRANGE) printf("?"); code += 4; break; default: code--; } } break; /* Anything else is just a one-node item */ default: printf(" %s", OP_names[*code]); break; } code++; printf("\n"); } printf("------------------------------------------------------------------\n"); /* This check is done here in the debugging case so that the code that was compiled can be seen. */ if (code - re->code > length) { *errorptr = ERR23; (pcre_free)(re); *erroroffset = ptr - (uschar *)pattern; return NULL; } #endif return (pcre *)re; } /************************************************* * Match a back-reference * *************************************************/ /* If a back reference hasn't been set, the length that is passed is greater than the number of characters left in the string, so the match fails. Arguments: offset index into the offset vector eptr points into the subject length length to be matched md points to match data block ims the ims flags Returns: TRUE if matched */ static BOOL match_ref(int offset, register const uschar *eptr, int length, match_data *md, unsigned long int ims) { const uschar *p = md->start_subject + md->offset_vector[offset]; #ifdef DEBUG if (eptr >= md->end_subject) printf("matching subject "); else { printf("matching subject "); pchars(eptr, length, TRUE, md); } printf(" against backref "); pchars(p, length, FALSE, md); printf("\n"); #endif /* Always fail if not enough characters left */ if (length > md->end_subject - eptr) return FALSE; /* Separate the caselesss case for speed */ if ((ims & PCRE_CASELESS) != 0) { while (length-- > 0) if (md->lcc[*p++] != md->lcc[*eptr++]) return FALSE; } else { while (length-- > 0) if (*p++ != *eptr++) return FALSE; } return TRUE; } /************************************************* * Match from current position * *************************************************/ /* On entry ecode points to the first opcode, and eptr to the first character in the subject string, while eptrb holds the value of eptr at the start of the last bracketed group - used for breaking infinite loops matching zero-length strings. Arguments: eptr pointer in subject ecode position in code offset_top current top pointer md pointer to "static" info for the match ims current /i, /m, and /s options eptrb pointer to chain of blocks containing eptr at start of brackets - for testing for empty matches flags can contain match_condassert - this is an assertion condition match_isgroup - this is the start of a bracketed group Returns: TRUE if matched */ static BOOL match(register const uschar *eptr, register const uschar *ecode, int offset_top, match_data *md, unsigned long int ims, eptrblock *eptrb, int flags) { unsigned long int original_ims = ims; /* Save for resetting on ')' */ eptrblock newptrb; /* At the start of a bracketed group, add the current subject pointer to the stack of such pointers, to be re-instated at the end of the group when we hit the closing ket. When match() is called in other circumstances, we don't add to the stack. */ if ((flags & match_isgroup) != 0) { newptrb.prev = eptrb; newptrb.saved_eptr = eptr; eptrb = &newptrb; } /* Now start processing the operations. */ for (;;) { int op = (int)*ecode; int min, max, ctype; register int i; register int c; BOOL minimize = FALSE; /* Opening capturing bracket. If there is space in the offset vector, save the current subject position in the working slot at the top of the vector. We mustn't change the current values of the data slot, because they may be set from a previous iteration of this group, and be referred to by a reference inside the group. If the bracket fails to match, we need to restore this value and also the values of the final offsets, in case they were set by a previous iteration of the same bracket. If there isn't enough space in the offset vector, treat this as if it were a non-capturing bracket. Don't worry about setting the flag for the error case here; that is handled in the code for KET. */ if (op > OP_BRA) { int offset; int number = op - OP_BRA; /* For extended extraction brackets (large number), we have to fish out the number from a dummy opcode at the start. */ if (number > EXTRACT_BASIC_MAX) number = (ecode[4] << 8) | ecode[5]; offset = number << 1; #ifdef DEBUG printf("start bracket %d subject=", number); pchars(eptr, 16, TRUE, md); printf("\n"); #endif if (offset < md->offset_max) { int save_offset1 = md->offset_vector[offset]; int save_offset2 = md->offset_vector[offset+1]; int save_offset3 = md->offset_vector[md->offset_end - number]; DPRINTF(("saving %d %d %d\n", save_offset1, save_offset2, save_offset3)); md->offset_vector[md->offset_end - number] = eptr - md->start_subject; do { if (match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup)) return TRUE; ecode += (ecode[1] << 8) + ecode[2]; } while (*ecode == OP_ALT); DPRINTF(("bracket %d failed\n", number)); md->offset_vector[offset] = save_offset1; md->offset_vector[offset+1] = save_offset2; md->offset_vector[md->offset_end - number] = save_offset3; return FALSE; } /* Insufficient room for saving captured contents */ else op = OP_BRA; } /* Other types of node can be handled by a switch */ switch(op) { case OP_BRA: /* Non-capturing bracket: optimized */ DPRINTF(("start bracket 0\n")); do { if (match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup)) return TRUE; ecode += (ecode[1] << 8) + ecode[2]; } while (*ecode == OP_ALT); DPRINTF(("bracket 0 failed\n")); return FALSE; /* Conditional group: compilation checked that there are no more than two branches. If the condition is false, skipping the first branch takes us past the end if there is only one branch, but that's OK because that is exactly what going to the ket would do. */ case OP_COND: if (ecode[3] == OP_CREF) /* Condition is extraction test */ { int offset = (ecode[4] << 9) | (ecode[5] << 1); /* Doubled ref number */ return match(eptr, ecode + ((offset < offset_top && md->offset_vector[offset] >= 0)? 6 : 3 + (ecode[1] << 8) + ecode[2]), offset_top, md, ims, eptrb, match_isgroup); } /* The condition is an assertion. Call match() to evaluate it - setting the final argument TRUE causes it to stop at the end of an assertion. */ else { if (match(eptr, ecode+3, offset_top, md, ims, NULL, match_condassert | match_isgroup)) { ecode += 3 + (ecode[4] << 8) + ecode[5]; while (*ecode == OP_ALT) ecode += (ecode[1] << 8) + ecode[2]; } else ecode += (ecode[1] << 8) + ecode[2]; return match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup); } /* Control never reaches here */ /* Skip over conditional reference or large extraction number data if encountered. */ case OP_CREF: case OP_BRANUMBER: ecode += 3; break; /* End of the pattern. If PCRE_NOTEMPTY is set, fail if we have matched an empty string - recursion will then try other alternatives, if any. */ case OP_END: if (md->notempty && eptr == md->start_match) return FALSE; md->end_match_ptr = eptr; /* Record where we ended */ md->end_offset_top = offset_top; /* and how many extracts were taken */ return TRUE; /* Change option settings */ case OP_OPT: ims = ecode[1]; ecode += 2; DPRINTF(("ims set to %02lx\n", ims)); break; /* Assertion brackets. Check the alternative branches in turn - the matching won't pass the KET for an assertion. If any one branch matches, the assertion is true. Lookbehind assertions have an OP_REVERSE item at the start of each branch to move the current point backwards, so the code at this level is identical to the lookahead case. */ case OP_ASSERT: case OP_ASSERTBACK: do { if (match(eptr, ecode+3, offset_top, md, ims, NULL, match_isgroup)) break; ecode += (ecode[1] << 8) + ecode[2]; } while (*ecode == OP_ALT); if (*ecode == OP_KET) return FALSE; /* If checking an assertion for a condition, return TRUE. */ if ((flags & match_condassert) != 0) return TRUE; /* Continue from after the assertion, updating the offsets high water mark, since extracts may have been taken during the assertion. */ do ecode += (ecode[1] << 8) + ecode[2]; while (*ecode == OP_ALT); ecode += 3; offset_top = md->end_offset_top; continue; /* Negative assertion: all branches must fail to match */ case OP_ASSERT_NOT: case OP_ASSERTBACK_NOT: do { if (match(eptr, ecode+3, offset_top, md, ims, NULL, match_isgroup)) return FALSE; ecode += (ecode[1] << 8) + ecode[2]; } while (*ecode == OP_ALT); if ((flags & match_condassert) != 0) return TRUE; ecode += 3; continue; /* Move the subject pointer back. This occurs only at the start of each branch of a lookbehind assertion. If we are too close to the start to move back, this match function fails. When working with UTF-8 we move back a number of characters, not bytes. */ case OP_REVERSE: #ifdef SUPPORT_UTF8 c = (ecode[1] << 8) + ecode[2]; for (i = 0; i < c; i++) { eptr--; BACKCHAR(eptr) } #else eptr -= (ecode[1] << 8) + ecode[2]; #endif if (eptr < md->start_subject) return FALSE; ecode += 3; break; /* Recursion matches the current regex, nested. If there are any capturing brackets started but not finished, we have to save their starting points and reinstate them after the recursion. However, we don't know how many such there are (offset_top records the completed total) so we just have to save all the potential data. There may be up to 99 such values, which is a bit large to put on the stack, but using malloc for small numbers seems expensive. As a compromise, the stack is used when there are fewer than 16 values to store; otherwise malloc is used. A problem is what to do if the malloc fails ... there is no way of returning to the top level with an error. Save the top 15 values on the stack, and accept that the rest may be wrong. */ case OP_RECURSE: { BOOL rc; int *save; int stacksave[15]; c = md->offset_max; if (c < 16) save = stacksave; else { save = (int *)(pcre_malloc)((c+1) * sizeof(int)); if (save == NULL) { save = stacksave; c = 15; } } for (i = 1; i <= c; i++) save[i] = md->offset_vector[md->offset_end - i]; rc = match(eptr, md->start_pattern, offset_top, md, ims, eptrb, match_isgroup); for (i = 1; i <= c; i++) md->offset_vector[md->offset_end - i] = save[i]; if (save != stacksave) (pcre_free)(save); if (!rc) return FALSE; /* In case the recursion has set more capturing values, save the final number, then move along the subject till after the recursive match, and advance one byte in the pattern code. */ offset_top = md->end_offset_top; eptr = md->end_match_ptr; ecode++; } break; /* "Once" brackets are like assertion brackets except that after a match, the point in the subject string is not moved back. Thus there can never be a move back into the brackets. Check the alternative branches in turn - the matching won't pass the KET for this kind of subpattern. If any one branch matches, we carry on as at the end of a normal bracket, leaving the subject pointer. */ case OP_ONCE: { const uschar *prev = ecode; const uschar *saved_eptr = eptr; do { if (match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup)) break; ecode += (ecode[1] << 8) + ecode[2]; } while (*ecode == OP_ALT); /* If hit the end of the group (which could be repeated), fail */ if (*ecode != OP_ONCE && *ecode != OP_ALT) return FALSE; /* Continue as from after the assertion, updating the offsets high water mark, since extracts may have been taken. */ do ecode += (ecode[1] << 8) + ecode[2]; while (*ecode == OP_ALT); offset_top = md->end_offset_top; eptr = md->end_match_ptr; /* For a non-repeating ket, just continue at this level. This also happens for a repeating ket if no characters were matched in the group. This is the forcible breaking of infinite loops as implemented in Perl 5.005. If there is an options reset, it will get obeyed in the normal course of events. */ if (*ecode == OP_KET || eptr == saved_eptr) { ecode += 3; break; } /* The repeating kets try the rest of the pattern or restart from the preceding bracket, in the appropriate order. We need to reset any options that changed within the bracket before re-running it, so check the next opcode. */ if (ecode[3] == OP_OPT) { ims = (ims & ~PCRE_IMS) | ecode[4]; DPRINTF(("ims set to %02lx at group repeat\n", ims)); } if (*ecode == OP_KETRMIN) { if (match(eptr, ecode+3, offset_top, md, ims, eptrb, 0) || match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup)) return TRUE; } else /* OP_KETRMAX */ { if (match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup) || match(eptr, ecode+3, offset_top, md, ims, eptrb, 0)) return TRUE; } } return FALSE; /* An alternation is the end of a branch; scan along to find the end of the bracketed group and go to there. */ case OP_ALT: do ecode += (ecode[1] << 8) + ecode[2]; while (*ecode == OP_ALT); break; /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating that it may occur zero times. It may repeat infinitely, or not at all - i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper repeat limits are compiled as a number of copies, with the optional ones preceded by BRAZERO or BRAMINZERO. */ case OP_BRAZERO: { const uschar *next = ecode+1; if (match(eptr, next, offset_top, md, ims, eptrb, match_isgroup)) return TRUE; do next += (next[1] << 8) + next[2]; while (*next == OP_ALT); ecode = next + 3; } break; case OP_BRAMINZERO: { const uschar *next = ecode+1; do next += (next[1] << 8) + next[2]; while (*next == OP_ALT); if (match(eptr, next+3, offset_top, md, ims, eptrb, match_isgroup)) return TRUE; ecode++; } break; /* End of a group, repeated or non-repeating. If we are at the end of an assertion "group", stop matching and return TRUE, but record the current high water mark for use by positive assertions. Do this also for the "once" (not-backup up) groups. */ case OP_KET: case OP_KETRMIN: case OP_KETRMAX: { const uschar *prev = ecode - (ecode[1] << 8) - ecode[2]; const uschar *saved_eptr = eptrb->saved_eptr; eptrb = eptrb->prev; /* Back up the stack of bracket start pointers */ if (*prev == OP_ASSERT || *prev == OP_ASSERT_NOT || *prev == OP_ASSERTBACK || *prev == OP_ASSERTBACK_NOT || *prev == OP_ONCE) { md->end_match_ptr = eptr; /* For ONCE */ md->end_offset_top = offset_top; return TRUE; } /* In all other cases except a conditional group we have to check the group number back at the start and if necessary complete handling an extraction by setting the offsets and bumping the high water mark. */ if (*prev != OP_COND) { int offset; int number = *prev - OP_BRA; /* For extended extraction brackets (large number), we have to fish out the number from a dummy opcode at the start. */ if (number > EXTRACT_BASIC_MAX) number = (prev[4] << 8) | prev[5]; offset = number << 1; #ifdef DEBUG printf("end bracket %d", number); printf("\n"); #endif if (number > 0) { if (offset >= md->offset_max) md->offset_overflow = TRUE; else { md->offset_vector[offset] = md->offset_vector[md->offset_end - number]; md->offset_vector[offset+1] = eptr - md->start_subject; if (offset_top <= offset) offset_top = offset + 2; } } } /* Reset the value of the ims flags, in case they got changed during the group. */ ims = original_ims; DPRINTF(("ims reset to %02lx\n", ims)); /* For a non-repeating ket, just continue at this level. This also happens for a repeating ket if no characters were matched in the group. This is the forcible breaking of infinite loops as implemented in Perl 5.005. If there is an options reset, it will get obeyed in the normal course of events. */ if (*ecode == OP_KET || eptr == saved_eptr) { ecode += 3; break; } /* The repeating kets try the rest of the pattern or restart from the preceding bracket, in the appropriate order. */ if (*ecode == OP_KETRMIN) { if (match(eptr, ecode+3, offset_top, md, ims, eptrb, 0) || match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup)) return TRUE; } else /* OP_KETRMAX */ { if (match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup) || match(eptr, ecode+3, offset_top, md, ims, eptrb, 0)) return TRUE; } } return FALSE; /* Start of subject unless notbol, or after internal newline if multiline */ case OP_CIRC: if (md->notbol && eptr == md->start_subject) return FALSE; if ((ims & PCRE_MULTILINE) != 0) { if (eptr != md->start_subject && eptr[-1] != NEWLINE) return FALSE; ecode++; break; } /* ... else fall through */ /* Start of subject assertion */ case OP_SOD: if (eptr != md->start_subject) return FALSE; ecode++; break; /* Assert before internal newline if multiline, or before a terminating newline unless endonly is set, else end of subject unless noteol is set. */ case OP_DOLL: if ((ims & PCRE_MULTILINE) != 0) { if (eptr < md->end_subject) { if (*eptr != NEWLINE) return FALSE; } else { if (md->noteol) return FALSE; } ecode++; break; } else { if (md->noteol) return FALSE; if (!md->endonly) { if (eptr < md->end_subject - 1 || (eptr == md->end_subject - 1 && *eptr != NEWLINE)) return FALSE; ecode++; break; } } /* ... else fall through */ /* End of subject assertion (\z) */ case OP_EOD: if (eptr < md->end_subject) return FALSE; ecode++; break; /* End of subject or ending \n assertion (\Z) */ case OP_EODN: if (eptr < md->end_subject - 1 || (eptr == md->end_subject - 1 && *eptr != NEWLINE)) return FALSE; ecode++; break; /* Word boundary assertions */ case OP_NOT_WORD_BOUNDARY: case OP_WORD_BOUNDARY: { BOOL prev_is_word = (eptr != md->start_subject) && ((md->ctypes[eptr[-1]] & ctype_word) != 0); BOOL cur_is_word = (eptr < md->end_subject) && ((md->ctypes[*eptr] & ctype_word) != 0); if ((*ecode++ == OP_WORD_BOUNDARY)? cur_is_word == prev_is_word : cur_is_word != prev_is_word) return FALSE; } break; /* Match a single character type; inline for speed */ case OP_ANY: if ((ims & PCRE_DOTALL) == 0 && eptr < md->end_subject && *eptr == NEWLINE) return FALSE; if (eptr++ >= md->end_subject) return FALSE; #ifdef SUPPORT_UTF8 if (md->utf8) while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; #endif ecode++; break; case OP_NOT_DIGIT: if (eptr >= md->end_subject || (md->ctypes[*eptr++] & ctype_digit) != 0) return FALSE; ecode++; break; case OP_DIGIT: if (eptr >= md->end_subject || (md->ctypes[*eptr++] & ctype_digit) == 0) return FALSE; ecode++; break; case OP_NOT_WHITESPACE: if (eptr >= md->end_subject || (md->ctypes[*eptr++] & ctype_space) != 0) return FALSE; ecode++; break; case OP_WHITESPACE: if (eptr >= md->end_subject || (md->ctypes[*eptr++] & ctype_space) == 0) return FALSE; ecode++; break; case OP_NOT_WORDCHAR: if (eptr >= md->end_subject || (md->ctypes[*eptr++] & ctype_word) != 0) return FALSE; ecode++; break; case OP_WORDCHAR: if (eptr >= md->end_subject || (md->ctypes[*eptr++] & ctype_word) == 0) return FALSE; ecode++; break; /* Match a back reference, possibly repeatedly. Look past the end of the item to see if there is repeat information following. The code is similar to that for character classes, but repeated for efficiency. Then obey similar code to character type repeats - written out again for speed. However, if the referenced string is the empty string, always treat it as matched, any number of times (otherwise there could be infinite loops). */ case OP_REF: { int length; int offset = (ecode[1] << 9) | (ecode[2] << 1); /* Doubled ref number */ ecode += 3; /* Advance past item */ /* If the reference is unset, set the length to be longer than the amount of subject left; this ensures that every attempt at a match fails. We can't just fail here, because of the possibility of quantifiers with zero minima. */ length = (offset >= offset_top || md->offset_vector[offset] < 0)? md->end_subject - eptr + 1 : md->offset_vector[offset+1] - md->offset_vector[offset]; /* Set up for repetition, or handle the non-repeated case */ switch (*ecode) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRPLUS: case OP_CRMINPLUS: case OP_CRQUERY: case OP_CRMINQUERY: c = *ecode++ - OP_CRSTAR; minimize = (c & 1) != 0; min = rep_min[c]; /* Pick up values from tables; */ max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; break; case OP_CRRANGE: case OP_CRMINRANGE: minimize = (*ecode == OP_CRMINRANGE); min = (ecode[1] << 8) + ecode[2]; max = (ecode[3] << 8) + ecode[4]; if (max == 0) max = INT_MAX; ecode += 5; break; default: /* No repeat follows */ if (!match_ref(offset, eptr, length, md, ims)) return FALSE; eptr += length; continue; /* With the main loop */ } /* If the length of the reference is zero, just continue with the main loop. */ if (length == 0) continue; /* First, ensure the minimum number of matches are present. We get back the length of the reference string explicitly rather than passing the address of eptr, so that eptr can be a register variable. */ for (i = 1; i <= min; i++) { if (!match_ref(offset, eptr, length, md, ims)) return FALSE; eptr += length; } /* If min = max, continue at the same level without recursion. They are not both allowed to be zero. */ if (min == max) continue; /* If minimizing, keep trying and advancing the pointer */ if (minimize) { for (i = min;; i++) { if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; if (i >= max || !match_ref(offset, eptr, length, md, ims)) return FALSE; eptr += length; } /* Control never gets here */ } /* If maximizing, find the longest string and work backwards */ else { const uschar *pp = eptr; for (i = min; i < max; i++) { if (!match_ref(offset, eptr, length, md, ims)) break; eptr += length; } while (eptr >= pp) { if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; eptr -= length; } return FALSE; } } /* Control never gets here */ /* Match a character class, possibly repeatedly. Look past the end of the item to see if there is repeat information following. Then obey similar code to character type repeats - written out again for speed. */ case OP_CLASS: { const uschar *data = ecode + 1; /* Save for matching */ ecode += 33; /* Advance past the item */ switch (*ecode) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRPLUS: case OP_CRMINPLUS: case OP_CRQUERY: case OP_CRMINQUERY: c = *ecode++ - OP_CRSTAR; minimize = (c & 1) != 0; min = rep_min[c]; /* Pick up values from tables; */ max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; break; case OP_CRRANGE: case OP_CRMINRANGE: minimize = (*ecode == OP_CRMINRANGE); min = (ecode[1] << 8) + ecode[2]; max = (ecode[3] << 8) + ecode[4]; if (max == 0) max = INT_MAX; ecode += 5; break; default: /* No repeat follows */ min = max = 1; break; } /* First, ensure the minimum number of matches are present. */ for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) return FALSE; GETCHARINC(c, eptr) /* Get character; increment eptr */ #ifdef SUPPORT_UTF8 /* We do not yet support class members > 255 */ if (c > 255) return FALSE; #endif if ((data[c/8] & (1 << (c&7))) != 0) continue; return FALSE; } /* If max == min we can continue with the main loop without the need to recurse. */ if (min == max) continue; /* If minimizing, keep testing the rest of the expression and advancing the pointer while it matches the class. */ if (minimize) { for (i = min;; i++) { if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; if (i >= max || eptr >= md->end_subject) return FALSE; GETCHARINC(c, eptr) /* Get character; increment eptr */ #ifdef SUPPORT_UTF8 /* We do not yet support class members > 255 */ if (c > 255) return FALSE; #endif if ((data[c/8] & (1 << (c&7))) != 0) continue; return FALSE; } /* Control never gets here */ } /* If maximizing, find the longest possible run, then work backwards. */ else { const uschar *pp = eptr; int len = 1; for (i = min; i < max; i++) { if (eptr >= md->end_subject) break; GETCHARLEN(c, eptr, len) /* Get character, set length if UTF-8 */ #ifdef SUPPORT_UTF8 /* We do not yet support class members > 255 */ if (c > 255) break; #endif if ((data[c/8] & (1 << (c&7))) == 0) break; eptr += len; } while (eptr >= pp) { if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; #ifdef SUPPORT_UTF8 BACKCHAR(eptr) #endif } return FALSE; } } /* Control never gets here */ /* Match a run of characters */ case OP_CHARS: { register int length = ecode[1]; ecode += 2; #ifdef DEBUG /* Sigh. Some compilers never learn. */ if (eptr >= md->end_subject) printf("matching subject against pattern "); else { printf("matching subject "); pchars(eptr, length, TRUE, md); printf(" against pattern "); } pchars(ecode, length, FALSE, md); printf("\n"); #endif if (length > md->end_subject - eptr) return FALSE; if ((ims & PCRE_CASELESS) != 0) { while (length-- > 0) if (md->lcc[*ecode++] != md->lcc[*eptr++]) return FALSE; } else { while (length-- > 0) if (*ecode++ != *eptr++) return FALSE; } } break; /* Match a single character repeatedly; different opcodes share code. */ case OP_EXACT: min = max = (ecode[1] << 8) + ecode[2]; ecode += 3; goto REPEATCHAR; case OP_UPTO: case OP_MINUPTO: min = 0; max = (ecode[1] << 8) + ecode[2]; minimize = *ecode == OP_MINUPTO; ecode += 3; goto REPEATCHAR; case OP_STAR: case OP_MINSTAR: case OP_PLUS: case OP_MINPLUS: case OP_QUERY: case OP_MINQUERY: c = *ecode++ - OP_STAR; minimize = (c & 1) != 0; min = rep_min[c]; /* Pick up values from tables; */ max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; /* Common code for all repeated single-character matches. We can give up quickly if there are fewer than the minimum number of characters left in the subject. */ REPEATCHAR: if (min > md->end_subject - eptr) return FALSE; c = *ecode++; /* The code is duplicated for the caseless and caseful cases, for speed, since matching characters is likely to be quite common. First, ensure the minimum number of matches are present. If min = max, continue at the same level without recursing. Otherwise, if minimizing, keep trying the rest of the expression and advancing one matching character if failing, up to the maximum. Alternatively, if maximizing, find the maximum number of characters and work backwards. */ DPRINTF(("matching %c{%d,%d} against subject %.*s\n", c, min, max, max, eptr)); if ((ims & PCRE_CASELESS) != 0) { c = md->lcc[c]; for (i = 1; i <= min; i++) if (c != md->lcc[*eptr++]) return FALSE; if (min == max) continue; if (minimize) { for (i = min;; i++) { if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; if (i >= max || eptr >= md->end_subject || c != md->lcc[*eptr++]) return FALSE; } /* Control never gets here */ } else { const uschar *pp = eptr; for (i = min; i < max; i++) { if (eptr >= md->end_subject || c != md->lcc[*eptr]) break; eptr++; } while (eptr >= pp) if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; return FALSE; } /* Control never gets here */ } /* Caseful comparisons */ else { for (i = 1; i <= min; i++) if (c != *eptr++) return FALSE; if (min == max) continue; if (minimize) { for (i = min;; i++) { if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; if (i >= max || eptr >= md->end_subject || c != *eptr++) return FALSE; } /* Control never gets here */ } else { const uschar *pp = eptr; for (i = min; i < max; i++) { if (eptr >= md->end_subject || c != *eptr) break; eptr++; } while (eptr >= pp) if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; return FALSE; } } /* Control never gets here */ /* Match a negated single character */ case OP_NOT: if (eptr >= md->end_subject) return FALSE; ecode++; if ((ims & PCRE_CASELESS) != 0) { if (md->lcc[*ecode++] == md->lcc[*eptr++]) return FALSE; } else { if (*ecode++ == *eptr++) return FALSE; } break; /* Match a negated single character repeatedly. This is almost a repeat of the code for a repeated single character, but I haven't found a nice way of commoning these up that doesn't require a test of the positive/negative option for each character match. Maybe that wouldn't add very much to the time taken, but character matching *is* what this is all about... */ case OP_NOTEXACT: min = max = (ecode[1] << 8) + ecode[2]; ecode += 3; goto REPEATNOTCHAR; case OP_NOTUPTO: case OP_NOTMINUPTO: min = 0; max = (ecode[1] << 8) + ecode[2]; minimize = *ecode == OP_NOTMINUPTO; ecode += 3; goto REPEATNOTCHAR; case OP_NOTSTAR: case OP_NOTMINSTAR: case OP_NOTPLUS: case OP_NOTMINPLUS: case OP_NOTQUERY: case OP_NOTMINQUERY: c = *ecode++ - OP_NOTSTAR; minimize = (c & 1) != 0; min = rep_min[c]; /* Pick up values from tables; */ max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; /* Common code for all repeated single-character matches. We can give up quickly if there are fewer than the minimum number of characters left in the subject. */ REPEATNOTCHAR: if (min > md->end_subject - eptr) return FALSE; c = *ecode++; /* The code is duplicated for the caseless and caseful cases, for speed, since matching characters is likely to be quite common. First, ensure the minimum number of matches are present. If min = max, continue at the same level without recursing. Otherwise, if minimizing, keep trying the rest of the expression and advancing one matching character if failing, up to the maximum. Alternatively, if maximizing, find the maximum number of characters and work backwards. */ DPRINTF(("negative matching %c{%d,%d} against subject %.*s\n", c, min, max, max, eptr)); if ((ims & PCRE_CASELESS) != 0) { c = md->lcc[c]; for (i = 1; i <= min; i++) if (c == md->lcc[*eptr++]) return FALSE; if (min == max) continue; if (minimize) { for (i = min;; i++) { if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; if (i >= max || eptr >= md->end_subject || c == md->lcc[*eptr++]) return FALSE; } /* Control never gets here */ } else { const uschar *pp = eptr; for (i = min; i < max; i++) { if (eptr >= md->end_subject || c == md->lcc[*eptr]) break; eptr++; } while (eptr >= pp) if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; return FALSE; } /* Control never gets here */ } /* Caseful comparisons */ else { for (i = 1; i <= min; i++) if (c == *eptr++) return FALSE; if (min == max) continue; if (minimize) { for (i = min;; i++) { if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; if (i >= max || eptr >= md->end_subject || c == *eptr++) return FALSE; } /* Control never gets here */ } else { const uschar *pp = eptr; for (i = min; i < max; i++) { if (eptr >= md->end_subject || c == *eptr) break; eptr++; } while (eptr >= pp) if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; return FALSE; } } /* Control never gets here */ /* Match a single character type repeatedly; several different opcodes share code. This is very similar to the code for single characters, but we repeat it in the interests of efficiency. */ case OP_TYPEEXACT: min = max = (ecode[1] << 8) + ecode[2]; minimize = TRUE; ecode += 3; goto REPEATTYPE; case OP_TYPEUPTO: case OP_TYPEMINUPTO: min = 0; max = (ecode[1] << 8) + ecode[2]; minimize = *ecode == OP_TYPEMINUPTO; ecode += 3; goto REPEATTYPE; case OP_TYPESTAR: case OP_TYPEMINSTAR: case OP_TYPEPLUS: case OP_TYPEMINPLUS: case OP_TYPEQUERY: case OP_TYPEMINQUERY: c = *ecode++ - OP_TYPESTAR; minimize = (c & 1) != 0; min = rep_min[c]; /* Pick up values from tables; */ max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; /* Common code for all repeated single character type matches */ REPEATTYPE: ctype = *ecode++; /* Code for the character type */ /* First, ensure the minimum number of matches are present. Use inline code for maximizing the speed, and do the type test once at the start (i.e. keep it out of the loop). Also we can test that there are at least the minimum number of bytes before we start, except when doing '.' in UTF8 mode. Leave the test in in all cases; in the special case we have to test after each character. */ if (min > md->end_subject - eptr) return FALSE; if (min > 0) switch(ctype) { case OP_ANY: #ifdef SUPPORT_UTF8 if (md->utf8) { for (i = 1; i <= min; i++) { if (eptr >= md->end_subject || (*eptr++ == NEWLINE && (ims & PCRE_DOTALL) == 0)) return FALSE; while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; } break; } #endif /* Non-UTF8 can be faster */ if ((ims & PCRE_DOTALL) == 0) { for (i = 1; i <= min; i++) if (*eptr++ == NEWLINE) return FALSE; } else eptr += min; break; case OP_NOT_DIGIT: for (i = 1; i <= min; i++) if ((md->ctypes[*eptr++] & ctype_digit) != 0) return FALSE; break; case OP_DIGIT: for (i = 1; i <= min; i++) if ((md->ctypes[*eptr++] & ctype_digit) == 0) return FALSE; break; case OP_NOT_WHITESPACE: for (i = 1; i <= min; i++) if ((md->ctypes[*eptr++] & ctype_space) != 0) return FALSE; break; case OP_WHITESPACE: for (i = 1; i <= min; i++) if ((md->ctypes[*eptr++] & ctype_space) == 0) return FALSE; break; case OP_NOT_WORDCHAR: for (i = 1; i <= min; i++) if ((md->ctypes[*eptr++] & ctype_word) != 0) return FALSE; break; case OP_WORDCHAR: for (i = 1; i <= min; i++) if ((md->ctypes[*eptr++] & ctype_word) == 0) return FALSE; break; } /* If min = max, continue at the same level without recursing */ if (min == max) continue; /* If minimizing, we have to test the rest of the pattern before each subsequent match. */ if (minimize) { for (i = min;; i++) { if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; if (i >= max || eptr >= md->end_subject) return FALSE; c = *eptr++; switch(ctype) { case OP_ANY: if ((ims & PCRE_DOTALL) == 0 && c == NEWLINE) return FALSE; #ifdef SUPPORT_UTF8 if (md->utf8) while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; #endif break; case OP_NOT_DIGIT: if ((md->ctypes[c] & ctype_digit) != 0) return FALSE; break; case OP_DIGIT: if ((md->ctypes[c] & ctype_digit) == 0) return FALSE; break; case OP_NOT_WHITESPACE: if ((md->ctypes[c] & ctype_space) != 0) return FALSE; break; case OP_WHITESPACE: if ((md->ctypes[c] & ctype_space) == 0) return FALSE; break; case OP_NOT_WORDCHAR: if ((md->ctypes[c] & ctype_word) != 0) return FALSE; break; case OP_WORDCHAR: if ((md->ctypes[c] & ctype_word) == 0) return FALSE; break; } } /* Control never gets here */ } /* If maximizing it is worth using inline code for speed, doing the type test once at the start (i.e. keep it out of the loop). */ else { const uschar *pp = eptr; switch(ctype) { case OP_ANY: /* Special code is required for UTF8, but when the maximum is unlimited we don't need it. */ #ifdef SUPPORT_UTF8 if (md->utf8 && max < INT_MAX) { if ((ims & PCRE_DOTALL) == 0) { for (i = min; i < max; i++) { if (eptr >= md->end_subject || *eptr++ == NEWLINE) break; while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; } } else { for (i = min; i < max; i++) { eptr++; while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; } } break; } #endif /* Non-UTF8 can be faster */ if ((ims & PCRE_DOTALL) == 0) { for (i = min; i < max; i++) { if (eptr >= md->end_subject || *eptr == NEWLINE) break; eptr++; } } else { c = max - min; if (c > md->end_subject - eptr) c = md->end_subject - eptr; eptr += c; } break; case OP_NOT_DIGIT: for (i = min; i < max; i++) { if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) != 0) break; eptr++; } break; case OP_DIGIT: for (i = min; i < max; i++) { if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) == 0) break; eptr++; } break; case OP_NOT_WHITESPACE: for (i = min; i < max; i++) { if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) != 0) break; eptr++; } break; case OP_WHITESPACE: for (i = min; i < max; i++) { if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) == 0) break; eptr++; } break; case OP_NOT_WORDCHAR: for (i = min; i < max; i++) { if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) != 0) break; eptr++; } break; case OP_WORDCHAR: for (i = min; i < max; i++) { if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) == 0) break; eptr++; } break; } while (eptr >= pp) { if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; #ifdef SUPPORT_UTF8 if (md->utf8) while (eptr > pp && (*eptr & 0xc0) == 0x80) eptr--; #endif } return FALSE; } /* Control never gets here */ /* There's been some horrible disaster. */ default: DPRINTF(("Unknown opcode %d\n", *ecode)); md->errorcode = PCRE_ERROR_UNKNOWN_NODE; return FALSE; } /* Do not stick any code in here without much thought; it is assumed that "continue" in the code above comes out to here to repeat the main loop. */ } /* End of main loop */ /* Control never reaches here */ } /************************************************* * Execute a Regular Expression * *************************************************/ /* This function applies a compiled re to a subject string and picks out portions of the string if it matches. Two elements in the vector are set for each substring: the offsets to the start and end of the substring. Arguments: external_re points to the compiled expression external_extra points to "hints" from pcre_study() or is NULL subject points to the subject string length length of subject string (may contain binary zeros) start_offset where to start in the subject string options option bits offsets points to a vector of ints to be filled in with offsets offsetcount the number of elements in the vector Returns: > 0 => success; value is the number of elements filled in = 0 => success, but offsets is not big enough -1 => failed to match < -1 => some kind of unexpected problem */ int pcre_exec(const pcre *external_re, const pcre_extra *external_extra, const char *subject, int length, int start_offset, int options, int *offsets, int offsetcount) { int resetcount, ocount; int first_char = -1; int req_char = -1; int req_char2 = -1; unsigned long int ims = 0; match_data match_block; const uschar *start_bits = NULL; const uschar *start_match = (const uschar *)subject + start_offset; const uschar *end_subject; const uschar *req_char_ptr = start_match - 1; const real_pcre *re = (const real_pcre *)external_re; const real_pcre_extra *extra = (const real_pcre_extra *)external_extra; BOOL using_temporary_offsets = FALSE; BOOL anchored; BOOL startline; if ((options & ~PUBLIC_EXEC_OPTIONS) != 0) return PCRE_ERROR_BADOPTION; if (re == NULL || subject == NULL || (offsets == NULL && offsetcount > 0)) return PCRE_ERROR_NULL; if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC; anchored = ((re->options | options) & PCRE_ANCHORED) != 0; startline = (re->options & PCRE_STARTLINE) != 0; match_block.start_pattern = re->code; match_block.start_subject = (const uschar *)subject; match_block.end_subject = match_block.start_subject + length; end_subject = match_block.end_subject; match_block.endonly = (re->options & PCRE_DOLLAR_ENDONLY) != 0; match_block.utf8 = (re->options & PCRE_UTF8) != 0; match_block.notbol = (options & PCRE_NOTBOL) != 0; match_block.noteol = (options & PCRE_NOTEOL) != 0; match_block.notempty = (options & PCRE_NOTEMPTY) != 0; match_block.errorcode = PCRE_ERROR_NOMATCH; /* Default error */ match_block.lcc = re->tables + lcc_offset; match_block.ctypes = re->tables + ctypes_offset; /* The ims options can vary during the matching as a result of the presence of (?ims) items in the pattern. They are kept in a local variable so that restoring at the exit of a group is easy. */ ims = re->options & (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL); /* If the expression has got more back references than the offsets supplied can hold, we get a temporary bit of working store to use during the matching. Otherwise, we can use the vector supplied, rounding down its size to a multiple of 3. */ ocount = offsetcount - (offsetcount % 3); if (re->top_backref > 0 && re->top_backref >= ocount/3) { ocount = re->top_backref * 3 + 3; match_block.offset_vector = (int *)(pcre_malloc)(ocount * sizeof(int)); if (match_block.offset_vector == NULL) return PCRE_ERROR_NOMEMORY; using_temporary_offsets = TRUE; DPRINTF(("Got memory to hold back references\n")); } else match_block.offset_vector = offsets; match_block.offset_end = ocount; match_block.offset_max = (2*ocount)/3; match_block.offset_overflow = FALSE; /* Compute the minimum number of offsets that we need to reset each time. Doing this makes a huge difference to execution time when there aren't many brackets in the pattern. */ resetcount = 2 + re->top_bracket * 2; if (resetcount > offsetcount) resetcount = ocount; /* Reset the working variable associated with each extraction. These should never be used unless previously set, but they get saved and restored, and so we initialize them to avoid reading uninitialized locations. */ if (match_block.offset_vector != NULL) { register int *iptr = match_block.offset_vector + ocount; register int *iend = iptr - resetcount/2 + 1; while (--iptr >= iend) *iptr = -1; } /* Set up the first character to match, if available. The first_char value is never set for an anchored regular expression, but the anchoring may be forced at run time, so we have to test for anchoring. The first char may be unset for an unanchored pattern, of course. If there's no first char and the pattern was studied, there may be a bitmap of possible first characters. */ if (!anchored) { if ((re->options & PCRE_FIRSTSET) != 0) { first_char = re->first_char; if ((ims & PCRE_CASELESS) != 0) first_char = match_block.lcc[first_char]; } else if (!startline && extra != NULL && (extra->options & PCRE_STUDY_MAPPED) != 0) start_bits = extra->start_bits; } /* For anchored or unanchored matches, there may be a "last known required character" set. If the PCRE_CASELESS is set, implying that the match starts caselessly, or if there are any changes of this flag within the regex, set up both cases of the character. Otherwise set the two values the same, which will avoid duplicate testing (which takes significant time). This covers the vast majority of cases. It will be suboptimal when the case flag changes in a regex and the required character in fact is caseful. */ if ((re->options & PCRE_REQCHSET) != 0) { req_char = re->req_char; req_char2 = ((re->options & (PCRE_CASELESS | PCRE_ICHANGED)) != 0)? (re->tables + fcc_offset)[req_char] : req_char; } /* Loop for handling unanchored repeated matching attempts; for anchored regexs the loop runs just once. */ do { int rc; register int *iptr = match_block.offset_vector; register int *iend = iptr + resetcount; /* Reset the maximum number of extractions we might see. */ while (iptr < iend) *iptr++ = -1; /* Advance to a unique first char if possible */ if (first_char >= 0) { if ((ims & PCRE_CASELESS) != 0) while (start_match < end_subject && match_block.lcc[*start_match] != first_char) start_match++; else while (start_match < end_subject && *start_match != first_char) start_match++; } /* Or to just after \n for a multiline match if possible */ else if (startline) { if (start_match > match_block.start_subject + start_offset) { while (start_match < end_subject && start_match[-1] != NEWLINE) start_match++; } } /* Or to a non-unique first char after study */ else if (start_bits != NULL) { while (start_match < end_subject) { register int c = *start_match; if ((start_bits[c/8] & (1 << (c&7))) == 0) start_match++; else break; } } #ifdef DEBUG /* Sigh. Some compilers never learn. */ printf(">>>> Match against: "); pchars(start_match, end_subject - start_match, TRUE, &match_block); printf("\n"); #endif /* If req_char is set, we know that that character must appear in the subject for the match to succeed. If the first character is set, req_char must be later in the subject; otherwise the test starts at the match point. This optimization can save a huge amount of backtracking in patterns with nested unlimited repeats that aren't going to match. We don't know what the state of case matching may be when this character is hit, so test for it in both its cases if necessary. However, the different cased versions will not be set up unless PCRE_CASELESS was given or the casing state changes within the regex. Writing separate code makes it go faster, as does using an autoincrement and backing off on a match. */ if (req_char >= 0) { register const uschar *p = start_match + ((first_char >= 0)? 1 : 0); /* We don't need to repeat the search if we haven't yet reached the place we found it at last time. */ if (p > req_char_ptr) { /* Do a single test if no case difference is set up */ if (req_char == req_char2) { while (p < end_subject) { if (*p++ == req_char) { p--; break; } } } /* Otherwise test for either case */ else { while (p < end_subject) { register int pp = *p++; if (pp == req_char || pp == req_char2) { p--; break; } } } /* If we can't find the required character, break the matching loop */ if (p >= end_subject) break; /* If we have found the required character, save the point where we found it, so that we don't search again next time round the loop if the start hasn't passed this character yet. */ req_char_ptr = p; } } /* When a match occurs, substrings will be set for all internal extractions; we just need to set up the whole thing as substring 0 before returning. If there were too many extractions, set the return code to zero. In the case where we had to get some local store to hold offsets for backreferences, copy those back references that we can. In this case there need not be overflow if certain parts of the pattern were not used. */ match_block.start_match = start_match; if (!match(start_match, re->code, 2, &match_block, ims, NULL, match_isgroup)) continue; /* Copy the offset information from temporary store if necessary */ if (using_temporary_offsets) { if (offsetcount >= 4) { memcpy(offsets + 2, match_block.offset_vector + 2, (offsetcount - 2) * sizeof(int)); DPRINTF(("Copied offsets from temporary memory\n")); } if (match_block.end_offset_top > offsetcount) match_block.offset_overflow = TRUE; DPRINTF(("Freeing temporary memory\n")); (pcre_free)(match_block.offset_vector); } rc = match_block.offset_overflow? 0 : match_block.end_offset_top/2; if (offsetcount < 2) rc = 0; else { offsets[0] = start_match - match_block.start_subject; offsets[1] = match_block.end_match_ptr - match_block.start_subject; } DPRINTF((">>>> returning %d\n", rc)); return rc; } /* This "while" is the end of the "do" above */ while (!anchored && match_block.errorcode == PCRE_ERROR_NOMATCH && start_match++ < end_subject); if (using_temporary_offsets) { DPRINTF(("Freeing temporary memory\n")); (pcre_free)(match_block.offset_vector); } DPRINTF((">>>> returning %d\n", match_block.errorcode)); return match_block.errorcode; } /* End of pcre.c */ vfu-4.10/vslib/pcre/pcre.h0000644000175000001440000000637311005727400014230 0ustar cadeusers/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* Copyright (c) 1997-2001 University of Cambridge */ #ifndef _PCRE_H #define _PCRE_H /* The file pcre.h is build by "configure". Do not edit it; instead make changes to pcre.in. */ #define PCRE_MAJOR 3 #define PCRE_MINOR 9 #define PCRE_DATE 02-Jan-2002 /* Win32 uses DLL by default */ #ifdef _WIN32 # ifdef STATIC # define PCRE_DL_IMPORT # else # define PCRE_DL_IMPORT __declspec(dllimport) # endif #else # define PCRE_DL_IMPORT #endif /* Have to include stdlib.h in order to ensure that size_t is defined; it is needed here for malloc. */ #include /* Allow for C++ users */ #ifdef __cplusplus extern "C" { #endif /* Options */ #define PCRE_CASELESS 0x0001 #define PCRE_MULTILINE 0x0002 #define PCRE_DOTALL 0x0004 #define PCRE_EXTENDED 0x0008 #define PCRE_ANCHORED 0x0010 #define PCRE_DOLLAR_ENDONLY 0x0020 #define PCRE_EXTRA 0x0040 #define PCRE_NOTBOL 0x0080 #define PCRE_NOTEOL 0x0100 #define PCRE_UNGREEDY 0x0200 #define PCRE_NOTEMPTY 0x0400 #define PCRE_UTF8 0x0800 /* Exec-time and get-time error codes */ #define PCRE_ERROR_NOMATCH (-1) #define PCRE_ERROR_NULL (-2) #define PCRE_ERROR_BADOPTION (-3) #define PCRE_ERROR_BADMAGIC (-4) #define PCRE_ERROR_UNKNOWN_NODE (-5) #define PCRE_ERROR_NOMEMORY (-6) #define PCRE_ERROR_NOSUBSTRING (-7) /* Request types for pcre_fullinfo() */ #define PCRE_INFO_OPTIONS 0 #define PCRE_INFO_SIZE 1 #define PCRE_INFO_CAPTURECOUNT 2 #define PCRE_INFO_BACKREFMAX 3 #define PCRE_INFO_FIRSTCHAR 4 #define PCRE_INFO_FIRSTTABLE 5 #define PCRE_INFO_LASTLITERAL 6 /* Types */ struct real_pcre; /* declaration; the definition is private */ struct real_pcre_extra; /* declaration; the definition is private */ typedef struct real_pcre pcre; typedef struct real_pcre_extra pcre_extra; /* Store get and free functions. These can be set to alternative malloc/free functions if required. Some magic is required for Win32 DLL; it is null on other OS. */ PCRE_DL_IMPORT extern void *(*pcre_malloc)(size_t); PCRE_DL_IMPORT extern void (*pcre_free)(void *); #undef PCRE_DL_IMPORT /* Functions */ extern pcre *pcre_compile(const char *, int, const char **, int *, const unsigned char *); extern int pcre_copy_substring(const char *, int *, int, int, char *, int); extern int pcre_exec(const pcre *, const pcre_extra *, const char *, int, int, int, int *, int); extern void pcre_free_substring(const char *); extern void pcre_free_substring_list(const char **); extern int pcre_get_substring(const char *, int *, int, int, const char **); extern int pcre_get_substring_list(const char *, int *, int, const char ***); extern int pcre_info(const pcre *, int *, int *); extern int pcre_fullinfo(const pcre *, const pcre_extra *, int, void *); extern const unsigned char *pcre_maketables(void); extern pcre_extra *pcre_study(const pcre *, int, const char **); extern const char *pcre_version(void); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* End of pcre.h */ vfu-4.10/vslib/pcre/pcre.txt0000644000175000001440000030240711005727400014615 0ustar cadeusersNAME pcre - Perl-compatible regular expressions. SYNOPSIS #include pcre *pcre_compile(const char *pattern, int options, const char **errptr, int *erroffset, const unsigned char *tableptr); pcre_extra *pcre_study(const pcre *code, int options, const char **errptr); int pcre_exec(const pcre *code, const pcre_extra *extra, const char *subject, int length, int startoffset, int options, int *ovector, int ovecsize); int pcre_copy_substring(const char *subject, int *ovector, int stringcount, int stringnumber, char *buffer, int buffersize); int pcre_get_substring(const char *subject, int *ovector, int stringcount, int stringnumber, const char **stringptr); int pcre_get_substring_list(const char *subject, int *ovector, int stringcount, const char ***listptr); void pcre_free_substring(const char *stringptr); void pcre_free_substring_list(const char **stringptr); const unsigned char *pcre_maketables(void); int pcre_fullinfo(const pcre *code, const pcre_extra *extra, int what, void *where); int pcre_info(const pcre *code, int *optptr, *firstcharptr); char *pcre_version(void); void *(*pcre_malloc)(size_t); void (*pcre_free)(void *); DESCRIPTION The PCRE library is a set of functions that implement regu- lar expression pattern matching using the same syntax and semantics as Perl 5, with just a few differences (see below). The current implementation corresponds to Perl 5.005, with some additional features from later versions. This includes some experimental, incomplete support for UTF-8 encoded strings. Details of exactly what is and what is not supported are given below. PCRE has its own native API, which is described in this document. There is also a set of wrapper functions that correspond to the POSIX regular expression API. These are described in the pcreposix documentation. The native API function prototypes are defined in the header file pcre.h, and on Unix systems the library itself is called libpcre.a, so can be accessed by adding -lpcre to the command for linking an application which calls it. The header file defines the macros PCRE_MAJOR and PCRE_MINOR to contain the major and minor release numbers for the library. Applications can use these to include support for different releases. The functions pcre_compile(), pcre_study(), and pcre_exec() are used for compiling and matching regular expressions. A sample program that demonstrates the simplest way of using them is given in the file pcredemo.c. The last section of this man page describes how to run it. The functions pcre_copy_substring(), pcre_get_substring(), and pcre_get_substring_list() are convenience functions for extracting captured substrings from a matched subject string; pcre_free_substring() and pcre_free_substring_list() are also provided, to free the memory used for extracted strings. The function pcre_maketables() is used (optionally) to build a set of character tables in the current locale for passing to pcre_compile(). The function pcre_fullinfo() is used to find out information about a compiled pattern; pcre_info() is an obsolete version which returns only some of the available information, but is retained for backwards compatibility. The function pcre_version() returns a pointer to a string containing the version of PCRE and its date of release. The global variables pcre_malloc and pcre_free initially contain the entry points of the standard malloc() and free() functions respectively. PCRE calls the memory management functions via these variables, so a calling program can replace them if it wishes to intercept the calls. This should be done before calling any PCRE functions. MULTI-THREADING The PCRE functions can be used in multi-threading applica- tions, with the proviso that the memory management functions pointed to by pcre_malloc and pcre_free are shared by all threads. The compiled form of a regular expression is not altered during matching, so the same compiled pattern can safely be used by several threads at once. COMPILING A PATTERN The function pcre_compile() is called to compile a pattern into an internal form. The pattern is a C string terminated by a binary zero, and is passed in the argument pattern. A pointer to a single block of memory that is obtained via pcre_malloc is returned. This contains the compiled code and related data. The pcre type is defined for the returned block; this is a typedef for a structure whose contents are not externally defined. It is up to the caller to free the memory when it is no longer required. Although the compiled code of a PCRE regex is relocatable, that is, it does not depend on memory location, the complete pcre data block is not fully relocatable, because it con- tains a copy of the tableptr argument, which is an address (see below). The size of a compiled pattern is roughly proportional to the length of the pattern string, except that each character class (other than those containing just a single character, negated or not) requires 33 bytes, and repeat quantifiers with a minimum greater than one or a bounded maximum cause the relevant portions of the compiled pattern to be repli- cated. The options argument contains independent bits that affect the compilation. It should be zero if no options are required. Some of the options, in particular, those that are compatible with Perl, can also be set and unset from within the pattern (see the detailed description of regular expres- sions below). For these options, the contents of the options argument specifies their initial settings at the start of compilation and execution. The PCRE_ANCHORED option can be set at the time of matching as well as at compile time. If errptr is NULL, pcre_compile() returns NULL immediately. Otherwise, if compilation of a pattern fails, pcre_compile() returns NULL, and sets the variable pointed to by errptr to point to a textual error message. The offset from the start of the pattern to the character where the error was discovered is placed in the variable pointed to by erroffset, which must not be NULL. If it is, an immediate error is given. If the final argument, tableptr, is NULL, PCRE uses a default set of character tables which are built when it is compiled, using the default C locale. Otherwise, tableptr must be the result of a call to pcre_maketables(). See the section on locale support below. This code fragment shows a typical straightforward call to pcre_compile(): pcre *re; const char *error; int erroffset; re = pcre_compile( "^A.*Z", /* the pattern */ 0, /* default options */ &error, /* for error message */ &erroffset, /* for error offset */ NULL); /* use default character tables */ The following option bits are defined in the header file: PCRE_ANCHORED If this bit is set, the pattern is forced to be "anchored", that is, it is constrained to match only at the start of the string which is being searched (the "subject string"). This effect can also be achieved by appropriate constructs in the pattern itself, which is the only way to do it in Perl. PCRE_CASELESS If this bit is set, letters in the pattern match both upper and lower case letters. It is equivalent to Perl's /i option. PCRE_DOLLAR_ENDONLY If this bit is set, a dollar metacharacter in the pattern matches only at the end of the subject string. Without this option, a dollar also matches immediately before the final character if it is a newline (but not before any other new- lines). The PCRE_DOLLAR_ENDONLY option is ignored if PCRE_MULTILINE is set. There is no equivalent to this option in Perl. PCRE_DOTALL If this bit is set, a dot metacharater in the pattern matches all characters, including newlines. Without it, new- lines are excluded. This option is equivalent to Perl's /s option. A negative class such as [^a] always matches a new- line character, independent of the setting of this option. PCRE_EXTENDED If this bit is set, whitespace data characters in the pat- tern are totally ignored except when escaped or inside a character class, and characters between an unescaped # out- side a character class and the next newline character, inclusive, are also ignored. This is equivalent to Perl's /x option, and makes it possible to include comments inside complicated patterns. Note, however, that this applies only to data characters. Whitespace characters may never appear within special character sequences in a pattern, for example within the sequence (?( which introduces a conditional sub- pattern. PCRE_EXTRA This option was invented in order to turn on additional functionality of PCRE that is incompatible with Perl, but it is currently of very little use. When set, any backslash in a pattern that is followed by a letter that has no special meaning causes an error, thus reserving these combinations for future expansion. By default, as in Perl, a backslash followed by a letter with no special meaning is treated as a literal. There are at present no other features controlled by this option. It can also be set by a (?X) option setting within a pattern. PCRE_MULTILINE By default, PCRE treats the subject string as consisting of a single "line" of characters (even if it actually contains several newlines). The "start of line" metacharacter (^) matches only at the start of the string, while the "end of line" metacharacter ($) matches only at the end of the string, or before a terminating newline (unless PCRE_DOLLAR_ENDONLY is set). This is the same as Perl. When PCRE_MULTILINE it is set, the "start of line" and "end of line" constructs match immediately following or immedi- ately before any newline in the subject string, respec- tively, as well as at the very start and end. This is equivalent to Perl's /m option. If there are no "\n" charac- ters in a subject string, or no occurrences of ^ or $ in a pattern, setting PCRE_MULTILINE has no effect. PCRE_UNGREEDY This option inverts the "greediness" of the quantifiers so that they are not greedy by default, but become greedy if followed by "?". It is not compatible with Perl. It can also be set by a (?U) option setting within the pattern. PCRE_UTF8 This option causes PCRE to regard both the pattern and the subject as strings of UTF-8 characters instead of just byte strings. However, it is available only if PCRE has been built to include UTF-8 support. If not, the use of this option provokes an error. Support for UTF-8 is new, experi- mental, and incomplete. Details of exactly what it entails are given below. STUDYING A PATTERN When a pattern is going to be used several times, it is worth spending more time analyzing it in order to speed up the time taken for matching. The function pcre_study() takes a pointer to a compiled pattern as its first argument, and returns a pointer to a pcre_extra block (another typedef for a structure with hidden contents) containing additional information about the pattern; this can be passed to pcre_exec(). If no additional information is available, NULL is returned. The second argument contains option bits. At present, no options are defined for pcre_study(), and this argument should always be zero. The third argument for pcre_study() is a pointer to an error message. If studying succeeds (even if no data is returned), the variable it points to is set to NULL. Otherwise it points to a textual error message. This is a typical call to pcre_study(): pcre_extra *pe; pe = pcre_study( re, /* result of pcre_compile() */ 0, /* no options exist */ &error); /* set to NULL or points to a message */ At present, studying a pattern is useful only for non- anchored patterns that do not have a single fixed starting character. A bitmap of possible starting characters is created. LOCALE SUPPORT PCRE handles caseless matching, and determines whether char- acters are letters, digits, or whatever, by reference to a set of tables. The library contains a default set of tables which is created in the default C locale when PCRE is com- piled. This is used when the final argument of pcre_compile() is NULL, and is sufficient for many applica- tions. An alternative set of tables can, however, be supplied. Such tables are built by calling the pcre_maketables() function, which has no arguments, in the relevant locale. The result can then be passed to pcre_compile() as often as necessary. For example, to build and use tables that are appropriate for the French locale (where accented characters with codes greater than 128 are treated as letters), the following code could be used: setlocale(LC_CTYPE, "fr"); tables = pcre_maketables(); re = pcre_compile(..., tables); The tables are built in memory that is obtained via pcre_malloc. The pointer that is passed to pcre_compile is saved with the compiled pattern, and the same tables are used via this pointer by pcre_study() and pcre_exec(). Thus for any single pattern, compilation, studying and matching all happen in the same locale, but different patterns can be compiled in different locales. It is the caller's responsi- bility to ensure that the memory containing the tables remains available for as long as it is needed. INFORMATION ABOUT A PATTERN The pcre_fullinfo() function returns information about a compiled pattern. It replaces the obsolete pcre_info() func- tion, which is nevertheless retained for backwards compabil- ity (and is documented below). The first argument for pcre_fullinfo() is a pointer to the compiled pattern. The second argument is the result of pcre_study(), or NULL if the pattern was not studied. The third argument specifies which piece of information is required, while the fourth argument is a pointer to a vari- able to receive the data. The yield of the function is zero for success, or one of the following negative numbers: PCRE_ERROR_NULL the argument code was NULL the argument where was NULL PCRE_ERROR_BADMAGIC the "magic number" was not found PCRE_ERROR_BADOPTION the value of what was invalid Here is a typical call of pcre_fullinfo(), to obtain the length of the compiled pattern: int rc; unsigned long int length; rc = pcre_fullinfo( re, /* result of pcre_compile() */ pe, /* result of pcre_study(), or NULL */ PCRE_INFO_SIZE, /* what is required */ &length); /* where to put the data */ The possible values for the third argument are defined in pcre.h, and are as follows: PCRE_INFO_OPTIONS Return a copy of the options with which the pattern was com- piled. The fourth argument should point to an unsigned long int variable. These option bits are those specified in the call to pcre_compile(), modified by any top-level option settings within the pattern itself, and with the PCRE_ANCHORED bit forcibly set if the form of the pattern implies that it can match only at the start of a subject string. PCRE_INFO_SIZE Return the size of the compiled pattern, that is, the value that was passed as the argument to pcre_malloc() when PCRE was getting memory in which to place the compiled data. The fourth argument should point to a size_t variable. PCRE_INFO_CAPTURECOUNT Return the number of capturing subpatterns in the pattern. The fourth argument should point to an int variable. PCRE_INFO_BACKREFMAX Return the number of the highest back reference in the pat- tern. The fourth argument should point to an int variable. Zero is returned if there are no back references. PCRE_INFO_FIRSTCHAR Return information about the first character of any matched string, for a non-anchored pattern. If there is a fixed first character, e.g. from a pattern such as (cat|cow|coyote), it is returned in the integer pointed to by where. Otherwise, if either (a) the pattern was compiled with the PCRE_MULTILINE option, and every branch starts with "^", or (b) every branch of the pattern starts with ".*" and PCRE_DOTALL is not set (if it were set, the pattern would be anchored), -1 is returned, indicating that the pattern matches only at the start of a subject string or after any "\n" within the string. Otherwise -2 is returned. For anchored patterns, -2 is returned. PCRE_INFO_FIRSTTABLE If the pattern was studied, and this resulted in the con- struction of a 256-bit table indicating a fixed set of char- acters for the first character in any matching string, a pointer to the table is returned. Otherwise NULL is returned. The fourth argument should point to an unsigned char * variable. PCRE_INFO_LASTLITERAL For a non-anchored pattern, return the value of the right- most literal character which must exist in any matched string, other than at its start. The fourth argument should point to an int variable. If there is no such character, or if the pattern is anchored, -1 is returned. For example, for the pattern /a\d+z\d+/ the returned value is 'z'. The pcre_info() function is now obsolete because its inter- face is too restrictive to return all the available data about a compiled pattern. New programs should use pcre_fullinfo() instead. The yield of pcre_info() is the number of capturing subpatterns, or one of the following negative numbers: PCRE_ERROR_NULL the argument code was NULL PCRE_ERROR_BADMAGIC the "magic number" was not found If the optptr argument is not NULL, a copy of the options with which the pattern was compiled is placed in the integer it points to (see PCRE_INFO_OPTIONS above). If the pattern is not anchored and the firstcharptr argument is not NULL, it is used to pass back information about the first character of any matched string (see PCRE_INFO_FIRSTCHAR above). MATCHING A PATTERN The function pcre_exec() is called to match a subject string SunOS 5.8 Last change: 9 against a pre-compiled pattern, which is passed in the code argument. If the pattern has been studied, the result of the study should be passed in the extra argument. Otherwise this must be NULL. Here is an example of a simple call to pcre_exec(): int rc; int ovector[30]; rc = pcre_exec( re, /* result of pcre_compile() */ NULL, /* we didn't study the pattern */ "some string", /* the subject string */ 11, /* the length of the subject string */ 0, /* start at offset 0 in the subject */ 0, /* default options */ ovector, /* vector for substring information */ 30); /* number of elements in the vector */ The PCRE_ANCHORED option can be passed in the options argu- ment, whose unused bits must be zero. However, if a pattern was compiled with PCRE_ANCHORED, or turned out to be anchored by virtue of its contents, it cannot be made unachored at matching time. There are also three further options that can be set only at matching time: PCRE_NOTBOL The first character of the string is not the beginning of a line, so the circumflex metacharacter should not match before it. Setting this without PCRE_MULTILINE (at compile time) causes circumflex never to match. PCRE_NOTEOL The end of the string is not the end of a line, so the dol- lar metacharacter should not match it nor (except in multi- line mode) a newline immediately before it. Setting this without PCRE_MULTILINE (at compile time) causes dollar never to match. PCRE_NOTEMPTY An empty string is not considered to be a valid match if this option is set. If there are alternatives in the pat- tern, they are tried. If all the alternatives match the empty string, the entire match fails. For example, if the pattern a?b? is applied to a string not beginning with "a" or "b", it matches the empty string at the start of the subject. With PCRE_NOTEMPTY set, this match is not valid, so PCRE searches further into the string for occurrences of "a" or "b". Perl has no direct equivalent of PCRE_NOTEMPTY, but it does make a special case of a pattern match of the empty string within its split() function, and when using the /g modifier. It is possible to emulate Perl's behaviour after matching a null string by first trying the match again at the same offset with PCRE_NOTEMPTY set, and then if that fails by advancing the starting offset (see below) and trying an ordinary match again. The subject string is passed as a pointer in subject, a length in length, and a starting offset in startoffset. Unlike the pattern string, the subject may contain binary zero characters. When the starting offset is zero, the search for a match starts at the beginning of the subject, and this is by far the most common case. A non-zero starting offset is useful when searching for another match in the same subject by calling pcre_exec() again after a previous success. Setting startoffset differs from just passing over a shortened string and setting PCRE_NOTBOL in the case of a pattern that begins with any kind of lookbehind. For example, consider the pattern \Biss\B which finds occurrences of "iss" in the middle of words. (\B matches only if the current position in the subject is not a word boundary.) When applied to the string "Mississipi" the first call to pcre_exec() finds the first occurrence. If pcre_exec() is called again with just the remainder of the subject, namely "issipi", it does not match, because \B is always false at the start of the subject, which is deemed to be a word boundary. However, if pcre_exec() is passed the entire string again, but with startoffset set to 4, it finds the second occurrence of "iss" because it is able to look behind the starting point to discover that it is preceded by a letter. If a non-zero starting offset is passed when the pattern is anchored, one attempt to match at the given offset is tried. This can only succeed if the pattern does not require the match to be at the start of the subject. In general, a pattern matches a certain portion of the sub- ject, and in addition, further substrings from the subject may be picked out by parts of the pattern. Following the usage in Jeffrey Friedl's book, this is called "capturing" in what follows, and the phrase "capturing subpattern" is used for a fragment of a pattern that picks out a substring. PCRE supports several other kinds of parenthesized subpat- tern that do not cause substrings to be captured. Captured substrings are returned to the caller via a vector of integer offsets whose address is passed in ovector. The number of elements in the vector is passed in ovecsize. The first two-thirds of the vector is used to pass back captured substrings, each substring using a pair of integers. The remaining third of the vector is used as workspace by pcre_exec() while matching capturing subpatterns, and is not available for passing back information. The length passed in ovecsize should always be a multiple of three. If it is not, it is rounded down. When a match has been successful, information about captured substrings is returned in pairs of integers, starting at the beginning of ovector, and continuing up to two-thirds of its length at the most. The first element of a pair is set to the offset of the first character in a substring, and the second is set to the offset of the first character after the end of a substring. The first pair, ovector[0] and ovec- tor[1], identify the portion of the subject string matched by the entire pattern. The next pair is used for the first capturing subpattern, and so on. The value returned by pcre_exec() is the number of pairs that have been set. If there are no capturing subpatterns, the return value from a successful match is 1, indicating that just the first pair of offsets has been set. Some convenience functions are provided for extracting the captured substrings as separate strings. These are described in the following section. It is possible for an capturing subpattern number n+1 to match some part of the subject when subpattern n has not been used at all. For example, if the string "abc" is matched against the pattern (a|(z))(bc) subpatterns 1 and 3 are matched, but 2 is not. When this happens, both offset values corresponding to the unused subpattern are set to -1. If a capturing subpattern is matched repeatedly, it is the last portion of the string that it matched that gets returned. If the vector is too small to hold all the captured sub- strings, it is used as far as possible (up to two-thirds of its length), and the function returns a value of zero. In particular, if the substring offsets are not of interest, pcre_exec() may be called with ovector passed as NULL and ovecsize as zero. However, if the pattern contains back references and the ovector isn't big enough to remember the related substrings, PCRE has to get additional memory for use during matching. Thus it is usually advisable to supply an ovector. Note that pcre_info() can be used to find out how many cap- turing subpatterns there are in a compiled pattern. The smallest size for ovector that will allow for n captured substrings in addition to the offsets of the substring matched by the whole pattern is (n+1)*3. If pcre_exec() fails, it returns a negative number. The fol- lowing are defined in the header file: PCRE_ERROR_NOMATCH (-1) The subject string did not match the pattern. PCRE_ERROR_NULL (-2) Either code or subject was passed as NULL, or ovector was NULL and ovecsize was not zero. PCRE_ERROR_BADOPTION (-3) An unrecognized bit was set in the options argument. PCRE_ERROR_BADMAGIC (-4) PCRE stores a 4-byte "magic number" at the start of the com- piled code, to catch the case when it is passed a junk pointer. This is the error it gives when the magic number isn't present. PCRE_ERROR_UNKNOWN_NODE (-5) While running the pattern match, an unknown item was encoun- tered in the compiled pattern. This error could be caused by a bug in PCRE or by overwriting of the compiled pattern. PCRE_ERROR_NOMEMORY (-6) If a pattern contains back references, but the ovector that is passed to pcre_exec() is not big enough to remember the referenced substrings, PCRE gets a block of memory at the start of matching to use for this purpose. If the call via pcre_malloc() fails, this error is given. The memory is freed at the end of matching. EXTRACTING CAPTURED SUBSTRINGS Captured substrings can be accessed directly by using the offsets returned by pcre_exec() in ovector. For convenience, the functions pcre_copy_substring(), pcre_get_substring(), and pcre_get_substring_list() are provided for extracting captured substrings as new, separate, zero-terminated strings. A substring that contains a binary zero is correctly extracted and has a further zero added on the end, but the result does not, of course, function as a C string. The first three arguments are the same for all three func- tions: subject is the subject string which has just been successfully matched, ovector is a pointer to the vector of integer offsets that was passed to pcre_exec(), and stringcount is the number of substrings that were captured by the match, including the substring that matched the entire regular expression. This is the value returned by pcre_exec if it is greater than zero. If pcre_exec() returned zero, indicating that it ran out of space in ovec- tor, the value passed as stringcount should be the size of the vector divided by three. The functions pcre_copy_substring() and pcre_get_substring() extract a single substring, whose number is given as string- number. A value of zero extracts the substring that matched the entire pattern, while higher values extract the captured substrings. For pcre_copy_substring(), the string is placed in buffer, whose length is given by buffersize, while for pcre_get_substring() a new block of memory is obtained via pcre_malloc, and its address is returned via stringptr. The yield of the function is the length of the string, not including the terminating zero, or one of PCRE_ERROR_NOMEMORY (-6) The buffer was too small for pcre_copy_substring(), or the attempt to get memory failed for pcre_get_substring(). PCRE_ERROR_NOSUBSTRING (-7) There is no substring whose number is stringnumber. The pcre_get_substring_list() function extracts all avail- able substrings and builds a list of pointers to them. All this is done in a single block of memory which is obtained via pcre_malloc. The address of the memory block is returned via listptr, which is also the start of the list of string pointers. The end of the list is marked by a NULL pointer. The yield of the function is zero if all went well, or PCRE_ERROR_NOMEMORY (-6) if the attempt to get the memory block failed. When any of these functions encounter a substring that is unset, which can happen when capturing subpattern number n+1 matches some part of the subject, but subpattern n has not been used at all, they return an empty string. This can be distinguished from a genuine zero-length substring by inspecting the appropriate offset in ovector, which is nega- tive for unset substrings. The two convenience functions pcre_free_substring() and pcre_free_substring_list() can be used to free the memory returned by a previous call of pcre_get_substring() or pcre_get_substring_list(), respectively. They do nothing more than call the function pointed to by pcre_free, which of course could be called directly from a C program. How- ever, PCRE is used in some situations where it is linked via a special interface to another programming language which cannot use pcre_free directly; it is for these cases that the functions are provided. LIMITATIONS There are some size limitations in PCRE but it is hoped that they will never in practice be relevant. The maximum length of a compiled pattern is 65539 (sic) bytes. All values in repeating quantifiers must be less than 65536. There max- imum number of capturing subpatterns is 65535. There is no limit to the number of non-capturing subpatterns, but the maximum depth of nesting of all kinds of parenthesized sub- pattern, including capturing subpatterns, assertions, and other types of subpattern, is 200. The maximum length of a subject string is the largest posi- tive number that an integer variable can hold. However, PCRE uses recursion to handle subpatterns and indefinite repeti- tion. This means that the available stack space may limit the size of a subject string that can be processed by cer- tain patterns. DIFFERENCES FROM PERL The differences described here are with respect to Perl 5.005. 1. By default, a whitespace character is any character that the C library function isspace() recognizes, though it is possible to compile PCRE with alternative character type tables. Normally isspace() matches space, formfeed, newline, carriage return, horizontal tab, and vertical tab. Perl 5 no longer includes vertical tab in its set of whitespace char- acters. The \v escape that was in the Perl documentation for a long time was never in fact recognized. However, the char- acter itself was treated as whitespace at least up to 5.002. In 5.004 and 5.005 it does not match \s. 2. PCRE does not allow repeat quantifiers on lookahead assertions. Perl permits them, but they do not mean what you might think. For example, (?!a){3} does not assert that the next three characters are not "a". It just asserts that the next character is not "a" three times. 3. Capturing subpatterns that occur inside negative looka- head assertions are counted, but their entries in the offsets vector are never set. Perl sets its numerical vari- ables from any such patterns that are matched before the assertion fails to match something (thereby succeeding), but only if the negative lookahead assertion contains just one branch. 4. Though binary zero characters are supported in the sub- ject string, they are not allowed in a pattern string because it is passed as a normal C string, terminated by zero. The escape sequence "\0" can be used in the pattern to represent a binary zero. 5. The following Perl escape sequences are not supported: \l, \u, \L, \U, \E, \Q. In fact these are implemented by Perl's general string-handling and are not part of its pat- tern matching engine. 6. The Perl \G assertion is not supported as it is not relevant to single pattern matches. 7. Fairly obviously, PCRE does not support the (?{code}) and (?p{code}) constructions. However, there is some experimen- tal support for recursive patterns using the non-Perl item (?R). 8. There are at the time of writing some oddities in Perl 5.005_02 concerned with the settings of captured strings when part of a pattern is repeated. For example, matching "aba" against the pattern /^(a(b)?)+$/ sets $2 to the value "b", but matching "aabbaa" against /^(aa(bb)?)+$/ leaves $2 unset. However, if the pattern is changed to /^(aa(b(b))?)+$/ then $2 (and $3) are set. In Perl 5.004 $2 is set in both cases, and that is also true of PCRE. If in the future Perl changes to a consistent state that is different, PCRE may change to follow. 9. Another as yet unresolved discrepancy is that in Perl 5.005_02 the pattern /^(a)?(?(1)a|b)+$/ matches the string "a", whereas in PCRE it does not. However, in both Perl and PCRE /^(a)?a/ matched against "a" leaves $1 unset. 10. PCRE provides some extensions to the Perl regular expression facilities: (a) Although lookbehind assertions must match fixed length strings, each alternative branch of a lookbehind assertion can match a different length of string. Perl 5.005 requires them all to have the same length. (b) If PCRE_DOLLAR_ENDONLY is set and PCRE_MULTILINE is not set, the $ meta- character matches only at the very end of the string. (c) If PCRE_EXTRA is set, a backslash followed by a letter with no special meaning is faulted. (d) If PCRE_UNGREEDY is set, the greediness of the repeti- tion quantifiers is inverted, that is, by default they are not greedy, but if followed by a question mark they are. (e) PCRE_ANCHORED can be used to force a pattern to be tried only at the start of the subject. (f) The PCRE_NOTBOL, PCRE_NOTEOL, and PCRE_NOTEMPTY options for pcre_exec() have no Perl equivalents. (g) The (?R) construct allows for recursive pattern matching (Perl 5.6 can do this using the (?p{code}) construct, which PCRE cannot of course support.) REGULAR EXPRESSION DETAILS The syntax and semantics of the regular expressions sup- ported by PCRE are described below. Regular expressions are also described in the Perl documentation and in a number of other books, some of which have copious examples. Jeffrey Friedl's "Mastering Regular Expressions", published by O'Reilly (ISBN 1-56592-257), covers them in great detail. The description here is intended as reference documentation. The basic operation of PCRE is on strings of bytes. However, there is the beginnings of some support for UTF-8 character strings. To use this support you must configure PCRE to include it, and then call pcre_compile() with the PCRE_UTF8 option. How this affects the pattern matching is described in the final section of this document. A regular expression is a pattern that is matched against a subject string from left to right. Most characters stand for themselves in a pattern, and match the corresponding charac- ters in the subject. As a trivial example, the pattern The quick brown fox matches a portion of a subject string that is identical to itself. The power of regular expressions comes from the ability to include alternatives and repetitions in the pat- tern. These are encoded in the pattern by the use of meta- characters, which do not stand for themselves but instead are interpreted in some special way. There are two different sets of meta-characters: those that are recognized anywhere in the pattern except within square brackets, and those that are recognized in square brackets. Outside square brackets, the meta-characters are as follows: \ general escape character with several uses ^ assert start of subject (or line, in multiline mode) $ assert end of subject (or line, in multiline mode) . match any character except newline (by default) [ start character class definition | start of alternative branch ( start subpattern ) end subpattern ? extends the meaning of ( also 0 or 1 quantifier also quantifier minimizer * 0 or more quantifier + 1 or more quantifier { start min/max quantifier Part of a pattern that is in square brackets is called a "character class". In a character class the only meta- characters are: \ general escape character ^ negate the class, but only if the first character - indicates character range ] terminates the character class The following sections describe the use of each of the meta-characters. BACKSLASH The backslash character has several uses. Firstly, if it is followed by a non-alphameric character, it takes away any special meaning that character may have. This use of backslash as an escape character applies both inside and outside character classes. For example, if you want to match a "*" character, you write "\*" in the pattern. This applies whether or not the follow- ing character would otherwise be interpreted as a meta- character, so it is always safe to precede a non-alphameric with "\" to specify that it stands for itself. In particu- lar, if you want to match a backslash, you write "\\". If a pattern is compiled with the PCRE_EXTENDED option, whi- tespace in the pattern (other than in a character class) and characters between a "#" outside a character class and the next newline character are ignored. An escaping backslash can be used to include a whitespace or "#" character as part of the pattern. A second use of backslash provides a way of encoding non- printing characters in patterns in a visible manner. There is no restriction on the appearance of non-printing charac- ters, apart from the binary zero that terminates a pattern, but when a pattern is being prepared by text editing, it is usually easier to use one of the following escape sequences than the binary character it represents: \a alarm, that is, the BEL character (hex 07) \cx "control-x", where x is any character \e escape (hex 1B) \f formfeed (hex 0C) \n newline (hex 0A) \r carriage return (hex 0D) \t tab (hex 09) \xhh character with hex code hh \ddd character with octal code ddd, or backreference The precise effect of "\cx" is as follows: if "x" is a lower case letter, it is converted to upper case. Then bit 6 of the character (hex 40) is inverted. Thus "\cz" becomes hex 1A, but "\c{" becomes hex 3B, while "\c;" becomes hex 7B. After "\x", up to two hexadecimal digits are read (letters can be in upper or lower case). After "\0" up to two further octal digits are read. In both cases, if there are fewer than two digits, just those that are present are used. Thus the sequence "\0\x\07" specifies two binary zeros followed by a BEL character. Make sure you supply two digits after the initial zero if the character that follows is itself an octal digit. The handling of a backslash followed by a digit other than 0 is complicated. Outside a character class, PCRE reads it and any following digits as a decimal number. If the number is less than 10, or if there have been at least that many previous capturing left parentheses in the expression, the entire sequence is taken as a back reference. A description of how this works is given later, following the discussion of parenthesized subpatterns. Inside a character class, or if the decimal number is greater than 9 and there have not been that many capturing subpatterns, PCRE re-reads up to three octal digits follow- ing the backslash, and generates a single byte from the least significant 8 bits of the value. Any subsequent digits stand for themselves. For example: \040 is another way of writing a space \40 is the same, provided there are fewer than 40 previous capturing subpatterns \7 is always a back reference \11 might be a back reference, or another way of writing a tab \011 is always a tab \0113 is a tab followed by the character "3" \113 is the character with octal code 113 (since there can be no more than 99 back references) \377 is a byte consisting entirely of 1 bits \81 is either a back reference, or a binary zero followed by the two characters "8" and "1" Note that octal values of 100 or greater must not be intro- duced by a leading zero, because no more than three octal digits are ever read. All the sequences that define a single byte value can be used both inside and outside character classes. In addition, inside a character class, the sequence "\b" is interpreted as the backspace character (hex 08). Outside a character class it has a different meaning (see below). The third use of backslash is for specifying generic charac- ter types: \d any decimal digit \D any character that is not a decimal digit \s any whitespace character \S any character that is not a whitespace character \w any "word" character \W any "non-word" character Each pair of escape sequences partitions the complete set of characters into two disjoint sets. Any given character matches one, and only one, of each pair. A "word" character is any letter or digit or the underscore character, that is, any character which can be part of a Perl "word". The definition of letters and digits is con- trolled by PCRE's character tables, and may vary if locale- specific matching is taking place (see "Locale support" above). For example, in the "fr" (French) locale, some char- acter codes greater than 128 are used for accented letters, and these are matched by \w. These character type sequences can appear both inside and outside character classes. They each match one character of the appropriate type. If the current matching point is at the end of the subject string, all of them fail, since there is no character to match. The fourth use of backslash is for certain simple asser- tions. An assertion specifies a condition that has to be met at a particular point in a match, without consuming any characters from the subject string. The use of subpatterns for more complicated assertions is described below. The backslashed assertions are \b word boundary \B not a word boundary \A start of subject (independent of multiline mode) \Z end of subject or newline at end (independent of multiline mode) \z end of subject (independent of multiline mode) These assertions may not appear in character classes (but note that "\b" has a different meaning, namely the backspace character, inside a character class). A word boundary is a position in the subject string where the current character and the previous character do not both match \w or \W (i.e. one matches \w and the other matches \W), or the start or end of the string if the first or last character matches \w, respectively. The \A, \Z, and \z assertions differ from the traditional circumflex and dollar (described below) in that they only ever match at the very start and end of the subject string, whatever options are set. They are not affected by the PCRE_NOTBOL or PCRE_NOTEOL options. If the startoffset argu- ment of pcre_exec() is non-zero, \A can never match. The difference between \Z and \z is that \Z matches before a newline that is the last character of the string as well as at the end of the string, whereas \z matches only at the end. CIRCUMFLEX AND DOLLAR Outside a character class, in the default matching mode, the circumflex character is an assertion which is true only if the current matching point is at the start of the subject string. If the startoffset argument of pcre_exec() is non- zero, circumflex can never match. Inside a character class, circumflex has an entirely different meaning (see below). Circumflex need not be the first character of the pattern if a number of alternatives are involved, but it should be the first thing in each alternative in which it appears if the pattern is ever to match that branch. If all possible alter- natives start with a circumflex, that is, if the pattern is constrained to match only at the start of the subject, it is said to be an "anchored" pattern. (There are also other con- structs that can cause a pattern to be anchored.) A dollar character is an assertion which is true only if the current matching point is at the end of the subject string, or immediately before a newline character that is the last character in the string (by default). Dollar need not be the last character of the pattern if a number of alternatives are involved, but it should be the last item in any branch in which it appears. Dollar has no special meaning in a character class. The meaning of dollar can be changed so that it matches only at the very end of the string, by setting the PCRE_DOLLAR_ENDONLY option at compile or matching time. This does not affect the \Z assertion. The meanings of the circumflex and dollar characters are changed if the PCRE_MULTILINE option is set. When this is the case, they match immediately after and immediately before an internal "\n" character, respectively, in addition to matching at the start and end of the subject string. For example, the pattern /^abc$/ matches the subject string "def\nabc" in multiline mode, but not otherwise. Conse- quently, patterns that are anchored in single line mode because all branches start with "^" are not anchored in mul- tiline mode, and a match for circumflex is possible when the startoffset argument of pcre_exec() is non-zero. The PCRE_DOLLAR_ENDONLY option is ignored if PCRE_MULTILINE is set. Note that the sequences \A, \Z, and \z can be used to match the start and end of the subject in both modes, and if all branches of a pattern start with \A it is always anchored, whether PCRE_MULTILINE is set or not. FULL STOP (PERIOD, DOT) Outside a character class, a dot in the pattern matches any one character in the subject, including a non-printing char- acter, but not (by default) newline. If the PCRE_DOTALL option is set, dots match newlines as well. The handling of dot is entirely independent of the handling of circumflex and dollar, the only relationship being that they both involve newline characters. Dot has no special meaning in a character class. SQUARE BRACKETS An opening square bracket introduces a character class, ter- minated by a closing square bracket. A closing square bracket on its own is not special. If a closing square bracket is required as a member of the class, it should be the first data character in the class (after an initial cir- cumflex, if present) or escaped with a backslash. A character class matches a single character in the subject; the character must be in the set of characters defined by the class, unless the first character in the class is a cir- cumflex, in which case the subject character must not be in the set defined by the class. If a circumflex is actually required as a member of the class, ensure it is not the first character, or escape it with a backslash. For example, the character class [aeiou] matches any lower case vowel, while [^aeiou] matches any character that is not a lower case vowel. Note that a circumflex is just a con- venient notation for specifying the characters which are in the class by enumerating those that are not. It is not an assertion: it still consumes a character from the subject string, and fails if the current pointer is at the end of the string. When caseless matching is set, any letters in a class represent both their upper case and lower case versions, so for example, a caseless [aeiou] matches "A" as well as "a", and a caseless [^aeiou] does not match "A", whereas a case- ful version would. The newline character is never treated in any special way in character classes, whatever the setting of the PCRE_DOTALL or PCRE_MULTILINE options is. A class such as [^a] will always match a newline. The minus (hyphen) character can be used to specify a range of characters in a character class. For example, [d-m] matches any letter between d and m, inclusive. If a minus character is required in a class, it must be escaped with a backslash or appear in a position where it cannot be inter- preted as indicating a range, typically as the first or last character in the class. It is not possible to have the literal character "]" as the end character of a range. A pattern such as [W-]46] is interpreted as a class of two characters ("W" and "-") fol- lowed by a literal string "46]", so it would match "W46]" or "-46]". However, if the "]" is escaped with a backslash it is interpreted as the end of range, so [W-\]46] is inter- preted as a single class containing a range followed by two separate characters. The octal or hexadecimal representation of "]" can also be used to end a range. Ranges operate in ASCII collating sequence. They can also be used for characters specified numerically, for example [\000-\037]. If a range that includes letters is used when caseless matching is set, it matches the letters in either case. For example, [W-c] is equivalent to [][\^_`wxyzabc], matched caselessly, and if character tables for the "fr" locale are in use, [\xc8-\xcb] matches accented E characters in both cases. The character types \d, \D, \s, \S, \w, and \W may also appear in a character class, and add the characters that they match to the class. For example, [\dABCDEF] matches any hexadecimal digit. A circumflex can conveniently be used with the upper case character types to specify a more res- tricted set of characters than the matching lower case type. For example, the class [^\W_] matches any letter or digit, but not underscore. All non-alphameric characters other than \, -, ^ (at the start) and the terminating ] are non-special in character classes, but it does no harm if they are escaped. POSIX CHARACTER CLASSES Perl 5.6 (not yet released at the time of writing) is going to support the POSIX notation for character classes, which uses names enclosed by [: and :] within the enclosing square brackets. PCRE supports this notation. For example, [01[:alpha:]%] matches "0", "1", any alphabetic character, or "%". The sup- ported class names are alnum letters and digits alpha letters ascii character codes 0 - 127 cntrl control characters digit decimal digits (same as \d) graph printing characters, excluding space lower lower case letters print printing characters, including space punct printing characters, excluding letters and digits space white space (same as \s) upper upper case letters word "word" characters (same as \w) xdigit hexadecimal digits The names "ascii" and "word" are Perl extensions. Another Perl extension is negation, which is indicated by a ^ char- acter after the colon. For example, [12[:^digit:]] matches "1", "2", or any non-digit. PCRE (and Perl) also recognize the POSIX syntax [.ch.] and [=ch=] where "ch" is a "collating element", but these are not supported, and an error is given if they are encountered. VERTICAL BAR Vertical bar characters are used to separate alternative patterns. For example, the pattern gilbert|sullivan matches either "gilbert" or "sullivan". Any number of alter- natives may appear, and an empty alternative is permitted (matching the empty string). The matching process tries each alternative in turn, from left to right, and the first one that succeeds is used. If the alternatives are within a subpattern (defined below), "succeeds" means matching the rest of the main pattern as well as the alternative in the subpattern. INTERNAL OPTION SETTING The settings of PCRE_CASELESS, PCRE_MULTILINE, PCRE_DOTALL, and PCRE_EXTENDED can be changed from within the pattern by a sequence of Perl option letters enclosed between "(?" and ")". The option letters are i for PCRE_CASELESS m for PCRE_MULTILINE s for PCRE_DOTALL x for PCRE_EXTENDED For example, (?im) sets caseless, multiline matching. It is also possible to unset these options by preceding the letter with a hyphen, and a combined setting and unsetting such as (?im-sx), which sets PCRE_CASELESS and PCRE_MULTILINE while unsetting PCRE_DOTALL and PCRE_EXTENDED, is also permitted. If a letter appears both before and after the hyphen, the option is unset. The scope of these option changes depends on where in the pattern the setting occurs. For settings that are outside any subpattern (defined below), the effect is the same as if the options were set or unset at the start of matching. The following patterns all behave in exactly the same way: (?i)abc a(?i)bc ab(?i)c abc(?i) which in turn is the same as compiling the pattern abc with PCRE_CASELESS set. In other words, such "top level" set- tings apply to the whole pattern (unless there are other changes inside subpatterns). If there is more than one set- ting of the same option at top level, the rightmost setting is used. If an option change occurs inside a subpattern, the effect is different. This is a change of behaviour in Perl 5.005. An option change inside a subpattern affects only that part of the subpattern that follows it, so (a(?i)b)c matches abc and aBc and no other strings (assuming PCRE_CASELESS is not used). By this means, options can be made to have different settings in different parts of the pattern. Any changes made in one alternative do carry on into subsequent branches within the same subpattern. For example, (a(?i)b|c) matches "ab", "aB", "c", and "C", even though when matching "C" the first branch is abandoned before the option setting. This is because the effects of option settings happen at compile time. There would be some very weird behaviour oth- erwise. The PCRE-specific options PCRE_UNGREEDY and PCRE_EXTRA can be changed in the same way as the Perl-compatible options by using the characters U and X respectively. The (?X) flag setting is special in that it must always occur earlier in the pattern than any of the additional features it turns on, even when it is at top level. It is best put at the start. SUBPATTERNS Subpatterns are delimited by parentheses (round brackets), which can be nested. Marking part of a pattern as a subpat- tern does two things: 1. It localizes a set of alternatives. For example, the pat- tern cat(aract|erpillar|) matches one of the words "cat", "cataract", or "caterpil- lar". Without the parentheses, it would match "cataract", "erpillar" or the empty string. 2. It sets up the subpattern as a capturing subpattern (as defined above). When the whole pattern matches, that por- tion of the subject string that matched the subpattern is passed back to the caller via the ovector argument of pcre_exec(). Opening parentheses are counted from left to right (starting from 1) to obtain the numbers of the captur- ing subpatterns. For example, if the string "the red king" is matched against the pattern the ((red|white) (king|queen)) the captured substrings are "red king", "red", and "king", and are numbered 1, 2, and 3, respectively. The fact that plain parentheses fulfil two functions is not always helpful. There are often times when a grouping sub- pattern is required without a capturing requirement. If an opening parenthesis is followed by "?:", the subpattern does not do any capturing, and is not counted when computing the number of any subsequent capturing subpatterns. For example, if the string "the white queen" is matched against the pat- tern the ((?:red|white) (king|queen)) the captured substrings are "white queen" and "queen", and are numbered 1 and 2. The maximum number of captured sub- strings is 99, and the maximum number of all subpatterns, both capturing and non-capturing, is 200. As a convenient shorthand, if any option settings are required at the start of a non-capturing subpattern, the option letters may appear between the "?" and the ":". Thus the two patterns (?i:saturday|sunday) (?:(?i)saturday|sunday) match exactly the same set of strings. Because alternative branches are tried from left to right, and options are not reset until the end of the subpattern is reached, an option setting in one branch does affect subsequent branches, so the above patterns match "SUNDAY" as well as "Saturday". REPETITION Repetition is specified by quantifiers, which can follow any of the following items: a single character, possibly escaped the . metacharacter a character class a back reference (see next section) a parenthesized subpattern (unless it is an assertion - see below) The general repetition quantifier specifies a minimum and maximum number of permitted matches, by giving the two numbers in curly brackets (braces), separated by a comma. The numbers must be less than 65536, and the first must be less than or equal to the second. For example: z{2,4} matches "zz", "zzz", or "zzzz". A closing brace on its own is not a special character. If the second number is omitted, but the comma is present, there is no upper limit; if the second number and the comma are both omitted, the quantifier specifies an exact number of required matches. Thus [aeiou]{3,} matches at least 3 successive vowels, but may match many more, while \d{8} matches exactly 8 digits. An opening curly bracket that appears in a position where a quantifier is not allowed, or one that does not match the syntax of a quantifier, is taken as a literal character. For example, {,6} is not a quantif- ier, but a literal string of four characters. The quantifier {0} is permitted, causing the expression to behave as if the previous item and the quantifier were not present. For convenience (and historical compatibility) the three most common quantifiers have single-character abbreviations: * is equivalent to {0,} + is equivalent to {1,} ? is equivalent to {0,1} It is possible to construct infinite loops by following a subpattern that can match no characters with a quantifier that has no upper limit, for example: (a?)* Earlier versions of Perl and PCRE used to give an error at compile time for such patterns. However, because there are cases where this can be useful, such patterns are now accepted, but if any repetition of the subpattern does in fact match no characters, the loop is forcibly broken. By default, the quantifiers are "greedy", that is, they match as much as possible (up to the maximum number of per- mitted times), without causing the rest of the pattern to fail. The classic example of where this gives problems is in trying to match comments in C programs. These appear between the sequences /* and */ and within the sequence, individual * and / characters may appear. An attempt to match C com- ments by applying the pattern /\*.*\*/ to the string /* first command */ not comment /* second comment */ fails, because it matches the entire string owing to the greediness of the .* item. However, if a quantifier is followed by a question mark, it ceases to be greedy, and instead matches the minimum number of times possible, so the pattern /\*.*?\*/ does the right thing with the C comments. The meaning of the various quantifiers is not otherwise changed, just the pre- ferred number of matches. Do not confuse this use of ques- tion mark with its use as a quantifier in its own right. Because it has two uses, it can sometimes appear doubled, as in \d??\d which matches one digit by preference, but can match two if that is the only way the rest of the pattern matches. If the PCRE_UNGREEDY option is set (an option which is not available in Perl), the quantifiers are not greedy by default, but individual ones can be made greedy by following them with a question mark. In other words, it inverts the default behaviour. When a parenthesized subpattern is quantified with a minimum repeat count that is greater than 1 or with a limited max- imum, more store is required for the compiled pattern, in proportion to the size of the minimum or maximum. If a pattern starts with .* or .{0,} and the PCRE_DOTALL option (equivalent to Perl's /s) is set, thus allowing the . to match newlines, the pattern is implicitly anchored, because whatever follows will be tried against every charac- ter position in the subject string, so there is no point in retrying the overall match at any position after the first. PCRE treats such a pattern as though it were preceded by \A. In cases where it is known that the subject string contains no newlines, it is worth setting PCRE_DOTALL when the pat- tern begins with .* in order to obtain this optimization, or alternatively using ^ to indicate anchoring explicitly. When a capturing subpattern is repeated, the value captured is the substring that matched the final iteration. For exam- ple, after (tweedle[dume]{3}\s*)+ has matched "tweedledum tweedledee" the value of the cap- tured substring is "tweedledee". However, if there are nested capturing subpatterns, the corresponding captured values may have been set in previous iterations. For exam- ple, after /(a|(b))+/ matches "aba" the value of the second captured substring is "b". BACK REFERENCES Outside a character class, a backslash followed by a digit greater than 0 (and possibly further digits) is a back SunOS 5.8 Last change: 30 reference to a capturing subpattern earlier (i.e. to its left) in the pattern, provided there have been that many previous capturing left parentheses. However, if the decimal number following the backslash is less than 10, it is always taken as a back reference, and causes an error only if there are not that many capturing left parentheses in the entire pattern. In other words, the parentheses that are referenced need not be to the left of the reference for numbers less than 10. See the section entitled "Backslash" above for further details of the han- dling of digits following a backslash. A back reference matches whatever actually matched the cap- turing subpattern in the current subject string, rather than anything matching the subpattern itself. So the pattern (sens|respons)e and \1ibility matches "sense and sensibility" and "response and responsi- bility", but not "sense and responsibility". If caseful matching is in force at the time of the back reference, the case of letters is relevant. For example, ((?i)rah)\s+\1 matches "rah rah" and "RAH RAH", but not "RAH rah", even though the original capturing subpattern is matched case- lessly. There may be more than one back reference to the same sub- pattern. If a subpattern has not actually been used in a particular match, any back references to it always fail. For example, the pattern (a|(bc))\2 always fails if it starts to match "a" rather than "bc". Because there may be up to 99 back references, all digits following the backslash are taken as part of a potential back reference number. If the pattern continues with a digit character, some delimiter must be used to terminate the back reference. If the PCRE_EXTENDED option is set, this can be whitespace. Otherwise an empty comment can be used. A back reference that occurs inside the parentheses to which it refers fails when the subpattern is first used, so, for example, (a\1) never matches. However, such references can be useful inside repeated subpatterns. For example, the pat- tern (a|b\1)+ matches any number of "a"s and also "aba", "ababbaa" etc. At each iteration of the subpattern, the back reference matches the character string corresponding to the previous itera- tion. In order for this to work, the pattern must be such that the first iteration does not need to match the back reference. This can be done using alternation, as in the example above, or by a quantifier with a minimum of zero. ASSERTIONS An assertion is a test on the characters following or preceding the current matching point that does not actually consume any characters. The simple assertions coded as \b, \B, \A, \Z, \z, ^ and $ are described above. More compli- cated assertions are coded as subpatterns. There are two kinds: those that look ahead of the current position in the subject string, and those that look behind it. An assertion subpattern is matched in the normal way, except that it does not cause the current matching position to be changed. Lookahead assertions start with (?= for positive assertions and (?! for negative assertions. For example, \w+(?=;) matches a word followed by a semicolon, but does not include the semicolon in the match, and foo(?!bar) matches any occurrence of "foo" that is not followed by "bar". Note that the apparently similar pattern (?!foo)bar does not find an occurrence of "bar" that is preceded by something other than "foo"; it finds any occurrence of "bar" whatsoever, because the assertion (?!foo) is always true when the next three characters are "bar". A lookbehind assertion is needed to achieve this effect. Lookbehind assertions start with (?<= for positive asser- tions and (? as in this example: (?>\d+)bar This kind of parenthesis "locks up" the part of the pattern it contains once it has matched, and a failure further into the pattern is prevented from backtracking into it. Back- tracking past it to previous items, however, works as nor- mal. An alternative description is that a subpattern of this type matches the string of characters that an identical stan- dalone pattern would match, if anchored at the current point in the subject string. Once-only subpatterns are not capturing subpatterns. Simple cases such as the above example can be thought of as a max- imizing repeat that must swallow everything it can. So, while both \d+ and \d+? are prepared to adjust the number of digits they match in order to make the rest of the pattern match, (?>\d+) can only match an entire sequence of digits. This construction can of course contain arbitrarily compli- cated subpatterns, and it can be nested. Once-only subpatterns can be used in conjunction with look- behind assertions to specify efficient matching at the end of the subject string. Consider a simple pattern such as abcd$ when applied to a long string which does not match. Because matching proceeds from left to right, PCRE will look for each "a" in the subject and then see if what follows matches the rest of the pattern. If the pattern is specified as ^.*abcd$ the initial .* matches the entire string at first, but when this fails (because there is no following "a"), it back- tracks to match all but the last character, then all but the last two characters, and so on. Once again the search for "a" covers the entire string, from right to left, so we are no better off. However, if the pattern is written as ^(?>.*)(?<=abcd) there can be no backtracking for the .* item; it can match only the entire string. The subsequent lookbehind assertion does a single test on the last four characters. If it fails, the match fails immediately. For long strings, this approach makes a significant difference to the processing time. When a pattern contains an unlimited repeat inside a subpat- tern that can itself be repeated an unlimited number of times, the use of a once-only subpattern is the only way to avoid some failing matches taking a very long time indeed. The pattern (\D+|<\d+>)*[!?] matches an unlimited number of substrings that either con- sist of non-digits, or digits enclosed in <>, followed by either ! or ?. When it matches, it runs quickly. However, if it is applied to aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa it takes a long time before reporting failure. This is because the string can be divided between the two repeats in a large number of ways, and all have to be tried. (The exam- ple used [!?] rather than a single character at the end, because both PCRE and Perl have an optimization that allows for fast failure when a single character is used. They remember the last single character that is required for a match, and fail early if it is not present in the string.) If the pattern is changed to ((?>\D+)|<\d+>)*[!?] sequences of non-digits cannot be broken, and failure hap- pens quickly. CONDITIONAL SUBPATTERNS It is possible to cause the matching process to obey a sub- pattern conditionally or to choose between two alternative subpatterns, depending on the result of an assertion, or whether a previous capturing subpattern matched or not. The two possible forms of conditional subpattern are (?(condition)yes-pattern) (?(condition)yes-pattern|no-pattern) If the condition is satisfied, the yes-pattern is used; oth- erwise the no-pattern (if present) is used. If there are more than two alternatives in the subpattern, a compile-time error occurs. There are two kinds of condition. If the text between the parentheses consists of a sequence of digits, the condition is satisfied if the capturing subpattern of that number has previously matched. The number must be greater than zero. Consider the following pattern, which contains non- significant white space to make it more readable (assume the PCRE_EXTENDED option) and to divide it into three parts for ease of discussion: ( \( )? [^()]+ (?(1) \) ) The first part matches an optional opening parenthesis, and if that character is present, sets it as the first captured substring. The second part matches one or more characters that are not parentheses. The third part is a conditional subpattern that tests whether the first set of parentheses matched or not. If they did, that is, if subject started with an opening parenthesis, the condition is true, and so the yes-pattern is executed and a closing parenthesis is required. Otherwise, since no-pattern is not present, the subpattern matches nothing. In other words, this pattern matches a sequence of non-parentheses, optionally enclosed in parentheses. If the condition is not a sequence of digits, it must be an assertion. This may be a positive or negative lookahead or lookbehind assertion. Consider this pattern, again contain- ing non-significant white space, and with the two alterna- tives on the second line: (?(?=[^a-z]*[a-z]) \d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} ) The condition is a positive lookahead assertion that matches an optional sequence of non-letters followed by a letter. In other words, it tests for the presence of at least one letter in the subject. If a letter is found, the subject is matched against the first alternative; otherwise it is matched against the second. This pattern matches strings in one of the two forms dd-aaa-dd or dd-dd-dd, where aaa are letters and dd are digits. COMMENTS The sequence (?# marks the start of a comment which contin- ues up to the next closing parenthesis. Nested parentheses are not permitted. The characters that make up a comment play no part in the pattern matching at all. If the PCRE_EXTENDED option is set, an unescaped # character outside a character class introduces a comment that contin- ues up to the next newline character in the pattern. RECURSIVE PATTERNS Consider the problem of matching a string in parentheses, allowing for unlimited nested parentheses. Without the use of recursion, the best that can be done is to use a pattern that matches up to some fixed depth of nesting. It is not possible to handle an arbitrary nesting depth. Perl 5.6 has provided an experimental facility that allows regular expressions to recurse (amongst other things). It does this by interpolating Perl code in the expression at run time, and the code can refer to the expression itself. A Perl pat- tern to solve the parentheses problem can be created like this: $re = qr{\( (?: (?>[^()]+) | (?p{$re}) )* \)}x; The (?p{...}) item interpolates Perl code at run time, and in this case refers recursively to the pattern in which it appears. Obviously, PCRE cannot support the interpolation of Perl code. Instead, the special item (?R) is provided for the specific case of recursion. This PCRE pattern solves the parentheses problem (assume the PCRE_EXTENDED option is set so that white space is ignored): \( ( (?>[^()]+) | (?R) )* \) First it matches an opening parenthesis. Then it matches any number of substrings which can either be a sequence of non- parentheses, or a recursive match of the pattern itself (i.e. a correctly parenthesized substring). Finally there is a closing parenthesis. This particular example pattern contains nested unlimited repeats, and so the use of a once-only subpattern for match- ing strings of non-parentheses is important when applying the pattern to strings that do not match. For example, when it is applied to (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa() it yields "no match" quickly. However, if a once-only sub- pattern is not used, the match runs for a very long time indeed because there are so many different ways the + and * repeats can carve up the subject, and all have to be tested before failure can be reported. The values set for any capturing subpatterns are those from the outermost level of the recursion at which the subpattern value is set. If the pattern above is matched against (ab(cd)ef) the value for the capturing parentheses is "ef", which is the last value taken on at the top level. If additional parentheses are added, giving \( ( ( (?>[^()]+) | (?R) )* ) \) ^ ^ ^ ^ the string they capture is "ab(cd)ef", the contents of the top level parentheses. If there are more than 15 capturing parentheses in a pattern, PCRE has to obtain extra memory to store data during a recursion, which it does by using pcre_malloc, freeing it via pcre_free afterwards. If no memory can be obtained, it saves data for the first 15 capturing parentheses only, as there is no way to give an out-of-memory error from within a recursion. PERFORMANCE Certain items that may appear in patterns are more efficient than others. It is more efficient to use a character class like [aeiou] than a set of alternatives such as (a|e|i|o|u). In general, the simplest construction that provides the required behaviour is usually the most efficient. Jeffrey Friedl's book contains a lot of discussion about optimizing regular expressions for efficient performance. When a pattern begins with .* and the PCRE_DOTALL option is set, the pattern is implicitly anchored by PCRE, since it can match only at the start of a subject string. However, if PCRE_DOTALL is not set, PCRE cannot make this optimization, because the . metacharacter does not then match a newline, and if the subject string contains newlines, the pattern may match from the character immediately following one of them instead of from the very start. For example, the pattern (.*) second matches the subject "first\nand second" (where \n stands for a newline character) with the first captured substring being "and". In order to do this, PCRE has to retry the match starting after every newline in the subject. If you are using such a pattern with subject strings that do not contain newlines, the best performance is obtained by setting PCRE_DOTALL, or starting the pattern with ^.* to indicate explicit anchoring. That saves PCRE from having to scan along the subject looking for a newline to restart at. Beware of patterns that contain nested indefinite repeats. These can take a long time to run when applied to a string that does not match. Consider the pattern fragment (a+)* This can match "aaaa" in 33 different ways, and this number increases very rapidly as the string gets longer. (The * repeat can match 0, 1, 2, 3, or 4 times, and for each of those cases other than 0, the + repeats can match different numbers of times.) When the remainder of the pattern is such that the entire match is going to fail, PCRE has in princi- ple to try every possible variation, and this can take an extremely long time. An optimization catches some of the more simple cases such as (a+)*b where a literal character follows. Before embarking on the standard matching procedure, PCRE checks that there is a "b" later in the subject string, and if there is not, it fails the match immediately. However, when there is no following literal this optimization cannot be used. You can see the difference by comparing the behaviour of (a+)*\d with the pattern above. The former gives a failure almost instantly when applied to a whole line of "a" characters, whereas the latter takes an appreciable time with strings longer than about 20 characters. UTF-8 SUPPORT Starting at release 3.3, PCRE has some support for character strings encoded in the UTF-8 format. This is incomplete, and is regarded as experimental. In order to use it, you must configure PCRE to include UTF-8 support in the code, and, in addition, you must call pcre_compile() with the PCRE_UTF8 option flag. When you do this, both the pattern and any sub- ject strings that are matched against it are treated as UTF-8 strings instead of just strings of bytes, but only in the cases that are mentioned below. If you compile PCRE with UTF-8 support, but do not use it at run time, the library will be a bit bigger, but the addi- tional run time overhead is limited to testing the PCRE_UTF8 flag in several places, so should not be very large. PCRE assumes that the strings it is given contain valid UTF-8 codes. It does not diagnose invalid UTF-8 strings. If you pass invalid UTF-8 strings to PCRE, the results are undefined. Running with PCRE_UTF8 set causes these changes in the way PCRE works: 1. In a pattern, the escape sequence \x{...}, where the contents of the braces is a string of hexadecimal digits, is interpreted as a UTF-8 character whose code number is the given hexadecimal number, for example: \x{1234}. This inserts from one to six literal bytes into the pattern, using the UTF-8 encoding. If a non-hexadecimal digit appears between the braces, the item is not recognized. 2. The original hexadecimal escape sequence, \xhh, generates a two-byte UTF-8 character if its value is greater than 127. 3. Repeat quantifiers are NOT correctly handled if they fol- low a multibyte character. For example, \x{100}* and \xc3+ do not work. If you want to repeat such characters, you must enclose them in non-capturing parentheses, for example (?:\x{100}), at present. 4. The dot metacharacter matches one UTF-8 character instead of a single byte. 5. Unlike literal UTF-8 characters, the dot metacharacter followed by a repeat quantifier does operate correctly on UTF-8 characters instead of single bytes. 4. Although the \x{...} escape is permitted in a character class, characters whose values are greater than 255 cannot be included in a class. 5. A class is matched against a UTF-8 character instead of just a single byte, but it can match only characters whose values are less than 256. Characters with greater values always fail to match a class. 6. Repeated classes work correctly on multiple characters. 7. Classes containing just a single character whose value is greater than 127 (but less than 256), for example, [\x80] or [^\x{93}], do not work because these are optimized into sin- gle byte matches. In the first case, of course, the class brackets are just redundant. 8. Lookbehind assertions move backwards in the subject by a fixed number of characters instead of a fixed number of bytes. Simple cases have been tested to work correctly, but there may be hidden gotchas herein. 9. The character types such as \d and \w do not work correctly with UTF-8 characters. They continue to test a single byte. 10. Anything not explicitly mentioned here continues to work in bytes rather than in characters. The following UTF-8 features of Perl 5.6 are not imple- mented: 1. The escape sequence \C to match a single byte. 2. The use of Unicode tables and properties and escapes \p, \P, and \X. SAMPLE PROGRAM The code below is a simple, complete demonstration program, to get you started with using PCRE. This code is also sup- plied in the file pcredemo.c in the PCRE distribution. The program compiles the regular expression that is its first argument, and matches it against the subject string in its second argument. No options are set, and default charac- ter tables are used. If matching succeeds, the program out- puts the portion of the subject that matched, together with the contents of any captured substrings. On a Unix system that has PCRE installed in /usr/local, you can compile the demonstration program using a command like this: gcc -o pcredemo pcredemo.c -I/usr/local/include -L/usr/local/lib -lpcre Then you can run simple tests like this: ./pcredemo 'cat|dog' 'the cat sat on the mat' Note that there is a much more comprehensive test program, called pcretest, which supports many more facilities for testing regular expressions. The pcredemo program is pro- vided as a simple coding example. On some operating systems (e.g. Solaris) you may get an error like this when you try to run pcredemo: ld.so.1: a.out: fatal: libpcre.so.0: open failed: No such file or directory This is caused by the way shared library support works on those systems. You need to add -R/usr/local/lib to the compile command to get round this problem. Here's the code: #include #include #include #define OVECCOUNT 30 /* should be a multiple of 3 */ int main(int argc, char **argv) { pcre *re; const char *error; int erroffset; int ovector[OVECCOUNT]; int rc, i; if (argc != 3) { printf("Two arguments required: a regex and a " "subject string\n"); return 1; } /* Compile the regular expression in the first argument */ re = pcre_compile( argv[1], /* the pattern */ 0, /* default options */ &error, /* for error message */ &erroffset, /* for error offset */ NULL); /* use default character tables */ /* Compilation failed: print the error message and exit */ if (re == NULL) { printf("PCRE compilation failed at offset %d: %s\n", erroffset, error); return 1; } /* Compilation succeeded: match the subject in the second argument */ rc = pcre_exec( re, /* the compiled pattern */ NULL, /* we didn't study the pattern */ argv[2], /* the subject string */ (int)strlen(argv[2]), /* the length of the subject */ 0, /* start at offset 0 in the subject */ 0, /* default options */ ovector, /* vector for substring information */ OVECCOUNT); /* number of elements in the vector */ /* Matching failed: handle error cases */ if (rc < 0) { switch(rc) { case PCRE_ERROR_NOMATCH: printf("No match\n"); break; /* Handle other special cases if you like */ default: printf("Matching error %d\n", rc); break; } return 1; } /* Match succeded */ printf("Match succeeded\n"); /* The output vector wasn't big enough */ if (rc == 0) { rc = OVECCOUNT/3; printf("ovector only has room for %d captured " substrings\n", rc - 1); } /* Show substrings stored in the output vector */ for (i = 0; i < rc; i++) { char *substring_start = argv[2] + ovector[2*i]; int substring_length = ovector[2*i+1] - ovector[2*i]; printf("%2d: %.*s\n", i, substring_length, substring_start); } return 0; } AUTHOR Philip Hazel University Computing Service, New Museums Site, Cambridge CB2 3QG, England. Phone: +44 1223 334714 Last updated: 15 August 2001 Copyright (c) 1997-2001 University of Cambridge. vfu-4.10/vslib/pcre/AUTHORS0000644000175000001440000000026311005727400014166 0ustar cadeusersWritten by: Philip Hazel University of Cambridge Computing Service, Cambridge, England. Phone: +44 1223 334714. Copyright (c) 1997-2001 University of Cambridge vfu-4.10/vslib/pcre/COPYING0000644000175000001440000000363011005727400014152 0ustar cadeusersPCRE LICENCE ------------ PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by: Philip Hazel University of Cambridge Computing Service, Cambridge, England. Phone: +44 1223 334714. Copyright (c) 1997-2001 University of Cambridge Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: 1. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. In practice, this means that if you use PCRE in software which you distribute to others, commercially or otherwise, you must put a sentence like this Regular expression support is provided by the PCRE library package, which is open source software, written by Philip Hazel, and copyright by the University of Cambridge, England. somewhere reasonably visible in your documentation and in any relevant files or online help data or similar. A reference to the ftp site for the source, that is, to ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/ should also be given in the documentation. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. If PCRE is embedded in any software that is released under the GNU General Purpose Licence (GPL), or Lesser General Purpose Licence (LGPL), then the terms of that licence shall supersede any condition above with which it is incompatible. The documentation for PCRE, supplied in the "doc" directory, is distributed under the same terms as the software itself. End vfu-4.10/vslib/ansiterm.h0000644000175000001440000000366611005727400014172 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * * SEE `README',LICENSE' OR COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: ansiterm.h,v 1.3 2003/01/21 19:56:35 cade Exp $ * */ #ifndef _ANSITERM_H_ #define _ANSITERM_H_ /////////////////////////////////////////////////////////////////////////// // // COLOR defines // #ifndef CONCOLOR // to avoid duplicates with UNICON #define CONCOLOR(f,b) (b*16+f) #define COLORFG(t) (t % 16) #define COLORBG(t) (t / 16) #endif // CONCOLOR #ifndef cNORMAL // to avoid duplicates with UNICON #define cNORMAL 7 #define cBOLD 8 #define cBLACK 0 #define cBLUE 1 #define cGREEN 2 #define cCYAN 3 #define cRED 4 #define cMAGENTA 5 #define cBROWN 6 #define cYELLOW 6 #define cLGRAY 7 #define chBLACK 7 #define cWHITE 7 #define cDGRAY 8 #define chBLUE 9 #define chGREEN 10 #define chCYAN 11 #define chRED 12 #define chMAGENTA 13 #define chYELLOW 14 #define chWHITE 15 #endif // cNORMAL int AnsiInit( int pANSI = -1 ); // 0=off, 1=on, -1=auto (TERM env.var) void AnsiDone(); void AnsiSuspend(); // suspends console (before system() for example) void AnsiRestore(); // restores console after suspend void AnsiCE( int attr = -1 ); // clear to end-of-line void AnsiCS( int attr = -1 ); // clear screen void AnsiOut( int x, int y, const char *s ); void AnsiOut( int x, int y, const char *s, int attr ); void AnsiPuts( const char *s ); void AnsiPuts( const char *s, int attr ); void AnsiCHide(); // cursor hide void AnsiCShow(); // cursor show int AnsiMaxX(); int AnsiMaxY(); int AnsiX(); int AnsiY(); void AnsiFG( int color ); void AnsiBG( int color ); void AnsiTA( int attr ); void AnsiXY( int x, int y ); // go to x,y int AnsiKbHit(); int AnsiGetch(); void AnsiBeep(); #endif //_ANSITERM_H_ // eof ansiterm.h vfu-4.10/vslib/clusters.h0000644000175000001440000001756711005727400014221 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * * SEE `README',LICENSE' OR COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: clusters.h,v 1.5 2003/01/21 19:56:35 cade Exp $ * */ /* * * This is general purpose array classes. * `CLUSTERS' name replaces boring `Arrays' name :) * It really doesn't make much difference however... * */ #ifndef _CLUSTERS_H_ #define _CLUSTERS_H_ #include #include #include #include #include #ifndef ASSERT #define ASSERT assert #endif #ifndef int32 #define int32 int #endif // cluster errors #define CE_OK 0 // ok -- no error #define CE_MEM 1 // low memory #define CE_OVR 128 // overflow #define CE_ERR 255 // error /**************************************************************************** ** ** FREE-LIST cluster ** ****************************************************************************/ class FLCluster { int32 es; // element size int32 ds; // data size int32 size; // elements allocated int32 used; // elements used == count int32 ff; // first free element int32 growby; // `grow by' elements char *data; // actual data public: int base; int null; FLCluster(); ~FLCluster(); int create( int32 pcnt, int32 pgrow, int32 pes ); // pes=element size, initial count & `grow by' void done(); int32 add( void* pe ); // insert element, return handle or -1 int del( int32 pn ); // delete element (memset(`+') & mark it `free'), ret E_OK or error int get( int32 pn, void* pe ); // get element, return E_OK or error char* get( int32 pn ); // get element pointer or NULL if error int is_used( int32 pn ); // 1 if pn element is used void dump(); // only for debugging protected: int Realloc( int32 pn ); // expand/shrink data list, return CE_OK, or error }; /**************************************************************************** ** ** BASE Cluster prototype ** ****************************************************************************/ class BaseCluster { protected: int es; int size; int cnt; int bsize; char *data; int status; void (*destructor_func)( void* ); public: BaseCluster() { data = NULL; es = 0; size = 0; cnt = 0; bsize = 0; destructor_func = NULL; }; virtual ~BaseCluster() { if (data) done(); }; int create( int p_size, int p_bsize, int p_es ); void done(); void del( int pn ); void delall(); void free( int pn ); void freeall(); int count() { return cnt; }; void shrink() { Realloc( cnt ); }; void set_destructor( void (*dfunc)(void*) ) { destructor_func = dfunc; }; protected: virtual void destroy_element( void* pe ) { if ( destructor_func != NULL ) destructor_func( pe ); }; int Realloc( int pn ); }; /**************************************************************************** ** ** DATA cluster ** ****************************************************************************/ class DCluster : public BaseCluster { public: int add( void* pe ); int ins( int pn, void* pe ); void put( int pn, void* pe ); void get( int pn, void* pe ); const void* operator [] ( int pn ) { ASSERT( pn >= 0 && pn < cnt ); return data + (pn*es); }; }; /**************************************************************************** ** ** TEMPLATE DATA cluster ** ****************************************************************************/ template< class T > class TDCluster : public DCluster { public: const T* operator [] ( int pn ) const { ASSERT( pn >= 0 && pn < cnt ); return (T*)(data + (pn*es)); }; T operator [] ( int pn ) { ASSERT( pn >= 0 && pn < cnt ); return (*((T*)(data + (pn*es)))); }; }; /**************************************************************************** ** ** POINTER cluster ** ****************************************************************************/ class PCluster : public BaseCluster { public: int create( int p_size, int p_bsize ) { return BaseCluster::create( p_size, p_bsize, sizeof(void*) ); }; int add( void* pe ); int ins( int pn, void* pe ); void put( int pn, void* pe ); void* get( int pn ); void* operator [] ( int pn ) { ASSERT( pn >= 0 && pn < cnt ); return ((void**)data)[pn]; }; protected: virtual void destroy_element( void* pe ) { if ( destructor_func != NULL ) destructor_func( ((void**)pe)[0] ); }; }; /**************************************************************************** ** ** TEMPLATE POINTER cluster ** ****************************************************************************/ template< class T > class TPCluster : public PCluster { public: int create( int p_size, int p_bsize ) { return BaseCluster::create( p_size, p_bsize, sizeof(void*) ); }; T* get( int pn ) {}; T* operator [] ( int pn ) { ASSERT( pn >= 0 && pn < cnt ); return ((T**)data)[pn]; }; protected: virtual void destroy_element( void* pe ) { delete ((T**)pe)[0]; }; }; /**************************************************************************** ** ** TEMPLATE cluster ** ****************************************************************************/ template< class T > class TCluster { int cnt; int size; int bsize; T *data; public: TCluster() { data = NULL; cnt = 0; size = 0; bsize = 0; }; ~TCluster() { if (data) done(); }; void create( int p_size, int p_bsize ) { bsize = p_bsize; Realloc( p_size ); }; void done() { if (data) delete [] data; data = NULL; cnt = 0; size = 0; bsize = 0; }; long count() const { return cnt; } void Realloc( int pn ) { if( pn == 0 ) { if( data ) delete [] data; size = 0; cnt = 0; data = NULL; return; } T *newdata = new T[pn]; int less = pn < cnt ? pn : cnt; int z; for( z = 0; z < less; z++ ) newdata[z] = data[z]; if( data ) delete [] data; cnt = less; size = pn; data = newdata; }; void add( T &e ) { if ( cnt == size ) Realloc( size + bsize ); data[cnt] = e; cnt++; }; T& operator [] ( int pn ) { ASSERT( pn >= 0 && pn < cnt ); return data[pn]; }; const T& operator [] ( int pn ) const { ASSERT( pn >= 0 && pn < cnt ); return data[pn]; }; }; /**************************************************************************** ** ** BIT-SET set ** ****************************************************************************/ class BSet { public: int size; // size (in bits) int datasize; // size (in bytes) char *data; BSet(); BSet( const char* str ); ~BSet(); void set1( int pn ); void set0( int pn ); int get ( int pn ); void set_range1( int start, int end ); void set_range0( int start, int end ); void set_str1( const char* str ); void set_str0( const char* str ); int in( const char *str ); // return 1 if all str's chars are in the set int in( int pn ) { if ( pn < 0 || pn >= size ) return 0; else return get( pn ); }; void reverse() { for(int z = 0; z < datasize; z++) data[z] = ~data[z]; }; void set( int pn, int val ) { if ( val ) set1( pn ); else set0( pn ); }; void set_all1() { if ( data ) memset( data, 0xff, datasize ); }; void set_all0() { if ( data ) memset( data, 0x00, datasize ); }; const int operator [] ( int pn ) { ASSERT( pn >= 0 && pn < size ); return get( pn ); }; int resize( int p_size ); BSet& operator = ( const BSet &b1 ); BSet& operator &= ( const BSet &b1 ); BSet& operator |= ( const BSet &b1 ); BSet operator ~ (); friend BSet operator & ( const BSet &b1, const BSet &b2 ); friend BSet operator | ( const BSet &b1, const BSet &b2 ); }; #endif //_CLUSTERS_H_ vfu-4.10/vslib/unicon.cpp0000644000175000001440000002021011310550237014157 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: unicon.cpp,v 1.4 2003/01/21 19:56:35 cade Exp $ * */ #include "unicon.h" /**************************************************************************** ** ** DJGPP/DOS Part ** ****************************************************************************/ #ifdef _TARGET_GO32_ #include #include #include #include "vstring.h" int original_ta; text_info ti; int __fg; int __bg; int __ta; int con_init() { gppconio_init(); gettextinfo( &ti ); original_ta = ti.attribute; return 0; } void con_done() { textattr( original_ta ); return; } void con_suspend() { return; } void con_restore() { return; } void con_ce( int attr ) { if (attr != -1) { int ta = __ta; textattr( attr ); clreol(); textattr( ta ); } else clreol(); } void con_cs( int attr ) { if (attr != -1) { int ta = __ta; textattr( attr ); clrscr(); gotoxy(1,1); textattr( ta ); } else { clrscr(); gotoxy(1,1); } } void con_puts( const char *s ) { #ifdef _TARGET_GO32_ VString str = s; str_replace( str, "\n", "\r\n" ); cputs( str ); #else cputs( s ); #endif } int con_max_x() { return ti.screenwidth; } int con_max_y() { return ti.screenheight; } int con_x() { return wherex(); } int con_y() { return wherey(); } void con_fg( int color ) { __fg = color; __ta = CONCOLOR(__fg,__bg); textattr( __ta ); } void con_bg( int color ) { __bg = color; __ta = CONCOLOR(__fg,__bg); textattr( __ta ); } void con_ta( int attr ) { __ta = attr; __bg = COLORBG(attr); __fg = COLORFG(attr); textattr( attr ); } void con_xy( int x, int y ) { gotoxy( x, y ); } void con_chide() { _setcursortype( _NOCURSOR ); } void con_cshow() { _setcursortype( _NORMALCURSOR ); } int con_kbhit() { return kbhit(); } int con_getch() { char ch = getch(); if ( ch == 0 ) return KEY_PREFIX + getch(); else return ch; } void con_beep() { sound(800); delay(1); // 1/10 second sound(0); } #endif /* _TARGET_GO32_ */ /**************************************************************************** ** ** UNIX Part ** ****************************************************************************/ #ifdef _TARGET_UNIX_ /**************************************************************************** ** This part is loosely based on `linconio': ** --------------------------------------------------------------------- ** File: conio.h Date: 03/09/1997 Version: 1.02 ** CONIO.H an implementation of the conio.h for Linux based on ncurses. ** This is copyright (c) 1996,97 by Fractor / Mental EXPlosion. ** If you want to copy it you must do this following the terms of the ** GNU Library Public License ** Please read the file "README" before using this library. ****************************************************************************/ int __fg; int __bg; int __ta; WINDOW *conio_scr; #define CON_PAIR(f,b) (((b)*8)+(f)+1) /* Some internals... */ int colortab(int a) /* convert UNIX/Curses Color code to DOS-standard */ { switch(a) { case cBLACK : return COLOR_BLACK; case cBLUE : return COLOR_BLUE; case cGREEN : return COLOR_GREEN; case cCYAN : return COLOR_CYAN; case cRED : return COLOR_RED; case cMAGENTA : return COLOR_MAGENTA; case cYELLOW : return COLOR_YELLOW; case cWHITE : return COLOR_WHITE; } return 0; } int con_init() { initscr(); start_color(); qiflush(); cbreak(); if ( !getenv("UNICON_NO_RAW") ) { /* To allow curses app to handle properly ctrl+z, ctrl+c, etc. I should not call raw() here, anyway it is known that this will cause misinterpretation of some keys (arrows) after resuming (SUSP -- ctrl+z)... So, unless UNICON_NO_RAW exported and set to any value raw() is called as usual. */ raw(); } noecho(); nonl(); // `return' translation off if (!has_colors()) fprintf(stderr,"Attention: A color terminal may be required to run this application !\n"); conio_scr=newwin(0,0,0,0); keypad(conio_scr,TRUE); // allow function keys (keypad) meta(conio_scr,TRUE); // switch to 8 bit terminal return values // intrflush(conio_scr,FALSE); // idlok(conio_scr,TRUE); // hardware line ins/del (required?) idcok(conio_scr,TRUE); // hardware char ins/del (required?) scrollok(conio_scr,TRUE); // scroll screen if required (cursor at bottom) /* Color initialization */ for ( __bg=0; __bg<8; __bg++ ) for ( __fg=0; __fg<8; __fg++ ) init_pair( CON_PAIR(__fg,__bg), colortab(__fg), colortab(__bg)); con_ta(7); return 0; } void con_done() { delwin(conio_scr); endwin(); } void con_suspend() { con_done(); } void con_restore() { con_init(); } void con_ta( int attr ) { __ta = attr; wattrset(conio_scr,0); /* (???) My curses-version needs this ... */ __fg = COLORFG(attr); __bg = COLORBG(attr); wattrset(conio_scr,COLOR_PAIR(CON_PAIR( __fg%8, __bg%8 )) | ( __bg > 7 )*(A_BLINK) | ( __fg > 7 )*(A_BOLD) ); wbkgdset( conio_scr, COLOR_PAIR(CON_PAIR( __fg%8, __bg%8 )) ); } void con_ce( int attr ) { if (attr != -1) { int ta = __ta; con_ta( attr ); wclrtoeol(conio_scr); wrefresh(conio_scr); con_ta( ta ); } else { wclrtoeol(conio_scr); wrefresh(conio_scr); } } void con_cs( int attr ) { if (attr != -1) { int ta = __ta; con_ta( attr ); wclear(conio_scr); wmove(conio_scr,0,0); wrefresh(conio_scr); con_ta( ta ); } else { wclear(conio_scr); wmove(conio_scr,0,0); wrefresh(conio_scr); } } void con_puts( const char *s ) { waddstr(conio_scr,s); wrefresh(conio_scr); } int con_max_x() { int x; int y; getmaxyx(conio_scr,y,x); return(x); } int con_max_y() { int x; int y; getmaxyx(conio_scr,y,x); return(y); } int con_x() { int y; int x; getyx(conio_scr,y,x); return(x+1); } int con_y() { int y; int x; getyx(conio_scr,y,x); return(y+1); } void con_fg( int color ) { __fg=color; con_ta( CONCOLOR( __fg, __bg ) ); } void con_bg( int color ) { __bg=color; con_ta( CONCOLOR( __fg, __bg ) ); } void con_xy( int x, int y ) { wmove(conio_scr,y-1,x-1); wrefresh(conio_scr); } void con_chide() { con_xy( 1, 1 ); leaveok(conio_scr,TRUE); curs_set( 0 ); } void con_cshow() { leaveok(conio_scr,FALSE); curs_set( 1 ); } int con_kbhit() { int i; nodelay(conio_scr,TRUE); i=wgetch(conio_scr); nodelay(conio_scr,FALSE); if (i==-1) i=0; else ungetch(i); return(i); } int con_getch() { int i; i=wgetch(conio_scr); if (i==-1) i=0; if (i == 27) if (con_kbhit()) i = KEY_PREFIX + wgetch(conio_scr); #ifndef _NO_ALT_ESCAPE_SAME_ if (i == KEY_PREFIX + 27) i = 27; #endif return(i); } void con_beep() { printf( "\007" ); fflush( stdout ); } #endif /* _TARGET_UNIX_ */ /**************************************************************************** ** ** COMMON Part ** ****************************************************************************/ void con_out( int x, int y, const char *s ) { con_out( x, y, s, __ta ); } void con_out( int x, int y, const char *s, int attr ) { int ta = __ta; con_ta( attr ); con_xy( x, y ); con_puts( s ); con_ta( ta ); } void con_puts( const char *s, int attr ) { int ta = __ta; con_ta( attr ); con_puts( s ); con_ta( ta ); } /**************************************************************************** ** EOF ****************************************************************************/ vfu-4.10/vslib/unicon.h0000644000175000001440000002642111005727400013635 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: unicon.h,v 1.4 2003/01/21 19:56:35 cade Exp $ * */ #ifndef _UNICON_H_ #define _UNICON_H_ #include "target.h" #ifdef _TARGET_UNKNOWN_ #error "I don't know what is the target platform" #endif #ifdef _TARGET_UNIX_ #if defined(_TARGET_LINUX_) #include #elif defined(_TARGET_NETBSD_) #include #else #include #endif #include #endif /**************************************************************************** ** ** COLOR defines ** ****************************************************************************/ #define CONCOLOR(f,b) (b*16+f) #define COLORFG(t) (t % 16) #define COLORBG(t) (t / 16) /***** std-colors/normal ******/ #define cNORMAL 7 #define cBOLD 8 #define cREVERSED CONCOLOR(cBLACK,cWHITE) /***** low-colors/normal ******/ #define cBLACK 0 #define cBLUE 1 #define cGREEN 2 #define cCYAN 3 #define cRED 4 #define cMAGENTA 5 #define cBROWN 6 #define cYELLOW 6 #define cLGRAY 7 /***** hi-colors/bright *******/ #define chBLACK 7 #define cWHITE 7 #define cDGRAY 8 #define chBLUE 9 #define chGREEN 10 #define chCYAN 11 #define chRED 12 #define chMAGENTA 13 #define chYELLOW 14 #define chWHITE 15 /**************************************************************************** ** ** KEY defines ** ****************************************************************************/ /******* common ************************************************************/ #define KEY_CTRL_A 1 #define KEY_CTRL_B 2 #define KEY_CTRL_C 3 #define KEY_CTRL_D 4 #define KEY_CTRL_E 5 #define KEY_CTRL_F 6 #define KEY_CTRL_G 7 #define KEY_CTRL_H 8 #define KEY_CTRL_I 9 #define KEY_CTRL_J 10 #define KEY_CTRL_K 11 #define KEY_CTRL_L 12 #define KEY_CTRL_M 13 #define KEY_CTRL_N 14 #define KEY_CTRL_O 15 #define KEY_CTRL_P 16 #define KEY_CTRL_Q 17 #define KEY_CTRL_R 18 #define KEY_CTRL_S 19 #define KEY_CTRL_T 20 #define KEY_CTRL_U 21 #define KEY_CTRL_V 22 #define KEY_CTRL_W 23 #define KEY_CTRL_X 24 #define KEY_CTRL_Y 25 #define KEY_CTRL_Z 26 #ifdef KEY_ENTER #undef KEY_ENTER #endif #define KEY_ENTER 13 /******* DJGPP/DOS *********************************************************/ #ifdef _TARGET_GO32_ #define KEY_PREFIX 1000 #define KEY_BACKSPACE 8 #define KEY_LEFT (KEY_PREFIX + 75) #define KEY_RIGHT (KEY_PREFIX + 77) #define KEY_UP (KEY_PREFIX + 72) #define KEY_DOWN (KEY_PREFIX + 80) #define KEY_HOME (KEY_PREFIX + 71) #define KEY_END (KEY_PREFIX + 79) #define KEY_PPAGE (KEY_PREFIX + 73) #define KEY_NPAGE (KEY_PREFIX + 81) #define KEY_IC (KEY_PREFIX + 82) #define KEY_DC (KEY_PREFIX + 83) #define KEY_F0 (KEY_PREFIX + 58) #define KEY_F(n) (KEY_PREFIX + (58+(n))) #define KEY_F1 (KEY_PREFIX + 59) #define KEY_F2 (KEY_PREFIX + 60) #define KEY_F3 (KEY_PREFIX + 61) #define KEY_F4 (KEY_PREFIX + 62) #define KEY_F5 (KEY_PREFIX + 63) #define KEY_F6 (KEY_PREFIX + 64) #define KEY_F7 (KEY_PREFIX + 65) #define KEY_F8 (KEY_PREFIX + 66) #define KEY_F9 (KEY_PREFIX + 67) #define KEY_F10 (KEY_PREFIX + 68) #define KEY_SH_F1 (KEY_PREFIX + 84) #define KEY_SH_F2 (KEY_PREFIX + 85) #define KEY_SH_F3 (KEY_PREFIX + 86) #define KEY_SH_F4 (KEY_PREFIX + 87) #define KEY_SH_F5 (KEY_PREFIX + 88) #define KEY_SH_F6 (KEY_PREFIX + 89) #define KEY_SH_F7 (KEY_PREFIX + 90) #define KEY_SH_F8 (KEY_PREFIX + 91) #define KEY_SH_F9 (KEY_PREFIX + 92) #define KEY_SH_F10 (KEY_PREFIX + 93) #define KEY_CTRL_F1 (KEY_PREFIX + 94) #define KEY_CTRL_F2 (KEY_PREFIX + 95) #define KEY_CTRL_F3 (KEY_PREFIX + 96) #define KEY_CTRL_F4 (KEY_PREFIX + 97) #define KEY_CTRL_F5 (KEY_PREFIX + 98) #define KEY_CTRL_F6 (KEY_PREFIX + 99) #define KEY_CTRL_F7 (KEY_PREFIX + 100) #define KEY_CTRL_F8 (KEY_PREFIX + 101) #define KEY_CTRL_F9 (KEY_PREFIX + 102) #define KEY_CTRL_F10 (KEY_PREFIX + 103) #define KEY_ALT_F1 (KEY_PREFIX + 104) #define KEY_ALT_F2 (KEY_PREFIX + 105) #define KEY_ALT_F3 (KEY_PREFIX + 106) #define KEY_ALT_F4 (KEY_PREFIX + 107) #define KEY_ALT_F5 (KEY_PREFIX + 108) #define KEY_ALT_F6 (KEY_PREFIX + 109) #define KEY_ALT_F7 (KEY_PREFIX + 110) #define KEY_ALT_F8 (KEY_PREFIX + 111) #define KEY_ALT_F9 (KEY_PREFIX + 112) #define KEY_ALT_F10 (KEY_PREFIX + 113) #define KEY_ALT_1 (KEY_PREFIX + 120) #define KEY_ALT_2 (KEY_PREFIX + 121) #define KEY_ALT_3 (KEY_PREFIX + 122) #define KEY_ALT_4 (KEY_PREFIX + 123) #define KEY_ALT_5 (KEY_PREFIX + 124) #define KEY_ALT_6 (KEY_PREFIX + 125) #define KEY_ALT_7 (KEY_PREFIX + 126) #define KEY_ALT_8 (KEY_PREFIX + 127) #define KEY_ALT_9 (KEY_PREFIX + 128) #define KEY_ALT_0 (KEY_PREFIX + 129) #define KEY_ALT_MINUS (KEY_PREFIX + 130) #define KEY_ALT_EQ (KEY_PREFIX + 131) #define KEY_ALT_Q (KEY_PREFIX + 16) #define KEY_ALT_W (KEY_PREFIX + 17) #define KEY_ALT_E (KEY_PREFIX + 18) #define KEY_ALT_R (KEY_PREFIX + 19) #define KEY_ALT_T (KEY_PREFIX + 20) #define KEY_ALT_Y (KEY_PREFIX + 21) #define KEY_ALT_U (KEY_PREFIX + 22) #define KEY_ALT_I (KEY_PREFIX + 23) #define KEY_ALT_O (KEY_PREFIX + 24) #define KEY_ALT_P (KEY_PREFIX + 25) #define KEY_ALT_A (KEY_PREFIX + 30) #define KEY_ALT_S (KEY_PREFIX + 31) #define KEY_ALT_D (KEY_PREFIX + 32) #define KEY_ALT_F (KEY_PREFIX + 33) #define KEY_ALT_G (KEY_PREFIX + 34) #define KEY_ALT_H (KEY_PREFIX + 35) #define KEY_ALT_J (KEY_PREFIX + 36) #define KEY_ALT_K (KEY_PREFIX + 37) #define KEY_ALT_L (KEY_PREFIX + 38) #define KEY_ALT_Z (KEY_PREFIX + 44) #define KEY_ALT_X (KEY_PREFIX + 45) #define KEY_ALT_C (KEY_PREFIX + 46) #define KEY_ALT_V (KEY_PREFIX + 47) #define KEY_ALT_B (KEY_PREFIX + 48) #define KEY_ALT_N (KEY_PREFIX + 49) #define KEY_ALT_M (KEY_PREFIX + 50) #endif /******* UNIX/NCURSES ******************************************************/ #ifdef _TARGET_UNIX_ #define KEY_F1 (KEY_F(0) + 1) #define KEY_F2 (KEY_F(0) + 2) #define KEY_F3 (KEY_F(0) + 3) #define KEY_F4 (KEY_F(0) + 4) #define KEY_F5 (KEY_F(0) + 5) #define KEY_F6 (KEY_F(0) + 6) #define KEY_F7 (KEY_F(0) + 7) #define KEY_F8 (KEY_F(0) + 8) #define KEY_F9 (KEY_F(0) + 9) #define KEY_F10 (KEY_F(0) + 10) #define KEY_SH_F1 (KEY_F(0) + 11) #define KEY_SH_F2 (KEY_F(0) + 12) #define KEY_SH_F3 (KEY_F(0) + 13) #define KEY_SH_F4 (KEY_F(0) + 14) #define KEY_SH_F5 (KEY_F(0) + 15) #define KEY_SH_F6 (KEY_F(0) + 16) #define KEY_SH_F7 (KEY_F(0) + 17) #define KEY_SH_F8 (KEY_F(0) + 18) #define KEY_SH_F9 (KEY_F(0) + 19) #define KEY_SH_F10 (KEY_F(0) + 20) #define KEY_CTRL_F1 (-1) #define KEY_CTRL_F2 (-1) #define KEY_CTRL_F3 (-1) #define KEY_CTRL_F4 (-1) #define KEY_CTRL_F5 (-1) #define KEY_CTRL_F6 (-1) #define KEY_CTRL_F7 (-1) #define KEY_CTRL_F8 (-1) #define KEY_CTRL_F9 (-1) #define KEY_CTRL_F10 (-1) #define KEY_ALT_F1 (-1) #define KEY_ALT_F2 (-1) #define KEY_ALT_F3 (-1) #define KEY_ALT_F4 (-1) #define KEY_ALT_F5 (-1) #define KEY_ALT_F6 (-1) #define KEY_ALT_F7 (-1) #define KEY_ALT_F8 (-1) #define KEY_ALT_F9 (-1) #define KEY_ALT_F10 (-1) #define KEY_PREFIX 1000 #define KEY_ALT_1 (KEY_PREFIX + '1') #define KEY_ALT_2 (KEY_PREFIX + '2') #define KEY_ALT_3 (KEY_PREFIX + '3') #define KEY_ALT_4 (KEY_PREFIX + '4') #define KEY_ALT_5 (KEY_PREFIX + '5') #define KEY_ALT_6 (KEY_PREFIX + '6') #define KEY_ALT_7 (KEY_PREFIX + '7') #define KEY_ALT_8 (KEY_PREFIX + '8') #define KEY_ALT_9 (KEY_PREFIX + '9') #define KEY_ALT_0 (KEY_PREFIX + '0') #define KEY_ALT_MINUS (KEY_PREFIX + '-') #define KEY_ALT_EQ (KEY_PREFIX + '=') #define KEY_ALT_Q (KEY_PREFIX + 'q') #define KEY_ALT_W (KEY_PREFIX + 'w') #define KEY_ALT_E (KEY_PREFIX + 'e') #define KEY_ALT_R (KEY_PREFIX + 'r') #define KEY_ALT_T (KEY_PREFIX + 't') #define KEY_ALT_Y (KEY_PREFIX + 'y') #define KEY_ALT_U (KEY_PREFIX + 'u') #define KEY_ALT_I (KEY_PREFIX + 'i') #define KEY_ALT_O (KEY_PREFIX + 'o') #define KEY_ALT_P (KEY_PREFIX + 'p') #define KEY_ALT_A (KEY_PREFIX + 'a') #define KEY_ALT_S (KEY_PREFIX + 's') #define KEY_ALT_D (KEY_PREFIX + 'd') #define KEY_ALT_F (KEY_PREFIX + 'f') #define KEY_ALT_G (KEY_PREFIX + 'g') #define KEY_ALT_H (KEY_PREFIX + 'h') #define KEY_ALT_J (KEY_PREFIX + 'j') #define KEY_ALT_K (KEY_PREFIX + 'k') #define KEY_ALT_L (KEY_PREFIX + 'l') #define KEY_ALT_Z (KEY_PREFIX + 'z') #define KEY_ALT_X (KEY_PREFIX + 'x') #define KEY_ALT_C (KEY_PREFIX + 'c') #define KEY_ALT_V (KEY_PREFIX + 'v') #define KEY_ALT_B (KEY_PREFIX + 'b') #define KEY_ALT_N (KEY_PREFIX + 'n') #define KEY_ALT_M (KEY_PREFIX + 'm') #endif /******* common (part 2) ***************************************************/ #define KEY_INSERT KEY_IC #define KEY_INS KEY_IC #define KEY_DELETE KEY_DC #define KEY_DEL KEY_DC /**************************************************************************** ** ** Functions ** ****************************************************************************/ int con_init(); // should be called before any other con_xxx() void con_done(); // should be called at the end of the console io actions void con_suspend(); // suspends console (before system() for example) void con_restore(); // restores console after suspend void con_ce( int attr = -1 ); // clear to end-of-line void con_cs( int attr = -1 ); // clear screen // following functions print string `s' at position `x,y' (col,row) with // color (attribute) `attr' void con_out( int x, int y, const char *s ); void con_out( int x, int y, const char *s, int attr ); void con_puts( const char *s ); void con_puts( const char *s, int attr ); void con_chide(); // cursor hide void con_cshow(); // cursor show int con_max_x(); // max screen x (column) int con_max_y(); // max screen y (row) int con_x(); // current screen x (column) int con_y(); // current screen y (row) void con_fg( int color ); // set foreground color void con_bg( int color ); // set background color void con_ta( int attr ); // set new attribute ( CONCOLOR(fg,bg) ) void con_xy( int x, int y ); // move cursor to position x,y int con_kbhit(); // return != 0 if key is waiting in "keyboard" buffer int con_getch(); // get single char from the "keyboard" void con_beep(); // make a "beep" sound #endif /* _UNICON_H_ */ /**************************************************************************** ** EOF ****************************************************************************/ vfu-4.10/vslib/getopt2.cpp0000644000175000001440000001107511005727400014260 0ustar cadeusers/* * $Header: /cvs/vslib/getopt2.cpp,v 1.2 2001/10/28 13:53:02 cade Exp $ * * Copyright (C) 1994 Arno Schaefer * * AU: Auswertung der Kommandozeile, der POSIX-Version von getopt () * nachempfunden. * * PO: ANSI C */ /* * Changed by on 12.march.1998,12.feb.2000: * when reach non option string return `+' w. optarg set to this string * instead of return `-1' * Changed code marked `+++ cade +++' and end w. `=== cade ===' * * $Id: getopt2.cpp,v 1.2 2001/10/28 13:53:02 cade Exp $ * */ #include #include #include "getopt2.h" /* Globale Variablen */ char *optarg; int optind = 1; int opterr = 1; int optopt; int optc = '?'; int opt_use_slash = 0; int opterr_report = 1; static char *nextarg = NULL; /* Funktion */ int getopt2(int argc, char *argv[], char *optstring) /* * AU: Auswertung der Kommandozeile * * VB: argc und argv sind die Parameter, die an main () uebergeben werden. * optstring ist ein String, der die Zeichen enthaelt, die als * Optionen erkannt werden. Wenn ein Zeichen von einem Doppelpunkt * gefolgt wird, hat die Option ein Argument, das direkt auf das Zeichen * folgt oder durch Space davon getrennt ist. Gueltige Optionszeichen * sind alle druckbaren Zeichen ausser '?', ' ' und ':'. * * optind ist der Index auf das naechste Element von argv[], das * bearbeitet wird. * * opterr ist ein Flag, das festlegt, ob bei Fehlern Fehlermeldungen * ausgegeben werden. * * optarg ist ein Zeiger auf das Argument, wenn eine Option ein * Argument hat. * * optopt enthaelt bei Fehlern das Optionszeichen, das den Fehler aus- * geloest hat. * * NB: Rueckgabewert ist das jeweils naechste Optionszeichen, oder -1 am * Ende der Optionsliste. * * Die Optionsliste ist zu Ende, wenn argv[optind] NULL ist, oder * argv[optind] nicht mit '-' (oder '/') beginnt, oder argv[optind] * ein einzelnes "-" ist. In diesem Fall wird optind nicht erhoeht. * Das Ende der Optionsliste kann mit "--" erzwungen werden, dann ist * argv[optind] das erste Argument nach "--". * * FB: Ein '?' wird zurueckgegeben, wenn ein Optionszeichen nicht in * optstring enthalten war oder ein ungueltiges Optionszeichen * uebergeben wurde ('?' oder ':'). Ausserdem bei einem fehlenden * Argument, wenn das erste Zeichen von optstring kein ':' ist. * * Ein ':' wird zurueckgegeben bei einem fehlenden Argument, wenn * das erste Zeichen von optstring ein ':' ist. */ { char *search; optarg = NULL; if (nextarg == NULL) { nextarg = argv[optind]; if (nextarg == NULL) { return (-1); } if (*nextarg != '-') { /* +++ cade +++ */ optarg = nextarg; nextarg = NULL; optind++; return('+'); /* === cade === */ /* return (-1); // this is the original code */ } nextarg++; } /* if */ optopt = *nextarg++; if (optopt == 0) { return (-1); } optind++; if (optopt == '-' && *nextarg == 0) { return (-1); } if (optopt == ':' || optopt == '?') { if (opterr) { if (opterr_report) fprintf ( stderr, "%s: illegal option -- %c\n", argv[0], optopt ); } return ('?'); } /* if */ search = strchr (optstring, optopt); if (search == NULL) { if (opterr) { if (opterr_report) fprintf ( stderr, "%s: illegal option -- %c\n", argv[0], optopt ); } return ('?'); } /* if */ if (*nextarg == 0) { nextarg = NULL; } if (search[1] != ':') { if (nextarg != NULL) { optind--; } return (optopt); } if (nextarg != NULL) { optarg = nextarg; nextarg = NULL; return (optopt); } optarg = argv[optind]; if (optind == argc) { if (opterr) { if (opterr_report) fprintf ( stderr, "%s: option requires an argument -- %c\n", argv[0], optopt ); } /* if */ if (optstring[0] == ':') { return (':'); } else { return ('?'); } } /* if */ else { optind++; } return (optopt); } /* getopt () */ vfu-4.10/vslib/vscrc.cpp0000644000175000001440000001167111310547340014020 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * * SEE `README',LICENSE' OR COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vscrc.cpp,v 1.2 2003/01/21 19:56:35 cade Exp $ * */ #include "vsuti.h" /*###########################################################################*/ /* CRC functions */ const unsigned long crc_32_tab[256] = { 0x00000000l, 0x77073096l, 0xee0e612cl, 0x990951bal, 0x076dc419l, 0x706af48fl, 0xe963a535l, 0x9e6495a3l, 0x0edb8832l, 0x79dcb8a4l, 0xe0d5e91el, 0x97d2d988l, 0x09b64c2bl, 0x7eb17cbdl, 0xe7b82d07l, 0x90bf1d91l, 0x1db71064l, 0x6ab020f2l, 0xf3b97148l, 0x84be41del, 0x1adad47dl, 0x6ddde4ebl, 0xf4d4b551l, 0x83d385c7l, 0x136c9856l, 0x646ba8c0l, 0xfd62f97al, 0x8a65c9ecl, 0x14015c4fl, 0x63066cd9l, 0xfa0f3d63l, 0x8d080df5l, 0x3b6e20c8l, 0x4c69105el, 0xd56041e4l, 0xa2677172l, 0x3c03e4d1l, 0x4b04d447l, 0xd20d85fdl, 0xa50ab56bl, 0x35b5a8fal, 0x42b2986cl, 0xdbbbc9d6l, 0xacbcf940l, 0x32d86ce3l, 0x45df5c75l, 0xdcd60dcfl, 0xabd13d59l, 0x26d930acl, 0x51de003al, 0xc8d75180l, 0xbfd06116l, 0x21b4f4b5l, 0x56b3c423l, 0xcfba9599l, 0xb8bda50fl, 0x2802b89el, 0x5f058808l, 0xc60cd9b2l, 0xb10be924l, 0x2f6f7c87l, 0x58684c11l, 0xc1611dabl, 0xb6662d3dl, 0x76dc4190l, 0x01db7106l, 0x98d220bcl, 0xefd5102al, 0x71b18589l, 0x06b6b51fl, 0x9fbfe4a5l, 0xe8b8d433l, 0x7807c9a2l, 0x0f00f934l, 0x9609a88el, 0xe10e9818l, 0x7f6a0dbbl, 0x086d3d2dl, 0x91646c97l, 0xe6635c01l, 0x6b6b51f4l, 0x1c6c6162l, 0x856530d8l, 0xf262004el, 0x6c0695edl, 0x1b01a57bl, 0x8208f4c1l, 0xf50fc457l, 0x65b0d9c6l, 0x12b7e950l, 0x8bbeb8eal, 0xfcb9887cl, 0x62dd1ddfl, 0x15da2d49l, 0x8cd37cf3l, 0xfbd44c65l, 0x4db26158l, 0x3ab551cel, 0xa3bc0074l, 0xd4bb30e2l, 0x4adfa541l, 0x3dd895d7l, 0xa4d1c46dl, 0xd3d6f4fbl, 0x4369e96al, 0x346ed9fcl, 0xad678846l, 0xda60b8d0l, 0x44042d73l, 0x33031de5l, 0xaa0a4c5fl, 0xdd0d7cc9l, 0x5005713cl, 0x270241aal, 0xbe0b1010l, 0xc90c2086l, 0x5768b525l, 0x206f85b3l, 0xb966d409l, 0xce61e49fl, 0x5edef90el, 0x29d9c998l, 0xb0d09822l, 0xc7d7a8b4l, 0x59b33d17l, 0x2eb40d81l, 0xb7bd5c3bl, 0xc0ba6cadl, 0xedb88320l, 0x9abfb3b6l, 0x03b6e20cl, 0x74b1d29al, 0xead54739l, 0x9dd277afl, 0x04db2615l, 0x73dc1683l, 0xe3630b12l, 0x94643b84l, 0x0d6d6a3el, 0x7a6a5aa8l, 0xe40ecf0bl, 0x9309ff9dl, 0x0a00ae27l, 0x7d079eb1l, 0xf00f9344l, 0x8708a3d2l, 0x1e01f268l, 0x6906c2fel, 0xf762575dl, 0x806567cbl, 0x196c3671l, 0x6e6b06e7l, 0xfed41b76l, 0x89d32be0l, 0x10da7a5al, 0x67dd4accl, 0xf9b9df6fl, 0x8ebeeff9l, 0x17b7be43l, 0x60b08ed5l, 0xd6d6a3e8l, 0xa1d1937el, 0x38d8c2c4l, 0x4fdff252l, 0xd1bb67f1l, 0xa6bc5767l, 0x3fb506ddl, 0x48b2364bl, 0xd80d2bdal, 0xaf0a1b4cl, 0x36034af6l, 0x41047a60l, 0xdf60efc3l, 0xa867df55l, 0x316e8eefl, 0x4669be79l, 0xcb61b38cl, 0xbc66831al, 0x256fd2a0l, 0x5268e236l, 0xcc0c7795l, 0xbb0b4703l, 0x220216b9l, 0x5505262fl, 0xc5ba3bbel, 0xb2bd0b28l, 0x2bb45a92l, 0x5cb36a04l, 0xc2d7ffa7l, 0xb5d0cf31l, 0x2cd99e8bl, 0x5bdeae1dl, 0x9b64c2b0l, 0xec63f226l, 0x756aa39cl, 0x026d930al, 0x9c0906a9l, 0xeb0e363fl, 0x72076785l, 0x05005713l, 0x95bf4a82l, 0xe2b87a14l, 0x7bb12bael, 0x0cb61b38l, 0x92d28e9bl, 0xe5d5be0dl, 0x7cdcefb7l, 0x0bdbdf21l, 0x86d3d2d4l, 0xf1d4e242l, 0x68ddb3f8l, 0x1fda836el, 0x81be16cdl, 0xf6b9265bl, 0x6fb077e1l, 0x18b74777l, 0x88085ae6l, 0xff0f6a70l, 0x66063bcal, 0x11010b5cl, 0x8f659effl, 0xf862ae69l, 0x616bffd3l, 0x166ccf45l, 0xa00ae278l, 0xd70dd2eel, 0x4e048354l, 0x3903b3c2l, 0xa7672661l, 0xd06016f7l, 0x4969474dl, 0x3e6e77dbl, 0xaed16a4al, 0xd9d65adcl, 0x40df0b66l, 0x37d83bf0l, 0xa9bcae53l, 0xdebb9ec5l, 0x47b2cf7fl, 0x30b5ffe9l, 0xbdbdf21cl, 0xcabac28al, 0x53b39330l, 0x24b4a3a6l, 0xbad03605l, 0xcdd70693l, 0x54de5729l, 0x23d967bfl, 0xb3667a2el, 0xc4614ab8l, 0x5d681b02l, 0x2a6f2b94l, 0xb40bbe37l, 0xc30c8ea1l, 0x5a05df1bl, 0x2d02ef8dl }; /* should start with `0xffffffff' for `crc' and result is crc = ~crc; */ crc32_t update_crc32( const unsigned char octet, const crc32_t crc ) { return (crc_32_tab[(unsigned char)((unsigned char)crc ^ octet)] ^ ((crc >> 8) & 0x00FFFFFFl)); } crc32_t mem_crc32( const void* buff, int size ) { crc32_t crc = 0xffffffff; int z; for ( z = 0; z < size; z++ ) crc = update_crc32( ((unsigned char*)buff)[z], crc ); return ~crc; } crc32_t str_crc32( const char *s ) { return mem_crc32( s, strlen(s) ); } crc32_t file_crc32( FILE *f, long buffsize ) /* return CRC32NULL for error */ { ASSERT( f ); char *buff = (char*)malloc( buffsize ); if (buff == NULL) return CRC32NULL; crc32_t crc = CRC32NULL; while(42) { long res = fread( buff, 1, buffsize, f ); if (res == -1) { fclose( f ); return CRC32NULL; } long z; for ( z = 0; z < res; z++ ) crc = update_crc32( buff[z], crc ); if ( res != buffsize ) break; } free( buff ); return ~crc; } crc32_t file_crc32( const char *fname, long buffsize ) // return `0xffffffff' for error { FILE *f = fopen( fname, "rb" ); if (!f) return CRC32NULL; crc32_t crc = file_crc32( f, buffsize ); fclose(f); return crc; } /*###########################################################################*/ /* eof vscrc.cpp */ vfu-4.10/vslib/README0000644000175000001440000000133211005727400013043 0ustar cadeusers VSLIB $Id: README,v 1.7 2005/08/28 16:26:29 cade Exp $ (c) Vladi Belperchinov-Shabanski "Cade" 1998-2005 Some files are taken "as is" from other packages and/or software implementations. All the appropriate credits are intact. All files are under the GPL license. Some file names and/or function names are changed just to keep this library namespace clean where needed. LICENSE AGREEMENT: GPL, SEE `COPYING' FOR THE FULL TEXT. Vladi Belperchinov-Shabanski "Cade" http://cade.datamax.bg/ vfu-4.10/vslib/THANKS.TO0000644000175000001440000000062311005727400013421 0ustar cadeusers $Id: THANKS.TO,v 1.2 2003/01/19 16:14:54 cade Exp $ I'd like to thank the following people for helping me for vslib: - Ivo Baylov for the KMP search hint. - Larry Wall for Perl. :) (most work done on this library is about the Perl-like structures) - Philip Hazel and University of Cambridge for the fantastic pcre library! vfu-4.10/vslib/conmenu.h0000644000175000001440000000231011103062376014000 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * * SEE `README',LICENSE' OR COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: conmenu.h,v 1.4 2003/01/21 19:56:35 cade Exp $ * */ #ifndef _CONMENU_H_ #define _CONMENU_H_ #include struct ToggleEntry { int key; char name[64]; int *data; const char **states; }; struct ConMenuInfo { ConMenuInfo() { defaults(); } void defaults() { cn = 112; ch = 47; ti = 95; bo = ec = ac = 0; } int cn; // normal color int ch; // highlight color int ti; // title color int bo; // should view borders? int ec; // exit char (used by con_menu_box) int ac; // alternative confirm (used by menu box) int st; // scroll type -- 1 dynamic and 0 normal/static char hide_magic[32]; }; extern ConMenuInfo con_default_menu_info; int con_toggle_box( int x, int y, const char *title, ToggleEntry* toggles, ConMenuInfo *menu_info ); int con_menu_box( int x, int y, const char *title, VArray *va, int hotkeys, ConMenuInfo *menu_info ); /* show full screen varray list (w/o last two lines of the screen) */ int con_full_box( int x, int y, const char *title, VArray *va, ConMenuInfo *menu_info ); #endif //_CONMENU_H_ vfu-4.10/vslib/vslib.cpp0000644000175000001440000000035611005727400014013 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vslib.cpp,v 1.8 2003/01/21 19:56:35 cade Exp $ * */ // eof vslib.cpp vfu-4.10/vslib/vslib.vpj0000644000175000001440000000362711005727400014034 0ustar cadeusers[CONFIGURATIONS] activeconfig=,Release config=,Release [GLOBAL] workingdir=/home/cade/pro/vslib macro=\n version=6.0 [ASSOCIATION] [STATE] SCREEN: 800 600 -4 -4 800 549 0 0 N 0 0 0 0 651 493 CWD: /home/cade/pro/twins BUFFER: BN="/home/cade/pro/twins/twins.pl" BI: MA=1 74 1 TABS=1 3 WWS=1 IWT=0 ST=0 IN=1 BW=0 US=32000 RO=0 SE=1 SN=0 BIN=0 MN=Perl HM=0 MF=544 VIEW: LN=.0 CL=1 LE=0 CX=0 CY=1 WI=5 BI=15 HT=0 HN=0 HF=0 HC=4 WINDOW: 0 0 439 332 0 0 M WF=0 WT=2 "alias-vga,10,0,1" BUFFER: BN="/home/cade/pro/twins/twins.pl" VIEW: LN=.875 CL=12 LE=0 CX=11 CY=3 WI=66 BI=15 HT=0 HN=0 HF=0 HC=4 FILEHIST: 9 /home/cade/public_html/hl/index.html /home/cade/public_html/mw/mw.pl /home/cade/public_html/hl/data/.mime.types /home/cade/pro/seek.pl/ls-1R.pl /home/cade/pro/seek.pl/loc.pl /home/cade/bin/xvpic.pl /home/cade/pro/palm-fe3/pro/p3_conf.pm /home/cade/public_html/hl/hl.pl /home/cade/pro/twins/twins.pl [COMPILER.Release] FILTEREXPANSION=1 1 1 1 1 includedirs=%(INCLUDE) tagfiles= reffile= compile=copts: concur|capture|menu: Compile:&Compilecmd: make %n.o CCDEF="-DTEST" make=copts: concur|capture|saveall|menu: Build:&Buildcmd: make CCDEF="-DTEST" rebuild=copts: concur|capture|menu: Rebuild:&Rebuildcmd: debug=copts: menu: Debug:&Debugcmd: xxgdb [exename-here] execute=copts: concur|capture|saveall|menu: Execute:E&xecutecmd: make CCDEF="-DTEST" && vslib user1=copts: hide|menu: User 1:User 1cmd: user2=copts: hide|menu: User 2:User 2cmd: [FILES] ansiterm.cpp ansiterm.h clusters.cpp clusters.h conmenu.cpp conmenu.h dlog.cpp dlog.h eval.cpp eval.h fnmatch2.cpp fnmatch2.h form_in.cpp form_in.h getopt2.cpp getopt2.h mm.conf scroll.cpp scroll.h target.h test.cpp unicon.cpp unicon.h vscrc.cpp vslib.cpp vslib.h vstring.cpp vstring.h vstrlib.cpp vstrlib.h vsuti.cpp vsuti.h pcre/chartables.c pcre/config.h pcre/get.c pcre/internal.h pcre/mm.conf pcre/pcre.c pcre/pcre.h pcre/pcreposix.c pcre/pcreposix.h pcre/study.c vfu-4.10/vslib/vslib.vpw0000644000175000001440000000076007753154370014063 0ustar cadeusers[ProjectFiles] vslib.vpj [CurrentProject] curproj=vslib.vpj [ProjectDates] vslib.vpj=20030428194746000 [TreeExpansion] vslib.vpj 0 [State] SCREEN: 1152 864 -3 -3 1152 819 0 0 N 0 0 0 0 976 763 CWD: /home/cade/work/bitlbee-0.82 FILEHIST: 9 /home/cade/notes.txt /home/cade/work/cvs/wget/src/progress.c /home/cade/work/cvs/wget/src/url.c /opt/cade/evolver/in/i/base.css /opt/cade/evolver/out/local/index.html /opt/cade/evolver/in/index.xml /tmp/rc.f /tmp/clan.map /home/cade/pro/cade-etc/etcade.cfg vfu-4.10/vslib/vslib.vtg0000644000175000001440000060000007663716564014051 0ustar cadeusersVSDBÜ àTAG_DATABASE_5.0`  P€ÿÿÿÿ@ÿÿÿÿ`ÿÿÿÿ`  P€ÿÿÿÿÿÿÿÿÿÿÿÿVS_OCCURRENCESÿ vsOccurrenceNamevsFileId vs_occur_name_ndxvs_occur_fk_ndxÿÿÿÿ7à1àVS_TAGSàÀÿvsTagNamevsTypeIdvsTagFlagsvsClassIdvsFileId vsLineNumber vsSignature©``@vs_tag_ndx€€€vs_file_fk_ndx©   vs_class_fk_ndx€ÿÿÿÿ1@O@VS_CLASSESvsClassId vsClassName!vsClassParentsÿ!vsClassOnlyÿ!vsClassSimple¹vs_class_id_ndx 5vs_class_ndx 5vs_cname_ndx 5vs_sname_ndxPÿÿÿÿ,@/@VS_TYPESvsTypeId@vsTypeName=vs_type_id_ndx=vs_type_ndx ÿÿÿÿ0@0@VS_EXTENSIONSvsExtensionIdÿvsExtensionName ÿÿÿÿ(À+ÀVS_FILESÀvsFileIdvsFileNamevsFileModificationDate vsFileType vsFileIncludedByvsFileExtension5vs_file_id_ndx5vs_file_inc_ndx©   vs_file_ndx @ÿÿÿÿÿÿÿÿÿÿÿÿ(ÀisnaÀsulcÀsulcÀmnocÀmnoc Àgold Àgold Àlave Àlave ÀamnfÀamnfÀmrofÀmrofÀotegÀotegÀercp!Àercp"Àercp#Àercp$Àercp%Àercp&Àercp'Àercp(Àercp)ÀorcsÀorcsÀgratÀtset*ÀcinuÀcinuÀrcsv+ÀilsvÀilsvÀrtsvÀrtsvÀrtsvÀrtsvÀtusvÀtusv À@0ÿÿÿÿÿÿÿÿüLL„íÝ̺«šŠ{k[K7&öç×ȹªœŒ{jWG6&öçÕ®Ÿ~n\J9+å¨^΄:ãȬ ’íy]ÎE.´™jQ5ô×»¡„ÿÿÿÿN@regmatch_tO@M@regex_tN@L@eptrblockM@K@match_dataL@J@compile_dataK@I@"real_pcre_extraJ@H@real_pcreI@G@___DIRH@F@/%VRegexp:SearchModeSearchModeG@E@VCharSetF@B@VRegexpE@?@VTrieBoxVRefB@=@ VArrayBoxVRef?@D@! VStringBoxVRef=@C@VRefD@A@VTrieC@@@VTrieNodeA@>@VArray@@<@VString>@;@ ScrollPos<@:@ TLogFile;@9@ ConMenuInfo:@8@ ToggleEntry9@7@TCluster8@4@$TPClusterPCluster7@6@&PClusterBaseCluster4@3@$TDClusterDCluster6@5@&DClusterBaseCluster3@2@BSet5@1@BaseCluster2@ÿÿÿÿFLClusterÿÿÿÿÿÿÿÿ cÿÿÿÿ.@,tag/@-@+cursor.@,@*subproc-@+@)subfunc,@*@(group+@)@'file*@(@&include)@'@%task(@&@$procproto'@%@#eventtab&@$@"control%@#@!menu$@"@ form#@!@trigger"@ @view!@@index @@column@@table@@database@@friend@@import@@param@@lib@@prog@@prop@@func@@const@@lvar@@var@@package@@destr@@ constr@@ interface@ @ label@ @ union @ @ class @ @enum @ @enumc @@struct @@gvar@@typedef@@define@@proto@ÿÿÿÿproc`@@ÿÿÿÿ`¤p?þÿsna" àahc" ulc".ÿÿnoc"[€noc"sold" ave"A mnf"L rof"U teg"@tni"’_ýÿrcp"j€rcp"KÀrcs"Ä¿þÿdts"MÀrat"$¿þÿinu"|¿þÿtsv"›ßýÿtsv"˜ßýÿusv"ôýÿ&¢à&j=&[=&›à=*zÀ+v?þÿ=+?þÿ=+gþÿ=+½ÿýÿl?þÿ=>h?þÿ][#][2][_][Øÿþÿ][8][¶ÿþÿ][¤À][’à][=][O d___ gb__Y¿þÿgf__[¿þÿtf__€eh__Ymk__[sq___sq__aat__W¿þÿsna_,àulc_“ànoc_àuoc_fàtad_càtad_S old_" ave_E ef_pàlif_• mnf_P rof_f xam_J@nim_H@gap_M@gap_I@gap_K@rcp_Àrcp_VÀsop_L@fer_IÀter_ràrcs_C@zis_P@zis_dàzis_T rat_€¿þÿrat_o@rat_p@rat_}@rat_n@rat_g@rat_r@rat_q@rat_¿þÿrat_l@rat_@inu_`ilv_â`tsv_BÀtsv_ usv_€gb_a àgf_aàat_aàca dda¼àddaqàddadda†àdda-dda‹àddaGelda(€eldap elda&€isnaàisna àisnaàisnaàisna àisnaàisnadàisna.àisna[àisna)àisnaKàisnaàisnaXàisna"àisnaMàisnaàisnaYàisnaàisnaLàisnaàisna^àisna$àisna_àisna-àisnaCàisnaàisnabàisna(àisnaUàisnaàisnaVàisna%àisna¬ÿÿisnaâÿÿisna©ÿÿisnaßÿÿisnaOàisnaàisnaNàisnaàisna`àisna*àisna\àisna&àisnaaàisna'àisna]àisna#àessaåýÿkcabt_ýÿesabi esabºàesab esab ob loobw€xobcÀxoboàxobsarbo tesbltesb®ÿþÿtesbnÿÿzisbzisb>sfub`ctacàtac ntacàntac tibcb tibc[ tibc_ tibcc tibc] tibc` tibca tibcY tibc\ tibc^ tibcZ tibc: tibcf albcçŸþÿulbcåŸþÿlobcëŸþÿorbcÛŸþÿayccáŸþÿrgdcÑŸþÿe_ec­àm_ec«ào_ec®ào_ec°àergcãŸþÿhcÑàlbhcÕŸþÿlbhcÏŸþÿychcËŸþÿcehcN@cehcF@cehcàcehc™ cehcÀcehcÀrghcÍŸþÿamhcÇŸþÿerhcÉŸþÿhwhcßþÿeyhcÅŸþÿrglcןþÿnolc\Ànolc  nolciànolc~ nolcnolcÀnolcnolcÀsolc2 solc gamcÝŸþÿncÐàroncíŸþÿtnctnc;edoc- olocïŸþÿolocñŸþÿolocS¿þÿpmocF pmocwpmocYÀpmockÀpmocvàpmoc#pmoc Àpmoc= pmoc< pmocv pmoc À_nocá`_noc-¿þÿ_nocÛ`_noc8¿þÿ_nocˆ€_nocG¿þÿ_noc€_noc4¿þÿ_noc‰€_nocE¿þÿ_noc‘€_noc2¿þÿ_nocîßþÿ_noc…€_nocO¿þÿ_nocÚ`_noc9¿þÿ_noc _noc0à_nocà`_noc/¿þÿ_noc„€_nocQ¿þÿ_nocÞ`_noc1¿þÿ_noc’€_nocA¿þÿ_noc×`_noc?¿þÿ_noc _nocu_noctþÿ_noc*¿þÿ_noc«@_nocqþÿ_nocC¿þÿ_noc‡€_nocK¿þÿ_noc†€_nocM¿þÿ_nocÜ`_nocI¿þÿ_noc _nocp_nocØ`_noc=¿þÿ_nocÝ`_noc6¿þÿ_nocÙ`_noc;¿þÿcnocóŸþÿinoc£@mnoc mnocÍàsnoc¢ÀnuocnuocEnuoc|à3crc€3crc€_crc àaerc¿àaercuàaercaerc~àaerc+aercaercCaerc5 aerc dercߟþÿverc`pytcU pytcT pytcX pytcS pytc pytcV pytc; pytc@ pytcg rrucàrrucžàihwcÓŸþÿleycÙŸþÿatad¹àatad atadOatad?atadÆàatad£ÀatadatadMulcd%ed’ afedÎàled¾àledzàledledàled~àled‰ led*led*À_led_ledâ?þÿaledaled‚àtsedtsedtsed9tsed atedfÀated atedsàated‡ atedatedated&À1odf 61odk 2odl 4odm 8odn enodÀàenodràenodenod{àenodDssodG€ssod€nwodS@nwodA@nwod irpd•_ýÿsd¯àpmudÂàpmud}àub_enàrf_epàun_eGàce tide˜ßþÿtide—ßþÿtnieOÀdneb@dne>@_dneO _dneL _dneM odneI rtpez rtpe~ 1rre´ 1rre 1rre  1rre  1rre  1rre  1rre  1rre 1rre 1rre 1rre 2rreµ 2rre 2rre 2rre 2rre 2rre 2rre 2rre 2rre 2rre 2rre 3rre¶ 3rre 3rre 3rre 3rre  3rre! 3rre" 4rre· 5rre¸ 6rre 7rre 8rre 9rre orreQ orre> srre? se²àse_cse€_cse}ýÿ_csezýÿ_csez€_cse{€_cse|€_csey€_cse€_csewýÿ_cse~€_csetýÿ_cseqýÿacseq rtseNÀlaveI laveC lave¹ßþÿcexe™ sixe(apxe½ýÿapxe€_þÿrtxe³ f, fàfôþÿslafx€ccf8 _ccfe ff·àff‘ b_ff– ifàifòþÿa_ifõ¿þÿd_if÷¿þÿl_ifù¿þÿm_if™ßþÿr_ifó¿þÿu_ifœßþÿelifÓýÿelif‹ßýÿelifÛýÿelifìýÿelif>€elif† elifÙßýÿelif”ÿýÿelifÜßýÿelifÞßýÿelifÃýÿelif{ßýÿelif:€elif elifËýÿelif„ßýÿelif8€elify elifàßýÿelif™ÿýÿelifÉýÿelif‚ßýÿelif2€elif€ elifÐýÿelifˆßýÿelifÖßýÿelif‘ÿýÿdnifÀdnifÀdnifdnifÀsrif+ srif ÀxifQ@xifE@xif¦Àlxif¥Àe_lfiàe_lflàgalf lclfÉàlclf³àlclfmàaolftþÿaolfó?þÿaolfÆÿýÿaolfÌ?þÿ_mnfW _mnfT _mnfV _mnfR _mnfX _mnfQ _mnfS amnfY amnfN dlofM mrof@eerfeerfƒàeerfeerf€àvasfrþÿvasfñ?þÿvasfÄÿýÿvasfÊ?þÿawtf9€awtf€awtfI€awtfJ€awtfH€awtfK€teg;ÿÿteg‡ÿÿteg"tegŠàteg1tegàtegStegàteg6teg{àteg‹ teg+teg)À_teg@ _tegv_tegM€_teg€ctegx_ýÿctegv_ýÿoteg&@oteg4@oteg$@oteg%@ogi@og?@worg´àevahR€evahP€evahO€2xehQ2xehAÀ_xeh _xehZedih emoh]@emoh=@i§Àiøþÿni\ni¢ÿþÿni^ ni snisni‡àsni.sniŒàsni}àsni„ 3tnioàa_si Àc_siÀs_si Àu_siÁàu_sivàaoti  peek/ yekˆà_yekCŸþÿ_yekKŸþÿ_yekJŸþÿ_yekIŸþÿ_yekHŸþÿ_yekGŸþÿ_yekFŸþÿ_yek\Ÿþÿ_yekEŸþÿ_yekDŸþÿ_yek6Ÿþÿ_yek…þÿ_yek+Ÿþÿ_yek4Ÿþÿ_yek>Ÿþÿ_yekAŸþÿ_yek3Ÿþÿ_yek¼þÿ_yekMŸþÿ_yekºþÿ_yek¸þÿ_yek¶þÿ_yek´þÿ_yek²þÿ€`ÿÿÿÿÿÿÿÿ'Ñÿÿ¦ÿÿ\ÿÿüßþÿŠÿþÿëßþÿÝßþÿÄßþÿ¼ßþÿ‰ÿþÿ±ßþÿ¦ßþÿßþÿì¿þÿÞ¿þÿË¿þÿ¼¿þÿ•¿þÿ}¿þÿ”ßþÿ¤þÿ(¿þÿ…_þÿÊÿýÿäýÿ¡ßýÿl_þÿ´ýÿN€¯ýÿ¦ýÿ©_ýÿð?ýÿÄ?ýÿ¬?ýÿ?ýÿ{?ýÿúýÿîýÿ @ÿÿÿÿÿÿÿÿÿÿÿÿLÔýÿ¯þÿ‡?ýÿŒÿþÿ?ýÿ“?ýÿ†ÿþÿ~ßýÿ›ýÿ9ÿÿHÿÿ„ÿÿêÿþÿõÿþÿåÿþÿàÿþÿÜÿþÿÑÿþÿÔÿþÿ™ÿþÿ²ÿþÿœÿþÿ¦ÿþÿ×ÿþÿÉÿþÿÃÿþÿµÿþÿ Wÿÿ ôßþÿ 6ÿÿ Ãßþÿ Óßþÿ Úßþÿ –¿þÿ ±¿þÿ Ÿ¿þÿ ¢?þÿ ©?þÿ ¥?þÿíþÿ ?þÿêþÿÊþÿ•þÿ›þÿ“þÿûÿýÿþÿj?þÿìÿýÿóÿýÿ¹?þÿèÿýÿÈÿýÿÞÿýÿX?þÿIÀ¬?þÿ´ßýÿ( Ãßýÿ°ßýÿ¤ßýÿ«ßýÿãýÿÏßýÿm_þÿÒ_ýÿÍ_ýÿÇ_ýÿ°_ýÿƒ_ýÿ?ýÿŠ?ýÿÀ0ÿÿÿÿü((TÖ²ŒhC þÞ¼œvR- åž|Z6ñЫˆc@üѪ†]8é¿™wTÿÿÿÿ*À#(Óv 8¸ˆvscrc.cpp+À)À"'Ó4'1¸ˆtest.cpp*À(À&&Ò²9âpcre/study.c)À'À*%Ò²9âpcre/pcreposix.h(À&À*$Ò²9âpcre/pcreposix.c'À%À%#Òõgà«pcre/pcre.h&À$À%"Ò²9¨Þpcre/pcre.c%À#À)!Ò²9âpcre/internal.h$À"À$ Ó5  pcre/get.c#À!À'Òõgà«pcre/config.h"À À+Òõg8Jpcre/chartables.c!ÀÀ!Ób!8Çvsuti.h ÀÀ#Ób!8Çvsuti.cppÀÀ#Ób!8Çvstrlib.hÀÀ%Ó4.}vstrlib.cppÀÀ#Ó.'7À]vstring.hÀÀ%Ó°) }vstring.cppÀÀ!Óv 8¸ˆvslib.hÀÀ#Óv 8¸ˆvslib.cppÀÀ"Óv 8¸ˆunicon.hÀÀ$Óv 8¸ˆunicon.cppÀÀ"Óv 8¸ˆtarget.hÀÀ"Ó%0PÃscroll.hÀÀ$Ó¡;xiscroll.cppÀÀ#Ñ0W5Ðgetopt2.hÀÀ%Ñ0W5Ðgetopt2.cppÀÀ#Óv 8¸ˆform_in.hÀÀ% Óï&5ø§form_in.cppÀÀ$ Ñ0W)°6fnmatch2.hÀ À& Ñõ\0˜·fnmatch2.cppÀ À Óv 8¸ˆeval.h À À" Óv 8¸ˆeval.cpp À À Óv 8¸ˆdlog.h À À"Óv 8¸ˆdlog.cpp ÀÀ#Óv 8¸ˆconmenu.h ÀÀ%Ó7¨Þconmenu.cppÀÀ$Óv 8¸ˆclusters.hÀÀ&Óv 8¸ˆclusters.cppÀÀ$Óv 8¸ˆansiterm.hÀÿÿÿÿ&Óv 8¸ˆansiterm.cppà0€üËÏPáÅ;Ï•wY\Ó ìŸºœƒÕ5°ö׋UQ4£pã½ýJ,—råð¿éKž}c„2Ò·ž¸kQ8:ëÑÇ›d²ŠûÚÖ¢T_BŽoP|Â(è9uWÿH ÿq<‘ãØ¬ýwÔ[Wþ±|#ä©ôoS2×òÒ«¿oG'Ü Ä £ h T ¯ =  û  ª x K … ø Ò ¬ ¡^ G  á Í ”  d , §òqÀ?Œ‚X7Ó$ ðR¸Ÿ†£‚ßÅý¯Y6"sÉŠoéU8ýdÒ»P€jàÏà&"clusters.h"&"vstring.h"&"unicon.h" chint cnint€ÍàÎà€ defaultsvoid€ ConMenuInfoToggleEntry stateschar** dataint*€ˆàŸàÆàËà namechar[64] keyint& _CONMENU_H_^con_full_boxintint x,int y,const char*title,VArray*va,ConMenuInfo*menu_info /FLCluster%NReallocintint32 pnKdumpvoid €³à¼à½à¾à¿àÀàÁàÂàÃàÄàÈà%Iis_usedintint32 pn€ÃàÄà#Ggetchar*int32 pn)Fgetintint32 pn,void*pe!Edelintint32 pn"Daddint32void*peBdonevoid<Acreateintint32 pcnt,int32 pgrow,int32 pes0?~FLCluster>FLCluster €¯à²à´àµà¶à·à¹àºà»à<nullint;baseint7datachar*6growbyint325ffint324usedint323sizeint322dsint321esint32'CE_ERR255&CE_OVR128%CE_MEM1$CE_OK0 int32intASSERTassert&&&&&_CLUSTERS_H_D5€àGàeàiàjàkàlàmànàpàqàràsàtàuàvàwàxàzà{à}à~à€àà‚àƒà…à†à‡à‰àŠà‹àŒààŽààà‘à”à•à–à—à˜à™àšà›àœààžà à¡à¢à£àà3Á|BSetconst BSet&b1,const BSet&b23¹&BSetconst BSet&b1,const BSet&b2¯~BSet'§|=BSet&const BSet&b1'Ÿ&=BSet&const BSet&b1&˜=BSet&const BSet&b1&„resizeintint p_size&|inintconst char*str-uset_str0voidconst char*str-nset_str1voidconst char*str2gset_range0voidint start,int end2`set_range1voidint start,int endZgetintint pn!Sset0voidint pn!Lset1voidint pn G~BSet€à‘à%>BSetconst char*str6BSet!*getvoid*int pn($putvoidint pn,void*pe'insintint pn,void*pe addintvoid*pe(getvoidint pn,void*pe(putvoidint pn,void*pe'õinsintint pn,void*pe ðaddintvoid*pe#ÛReallocintint pnÔfreeallvoid!Ífreevoidint pnÆdelallvoid ¾delvoidint pn´donevoid;ªcreateintint p_size,int p_bsize,int p_esšdumpvoid%„Reallocintint32 pn €màqàràsàtàuàvàwàxàzà}à%is_usedintint32 pn!rdelintint32 pn€sàxà#hgetchar*int32 pn)[getintint32 pn,void*pe"Faddint32void*pe<5createintint32 pcnt,int32 pgrow,int32 pes 0~FLCluster*donevoidFLClusterE_FREE(0)E_NULL(-1)E_BUSY(-2)=FL_ED((char*)(data+(n)*es+sizeof(int32)))n5FL_EF(((int32*)(data+(n)*es))[0])n,RETURN{return status=n;}n& "clusters.h"& & OAnsiBeepvoidNAnsiGetchintMAnsiKbHitint(KAnsiXYvoidint x,int y%IAnsiTAvoidint attr&HAnsiBGvoidint color&GAnsiFGvoidint colorEAnsiYintDAnsiXintCAnsiMaxYintBAnsiMaxXint40€,à1à2à3à4à5à6à7à8à9à:à;à<à=à>à?à@àAàBàCàDàEàFàHàIàJàKàLàMàNàOàPàQàRàSàUàVàXàYà[à\à]à^à_à`àaàbàdà@AnsiCShowvoid?AnsiCHidevoid€PàQà4=AnsiPutsvoidconst char*s,int attr+<AnsiPutsvoidconst char*s€RàSà?;AnsiOutvoidint x,int y,const char*s,int attr6:AnsiOutvoidint x,int y,const char*s(8AnsiCSvoidint attr=-1(7AnsiCEvoidint attr=-1!5AnsiRestorevoid!4AnsiSuspendvoid2AnsiDonevoid*1AnsiInitintint pANSI=-1.chWHITE15-chYELLOW14,chMAGENTA13+chRED12*chCYAN11)chGREEN10(chBLUE9'cDGRAY8&cWHITE7%chBLACK7$cLGRAY7#cYELLOW6"cBROWN6!cMAGENTA5 cRED4cCYAN3cGREEN2cBLUE1cBLACK0cBOLD8cNORMAL7!COLORBG(t/16)t!COLORFG(t%16)t&CONCOLOR(b*16+f)f,b _ANSITERM_H_Ämainint4&€àààà à à à à ààààààààààààààààà à"à#à$à%à&à'à(à)à*à+à-à.àÀAnsiBeepvoid¿AnsiGetchint¾AnsiKbHitint(·AnsiXYvoidint x,int y%£AnsiTAvoidint attr&žAnsiBGvoidint color&™AnsiFGvoidint color—AnsiYint–AnsiXint•AnsiMaxYint”AnsiMaxXint’AnsiCShowvoid‘AnsiCHidevoid€à à4‰AnsiPutsvoidconst char*s,int attr+„AnsiPutsvoidconst char*s€àà?~AnsiOutvoidint x,int y,const char*s,int attr6xAnsiOutvoidint x,int y,const char*s%gAnsiCSvoidint attr%WAnsiCEvoidint attr!QAnsiRestorevoid!JAnsiSuspendvoidCAnsiDonevoid'-AnsiInitintint pANSI'colortabintint colorANSIintansi_o_tainta_tainta_bginta_fgintAnsi_YintAnsi_XintAnsi_MAXYintAnsi_MAXXint&"ansiterm.h"& & & 0ÀüuwoåÌ@´š´[äÆÑ‹qÓQ5ð¹e8ôÀt€YEõÏ«‘nR>*Õ±‘jV. íÖ¦+VB%øÕ½¤v^D)öÜÁ€c@,ø½ Œq[6"ª êÉìxFÔÆ¨”‹wO1¯e?û­–c0ëGÏݲ–yos?ÃTL€à à à ààààààn  F H [ \ ] ^ _ a b @@ @ @@@@@@@@@@ @!@#@'@)@+@.@0@2@†@‹@Œ@@Ž@£@¤@¦@¨@dj # N€q s t u w x y  ‚ ‡   ‘ 7À:ÀLÀNÀOÀ à€Éà %*34:l: d@PÀaÀ8ànàDJ R €E F I €q@ ã` €0àmnopqrsu&j‘con_menu_boxintint x,int y,const char*title,VArray*va,int hotkeys,ConMenuInfo*menu_infoj con_toggle_boxintint x,int y,const char*title,ToggleEntry*toggles,ConMenuInfo*menu_info2'con_default_menu_infoConMenuInfo&"conmenu.h"&&& &   BSet€jk37|BSetconst BSet&b1,const BSet&b236&BSetconst BSet&b1,const BSet&b24~BSet'3|=BSet&const BSet&b1'2&=BSet&const BSet&b1€FPQSTUVWXY[\efhi&1=BSet&const BSet&b1&/resizeintint p_size$€,[]const intint pn€àà‘à”à•à–à—à˜à™àšà›àœààžà à¡à]_`abc€*set_all0void€)set_all1void(€(setvoidint pn,int val€'reversevoid€œà]€$inintint pn&#inintconst char*str-!set_str0voidconst char*str- set_str1voidconst char*str2set_range0voidint start,int end2set_range1voidint start,int endgetintint pn!set0voidint pn!set1voidint pn0~BSet€PQ%BSetconst char*strBSetdatachar*€LMOdatasizeintsizeint" ÔTClusterclass T €@ABCDEGHIgà€HI#[]const T&int pn€[]T&int pn€ûaddvoidT&e$€åReallocvoidint pnäcountlong€âdonevoid3€ácreatevoidint p_size,int p_bsize€0ß~TCluster€ÞTClusterÚdataT*Ùbsizeint€;<>?Øsizeint×cntint# ¿TPClusterclass T-!…Êdestroy_elementvoidvoid*pe€Ç[]T*int pn€689€ÆgetT*int pn2€Ãcreateintint p_size,int p_bsize §PCluster-!…µdestroy_elementvoidvoid*pe €²[]void*int pn!°getvoid*int pn(¯putvoidint pn,void*pe€-.01'®insintint pn,void*pe ­addintvoid*pe€‹àŒàŽàà+22€ªcreateintint p_size,int p_bsize# ˜TDClusterclass T€&'€&'€ž[]Tint pn#[]const T*int pn ‡DCluster€†à‡à‰àŠà#&€[]const void*int pn(getvoidint pn,void*pe(Œputvoidint pn,void*pe€!"'‹insintint pn,void*pe Šaddintvoid*pe XBaseCluster#}Reallocintint pn €{à~à€àà‚àƒà…à 0-!…{destroy_elementvoidvoid*pe8 €wset_destructorvoidvoid(*dfunc)(void*)€ushrinkvoid€scountintqfreeallvoid€!pfreevoidint pnodelallvoid ndelvoidint pnldonevoid;kcreateintint p_size,int p_bsize,int p_es0i~BaseCluster€hBaseCluster?!ddestructor_funcvoid(*destructor_func)()void*bstatusint€  `datachar*_bsizeint^cntint]sizeint\esint 0€ ü³µøè¶5hѺ£Q-‡ ʶLâ~ êèÐ)›À_E*ß]w’['»Bš Ó»|^@vç4«‘B×ì™Äp³bHzüؾŸ‹Þ_D) ÂwS6îÌ¡–zV8ç³üZ;PÁÀ¢nð !Ü È ´ ê   n G $  f Æ ¦ „ ü K 1  ‘ á Ç «  v X = «  ä É ­Žq P 2  òв‘rS1ðÐÌ®lL/òÒ´“uT8æsR1 îÓ¸^>$þÒ¥l/ø7!ERR5"number too big in {} quantifier"=!ERR4"numbers out of order in {} quantifier"9!ERR3"unrecognized character follows \\"-!ERR2"\\c at end of pattern",!ERR1"\\ at end of pattern"&#!EXTRACT_BASIC_MAX150!OP_BRA71 !OP_BRANUMBER70!!þOP_BRAMINZERO69!ýOP_BRAZERO68!ûOP_CREF67!úOP_COND66!ùOP_ONCE65!ôOP_REVERSE64%#!óOP_ASSERTBACK_NOT63!!òOP_ASSERTBACK62!!ñOP_ASSERT_NOT61!ðOP_ASSERT60!ìOP_KETRMIN59!ëOP_KETRMAX58!êOP_KET57!éOP_ALT56!çOP_RECURSE55!æOP_REF54!åOP_CLASS53!!ãOP_CRMINRANGE52!âOP_CRRANGE51!!áOP_CRMINQUERY50!àOP_CRQUERY49 !ßOP_CRMINPLUS48!ÞOP_CRPLUS47 !ÝOP_CRMINSTAR46!ÜOP_CRSTAR45 !ÚOP_TYPEEXACT44" !ÙOP_TYPEMINUPTO43!ØOP_TYPEUPTO42#!!×OP_TYPEMINQUERY41 !ÖOP_TYPEQUERY40" !ÕOP_TYPEMINPLUS39!ÔOP_TYPEPLUS38" !ÓOP_TYPEMINSTAR37!ÒOP_TYPESTAR36!ÐOP_NOTEXACT35!!ÏOP_NOTMINUPTO34!ÎOP_NOTUPTO33" !ÍOP_NOTMINQUERY32!ÌOP_NOTQUERY31!!ËOP_NOTMINPLUS30!ÊOP_NOTPLUS29!!ÉOP_NOTMINSTAR28!ÈOP_NOTSTAR27!ÆOP_EXACT26!ÅOP_MINUPTO25!ÄOP_UPTO24!ÃOP_MINQUERY23!ÂOP_QUERY22!ÁOP_MINPLUS21!ÀOP_PLUS20!¿OP_MINSTAR19!¾OP_STAR18!¼OP_NOT17!»OP_CHARS16!ºOP_ANY15!¹OP_DOLL14!¸OP_CIRC13!·OP_OPT12!µOP_EOD11!´OP_EODN10!³OP_WORDCHAR9"!!²OP_NOT_WORDCHAR8 !±OP_WHITESPACE7$#!°OP_NOT_WHITESPACE6!¯OP_DIGIT5!®OP_NOT_DIGIT4#"!­OP_WORD_BOUNDARY3'&!¬OP_NOT_WORD_BOUNDARY2!«OP_SOD1!§OP_END0D;€@@…@†@‡@ˆ@‰@‹@Œ@@Ž@@@‘@’@“@”@•@–@—@˜@™@š@›@œ@@ž@Ÿ@ @¡@¢@£@¤@¦@¨@ª@«@¬@®@°@²@´@¶@¸@º@¼@¾@À@Â@Ä@Æ@É@Ë@Í@Ð@Ò@Ô@Õ@×@€_ @€b @€a @€H @ _FORM_IN_H_€ ` Œ TextInputintint x,int y,const char*prompt,int maxlen,int fieldlen,char*strres,void(*handlekey)(int key,VString&s,int&pos) TextInputintint x,int y,const char*prompt,int maxlen,int fieldlen,VString*strres,void(*handlekey)(int key,VString&s,int&pos) EditStrFHint € B H U [ \ ] ^ _ ` a b  EditStrBFint FI_MASKSBSet FI_USERSBSet FI_REALSBSet! FI_ALPHANUMBSet FI_DIGITSBSet  FI_LETTERSBSet& "scroll.h"& "form_in.h" €P Q R S T V W X Y Q -fnmatchintconst char*__pattern,const char*__string,int __flags )FNM_NOMATCH1$ %FNM_CASEFOLD(1<<4)'! $FNM_LEADING_DIR(1<<3)+ #FNM_FILE_NAMEFNM_PATHNAME" FNM_PERIOD(1<<2)$ FNM_NOESCAPE(1<<1)$ FNM_PATHNAME(1<<0) _FNMATCH_H1€J K L M N mK fnmatchintconst char*pattern,const char*string,int flagsI !FOLD((flags&FNM_CASEFOLD)&&isupper(c)?tolower(c):(c))c& "fnmatch2.h"& & , Evaldoubleconst char*pExp€ F  EvalResultint _EVAL_H_€ ? @ A C q- Evaldoubleconst char*a_exp EvalResultint& "eval.h"& &  TLogFile€4 7 8 9 ; 7 )logvoidconst char*msg,const char*arg €. 2 3 4 5 6 7 8 9 ; . (logvoidconst char*msg,int n€" ( ) * + , . / 0 1 2 3 4 5 6 7 8 9 : ; ( 'logvoidconst char*msgH &logvoidconst char*fname,int line,const char*msg,int nB %logvoidconst char*fname,int line,const char*msg #closevoid "openvoid< !createvoidconst char*fname,int pkeep_open0 ~TLogFile TLogFile€) , / 0 1  on_stderrint on_stdoutint keep_openint! log_fnchar[255] fFILE*:LOGNlog(__FILE__,__LINE__,what,n)what,n5LOGlog(__FILE__,__LINE__,what)what& _DLOG_H_ €          ! $ % €  ! $ % H blogvoidconst char*fname,int line,const char*msg,int n €       ! $ % 7 [logvoidconst char*msg,const char*arg. Tlogvoidconst char*msg,int n( Ologvoidconst char*msgB 3logvoidconst char*fname,int line,const char*msg -closevoid 'openvoid< createvoidconst char*fname,int pkeep_open ~TLogFile TLogFile& "dlog.h"& & ^0con_full_boxintint x,int y,const char*title,VArray*va,ConMenuInfo*menu_info€à„àˆàŸàÆàËàÌàÍàÎàÐàÑà           j-con_menu_boxintint x,int y,const char*title,VArray*va,int hotkeys,ConMenuInfo*menu_infoj ,con_toggle_boxintint x,int y,const char*title,ToggleEntry*toggles,ConMenuInfo*menu_info€n 2'*con_default_menu_infoConMenuInfoConMenuInfo$ 'hide_magicchar[32] &stint $acint€ÐàÑà       #ecint !boint tiint„v€gàoà“à¥à§à¨àªà«à¬à­à®à¯à°à²à³à´àµà¶à·à¹àºà»à¼à½à¾à¿àÀàÁàÂàÃàÄàÈàÉà    !"#%&'*+-.01234689:;<>?@ABCDEFGHILMOPQSTUVWXY[\]_`abcefhijkl@0`àüÙß|Üä [È©•t`B.òÔ¶*æRÁ­’vY<!ZëÒ°|<üâœkP<! ëòÞű{;œ¹Ö‰u[B~*ô/¢eK3¬ýjäʈP7¢é´êdº„Òí¡¼kÔM¿†h2Ú+í_ήÍ? î`<®{ˆ£ íÎY<ÙuE-¨ ù Ü @ ‹ r Y à #  Ë 0 ž y N ¸  ø Þ & ’ m E ­  é Áü ” € g S : & I Ï ¬ ˜ { g í5  ß˦’mY4 õáï‘}cO5!ûç­…qR> Ù»§‰u?ì¸T7þêÏ´˜|&&&&€Û@`€&"target.h"&& €7@Ù@Ú@Û@â`ã`ä`æ`ç`é`ê`ë`€r7@&4ƒcon_putsvoidconst char*s,int attr€Ô@Õ@?zcon_outvoidint x,int y,const char*s,int attr6ucon_outvoidint x,int y,const char*s€Ÿ@Ò@gcon_beepvoid€’@Ð@Ycon_getchint€¡@°@Lcon_kbhitint€ @Í@Fcon_cshowvoid€›@Ë@?con_chidevoid€ž@É@(9con_xyvoidint x,int y€œ@¢@&2con_bgvoidint color€—@Æ@&,con_fgvoidint color€š@Ä@$con_yint€™@Â@con_xint€˜@À@con_max_yint€“@¾@ con_max_xint€–@¼@×@+con_putsvoidconst char*s€•@º@%ócon_csvoidint attr€”@¸@%âcon_cevoidint attr€@¶@%Øcon_tavoidint attr€@´@!Ócon_restorevoid€@²@!Îcon_suspendvoid€‘@ª@Ècon_donevoid€@®@¤con_initint€ à¬@#•colortabintint a-’CON_PAIR(((b)*8)+(f)+1)f,b*conio_scrstruct _win_st*€‹@¨@__taint€Ž@¦@Ž__bgint€@¤@__fgintqcon_beepvoidhcon_getchintgcon_kbhitintecon_cshowvoiddcon_chidevoid(bcon_xyvoidint x,int y%acon_tavoidint attr&`con_bgvoidint color&_con_fgvoidint color^con_yint]con_xint\con_max_yint[con_max_xint+Pcon_putsvoidconst char*s%?con_csvoidint attr%2con_cevoidint attr!0con_restorevoid!/con_suspendvoid)con_donevoid!con_initint__taint__bgint__fginttitext_info original_taint&"vstring.h"&&&€à@& "unicon.h"€@g@l@m@n@o@p@q@r@s@t@u@v@w@x@y@{@|@}@~@‚@7&I_TARGET_DESCRIPTION_"UNKNOWN/UNKNOWN",&C_TARGET_DESCRIPTION_"UNIX"€s@u@v@w@~@B_TARGET_UNIX_€m@t@x@y@{@|@‚@+&;_TARGET_DESCRIPTION_"GNU":_TARGET_UNIX_9_TARGET_GNU_1&2_TARGET_DESCRIPTION_"DOS/WIN32"1_TARGET_UNIX_ 0_TARGET_WIN32_3&)_TARGET_DESCRIPTION_"UNIX/NETBSD"(_TARGET_UNIX_!'_TARGET_NETBSD_2& _TARGET_DESCRIPTION_"UNIX/LINUX"_TARGET_UNIX_ _TARGET_LINUX_1&_TARGET_DESCRIPTION_"DOS/DJGPP"_TARGET_DOS_ _TARGET_DJGPP__TARGET_GO32_"_TARGET_UNKNOWN_ _TARGET_H_$!€C@G@H@I@J@K@L@M@N@P@Q@R@S@T@U@V@W@X@Y@Z@[@\@]@^@_@`@b@c@d@e@f@h@i@ ScrollPos €N@Q@S@]@_@b@e@f@i@$ Egovoidint new_pos€ Cnpagevoid€ Bppagevoid @pagedownvoid ?pageupvoid =downvoid <upvoid ;endvoid :homevoid€:@=@>@?@@@A@B@E@F@G@R@U@V@W@X@Y@Z@[@\@^@`@c@h@€ 8stepint€ 7pagesizeint€ 6pageint€ 5posint€ 4maxint€ 3minint1€ /set_pagestepvoidint a_pagestep1€ ,set_pagesizevoidint a_pagesize)€ *set_pagevoidint a_page'€ (set_posvoidint a_pos5€ &set_min_maxvoidint a_min,int a_max€  ScrollPos wrapint checkint fixvoid _sizeint _pagestepint€H@I@J@K@L@M@P@T@ _pagesizeint _pageint _posint _maxint _minint _SCROLL_H_ qcheckint afixvoid$ [govoidint new_pos €-@8@:@;@=@>@?@@@A@B@E@F@ Mpagedownvoid Bpageupvoid 2downvoid "upvoid endvoid homevoid€B ;@&"scroll.h"ASSERTassert& €%@&@'@)@+@.@0@2@4@@@!getopt2intint argc,char*argv[],char*optstring€@2@"opterr_reportint€ @0@optcint€@.@optoptint€@+@opterrint€@)@optindint€@'@optargchar*FGETOPTwhile((optc=getopt2(argc,argv,opts))!=-1)opts GETOPT_H@+getopt2intint argc,char*argv[],char*optstring&nextargchar*"$opterr_reportint €@@@@@@@@ @!@#@$@"#opt_use_slashint"optcint!optoptint opterrintoptindintoptargchar*&"getopt2.h"&&€@@‘ TextInputintint x,int y,const char*prompt,int maxlen,int fieldlen,char*strres,void(*handlekey)(int key,VString&s,int&pos)=NULL”TextInputintint x,int y,const char*prompt,int maxlen,int fieldlen,VString*strres,void(*handlekey)(int key,VString&s,int&pos)=NULL€à±àÏàf @@ @ @@@@@@@@ŒFormInputintint x,int y,const char*prompt,const char*mask,VString*strres,void(*handlekey)(int key,VString&s,int&pos)=NULLEditStrFHintEditStrBFintFI_MASKSBSetFI_USERSBSet€[  @FI_REALSBSet€^  @!FI_ALPHANUMBSet€] @FI_DIGITSBSet€\ @ FI_LETTERSBSet`0€@üçé—àÄ?¨‹o[äЯ›ÊmUAPöⶉq]F2aêÖ¼¨{«M4 óÚÆï—}i/< UÛÀ¬rá8þħ‰kMLóÕ·™{]?!¶åÇ©Œl¶ #ùÒ©€X.Ý2a:ìÅžwP)Ú°†\xÞ´Š`5 ݱ…Y-Ó¦½ L ôÈœpDì¿”i>è  ’ g <  â ÜŒ b 8  ä º f < è ¾ ” j @  ì  ˜ n D  ðÈ´ ŒxdP<(ìØÄ°œˆt`L8$üèÔÀ¬˜„p\H4  øäƬ’lF!ùÛ½Ÿ…hK7üáÇ«—€oë`&&&&&€„àä`&& _VLIB_H_econ_beepvoiddcon_getchintccon_kbhitint(acon_xyvoidint x,int y%_con_tavoidint attr&^con_bgvoidint color&]con_fgvoidint color[con_yintZcon_xintYcon_max_yint€±`y€€°`x€€¯`w€€®`v€€­`u€€¬`t€€«`s€€ª`r€€©`q€€¨`p€€§`o€€¦`n€€¥`m€€”`l€€£`k€€¢`j€€¡`i€€ `h€€Ÿ`g€€ž`f€€`e€€œ`d€€›`c€€Z`b€€™`a€€˜``€€—`_€€–`^€€•`]€€„`[€€“`Z€€’`Y€€‘`X€€`W€€`V€€Y`U€€Ž`T€€`S€€Œ`R€*ÔKEY_ALT_V(KEY_PREFIX+47)*ÓKEY_ALT_C(KEY_PREFIX+46)*ÒKEY_ALT_X(KEY_PREFIX+45)*ÑKEY_ALT_Z(KEY_PREFIX+44)*ÏKEY_ALT_L(KEY_PREFIX+38)*ÎKEY_ALT_K(KEY_PREFIX+37)*ÍKEY_ALT_J(KEY_PREFIX+36)*ÌKEY_ALT_H(KEY_PREFIX+35)*ËKEY_ALT_G(KEY_PREFIX+34)*ÊKEY_ALT_F(KEY_PREFIX+33)*ÉKEY_ALT_D(KEY_PREFIX+32)*ÈKEY_ALT_S(KEY_PREFIX+31)*ÇKEY_ALT_A(KEY_PREFIX+30)*ÅKEY_ALT_P(KEY_PREFIX+25)*ÄKEY_ALT_O(KEY_PREFIX+24)*ÃKEY_ALT_I(KEY_PREFIX+23)*ÂKEY_ALT_U(KEY_PREFIX+22)*ÁKEY_ALT_Y(KEY_PREFIX+21)*ÀKEY_ALT_T(KEY_PREFIX+20)*¿KEY_ALT_R(KEY_PREFIX+19)*¾KEY_ALT_E(KEY_PREFIX+18)*½KEY_ALT_W(KEY_PREFIX+17)*¼KEY_ALT_Q(KEY_PREFIX+16),ºKEY_ALT_EQ(KEY_PREFIX+131)/¹KEY_ALT_MINUS(KEY_PREFIX+130)+¸KEY_ALT_0(KEY_PREFIX+129)+·KEY_ALT_9(KEY_PREFIX+128)+¶KEY_ALT_8(KEY_PREFIX+127)+µKEY_ALT_7(KEY_PREFIX+126)+´KEY_ALT_6(KEY_PREFIX+125)+³KEY_ALT_5(KEY_PREFIX+124)+²KEY_ALT_4(KEY_PREFIX+123)+±KEY_ALT_3(KEY_PREFIX+122)+°KEY_ALT_2(KEY_PREFIX+121)+¯KEY_ALT_1(KEY_PREFIX+120)-­KEY_ALT_F10(KEY_PREFIX+113),¬KEY_ALT_F9(KEY_PREFIX+112),«KEY_ALT_F8(KEY_PREFIX+111),ªKEY_ALT_F7(KEY_PREFIX+110),©KEY_ALT_F6(KEY_PREFIX+109),¨KEY_ALT_F5(KEY_PREFIX+108),§KEY_ALT_F4(KEY_PREFIX+107),¦KEY_ALT_F3(KEY_PREFIX+106),¥KEY_ALT_F2(KEY_PREFIX+105),¤KEY_ALT_F1(KEY_PREFIX+104).¢KEY_CTRL_F10(KEY_PREFIX+103)-¡KEY_CTRL_F9(KEY_PREFIX+102)- KEY_CTRL_F8(KEY_PREFIX+101)-ŸKEY_CTRL_F7(KEY_PREFIX+100),žKEY_CTRL_F6(KEY_PREFIX+99),KEY_CTRL_F5(KEY_PREFIX+98),œKEY_CTRL_F4(KEY_PREFIX+97),›KEY_CTRL_F3(KEY_PREFIX+96),šKEY_CTRL_F2(KEY_PREFIX+95),™KEY_CTRL_F1(KEY_PREFIX+94)+—KEY_SH_F10(KEY_PREFIX+93)*–KEY_SH_F9(KEY_PREFIX+92)*•KEY_SH_F8(KEY_PREFIX+91)*”KEY_SH_F7(KEY_PREFIX+90)*“KEY_SH_F6(KEY_PREFIX+89)*’KEY_SH_F5(KEY_PREFIX+88)*‘KEY_SH_F4(KEY_PREFIX+87)*KEY_SH_F3(KEY_PREFIX+86)*KEY_SH_F2(KEY_PREFIX+85)*ŽKEY_SH_F1(KEY_PREFIX+84)(ŒKEY_F10(KEY_PREFIX+68)'‹KEY_F9(KEY_PREFIX+67)'ŠKEY_F8(KEY_PREFIX+66)'‰KEY_F7(KEY_PREFIX+65)'ˆKEY_F6(KEY_PREFIX+64)'‡KEY_F5(KEY_PREFIX+63)'†KEY_F4(KEY_PREFIX+62)'…KEY_F3(KEY_PREFIX+61)'„KEY_F2(KEY_PREFIX+60)'ƒKEY_F1(KEY_PREFIX+59).KEY_F(KEY_PREFIX+(58+(n)))n'€KEY_F0(KEY_PREFIX+58)'~KEY_DC(KEY_PREFIX+83)'}KEY_IC(KEY_PREFIX+82)*|KEY_NPAGE(KEY_PREFIX+81)*{KEY_PPAGE(KEY_PREFIX+73)(zKEY_END(KEY_PREFIX+79))yKEY_HOME(KEY_PREFIX+71))xKEY_DOWN(KEY_PREFIX+80)'wKEY_UP(KEY_PREFIX+72)*vKEY_RIGHT(KEY_PREFIX+77))uKEY_LEFT(KEY_PREFIX+75) tKEY_BACKSPACE8 sKEY_PREFIX1000nKEY_ENTER13iKEY_CTRL_Z26hKEY_CTRL_Y25gKEY_CTRL_X24fKEY_CTRL_W23eKEY_CTRL_V22dKEY_CTRL_U21cKEY_CTRL_T20bKEY_CTRL_S19aKEY_CTRL_R18`KEY_CTRL_Q17_KEY_CTRL_P16^KEY_CTRL_O15]KEY_CTRL_N14\KEY_CTRL_M13[KEY_CTRL_L12ZKEY_CTRL_K11YKEY_CTRL_J10XKEY_CTRL_I9WKEY_CTRL_H8VKEY_CTRL_G7UKEY_CTRL_F6TKEY_CTRL_E5SKEY_CTRL_D4RKEY_CTRL_C3QKEY_CTRL_B2PKEY_CTRL_A1€Jà<`FchWHITE15€Ià2`EchYELLOW14€Hà8`DchMAGENTA13€?à`CchRED12€Fà4`BchCYAN11€Eà*`AchGREEN10€Dà0`@chBLUE9€;à.`?cDGRAY8€Bà,`>cWHITE7€Aà"`=chBLACK7€@à(`9cLGRAY7€7à&`8cYELLOW6€>à$`7cBROWN6€=à`6cMAGENTA5€<à `5cRED4€2à`4cCYAN3€:à`3cGREEN2€9à`2cBLUE1€8à`1cBLACK02-cREVERSEDCONCOLOR(cBLACK,cWHITE)€3à`,cBOLD8€6à `+cNORMAL7€5à`!'COLORBG(t/16)t€4à`!&COLORFG(t%16)t€1à `&%CONCOLOR(b*16+f)f,b&€` `&&&&"target.h" _UNICON_H_€0à`ü™Ò¨~ZF"êÖ²žzfB. öÒ¾š†`L$èÔ¬˜p\4 øä¼¨€lD0óÒ¾‰hT3þêɵ”€_K*ôàÀ¬ŒxXD$ðܼ¨ˆtxX8÷Ì¡vK õ á ¶ ‹ ` 5  Ú¯„Y.Ø­‚W,Ö«€U*ÿÔ©~S(ýÒ¾“T@ÿݾ¡ƒbAñ»|h= õÖ·™Xcon_max_xintVcon_cshowvoidUcon_chidevoid€€Ž€4Scon_putsvoidconst char*s,int attr+Rcon_putsvoidconst char*s€Š€‹€?Qcon_outvoidint x,int y,const char*s,int attr6Pcon_outvoidint x,int y,const char*s(Lcon_csvoidint attr=-1(Kcon_cevoidint attr=-1!Icon_restorevoid!Hcon_suspendvoidFcon_donevoidEcon_initint=KEY_DELKEY_DC"<KEY_DELETEKEY_DC;KEY_INSKEY_IC":KEY_INSERTKEY_IC€€~€+4KEY_ALT_M(KEY_PREFIX+'m')€€|€+3KEY_ALT_N(KEY_PREFIX+'n')€€z€+2KEY_ALT_B(KEY_PREFIX+'b')+1KEY_ALT_V(KEY_PREFIX+'v')+0KEY_ALT_C(KEY_PREFIX+'c')+/KEY_ALT_X(KEY_PREFIX+'x')+.KEY_ALT_Z(KEY_PREFIX+'z')+,KEY_ALT_L(KEY_PREFIX+'l')++KEY_ALT_K(KEY_PREFIX+'k')+*KEY_ALT_J(KEY_PREFIX+'j')+)KEY_ALT_H(KEY_PREFIX+'h')+(KEY_ALT_G(KEY_PREFIX+'g')+'KEY_ALT_F(KEY_PREFIX+'f')+&KEY_ALT_D(KEY_PREFIX+'d')+%KEY_ALT_S(KEY_PREFIX+'s')+$KEY_ALT_A(KEY_PREFIX+'a')+"KEY_ALT_P(KEY_PREFIX+'p')+!KEY_ALT_O(KEY_PREFIX+'o')+ KEY_ALT_I(KEY_PREFIX+'i')+KEY_ALT_U(KEY_PREFIX+'u')+KEY_ALT_Y(KEY_PREFIX+'y')+KEY_ALT_T(KEY_PREFIX+'t')+KEY_ALT_R(KEY_PREFIX+'r')+KEY_ALT_E(KEY_PREFIX+'e')+KEY_ALT_W(KEY_PREFIX+'w')+KEY_ALT_Q(KEY_PREFIX+'q'),KEY_ALT_EQ(KEY_PREFIX+'=')/KEY_ALT_MINUS(KEY_PREFIX+'-')+KEY_ALT_0(KEY_PREFIX+'0')+KEY_ALT_9(KEY_PREFIX+'9')+KEY_ALT_8(KEY_PREFIX+'8')+KEY_ALT_7(KEY_PREFIX+'7')````` ` ` ``````````` `"`$`&`(`*`,`.`0`2`4`6`8`:`<`>`?`@`A`B`C`D`E`F`G`H`I`J`K`L`M`N`O`P`Q`R`S`T`U`V`W`X`Y`Z`[`\`]`^`_```a`b`c`d`e`f`g`h`i`j`k`l`m`n`o`p`q`r`s`t`u`v`w`x`y`z`{`|`}`~``€``‚`ƒ`„`…`†`‡`ˆ`‰`Š`‹`Œ``Ž```‘`’`“`”`•`–`—`˜`™`›`œ``ž`Ÿ` `¡`¢`£`¥`¦`§`¨`©`ª`«`¬`­`®`¯`°`±`×`Ø`Ù`Ú`Û`Ü`Ý`Þ`à`á`€€€€ € € €€€€€€€€€€!€#€%€'€)€+€-€/€1€3€5€7€9€;€=€?€A€C€E€G€I€K€M€O€R€S€T€U€V€W€X€Y€Z€[€]€^€_€`€a€b€c€d€e€f€g€h€i€j€k€l€m€n€o€p€q€r€s€t€u€v€w€x€y€z€|€~€€€€‚€ƒ€„€…€†€‡€ˆ€‰€Š€‹€€Ž€€‘€’€+KEY_ALT_6(KEY_PREFIX+'6')+KEY_ALT_5(KEY_PREFIX+'5')+KEY_ALT_4(KEY_PREFIX+'4')+KEY_ALT_3(KEY_PREFIX+'3')+ KEY_ALT_2(KEY_PREFIX+'2')+ KEY_ALT_1(KEY_PREFIX+'1')  KEY_PREFIX1000! KEY_ALT_F10(-1) KEY_ALT_F9(-1) KEY_ALT_F8(-1)þã,à1à2à3à4à5à6à7à8à9à:à;à<à=à>à?à@àAàBàDàEàFàGàHàIàJàiàkàlànàoàpàà“à«à¬à­à®à°à" * + E M P Q R S T V W X f ³ ´ µ ¶ · ¸ @%@&@8@C@g@l@m@n@o@p@q@r@s@t@u@v@w@x@y@{@|@}@~@‚@«@` ` ``````````` `"`$`&`(`*`,`.`0`2`4`6`8`:`<`>`?`@`A`B`C`D`E`F`G`H`I`J`K`L`M`N`O`P`Q`R`S`T`U`V`W`X`Y`Z`[`\`]`^`_```a`b`c`d`e`f`g`h`i`j`k`l`m`n`o`p`q`r`s`t`u`v`w`x`y`z`{`|`}`~``€``‚`ƒ`„`…`†`‡`ˆ`‰`Š`‹`Œ``Ž```‘`’`“`”`•`–`—`˜`™`›`œ``ž`Ÿ` `¡`¢`£`¥`¦`§`¨`©`ª`«`¬`­`®`¯`°`±`â`€€€€ € € €€€€€€€€€€!€#€%€'€)€+€-€/€1€3€5€7€9€;€=€?€A€C€E€G€I€K€M€O€R€S€T€U€V€W€X€Y€Z€[€]€^€_€`€a€b€c€d€e€f€g€h€i€j€k€l€m€n€o€p€q€r€s€t€u€v€w€x€y€z€|€~€€€€‚€ƒ€  1 – — ˜ ™ BÀDÀJÀKÀLÀbÀX^`     - f i j k l m n €€€€H€I€J€K€O€P€R€S€\€_€h€k€l€m€n€o€p€q€r€s€t€u€v€x€y€z€{€|€~€                                   ! " 0 S T U V X Y Z [ \ ] ^ _ ` a b c d e f g h i j l o p  ƒ „ … † ‰ ‹ “ ” ÀÀÀÀÀÀÀÀÀÀ À!À"À#À$À%À&À'À(À)À*À+À,À-À.À/À0À1À2À3À4À5À6ÀVÀXÀYÀZÀ[À]À^Àà€‹`O€ KEY_ALT_F7(-1)€Š`M€ KEY_ALT_F6(-1)€‰`K€ KEY_ALT_F5(-1)€ˆ`I€ KEY_ALT_F4(-1)€‡`G€ KEY_ALT_F3(-1)€†`E€ KEY_ALT_F2(-1)€…`C€ KEY_ALT_F1(-1)€t`A€"þKEY_CTRL_F10(-1)€ƒ`?€!ýKEY_CTRL_F9(-1)€‚`=€!üKEY_CTRL_F8(-1)€`;€!ûKEY_CTRL_F7(-1)€€`9€!úKEY_CTRL_F6(-1)€`7€!ùKEY_CTRL_F5(-1)€~`5€!øKEY_CTRL_F4(-1)€}`3€!÷KEY_CTRL_F3(-1)€|`1€!öKEY_CTRL_F2(-1)€{`/€!õKEY_CTRL_F1(-1)€z`-€)óKEY_SH_F10(KEY_F(0)+20)€y`+€(òKEY_SH_F9(KEY_F(0)+19)€x`)€(ñKEY_SH_F8(KEY_F(0)+18)€w`'€(ðKEY_SH_F7(KEY_F(0)+17)€v`%€(ïKEY_SH_F6(KEY_F(0)+16)€u`#€(îKEY_SH_F5(KEY_F(0)+15)€d`!€(íKEY_SH_F4(KEY_F(0)+14)€s`€(ìKEY_SH_F3(KEY_F(0)+13)€r`€(ëKEY_SH_F2(KEY_F(0)+12)€q`€(êKEY_SH_F1(KEY_F(0)+11)€p`€&èKEY_F10(KEY_F(0)+10)€o`€$çKEY_F9(KEY_F(0)+9)€n`€$æKEY_F8(KEY_F(0)+8)€m`€$åKEY_F7(KEY_F(0)+7)€l`€$äKEY_F6(KEY_F(0)+6)€k`€$ãKEY_F5(KEY_F(0)+5)€j` €$âKEY_F4(KEY_F(0)+4)€i` €$áKEY_F3(KEY_F(0)+3)€h` €$àKEY_F2(KEY_F(0)+2)€g`€$ßKEY_F1(KEY_F(0)+1)*×KEY_ALT_M(KEY_PREFIX+50)*ÖKEY_ALT_N(KEY_PREFIX+49)*ÕKEY_ALT_B(KEY_PREFIX+48) 0à€ü“–àÆ²•hF|íéÆ.¢×Uqì§1š©X»ºn4ù¥|3é¯q1ô§x;ëK$ãÏ‚S#í¹qA-ä’^J ù¿«lXÎ ¼¨[G`LË·~j(àÌŽ ~1Ï»xd  ẠŒ x > * ó ß ˜ „ [ G  Ù Å — ƒ A - Ü O] )  ß Í¶ ¢  { F ƒûÏ©°c•{[:”^96„EXEC_ACCESS(S_IXUSR|S_IXGRP|S_IXOTH)%ƒWRITE_ACCESSS_IWUSR6‚READ_ACCESS(S_IRUSR|S_IRGRP|S_IROTH).€ff_blk(((___DIR*)(dir))->ff)?"p_file_time_stamptime_tunsigned int dos_ftimee___DIR4/€   f Œ Ž   ‘ ’ • – — ˜ ™ c d f g i j k l m n o p q r s t v w y z { }  €  ƒ † ‡ ˆ €€€€)&kneed_fake_dot_dotdotint€  Œ Ž  ‘ ’ !jdestruct dirent iffstruct ffblkhflagsintgnamechar*fnum_readint€ f 3Qexpand_pathVStringconst char*src;Dexpand_pathchar*const char*src,char*destĘ€Ý@ß@á@â@                              ! " # $ % & ' ( ) * + , - . / 0 1 2 4 5 6 7 8 9 : < = > @ B D F H J L N P R T V X Z \ ^ ` b d h j l n p r t v x z | } ~  ‚ „ … ‡ ˆ ‰ Š ‹  ÀÀÀÀÀ À À ÀÀÀÀÀÀÀÀÀÀÀÀÀ!À#À$À&À'À(À)À*À+À,À-À.À/À1À2À5À7À8À9À:À<À=À>À?À@ÀAÀàà!à#à%à&à'à -popconst char*&'pushintconst char*s&getconst char*int n,setvoidint n,const char*sdelvoidint n,÷insvoidint n,const char*sïdetachvoid'ãVArrayconst VTrie&tr€‚ … à)ÜVArrayconst VArray&arr)­resizevoidint new_size!ŸcloneVArrayBox*4str_is_doubleintconst char*target1‚str_is_intintconst char*targetNtstr_str_countintconst char*target,const char*s,int startposQhstr_countintconst char*target,const char*charlist,int startpos€9 x BGstr_squeezechar*char*target,const char*sq_chars€8 v .:str_reversechar*char*target€7 t 0/str_flip_casechar*char*target€6 r *(str_lowchar*char*target€5 p )!str_upchar*char*target€4 n Gstr_trchar*char*target,const char*from,const char*to€* l 7str_commachar*char*target,char delim€) j :æstr_padchar*char*target,int len,char ch€( h .Þstr_cut_spcchar*char*target€# F >×str_cutchar*char*target,const char*charlist€& d DÎstr_cut_rightchar*char*target,const char*charlist€% b CÄstr_cut_leftchar*char*target,const char*charlist€ ` N·str_rwordchar*char*target,const char*delimiters,char*result€. ^ Mªstr_wordchar*char*target,const char*delimiters,char*result€- = :Ÿstr_add_chvoidchar*target,const char ch€, Z 4–str_get_chcharchar*target,int pos€' X Bstr_set_chvoidchar*target,int pos,const char ch€$ V 9 ƒstr_trim_rightchar*char*target,int len€ T 8ystr_trim_leftchar*char*target,int len€" R 5nstr_srightchar*char*target,int len€! P 4hstr_sleftchar*char*target,int len€  N Fcstr_rightchar*char*target,const char*source,int len€ L E^str_leftchar*char*target,const char*source,int len€ J MKstr_copychar*char*target,const char*source,int pos,int len€ H K<str_replacechar*char*target,const char*out,const char*in€ / =3str_ins_chchar*char*target,int pos,char ch€ D ? str_inschar*char*target,int pos,const char*s€ B :str_delchar*char*target,int pos,int len€+ @ =str_rfindintconst char*target,const char*s€< > Iûstr_findintconst char*target,const char*s,int startpos=óstr_rfindintconst char*target,const char cIèstr_findintconst char*target,const char s,int startpos€ : 0Õstr_mulchar*char*target,int nHÇstr_squeezeVString&VString&target,const char*sq_chars4Àstr_reverseVString&VString&target6¹str_flip_caseVString&VString&target0²str_lowVString&VString&target/«str_upVString&VString&targetM¤str_trVString&VString&target,const char*from,const char*to€0 2 A˜sprintfintVString&target,const char*format,...'#šVSPRINTF_BUF_SIZE1024OŒsprintfintint init_size,VString&target,const char*format,...Q„str_rwordchar*VString&target,const char*delimiters,char*resultP|str_wordchar*VString&target,const char*delimiters,char*result=sstr_add_chvoidVString&target,const char ch7lstr_get_chcharVString&target,int posEdstr_set_chvoidVString&target,int pos,const char ch=[str_commaVString&VString&target,char delim@Sstr_padVString&VString&target,int len,char ch4Nstr_cut_spcVString&VString&targetDEstr_cutVString&VString&target,const char*charlistJ=str_cut_rightVString&VString&target,const char*charlistI5str_cut_leftVString&VString&target,const char*charlist? -str_trim_rightVString&VString&target,int len>%str_trim_leftVString&VString&target,int len;str_srightVString&VString&target,int len:str_sleftVString&VString&target,int lenL str_rightVString&VString&target,const char*source,int lenKstr_leftVString&VString&target,const char*source,int lenSòstr_copyVString&VString&target,const char*source,int pos,int lenQãstr_replaceVString&VString&target,const char*out,const char*inCÚstr_ins_chVString&VString&target,int pos,char chEÑstr_insVString&VString&target,int pos,const char*s@Èstr_delVString&VString&target,int pos,int len6Àstr_mulVString&VString&target,int n0¯catnvoidconst char*ps,int len0žsetnvoidconst char*ps,int len'“catvoidconst char*ps'€setvoidconst char*ps'wfivoidconst double d&lfvoidconst double d$elvoidconst long n#^ivoidconst int nVdetachvoid- -resize_bufvoidint new_size" #cloneVStringBox*-itoasprintf(s,"%d",n)n,s,r&"vstring.h"€   €&&À0ü ¦`Ó±ÞŽiU*ÿÜÊ©•Kùl¿¤ˆ@òñ- øÑ’~ÝX$¤uM“Ô·âmY.έ™~@dz€Là¨}`EÓ)  ñU¬nô?(¡qÛ·Šð]E) NΡrÀ2ïÔ¤y`¢9]îʈŠ4æ·Ô¤\,ÄÕvGò„Ib ì œC (å ° | ù Ã Š T @ Ò ‰ T tå Ñ › c .  ä¬ v b ,  ãĨl`H €À!À#À$À&À'À(À)À*À+À,À-À.À/À1À2À5À7À(-=>?AB&à'à €'à€%à €ÀÀÀ!à#à%à €à¥à( @Ý@CÀ €€ˆÀ&4'€‚ „ … ‡ ˆ ‰ Š ‹  ÀÀÀÀÀ À À ÀÀÀÀÀÀÀÀ|àà’à“à”à–à—à˜àšà›àœààžààà$ôlvoidconst long n#óivoidconst int n€îfixvoid€ëfixlenvoid€ß[]char&int n!€Ýdataconst char*(Üconst char*const char*6€Ú<=intconst VString&s1,const char*s2€žÀŸÀ¡À6€Ù<=intconst char*s1,const VString&s29€Ø<=intconst VString&s1,const VString&s25€Ö=intconst VString&s1,const char*s2€ƒÀ—À™À6€Ñ>=intconst char*s1,const VString&s29€Ð>=intconst VString&s1,const VString&s25€Î>intconst VString&s1,const char*s2€’À“À•À5€Í>intconst char*s1,const VString&s28€Ì>intconst VString&s1,const VString&s26€Ê!=intconst VString&s1,const char*s2€ŽÀÀ‘À6€É!=intconst char*s1,const VString&s29€È!=intconst VString&s1,const VString&s26€Æ==intconst VString&s1,const char*s2€†À‹ÀÀ6€Å==intconst char*s1,const VString&s29€Ä==intconst VString&s1,const VString&s2 €oÀ{À€ÀÀ‚À„À…À‡À‰À€<€Á+VStringconst double n,const VString&str2<€¿+VStringconst VString&str1,const double n:€½+VStringconst long n,const VString&str2:€»+VStringconst VString&str1,const long n9€¹+VStringconst int n,const VString&str29€·+VStringconst VString&str1,const int n;€´+VStringconst char*ps,const VString&str2;€²+VStringconst VString&str1,const char*ps@€°+VStringconst VString&str1,const VString&str2.€­*=const VString&const int n€uÀvÀ|À}À~À€1€ª+=const VString&const double n/€¨+=const VString&const long n.€¦+=const VString&const int n0€¤+=const VString&const char*ps4€¢+=const VString&const VString&str€pÀsÀtÀwÀxÀ€0€ =const VString&const double n.€Ÿ=const VString&const long n-€ž=const VString&const int n/€=const VString&const char*ps3€•=const VString&const VString&str€’undefvoid)€resizevoidint new_size+€Œcompactvoidint a_compact€0Š~VString(€‰VStringconst double n€eÀgÀhÀiÀjÀlÀ&€ˆVStringconst long n%€‡VStringconst int n'€†VStringconst char*ps€…VString+€VStringconst VString&str{detachvoid€cÀdÀyretchchar xboxVStringBox*# tSTR_BLOCK_SIZE256 ZVStringBox€   VÀZÀ_À€ jundefvoid€\À]À- iresize_bufvoidint new_size" gcloneVStringBox*€0 e~VStringBox€ dVStringBox bcompactint `schar*€RÀUÀXÀYÀ _sizeint ^slint EVRef€MÀNÀOÀQÀSÀ0€Qrefsint€Ounrefvoid€Nrefvoid0L~VRef€KVRefG_refint!=VRegExpVRegexp;<VHashVTrie;'#6VARRAY_BLOCK_SIZE2048-ASSERTassert&+&)&(&'%_VSTRING_H_+­hex2longlongconst char*s8!‘str_reduce_pathVStringconst char*path4ƒstr_file_pathVStringconst char*ps8#wstr_file_name_extVStringconst char*ps4fstr_file_nameVStringconst char*ps3Zstr_file_extVStringconst char*ps€9À:ÀARstr_fix_pathconst char*VString&s,int slashtype8Gstr_fix_pathchar*char*s,int slashtype> 4str_dot_reduceVStringconst char*s,int width#printvoid€2À5À!fsaveintFILE*f€.À1À!floadintFILE*f+ fsaveintconst char*fname+floadintconst char*fname€+À/À&÷mergevoidVArray*arr$ëmergevoidVTrie*trÞreversevoid×valuesVArrayÐkeysVArray?!Ëkeys_and_valuesvoidVArray*keys,VArray*values(Ädelvoidconst char*key/ºgetconst char*const char*key9¯setvoidconst char*key,const char*valueG¡trace_nodevoidVTrieNode*node,VArray*keys,VArray*vals™detachvoid&VTrieconst VTrie&tr€!À$À&à(‡VTrieconst VArray&arr tcloneVTrieBox*bprintvoid!XcloneVTrieNode*?4find_nodeVTrieNode*const char*key,int createÔmin_lenintÆmax_lenint¿printvoid±shufflevoid¥reversevoidR‡q_sortvoidint lo,int hi,int(*q_strcmp)(const char*,const char*)Jsortvoidint rev,int(*q_strcmp)(const char*,const char*)€ ÀÀ!tfsaveintFILE*f€À À!dfloadintFILE*f+[fsaveintconst char*fname+Qfloadintconst char*fname€ÀÀ%ImergeintVArray*arr#CmergeintVTrie*tr";shiftconst char*)5unshiftintconst char*sà0@ üš›Ö¯™…nZA-ÿرQØšFС‹H÷•V Ð…WψA ÉC Ï=.ßžŠðÞ¨$¨e-ý.ÄGü¬g!í¸€GÑ—Jü¹u7 Ë I ö Æ ˜ V Î ƒ o 2  Ë { J  ö Ü È ­ ’ v U ,  ýÙ¾Ÿ‡sR6ä3Ȱ‡sL|í΢Ða;ò­ˆtYHâέ™+컌xFäЂa="€ current_indexint$€currentconst char*!€nextconst char*€resetvoid3€ý+=const VArray&const VString&str€—à˜àšà0€û+=const VArray&const VTrie&tr2€ù+=const VArray&const VArray&arr2€÷=const VArray&const VString&str€“à”à–à/€õ=const VArray&const VTrie&tr1€í=const VArray&const VArray&arr"€ã[]VString&int náshufflevoidàreversevoidQßsortvoidint rev=0,int(*q_strcmp)(const char*,const char*)=NULL€Šàà!ÝfsaveintFILE*f€<à‹à!ÜfloadintFILE*f+Ûfsaveintconst char*fname+Úfloadintconst char*fnameØprintvoid€…à†à%ÖmergeintVArray*arr#ÕmergeintVTrie*tr"Óshiftconst char*)Òunshiftintconst char*s Ðpopconst char*&Ïpushintconst char*s€Ìundefvoid&Êgetconst char*int n,Ésetvoidint n,const char*sÈdelvoidint n,Çinsvoidint n,const char*s€Åcountint0Ã~VArray'ÂVArrayconst VTrie&tr€wàxàzà)ÁVArrayconst VArray&arrÀVArray¾compactintRºq_sortvoidint lo,int hi,int(*q_strcmp)(const char*,const char*)¹detachvoid!·_ret_strVString€oàpàràvàµ_feint³boxVArrayBox* šVArrayBox€~  gàhàlà€¨undefvoid€iàjà)§resizevoidint new_size!¥cloneVArrayBox*€0£~VArrayBox€¢VArrayBox _countint€càdàfàŸ_sizeint ž_dataVString**4’str_is_doubleintconst char*target1‘str_is_intintconst char*targetPstr_str_countintconst char*target,const char*s,int startpos=0SŽstr_countintconst char*target,const char*charlist,int startpos=0€Zà]à=Œstr_rfindintconst char*target,const char*s€Yà[àK‹str_findintconst char*target,const char*s,int startpos=0=Šstr_rfindintconst char*target,const char cK‰str_findintconst char*target,const char c,int startpos=0Bstr_squeezechar*char*target,const char*sq_chars.str_reversechar*char*target0}str_flip_casechar*char*target*|str_lowchar*char*target){str_upchar*char*targetGystr_trchar*char*target,const char*from,const char*to;ustr_commachar*char*target,char delim=','>qstr_padchar*char*target,int len,char ch=' '.nstr_cut_spcchar*char*target>mstr_cutchar*char*target,const char*charlistDlstr_cut_rightchar*char*target,const char*charlistCkstr_cut_leftchar*char*target,const char*charlistNistr_rwordchar*char*target,const char*delimiters,char*resultMgstr_wordchar*char*target,const char*delimiters,char*result:cstr_add_chvoidchar*target,const char ch4bstr_get_chcharchar*target,int posBastr_set_chvoidchar*target,int pos,const char ch9 ]str_trim_rightchar*char*target,int len8\str_trim_leftchar*char*target,int len5Zstr_srightchar*char*target,int len4Ystr_sleftchar*char*target,int lenFXstr_rightchar*char*target,const char*source,int lenEWstr_leftchar*char*target,const char*source,int lenPVstr_copychar*char*target,const char*source,int pos,int len=-1KTstr_replacechar*char*target,const char*out,const char*in=Sstr_ins_chchar*char*target,int pos,char ch?Rstr_inschar*char*target,int pos,const char*s:Qstr_delchar*char*target,int pos,int len0Ostr_mulchar*char*target,int n8€Mstr_setchar*char*target,const char*ps*€Lstr_lenintconst char*ps vVStringH<str_squeezeVString&VString&target,const char*sq_chars4;str_reverseVString&VString&target €ààààààààà à!à"à#à$à%à&à'à(à)à*à+à,à-à.à/à0à2à3à4à5à7à69str_flip_caseVString&VString&target08str_lowVString&VString&target/7str_upVString&VString&targetM6str_trVString&VString&target,const char*from,const char*to€/à0àA3sprintfintVString&target,const char*format,...O1sprintfintint init_size,VString&target,const char*format,...Q)str_rwordchar*VString&target,const char*delimiters,char*resultP(str_wordchar*VString&target,const char*delimiters,char*result=&str_add_chvoidVString&target,const char ch7%str_get_chcharVString&target,int posE$str_set_chvoidVString&target,int pos,const char chA!str_commaVString&VString&target,char delim=','D str_padVString&VString&target,int len,char ch=' '4str_cut_spcVString&VString&targetDstr_cutVString&VString&target,const char*charlistJstr_cut_rightVString&VString&target,const char*charlistIstr_cut_leftVString&VString&target,const char*charlist? str_trim_rightVString&VString&target,int len>str_trim_leftVString&VString&target,int len;str_srightVString&VString&target,int len:str_sleftVString&VString&target,int lenLstr_rightVString&VString&target,const char*source,int lenKstr_leftVString&VString&target,const char*source,int lenVstr_copyVString&VString&target,const char*source,int pos,int len=-1Qstr_replaceVString&VString&target,const char*out,const char*inCstr_ins_chVString&VString&target,int pos,char chEstr_insVString&VString&target,int pos,const char*s@ str_delVString&VString&target,int pos,int len6 str_mulVString&VString&target,int nTE€          eÀgÀhÀiÀjÀkÀlÀnÀoÀpÀqÀrÀsÀtÀuÀvÀwÀxÀzÀ{À|À}À~À€ÀÀ‚ÀƒÀ„À…À†À‡ÀˆÀ‰À‹ÀÀŽÀÀ‘À’À“À•À—À™ÀšÀ›ÀžÀŸÀ¡À¢À£À¤À¥À¦Ààà à à àààˆÀ>€ str_setVString&VString&target,const char*ps+€ str_lenintVString&target€checkint €fÀ§À©Ààààààà0catnvoidconst char*ps,int len0ÿsetnvoidconst char*ps,int len'þcatvoidconst char*ps'ýsetvoidconst char*ps€  à€ûfidouble€   à€úfdouble€  à€ùllong€ à€øiint'öfivoidconst double d&õfvoidconst double d0À ü{‚_àlP8áÁ­–x\"áÀœfF,ýݨŠn'EòÖ¿—ƒ]Œ å¶·q2øÛ¼‘}bf;盇fR'ùɵ„UA*ÿκ|@û ç ´ € H  Ü ± – y Í I  ô § a  ý © Œ J ù¸ h  @lØÄgÈ´bæ´_~jÏ;'©aMå¼”s€(à!áundefvoidint n(×pushvoidint n,int val)¼resizevoidint new_size!œsub_epintint n!Žsub_spintint n&xsubconst char*int n€z{Hrmintconst char*line,const char*pattern,const char*opt&Rmintconst char*lineJokintEstudyint;compintconst char*pattern,const char*opt/get_optionsintconst char*opt€rà6ïVRegexpconst char*rs,const char*optO#¹mem_string_searchintconst char*p,const char*d,const char*opt€imK$file_string_searchlongconst char*p,FILE*f,const char*optR$”file_string_searchlongconst char*p,const char*fn,const char*opt€hkO_file_greplongconst char*re_string,FILE*f,int nocase,int spos)&^file_grep_lines_readint'$]file_grep_max_lineint]Tfile_greplongconst char*re_string,const char*file_name,int nocase,int spos€ef”%Afile_pattern_searchlongconst char*p,int ps,const char*fn,const char*opt,int(*mem_search)(const char*p,int ps,const char*d,int ds)%file_pattern_searchlongconst char*p,int ps,FILE*f,const char*opt,int(*mem_search)(const char*p,int ps,const char*d,int ds)$BUFSIZE(1024*1024)K ïmem_sum_searchintconst char*p,int ps,const char*d,int dsP%Ñmem_quick_search_ncintconst char*p,int ps,const char*d,int dsE$Ê__qs_preprocess_ncvoidconst char*p,int ps,int*badcM"¸mem_quick_searchintconst char*p,int ps,const char*d,int dsB!±__qs_preprocessvoidconst char*p,int ps,int*badc¯QS_ASIZE256K mem_kmp_searchintconst char*p,int ps,const char*d,int ds*&MAX_KMP_PATTERN_SIZE1024C"€__kmp_preprocessvoidconst char*p,int ps,int*nextF'hhex_string_to_patternintconst char*str,char*pattern&`__hex_codeintint chJ"Gstr_rfind_regexpintconst char*target,const char*pattern2str2timetime_tconst char*timstr0time2strchar*const time_t tim&"vstrlib.h"&+³hex2longlongconst char*s8!«str_reduce_pathVStringconst char*path4¨str_file_pathVStringconst char*ps8#§str_file_name_extVStringconst char*ps4¦str_file_nameVStringconst char*ps3¥str_file_extVStringconst char*ps€IJE£str_fix_pathconst char*VString&s,int slashtype='/'<¢str_fix_pathchar*char*s,int slashtype='/'> ˜str_dot_reduceVStringconst char*s,int width€EF1€“str_chopVString&VString&target+€’str_chopchar*char*target CVTrie€AB/€‡+=const VTrie&const VTrie&tr1€…+=const VTrie&const VArray&arr€>?0€ƒ=const VTrie&const VArray&arr.€{=const VTrie&const VTrie&tr+€q[]VString&const char*key€2;!ofsaveintFILE*f€79!nfloadintFILE*f+mfsaveintconst char*fname€ $%')*+,./0123579;+lfloadintconst char*fnameþBÀCÀDÀEÀFÀHÀIÀJÀKÀLÀMÀNÀOÀPÀQÀRÀSÀUÀVÀXÀYÀZÀ\À]À_ÀaÀbÀcÀdÀeÀfÀgÀhÀiÀjÀkÀlÀnÀoÀpÀqÀrÀsÀtÀuÀvÀwÀxÀzÀ{À|À}À~À€ÀÀ‚ÀƒÀ„À…À†À‡ÀˆÀ‰À‹ÀÀŽÀÀ‘À’À“À•À—À™ÀšÀ›ÀžÀŸÀ¡À¢À£À¤À¥À¦À§À©Ààààà à à àààààààààààààààà à!à"à#à$à%à&à'à(à)à*à+à,à-à.à/à0à2à3à4à5à7à8à9à:à;à<à=à>à?à@àAàBàCàDàEàFàGàHàIàJàKàLàMàNàOàPàQàRàSàTàUàVàWàXàYàZà[à]à_à`àaàbàcàdàfàgàhàiàjàlànàoàpàràsàtàuàvàwàxàzà{à|à}à~àà€àà‚àƒà„à…à†àˆà‰àŠà‹ààà‘à’à“à”à–à—à˜àšà›àœààžà     !#$%'()*+,-./0123579;=>?ABDEFHIJLMNOPQjprintvoid€,3&gmergevoidVArray*arr$fmergevoidVTrie*trdreversevoidbvaluesVArrayakeysVArray?!_keys_and_valuesvoidVArray*keys,VArray*values€\undefvoid*€Yexistsintconst char*key/Wgetconst char*const char*key(Vdelvoidconst char*key8Usetvoidconst char*key,const char*data0S~VTrie&RVTrieconst VTrie&tr€$%'(QVTrieconst VArray&arrPVTrieNcompactint€!#!Jtemp_keyVStringGHtrace_nodevoidVTrieNode*node,VArray*keys,VArray*valsGdetachvoidEboxVTrieBox* 0VTrieBox€:undefvoid 9cloneVTrieBox*€07~VTrieBox€À€6VTrieBox 4rootVTrieNode* VTrieNode'printvoid€  !&cloneVTrieNode*A$find_nodeVTrieNode*const char*key,int create=0:#del_nodevoidconst char*key,int branch=0€"detachvoid dataVString*cchar€   downVTrieNode* nextVTrieNode*0~VTrieNodeVTrieNode ±VArray min_lenint€<àsàtàuàwàxàzà{à}à~àà€à‚àƒà„à…à†àˆà‰àŠà‹ààà‘à max_lenint 0àü€…îáͰ“w Y=#ìŤ}QÇT7쟘oÓ¿/„[Gç•AäÐ]°#ñÔ.‘xY¤|øßÈ”]>ö.¶¢ˆH6ñu\ôÒŽhO*üÓ¹žtS/ã¹x]@†ÿëϵ½ S í µ c $ ñ ¹ o [ +  ñ ? + é Õ ŸE  ÿ΋Z#î5make_pathintconst char*s,long mode7ñtilde_expandVStringconst char*a_path1åfile_existsintconst char*fname€ ƒ /àfile_is_dirintstruct stat st1×file_is_dirintconst char*fname àààààààààààà à"à#à$à%à&à'à(à)à*à+à-à.à0à¢à£àpu C N ` @$@@@‘@’@“@”@•@–@—@˜@™@š@›@œ@@ž@Ÿ@ @¡@¢@ª@¬@®@°@²@´@¶@¸@º@¼@¾@À@Â@Ä@Æ@É@Ë@Í@Ð@Ò@Ô@Õ@×@            ! " # $ % & ' ( ) * + , - . / 0 2 4 5 6 7 8 9 : < = > @ B D F H J L N P R T V X Z \ ^ ` b d f h j l n p r t v x z | } • 8À9À:À<À=À>À?À@ÀAÀ9à:àEFTUVYZ[\]_abcefhikmpo p q r s t v w y z { }  €  ƒ † ‡ ˆ €€€€U€V€W€X€Y€^€Ž ’ • — ˜ ™ ÀÀÀÀÀ À À À À ÀÀÀÀÀÀPÀQÀRÀSÀUÀ„À†À‡ÀŠÀ‹ÀŒÀÀÀààà àààààà(à-à/à1à2Êfile_is_linkintconst char*fnameH!½file_save_crc32intconst char*fname,void*buff,int sizeH!®file_load_crc32intconst char*fname,void*buff,int size€z } B£file_saveintconst char*fname,void*buff,int size€s { B˜file_loadintconst char*fname,void*buff,int size8‘file_saveintFILE*f,void*buff,int size8Šfile_loadintFILE*f,void*buff,int size€v w &{file_sizelongFILE*f0rfile_sizelongconst char*fname€o t Fffile_adler32adler32_tconst char*fname,long buffsize<Lfile_adler32adler32_tFILE*f,long buffsize3Estr_adler32adler32_tconst char*s?>mem_adler32adler32_tconst void*buff,int sizeZ"adler32unsigned longunsigned long adler,const char*buf,unsigned int len0DO16DO8(buf,0);DO8(buf,8);buf3DO8DO4(buf,i);DO4(buf,i+4);buf,i3DO4DO2(buf,i);DO2(buf,i+2);buf,i3DO2DO1(buf,i);DO1(buf,i+1);buf,i/DO1{s1+=buf[i];s2+=s1;}buf,iNMAX5552BASE65521L€Sg ‰À& "vstrlib.h"€±à‰@   d €& "vstring.h"& "vsuti.h"Astr_joinVStringVArray array,const char*glue=""c"str_split_simpleVArrayconst char*delimiter_str,const char*source,int maxcount=-1Ystr_splitVArrayconst char*regexp_str,const char*source,int maxcount=-1 ÞVCharSetTI€                      ! # % & ( ) + - . / 0 2 3 4 5 6 7 8 9 : ; < > ? @ A B C E F G H I J M N O Q R S T V W X Y Z [ ^ ` a b îinintint n€X [ ìundefvoid€V W X Y Z [ ^ !ëundefvoidint n*êpushvoidint n,int val=10è~VCharSetçVCharSet)ãresizevoidint new_size€S T á_sizeint%à_dataunsigned char* ¦VRegexp&€Õerror_strconst char*€nrtvwxyz{O Q àà"€Ò[]VString&int n!Ðsub_epintint n!Ïsub_spintint n&Îsubconst char*int n €8 @ A B C E F G H I M N €8 I MÌmintconst char*line,const char*pattern,const char*opt=NULL&Ëmintconst char*lineÉokintÈstudyint@Çcompintconst char*pattern,const char*opt=NULL0Å~VRegexp€A C @ÄVRegexpconst char*pattern,const char*opt=NULLÃVRegexp/¿get_optionsintconst char*opt½errstrVString¼substrVString¹posint €. 3 4 5 6 7 9 : ; < > ? ¸plint·ptchar*´lpconst char*³rcint+²spint[VREGEXP_MAX_SUBS*3]±pepcre_extra*°repcre*­opt_nocaseint$¬opt_modeSearchMode©MODE_HEX0+2€/ 0 2 ©MODE_FIND0+1©MODE_REGEXP0©SearchMode$"¤VREGEXP_MAX_SUBS32O#‡mem_string_searchintconst char*p,const char*d,const char*opt€! ) K$…file_string_searchlongconst char*p,FILE*f,const char*optR$„file_string_searchlongconst char*p,const char*fn,const char*opt€% & Rvfile_greplongconst char*re_string,FILE*f,int nocase,int spos=-1`ufile_greplongconst char*re_string,const char*file_name,int nocase,int spos=-1€j# )&tfile_grep_lines_readint€d '$sfile_grep_max_lineint€  œ%dfile_pattern_searchlongconst char*p,int ps,const char*fn,const char*opt="",int(*mem_search)(const char*p,int ps,const char*d,int ds)=NULL•%`file_pattern_searchlongconst char*p,int ps,FILE*f,const char*opt="",int(*mem_search)(const char*p,int ps,const char*d,int ds)=NULLP%Wmem_quick_search_ncintconst char*p,int ps,const char*d,int dsK Smem_sum_searchintconst char*p,int ps,const char*d,int dsM"Rmem_quick_searchintconst char*p,int ps,const char*d,int dsK Qmem_kmp_searchintconst char*p,int ps,const char*d,int dsF'Ghex_string_to_patternintconst char*str,char*patternJ";str_rfind_regexpintconst char*target,const char*patternX!8str_find_regexpintconst char*target,const char*pattern,int startpos=026str2timetime_tconst char*timstr05time2strchar*const time_t tim#,MAX_GREP_LINE4096!)MAX_PATTERN2048'%&VCHARSET_BLOCK_SIZE32&"vstring.h"&&&ASSERTassert&_VSTRLIB_H_ëinintint n€… æundefvoid@@ÿÿÿÿ``°þÿ_yekfŸþÿ_yekNŸþÿ_yek2Ÿþÿ_yek1Ÿþÿ_yek9Ÿþÿ_yek0Ÿþÿ_yek/Ÿþÿ_yek.Ÿþÿ_yekþÿ_yekBŸþÿ_yekƒþÿ_yek8Ÿþÿ_yek7Ÿþÿ_yek@Ÿþÿ_yek=Ÿþÿ_yek5Ÿþÿ_yek<Ÿþÿ_yek:Ÿþÿ_yek*Ÿþÿ_yek?Ÿþÿ_yek,Ÿþÿ_yek;Ÿþÿ_yek-Ÿþÿ_yekJ`_yek>`_yek?`_yek:`_yekA`_yekB`_yekC`_yekÐþÿ_yek¾þÿ_yekÎþÿ_yekÌþÿ_yekÊþÿ_yekÈþÿ_yekÆþÿ_yekÄþÿ_yekÂþÿ_yekÀþÿ_yek@`_yekE`_yekF`_yekG`_yekH`_yekI`_yek6`_yekK`_yekL`_yekM`_yekN`_yekO`_yekP`_yekQ`_yekR`_yekS`_yekD`_yekU`_yekV`_yekW`_yekT`_yekƒ€_yek‚€_yek^`_yek``_yekX`_yekf`_yeke`_yekøþÿ_yekæþÿ_yeköþÿ_yekôþÿ_yekòþÿ_yekðþÿ_yekîþÿ_yekìþÿ_yekêþÿ_yekèþÿ_yek_`_yekc`_yek€_yek€€_yek[`_yekb`_yeka`_yekLŸþÿ_yek\`_yekäþÿ_yekÒþÿ_yekâþÿ_yekàþÿ_yekÞþÿ_yekÜþÿ_yekÚþÿ_yekØþÿ_yekÖþÿ_yekÔþÿ_yek]`syek/syekÀsyek.syek'Àl©Àlöþÿccl7 cclC _ccld gol* golÂßþÿgolÙßþÿ_gol) ngol+ pl: mµßýÿm„ÿýÿigamv€igam$ niamöýÿekam@€ekamˆ ctamÀctam0 ctamR ctamQ ctam ctamÀxam\@_xam _xamX_xam_xamÀ_xam€_xam lxamŽ_ýÿ_mem)€_memq _mem!€_memà_mem _mem]_mem _mem\_mem _memb_mem+ _memp_mem _memcmmem ýÿgremyþÿgrem÷?þÿgremÌÿýÿgremÐ?þÿnimW@_nim_nimÀedom0 edom2 edom/ emanŸàemanŽ deen  lwenS€txenœàtxen txen#@xamnj btonF etonJ etonG gapnh@llun»à_munŒ sffoA sffoB sffoE sffo? sffok€koH kots_no1 s_no0 a_po¥ a_po| a_po§ a_po¨ a_po© a_poª b_po² b_po° b_po± b_po¯ c_po} c_pou c_po¢ c_po­ c_po® c_po c_poŸ c_po¡ c_po› c_poœ c_pož c_po  c_poš d_poj d_po{ e_po e_pox e_pow e_pov k_po– k_po— k_po¦ m_po~ m_po„ m_po€ m_po‚ n_pou n_poz n_pop n_por n_pon n_pot n_po n_po‹ n_po n_po‰ n_po n_poŠ n_poŒ n_poˆ n_poŽ o_po¬ o_poy p_po q_poƒ r_po¤ r_po£ r_po« s_pom s_po t_po™ t_po” t_po† t_po’ t_po˜ t_po“ t_po• t_po‘ t_po‡ u_po… w_pos w_poo w_poq nepo6 nepo _tpo. _tpo4 _tpo!@atpoØ¿þÿctpoÏ¿þÿetpoÔ¿þÿetpoÍ¿þÿitpoÖ¿þÿitpo( itpo1 otpoÑ¿þÿ2droŽ giro†@egap^@egapf@egap:@egap[@egape@egapB@tapàahcp˜ ulcp4ercp8Àercp"ÀercpÀercp>ÀercpÀercp?ÀercpU€ercpÀercpN€ercpå?ýÿercpÀercp Àercp-Àercp,Àercp*Àercp+Àercp0Àercp'Àercp.Àercp@ÀercpÀercp!Àercp$Àercp9Àercph€ercpÃ?ýÿercpAÀercpV€ercpBÀercpX€ercpFÀercp— ercpCÀercpY€ercpDÀercpW€ercpm€ercpl€ercpEÀercp’ ercp4Àercp/Àercp5Àercp6Àercp3Àercp1Àercp2Àercpp€ercpÀercpGÀercpÅ?ýÿercp^€ercpÀercpÀercp%Àercp(Àercp&ÀercpQÀercpn€ercpo€ercpHÀercp‡Àercpr€ercp#Àercp)ÀercpIÀercp• ep7 lp< popƒàpop sopY@sop9 isopy isopx isopw gappc@verp{ nirpˆànirpÀnirp nirpÀnirp5nirp7ÀrtspLÀtp; lbupt€lbups€lbupq€hsup‚àhsupˆ hsupZ hsup„tup!tup‰àtup0tupŽàos_qtàos_qÀa_sq^cr5 er6 e_ertÀn_errÀp_er\Àdaer— daerÀlaer/ laer* laer6 laer4 laerÈàlaerwàlaerlaer…àlaerBferQÀsferSÀ_ger_À_geraÀ_gerbÀ_gercÀ_gerdÀ_ger`À_gerfÀ_gergÀ_gerhÀ_gereÀ_gerjÀ_gerkÀ_gerlÀ_geriÀ_gernÀ_ger]À_gerYÀ_geroÀ_gerZÀ_gerpÀ_ger^À_ger[À_gerXÀcgerÀcgerPÀeger|ÀegerRÀegerwÀegeruÀeger€ÀegerUÀfger‚ÀfgerSÀmger~Àmger}ÀogerxÀ_pert _pers _qer, eser›àisereiseràiserqÀiserjàiser iserV iserƒiser]Àiser cterdÀuterkàever`everàever Àever1ever-Àe_mr{Às_mrzÀtoorsXÀevas| orcsd@orcsU@raes( tesatesàtes tesàtesŠ tes)tes(À0tesV0tes–à1tesU1tes•à_tesc_tesb_tes„À_tes_tesV@_tesX@_tesG@_tesZ@_tesR@_tesY_tes™à_tesX_tes˜à_tes†À_tesW_tes—à_tesF_tesšàntesàntes fihs€àfihsÀirhsfuhs‘àfuhsÀezisµàezisezisLezis<ezisRÀezis% lsUÀtros‰àtrosÀps3 irpsÍ_þÿirpsÏþÿts rats2 ratsN ratsK ratsH tatsËàtatspets`@2rts 2rtsV_rtsJà_rts£_þÿ_rts,à_rts*€_rtsr _rtsbÀ_rts¹ÿýÿ_rtsRà_rts“_þÿ_rts%à_rtsAà_rtsµ_þÿ_rtsà_rts_à_rtsz _rts€_rtsà_rtsOà_rts™_þÿ_rts&à_rtsMà_rts_þÿ_rts$à_rtsNà_rts›_þÿ_rts!à_rtsPà_rts—_þÿ_rts'à_rts=à_rts½_þÿ_rtsà_rtsH_rts8À_rtsL_rts<À_rtsM_rts=À_rtsN_rts>À_rtsO_rts?À_rts¤þÿ_rtsÁ_þÿ_rts _rtsÿýÿ_rtsµÿýÿ_rtsÅ?þÿ_rtsVà_rts‹_þÿ_rts5à_rtsIà_rts¥_þÿ_rts+à_rts>à_rts»_þÿ_rtsà_rts?à_rts¹_þÿ_rtsà_rtsbà_rts} _rtsaà_rts| _rtsb _rtsÎýÿ_rtsBà_rts³_þÿ_rtsà_rts9à_rtsà_rtsUà_rts_þÿ_rts4à_rts;à_rtsÅ_þÿ_rtsà_rtsQà_rts•_þÿ_rts(à_rtsP_rts@À_rts@à_rts·_þÿ_rtsà_rtsWà_rts‰_þÿ_rts2à_rts¢þÿ_rts¿_þÿ_rts _rtsT_rtsCà_rts±_þÿ_rtsà_rtsLà_rtsŸ_þÿ_rts.à_rts:à_rtsà_rtsHà_rts§_þÿ_rts*à_rtsDà_rts¯_þÿ_rts à_rts` _rtsÒýÿ_rtsa _rtsÐýÿ_rtsXà_rts‡_þÿ_rts7à_rtsEà_rts­_þÿ_rtsà_rts`à_rts\ _rtsSà_rts‘_þÿ_rts-à_rtsFà_rts«_þÿ_rts"à_rtsGà_rts©_þÿ_rts#à_rtsTà_rts_þÿ_rts3à_rtsKà_rts¡_þÿ_rts)àirts“ dutsB dutsnbusG busx_busN _bus_busM _busysbus> lbat' lbath ulct3ulct@lcdt*pmet!tset‹ÀtsetŒÀtsetÀtsetŠÀtsetÀtsetàtsetàtsetàtxeté¿þÿtxet›ßþÿitŒ@it dlit?€dlit‡ emit emitUgolt: golt. golt ggotÌà_pot& _pot) lcpt:cartcart#Àeurtu€ednu_ÀednurÀednulàednuàednuednu-ednu£ßýÿednuûßýÿernuMÀhsnu„àhsnuÀpu_@pu@@adpu €adpuàhcsu# desu¶à8ftuD 8ftu‡ 8ftu 8ftu 8ftu‘ ulav0ulav,Àrravrrav‡þÿrrav}_þÿrravJÀrravnàrravgàahcvJ ahcvW ahcvçýÿahcv sahvKÀfervPÀfervNÀgervLÀgervR gerv¼ßýÿgervÿýÿgerv- rpsv1 rtsv8àrtsv“?þÿrtsvaÀrtsvZÀirtvDirtvÚÿýÿirtvÞ?þÿirtvirtvirtvirtvirtvÞýÿparwT@tirw˜ rtsx” |£à|k=|h=| à~i~¡àsab~esb~Tesb~”àclf~½àclf~tàlct~Aolt~3 olt~ rav~uàrav~àýÿrav~hàhcv~Y hcv~åýÿerv~OÀerv~E erv~éýÿtsv~nÀtsv~VÀrtv~ rtv~c?þÿrtv~rtv~ rtv~Üýÿ`@ÿÿÿÿÿÿÿÿÿÿÿÿ`_yek‹`@€0  üŠšÄ‡H-óØ´šucG+œö׸ÒxZ6üð«Z¯dP$¸¾Lë¤tN:ÿn°kWþ¶Ù< ÜÈ—`ó¸…qUA(ò×¼ „pšfF'ö Ù » > ¯ Î Œ  ë “ h ”  ß Ë ° € d Y%Õ»t0cÞ´Œ<ŸE«óÚÂ>’wYk# óSÛǯ—ƒâ?'ûɵš! ESC_REF12€‡€Ž€! ESC_z11! ESC_Z10€Š€‹€!ŸESC_w9!ŸESC_W8€}€€!ŸESC_s7!ŸESC_S6€„€…€!ŸESC_d5!ŸESC_D4€€€‚€!ŸESC_b3!ŸESC_B2!ŸESC_A1!“ESC_T'\t'!ESC_R'\r'!‹ESC_NNEWLINE!‡ESC_F'\f'!ƒESC_E27!|TRUE1!{FALSE0!yBOOLint+!uMAGIC_NUMBER0x50435245 UL'&!qPUBLIC_STUDY_OPTIONS0Z%!nPUBLIC_EXEC_OPTIONS(PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY) !jPUBLIC_OPTIONS(PCRE_CASELESS|PCRE_EXTENDED|PCRE_ANCHORED|PCRE_MULTILINE|PCRE_DOTALL|PCRE_DOLLAR_ENDONLY|PCRE_EXTRA|PCRE_UNGREEDY|PCRE_UTF8)'#!ePCRE_STUDY_MAPPED0x01)!aPCRE_ICHANGED0x04000000(!`PCRE_INGROUP0x08000000* !_PCRE_STARTLINE0x10000000)!^PCRE_REQCHSET0x20000000)!]PCRE_FIRSTSET0x40000000D!UPCRE_IMS(PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL)G!Poffsetof((size_t)&(((p_type*)0)->field))p_type,field&!J"pcre.h" €ààgà @â@FÀ €b€_ &!I €àeà¨à` EÀ €f€ÀWÀ&!H&!Gtt€àààà ààeàgàjà„à¥à§à¨àªà±àÏàmoqrs   ( ? @ A B J K L U @@@-@7@;@@…@‡@ˆ@‰@Ù@Ú@Û@Ý@ß@á@â@```` `ã`ä`æ`ç`é`ê`ë`    CÀEÀFÀHÀRS     c d g  € € € €€€€€€€€€€€€D€F€T€[€]€a€b€d€f€j€m  ÀJÀKÀMÀWÀƒÀˆÀ‰À à&!F€ªà]€&!E&!D€\€_€2!>memmovepcre_memmove(a,b,c)a,b,cW!6pcre_memmovevoid*unsigned char*dest,const unsigned char*src,size_t n+!4memmovebcopy(b,a,c)a,b,c&!("config.h"<% Ýpcre_free_substringvoidconst char*pointer€T€U€V€W€X€Y€}$ ¾pcre_get_substringintconst char*subject,int*ovector,int stringcount,int stringnumber,const char**stringptrB* pcre_free_substring_listvoidconst char**pointerp) ppcre_get_substring_listintconst char*subject,int*ovector,int stringcount,const char***listptr}% Jpcre_copy_substringintconst char*subject,int*ovector,int stringcount,int stringnumber,char*buffer,int size& +"internal.h"-NEWLINE'\n'&HAVE_BCOPY1€O€P€R€S€ HAVE_MEMMOVE1 HAVE_STRERROR14% pcre_default_tablesunsigned char[]?"¡get_rc_directoryVStringconst char*dir_prefix—‘ftwalkintconst char*origin_dir,int(*func)(const char*origin,const char*fname,const struct stat*st,int is_link,int flag),int level=-1D7€€ € € € €€€€€€€€€€€€€€€€ €!€#€$€&€'€(€)€*€+€.€/€1€2€3€4€6€8€9€:€;€<€>€?€@€A€B€D€F€G€H€I€J€K€M€ŽFTWALK_NS4FTWALK_DX3ŒFTWALK_D2‹FTWALK_F16dosstatintDIR*dir,struct stat*stbuf&€€€D€&€A€B€3vexpand_pathVStringconst char*src;uexpand_pathchar*const char*src,char*destmlmake_pathintconst char*s,long mode=S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH7btilde_expandVStringconst char*a_path1Yfile_existsintconst char*fname€;€<€/Xfile_is_dirintstruct stat st1Wfile_is_dirintconst char*fname2Vfile_is_linkintconst char*fnameH!Tfile_save_crc32intconst char*fname,void*buff,int sizeH!Sfile_load_crc32intconst char*fname,void*buff,int size€3€6€EQfile_saveintconst char*fname,void*buff,int size=-1€1€4€EPfile_loadintconst char*fname,void*buff,int size=-1;Ofile_saveintFILE*f,void*buff,int size=-1Ħ€CàKàLàMàNàOàPàQàRàSàUàVàXàYà[à\à]à^à_à`àaàbàdà   I Y @@@4@×`Ø`Ù`Ú`Û`Ü`Ý`Þ`à`á`„€…€†€‡€ˆ€‰€Š€‹€€Ž€€‘€’€;à=à>à?à@àAàBàCàDàEàFàGàHàIàJàKàLàMàNàOàPàQàRàSàTàUàVàWàXàYàZà[à]à_à`àaàbàHIJLMNOPQ           ! % & ) + ` a b € €!€#€$€'€(€)€*€+€.€/€1€2€3€4€6€8€9€:€;€<€>€?€@€A€B€G€M€v >À?À@ÀAÀBÀCÀDÀEÀFÀGÀHÀIÀ|ÀÀ€À‚À;Nfile_loadintFILE*f,void*buff,int size=-1€.€/€&Lfile_sizelongFILE*f0Kfile_sizelongconst char*fname€'€+€OFfile_adler32adler32_tconst char*fname,long buffsize=256*1024EEfile_adler32adler32_tFILE*f,long buffsize=256*10243Dstr_adler32adler32_tconst char*s?Cmem_adler32adler32_tconst void*buff,int sizeRAadler32adler32_tadler32_t adler,const char*buf,unsigned int len,?adler32_tunsigned long int€#€$€K;file_crc32crc32_tconst char*fname,long buffsize=256*1024A:file_crc32crc32_tFILE*f,long buffsize=256*1024/9str_crc32crc32_tconst char*s;8mem_crc32crc32_tconst void*buff,int sizeQ6update_crc32crc32_tconst unsigned char octet,const crc32_t crc'3CRC32NULL(0xffffffff)*1crc32_tunsigned long int+MAX_PATH512&$"vstring.h"€¬à8@DÀ €!ASSERTassert€§à-@HÀ €&&&&&&"target.h"&&&&&€mK ß@R €a€&&& _VSUTI_H_?"get_rc_directoryVStringconst char*dir_prefixúftwalkintconst char*origin,int(*func)(const char*origin,const char*fname,const struct stat*st,int is_link,int flag),int level­"´__ftwalk_processintconst char*origin,const char*path,int(*func)(const char*origin,const char*fname,const struct stat*st,int is_link,int flag),int level=-18~dosstatintDIR*dir,struct stat*statbuf 0 Àü“–l»y<ˆP+ Ç–dØ 4þÉœn8ÿ¾‹A Ú©f¼rBîÒ¦|Mnüܽ‰CE$þêÉ’pN:ñÓ¢„aÜB#e·›ÒH*þÛ¨~Rþ¿’qO. ø ¸ › | ^ @ !  ä Å ¦ ‡ g J + Ñ Ÿ | a M à /  ù Þ  ¯ Š e >  ê ¸ ‹ kîű–¶"錉Z;x¯›\H(gäªK'ùAíl"ôcheck_escapeintconst uschar**ptrptr,const char**errorptr,int bracount,int options,BOOL isclass,compile_data*cdT"Ðpcharsvoidconst uschar*p,int length,BOOL is_subject,match_data*mdi"Špcre_fullinfointconst pcre*external_re,const pcre_extra*study_data,int what,void*whereO"kpcre_infointconst pcre*external_re,int*optptr,int*first_char."Lpcre_versionconst char*void$"JXSTRINGSTRING(s)s"ISTRING#aa6"2ord2utf8intint cvalue,uschar*buffer%"utf8_table4uschar[]""utf8_table3int[]""utf8_table2int[]""utf8_table1int[] &""chartables.c"€† ‹ ?"õBACKCHARwhile((*eptr&0xc0)==0x80)eptr--;eptr€… ‰ É"áGETCHARLENc=*eptr;len=1;if(md->utf8&&(c&0xc0)==0xc0){int i;int a=utf8_table4[c&0x3f];int s=6*a;c=(c&utf8_table3[a])<utf8&&(c&0xc0)==0xc0){int a=utf8_table4[c&0x3f];int s=6*a;c=(c&utf8_table3[a])<0){s-=6;c|=(*eptr++&0x3f)< ? @ A B C D E F G H I J K L M N O Q R S T U V X Y Z [ \ ] ^ _ ` a b c d e f g h "!€ctype_xdigit0x08!!ctype_digit0x04"!~ctype_letter0x02!!}ctype_space0x01-!fmatch_datastruct match_data!fmatch_data# !xend_offset_topint€> ? @ A B C D E F G H I J K L M N O ,!wend_match_ptrconst uschar**!vstart_matchconst uschar**!uend_subjectconst uschar*,!tstart_subjectconst uschar*,!sstart_patternconst uschar*!rnotemptyBOOL!qendonlyBOOL!putf8BOOL!onoteolBOOL!nnotbolBOOL%!!moffset_overflowBOOL%!lctypesconst uschar*"!klccconst uschar*!joffset_maxint!ioffset_endint#!hoffset_vectorint*!gerrorcodeint1!\compile_datastruct compile_data!\compile_data%!`ctypesconst uschar*$!_cbitsconst uschar*€7 8 : ; "!^fccconst uschar*"!]lccconst uschar*7!!Sreal_pcre_extrastruct real_pcre_extra!!Sreal_pcre_extra€1 2 &!Ustart_bitsuschar[32]!Toptionsuschar+!Ereal_pcrestruct real_pcre!Ereal_pcre €$ % & ' ( ) + , - !Ncodeuschar[1] !Mreq_charuschar"!Lfirst_charuschar/!Ktop_backrefunsigned short int/!Jtop_bracketunsigned short int*!Ioptionsunsigned long int,!Htablesconst unsigned char*!Gsizesize_t/!Fmagic_numberunsigned long int%!@uscharunsigned char0!7ERR35"invalid condition (?(0)"J!6ERR34"character value in \\x{...} sequence is too large"V!5ERR33"characters with values > 255 are not yet supported in classes"T!4ERR32"this version of PCRE is not compiled with PCRE_UTF8 support"C!3ERR31"POSIX collating elements are not supported"1!2ERR30"unknown POSIX class name"2!1ERR29"(?p must be followed by )"5!0ERR28"assertion expected after (?("J!/ERR27"conditional group contains more than two branches"3!.ERR26"malformed number after (?("A!-ERR25"lookbehind assertion is not fixed length"9!,ERR24"unrecognized character after (?<"6!+ERR23"internal error: code overflow".!*ERR22"unmatched parentheses"-!)ERR21"failed to get memory"5!(ERR20"regular expression too large"6!'ERR19"parentheses nested too deeply"0!&ERR18"missing ) after comment"2!%ERR17"unknown option bit(s) set"1!$ERR16"erroffset passed as NULL"B!#ERR15"back reference to non-existent subpattern""!"ERR14"missing )"%!!ERR13"unused error"8! ERR12"unrecognized character after (?":!ERR11"internal error: unexpected repeat"Q!ERR10"operand of unlimited repeat could match the empty string")!ERR9"nothing to repeat"=!ERR8"range out of order in character class"B!ERR7"invalid escape sequence in character class"A!ERR6"missing terminating ] for character class"À0 ÿÿÿÿü‹Œ³¶?¤f¶é~? ÊH4É<wZÂ=÷'®ŽrMߺmJ'oݼ”ÆEï,švU߸Æj8ðܲX °{@ó¤p&ì¨z\=º !û à € ƒ % û Ç  ú Þ ^ ¿ ž ~ :? #  v ê Í ° “ ÿ W :  ˆ á à ¦ Xi K , –ãʼoRïÐâ s>ö"¼žK7ÑrW:Îé³'ìtest5void'§test4void';test3void'%test2void'test1void&' "vstrlib.h"&' _&Wpcre_studypcre_extra*const pcre*external_re,int options,const char**errorptrf &Vset_start_bitsBOOLconst uschar*code,uschar*start_bits,BOOL caseless,compile_data*cd€ƒÀ„À†À‡ÀS&;set_bitvoiduschar*start_bits,int c,BOOL caseless,compile_data*cd&&'"internal.h"&%Rregfreevoidregex_t*@%Qregerrorsize_tint,const regex_t*,char*,size_t4'€VÀWÀXÀYÀZÀ[À\À]À^À_À`ÀaÀbÀcÀdÀeÀfÀgÀhÀiÀjÀkÀlÀnÀoÀpÀrÀtÀuÀwÀxÀzÀ{À|À}À~ÀÀ€À‚ÀH%Pregexecintregex_t*,const char*,size_t,regmatch_t*,int5%Oregcompintregex_t*,const char*,int-%Hregmatch_tstruct regmatch_t%Hregmatch_t€zÀ{À%Jrm_eoregoff_t%Irm_soregoff_t€€&€w€# / 6 = R z 8À9ÀwÀxÀ~À%Fregoff_tint'%>regex_tstruct regex_t €Ìà  * 4 < Q ~ uÀ}À%>regex_t$%Are_erroffsetsize_t€\ÀrÀtÀ%@re_nsubsize_t%?re_pcrevoid*te€ j m n o p q r s t u v w x y z { | } ~  €  ‚ ƒ „ … † ‡ ˆ ‰ Š ‹ Œ  Ž   ‘ ’ “ ” • – — ˜ ™ š › œ  ž Ÿ   ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ­ ® ¯ ° ± ² }€€€€€‚€„€…€‡€Š€‹€Ž€€_À`ÀaÀbÀcÀdÀeÀfÀgÀhÀiÀjÀkÀlÀnÀoÀpÀ%8REG_NOMATCH17%7REG_INVARG16%6REG_ESUBREG15%5REG_ESPACE14%4REG_ESIZE13%3REG_ERANGE12%2REG_EPAREN11%1REG_EMPTY10%0REG_EESCAPE9%/REG_ECTYPE8%.REG_ECOLLATE7%-REG_EBRACK6%,REG_EBRACE5%+REG_BADRPT4%*REG_BADPAT3%)REG_BADBR2%(REG_ASSERT1%#REG_NOSUB0%"REG_EXTENDED0 %REG_NOTEOL0x08 %REG_NOTBOL0x04!%REG_NEWLINE0x02%REG_ICASE0x01&%%_PCREPOSIX_Hh$ãregexecintregex_t*preg,const char*string,size_t nmatch,regmatch_t pmatch[],int eflagsG$Äregcompintregex_t*preg,const char*pattern,int cflags €JÀKÀLÀMÀNÀOÀPÀQÀRÀSÀUÀ*$­regfreevoidregex_t*preg^$Šregerrorsize_tint errcode,const regex_t*preg,char*errbuf,size_t errbuf_size7'${pcre_posix_error_codeintconst char*s&$\pstringconst char*[]$4eintint[]&$.estringconst char*[]&$("stdlib.h"&$'"pcreposix.h"&$&"internal.h".#kpcre_versionconst char*voidD#jpcre_studypcre_extra*const pcre*,int,const char**:!#ipcre_maketablesconst unsigned char*voidJ#hpcre_fullinfointconst pcre*,const pcre_extra*,int,void*4#gpcre_infointconst pcre*,int*,int*O)#fpcre_get_substring_listintconst char*,int*,int,const char***M$#epcre_get_substringintconst char*,int*,int,int,const char**;*#dpcre_free_substring_listvoidconst char**5%#cpcre_free_substringvoidconst char*]#apcre_execintconst pcre*,const pcre_extra*,const char*,int,int,int,int*,intK%#`pcre_copy_substringintconst char*,int*,int,int,char*,intZ#^pcre_compilepcre*const char*,int,const char**,int*,const unsigned char*€ 7ÀB#Xpcre_freePCRE_DL_IMPORT void(*pcre_free)()void*42€ÀÀÀÀÀÀÀÀÀÀÀ À!À"À#À$À%À&À'À(À)À*À+À,À-À.À/À0À1À2À3À4À5À6À7À8À9À:À>À?À@ÀAÀBÀCÀDÀEÀFÀGÀHÀIÀ€‚ :ÀH#Wpcre_mallocPCRE_DL_IMPORT void*(*pcre_malloc)()size_t2#Qpcre_extrastruct real_pcre_extra&#Ppcrestruct real_pcre('#IPCRE_INFO_LASTLITERAL6'&#HPCRE_INFO_FIRSTTABLE5&%#GPCRE_INFO_FIRSTCHAR4'&#FPCRE_INFO_BACKREFMAX3)(#EPCRE_INFO_CAPTURECOUNT2! #DPCRE_INFO_SIZE1$##CPCRE_INFO_OPTIONS0,(#?PCRE_ERROR_NOSUBSTRING(-7))%#>PCRE_ERROR_NOMEMORY(-6)-)#=PCRE_ERROR_UNKNOWN_NODE(-5))%#<PCRE_ERROR_BADMAGIC(-4)*&#;PCRE_ERROR_BADOPTION(-3)%!#:PCRE_ERROR_NULL(-2)($#9PCRE_ERROR_NOMATCH(-1)!#5PCRE_UTF80x0800%#4PCRE_NOTEMPTY0x0400%#3PCRE_UNGREEDY0x0200##2PCRE_NOTEOL0x0100##1PCRE_NOTBOL0x0080"#0PCRE_EXTRA0x0040+%#/PCRE_DOLLAR_ENDONLY0x0020%#.PCRE_ANCHORED0x0010%#-PCRE_EXTENDED0x0008##,PCRE_DOTALL0x0004& #+PCRE_MULTILINE0x0002%#*PCRE_CASELESS0x0001&# #PCRE_DL_IMPORT€ÀÀÀ5 #PCRE_DL_IMPORT__declspec(dllimport) #PCRE_DL_IMPORT&#PCRE_DATE02-Jan-2002#PCRE_MINOR9# PCRE_MAJOR3#_PCRE_H¬"pcre_execintconst pcre*external_re,const pcre_extra*external_extra,const char*subject,int length,int start_offset,int options,int*offsets,int offsetcount"Š matchBOOLconst uschar*eptr,const uschar*ecode,int offset_top,match_data*md,unsigned long int ims,eptrblock*eptrb,int flagsk"L match_refBOOLint offset,const uschar*eptr,int length,match_data*md,unsigned long int imsD8€0 i j l m o p q s t u v w x y z { | ~   ‚ ƒ „ … † ‡ ‰ ‹  Ž   ‘ ’ “ ” • — ˜ ™ ÀÀÀÀÀ À À À À ÀÀÀÀÀÀ‚"­ pcre_compilepcre*const char*pattern,int options,const char**errorptr,int*erroroffset,const unsigned char*tablesA "l find_firstcharintconst uschar*code,int*options4"H is_startlineBOOLconst uschar*code?"$ is_anchoredBOOLconst uschar*code,int*optionsk("ãfirst_significant_codeconst uschar*const uschar*code,int*options,int optbit,BOOL optstopÍ"Ncompile_regexBOOLint options,int optchanged,int*brackets,uschar**codeptr,const uschar**ptrptr,const char**errorptr,BOOL lookbehind,int skipbytes,int*reqchar,int*countlits,compile_data*cd° "æcompile_branchBOOLint options,int*brackets,uschar**codeptr,const uschar**ptrptr,const char**errorptr,int*optchanged,int*reqchar,int*countlits,compile_data*cd>""Ácheck_posix_nameintconst uschar*ptr,int len^$"¡check_posix_syntaxBOOLconst uschar*ptr,const uschar**endptr,compile_data*cd=""úfind_fixedlengthintuschar*code,int optionsw$"Æread_repeat_countsconst uschar*const uschar*p,int*minp,int*maxp,const char**errorptr,compile_data*cdF#"¡is_counted_repeatBOOLconst uschar*p,compile_data*cdà0 ÿÿÿÿü+/—áÆ’w&øäɵj0õÆ¢(8ìéØÄx_K0ì´…/ÙÅeQ«—€1à>¢str_joinVStringVArray array,const char*glue ¶~VCharSet°VCharSet ü~VRegexpäVRegexp€/à`"†str_split_simpleVArrayconst char*delimiter_str,const char*source,int maxcount€-àVjstr_splitVArrayconst char*regexp_str,const char*source,int maxcountV!6str_find_regexpintconst char*target,const char*pattern,int startpos ”~VTrie‚VTrie8÷del_nodevoidconst char*key,int branch€#à ð~VTrieNode€!àèVTrieNode€à ê~VArrayÖVArray €ƒ„…  ààD1€RSTUVXYZ[\]^_`abcdefhijkmnprtvwxyz{ƒ„…  àààà(à-à/à1à€à€à€à€ààB(_file_crc32crc32_tconst char*fname,long buffsize8(Ffile_crc32crc32_tFILE*f,long buffsize€ à àààààà/(Astr_crc32crc32_tconst char*s;(9mem_crc32crc32_tconst void*buff,int sizeQ(4update_crc32crc32_tconst unsigned char octet,const crc32_t crc4(crc_32_tabconst unsigned long[256]€c  à&( "vsuti.h"€+à à.'wmainintint argc,char*argv[]Q'|PAT"MARINOW Uliqn P. prof. dtn kw.Wladaq ul.Witoshki granit 11"'[test8void €ˆÀ‰ÀŠÀ‹ÀŒÀÀÀàààà à':test7void'test6voidvfu-4.10/vslib/conmenu.cpp0000644000175000001440000002020311310550223014325 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * * SEE `README',LICENSE' OR COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: conmenu.cpp,v 1.11 2008/01/18 18:40:46 cade Exp $ * */ #include #include #include #include #include "conmenu.h" ConMenuInfo con_default_menu_info; int con_toggle_box( int x, int y, const char *title, ToggleEntry* toggles, ConMenuInfo *menu_info ) { ScrollPos scroll; int z; int w = -1; int h = -1; int maxlen = 0; int count = 0; while( toggles[count].key != -1 ) { int sl = strlen( toggles[count].name ); if (sl > maxlen) maxlen = sl; count++; } maxlen += 6+3; // 6 for state string and 3 for " key " string in the front if (w == -1) w = maxlen; if (h == -1) h = count; z = strlen(title); if (w < z) w = z; if (h > count) h = count; if (h == 0) h = 1; // FIXME: those should be fixed!!! if (x + w > con_max_x()) w = con_max_x() - x - 1; if (y + h > con_max_y()-4) h = con_max_y() - y - 5; VString str; VString str1; VString hots = ""; for(z = 0; z < count; z++) if (strncmp("--", toggles[z].name, 2)) str_add_ch( hots, toggles[z].key ); else str_add_ch( hots,' ' ); con_xy(x,y); int ch = 0; str = ""; str = title; str_pad( str,-w, menu_info->bo ? '-' : ' ' ); if (str_len(str) > w) str_sleft(str,w); if (menu_info->bo) str = ".-" + str + "-."; else str = " " + str + " "; con_out(x,y,str,menu_info->ti); y++; scroll.wrap = 1; scroll.set_min_max( 0, count-1 ); scroll.set_pagesize( h ); scroll.go( 0 ); while(1) { for( z = 0; z < scroll.pagesize(); z++ ) { if (scroll.page() + z >= count) { str = " ~"; str_pad( str, -(w+2), ' '); } else { int sep = (strncmp("--", toggles[scroll.page()+z].name, 2) == 0); if (sep) { str = ""; str += toggles[scroll.page()+z].name; str_pad( str, -w, '-'); str += "--"; } else { str = " "; str_add_ch( str, toggles[scroll.page()+z].key ); str += " "; str += toggles[scroll.page()+z].name; str_pad( str, -(w-6), ' '); str1 = toggles[scroll.page()+z].states[*(toggles[scroll.page()+z].data)]; str_pad( str1, 6, ' '); str1 += " "; str += " " + str1; } } if (menu_info->bo) str = "|" + str + "|"; else str = " " + str + " "; // if (str.len() > w) StrSLeft(str,w); // str = " " + str + " "; con_out( x, y+z, str, ( scroll.page()+z != scroll.pos() ) ? menu_info->cn : menu_info->ch ); } if (menu_info->bo) { str = ""; str_pad( str, w+2, '-' ); str = "`" + str + "'"; con_out( x, y+scroll.pagesize(), str, menu_info->cn ); } ch = con_getch(); menu_info->ec = ch; if ( ch == KEY_UP ) scroll.up(); if ( ch == KEY_DOWN ) scroll.down(); if ( ch == KEY_NPAGE ) scroll.npage(); if ( ch == KEY_PPAGE ) scroll.ppage(); if ( ch == KEY_HOME ) scroll.home(); if ( ch == KEY_END ) scroll.end(); if ( ch < 0 || ch > 255 ) continue; if ( ch == 27 ) return 0; if ( ch == 13 /* && strncmp("--", toggles[scroll.pos].name, 2) */ ) return 1; z = ( ch == ' ' ) ? scroll.pos() : str_find( hots, ch ); if (z > -1 && strncmp("--", toggles[z].name, 2) ) { int state = *(toggles[z].data) + 1; if (toggles[z].states[state] == NULL) state = 0; *(toggles[z].data) = state; } } return -1; } int con_menu_box( int x, int y, const char *title, VArray *va, int hotkeys, ConMenuInfo *menu_info ) { ScrollPos scroll; int z; int w = -1; int h = -1; if (w == -1) w = va->max_len(); if (h == -1) h = va->count(); z = strlen(title); if (w < z) w = z; if (h > va->count()) h = va->count(); if (h == 0) h = 1; // FIXME: those should be fixed!!! if (x + w > con_max_x()) w = con_max_x() - x - 4; if (y + h > con_max_y()-4) h = con_max_y() - y - 4; VString str; VString hots = ""; if ( hotkeys > -1 ) { for(z = 0; z < va->count(); z++) if (strncmp("--", va->get(z), 2)) str_add_ch( hots, char(((const char*)(va->get(z)))[hotkeys]) ); else str_add_ch( hots,' ' ); str_up(hots); } con_xy(x,y); int ch = 0; str = " "; str += title; str += " "; str_pad( str,-(w), menu_info->bo ? '-' : ' ' ); if (str_len(str) > w) str_sleft(str,w); if (menu_info->bo) str = ".-" + str + "-."; else str = " " + str + " "; con_out(x,y,str,menu_info->ti); y++; scroll.wrap = 1; scroll.set_min_max( 0, va->count()-1 ); scroll.set_pagesize( h ); scroll.go( 0 ); while(1) { for( z = 0; z < scroll.pagesize(); z++ ) { str = (scroll.page()+z >= va->count())? "~" : va->get(scroll.page()+z); if ( menu_info->hide_magic[0] ) { int i = str_rfind( str, menu_info->hide_magic ); if ( i != -1) str_sleft( str, i ); } str_pad( str,-w , (strncmp("--", str, 2) == 0)?'-':' '); if (str_len(str) > w) str = str_dot_reduce( str, w ); if (menu_info->bo) str = "| " + str + " |"; else str = " " + str + " "; con_out( x, y+z, str, ( scroll.page()+z != scroll.pos() ) ? menu_info->cn : menu_info->ch ); } if (menu_info->bo) { str = ""; str_pad( str, w+2, '-' ); str = "`" + str + "'"; con_out( x, y+scroll.pagesize(), str, menu_info->cn ); } ch = con_getch(); menu_info->ec = ch; if ( ch == KEY_UP ) scroll.up(); if ( ch == KEY_DOWN ) scroll.down(); if ( ch == KEY_NPAGE ) scroll.npage(); if ( ch == KEY_PPAGE ) scroll.ppage(); if ( ch == KEY_HOME ) scroll.home(); if ( ch == KEY_END ) scroll.end(); if ( ch < 0 || ch > 255 ) continue; if ( ch == 27 ) { menu_info->ac = 0; return -1; } if ( ch == 13 ) { if (strncmp("--", va->get(scroll.pos()), 2) != 0) // ako e "--" e separator { menu_info->ec = hots[scroll.pos()]; menu_info->ac = -1; return scroll.pos(); } } if ( menu_info->ac > -1 && ch == menu_info->ac ) { if (strncmp("--", va->get(scroll.pos()), 2) != 0) // ako e "--" e separator { menu_info->ec = hots[scroll.pos()]; menu_info->ac = -2; return scroll.pos(); } } z = str_find( hots, toupper(ch) ); if (z > -1) { menu_info->ec = hots[z]; menu_info->ac = -1; return z; } } menu_info->ac = -1; return -1; } int con_full_box( int x, int y, const char *title, VArray *va, ConMenuInfo *menu_info ) { ScrollPos scroll; scroll.wrap = 0; scroll.set_min_max( 0, va->count()-1 ); scroll.set_pagesize( con_max_y() - 3 ); /* one title and two status */ scroll.go( 0 ); char pos_str[32]; con_xy( 1, 1 ); con_puts( title, menu_info->ti ); con_ce( menu_info->ti ); while(4) { VString str; int z; for( z = 0; z < scroll.pagesize(); z++ ) { if ( scroll.page() + z < va->count() ) str = va->get( scroll.page() + z ); else str = "~"; str = str_dot_reduce( str, con_max_x()-1 ); con_xy( 1, z + 2 ); int c = ( scroll.page() + z == scroll.pos() ) ? menu_info->ch : menu_info->cn; con_puts( str, c ); con_ce( c ); } sprintf( pos_str, " %5d of %5d", scroll.pos()+1, scroll.max()+1 ); con_out( con_max_x() - 15, 1, pos_str, menu_info->ti ); int ch; switch( (ch = con_getch()) ) { case 27 : menu_info->ec = 27; return -1; break; case 13 : menu_info->ec = 13; return scroll.pos(); break; case KEY_UP : scroll.up(); break; case KEY_DOWN : scroll.down(); break; case KEY_NPAGE : scroll.npage(); break; case KEY_PPAGE : scroll.ppage(); break; case KEY_HOME : scroll.home(); break; case KEY_END : scroll.end(); break; default: if ( tolower(ch) == tolower(menu_info->ac) ) { menu_info->ec = menu_info->ac; return -2; } break; } } } vfu-4.10/vslib/test.cpp0000644000175000001440000002415511005727400013656 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: test.cpp,v 1.18 2008/01/18 18:40:46 cade Exp $ * */ #include #include "vstrlib.h" void test1() { VString str = "Hello"; str += " World"; // str is `Hello World' now str_reverse( str ); // str is `dlroW olleH' now str_low( str ); // lower case VArray va = str_split( " +", str ); // array contains `dlroW' at pos 0 and `olleH' at 1 va.reverse(); // array reversed: `dlroW' at pos 1 and `olleH' at 0 int z; for( z = 0; z < va.count(); z++ ) { str_reverse( va[z] ); // reverses each string element } str = str_join( va, " " ); // joins into temporary string printf( "************************ test 1 result is: %s\n", str.data() ); // this should print `hello world' } void test2() { VArray va; va.push( "hello" ); // pos 0 va.push( "world" ); // pos 1 va.ins( 1, "your" ); // pos 1 shifted va[1] = "my"; // replaces `your' va[3] = "!"; // set outside the size, array is extended VString str = va.pop(); // pops last element, str is now `!' str = str_join( va, "-" ); // joins to given string str_tr( str, "-", " " ); // replaces dashes with spaces str_replace( str, " my ", " " ); // removes ` my ' printf( "************************ test 2 result is: %s\n", str.data() ); // this should print `hello world' } void test3() { VTrie tr; // hash-like VArray va; // inserting keys and values tr[ "tralala" ] = "data1"; tr[ "opala" ] = "data2"; tr[ "keynext" ] = "data3"; // inserting elements into the array va.push( "this" ); va.push( "just" ); va.push( "test" ); va.push( "simple" ); // adding string to the first element of the array va[1] += " x2"; // the array is converted to trie (hash) and merged into `tr' tr += va; // same as: tr.merge( &va ); // clear the array--remove all elements va.undef(); // take keys from `tr' as array and store them into va, returns count // i.e. i = tr.count(); int i; va = tr.keys(); printf( "keys count = %d\n", va.count() ); // printing the array and trie data for( i = 0; i < va.count(); i++ ) { printf( "%d -> %s (%s)\n", i, va[i].data(), tr[ va[i] ].data() ); } VArray v1; printf( "--------------------\n" ); v1 = tr; // same as: v1.undef; v1.merge( &tr ); v1.print(); // print array data VRegexp re( "a([0-9]+)" ); // compiling new regexp if( re.m( "tralala85." ) ) // match against regexp printf( "sub 1 = %s\n", re[1].data() ); // re[1] returns `85' VString vs; if( re.m( "tralala85.", "(la)+" ) ) // match against regexp { printf( "sub 0 = %s\n", re[0].data() ); // `lala' printf( "sub 1 = %s\n", re[1].data() ); // `la' } printf( "--------------------\n" ); v1 = str_split( ",", "*.tralala,opala and another one" ); // splits on spaces v1.print(); printf( "joined: %s\n", (const char*)str_join( v1, "---" ) ); // join the same data back VString m1 = v1[0]; VString m2 = v1[1]; printf( "1[%s] 2[%s]\n", m1.data(), m2.data() ); printf( "--------------------\n" ); v1 = str_split( " +", "tralala opala and another one", 3 ); // splits data on spaces up to 3 elements v1.print(); printf( "--------------------\n" ); v1[1] = "hack this one here"; // set (overwrite) element 1 str_sleft( v1[2], 11 ); // reset element 2 to the left 11 chars only v1[0] = 12345; // convert integer into string v1.print(); printf( "--------------------\n" ); VArray aa[3]; // array of arrays aa[0] = str_split( " ", "this is just a simple test" ); aa[1] = str_split( " ", "never ending story" ); aa[2] = str_split( " ", "star-wars rulez" ); aa[0][1] = "was"; // first array, second element, replaces `is' with `was' aa[2][0] = "slackware"; // third array, first element, `star-wars' is now `slackware' // expands the array from 3 to 11 elements aa[1][10] = "king of the hill"; for( i = 0; i < 3; i++ ) { printf("---\n"); aa[i].print(); } printf( "---box test-----------------------------\n" ); i = 20; while( i-- ) { v1.push( "this" ); v1.push( "just" ); v1.push( "test" ); v1.push( "simple" ); } v1.print(); VArray vv = v1; // this makes vv data aliased to the data of v1 vv.print(); // actually print the v1's data which is shared right now vv.set( 0, "---" ); // vv makes own copy of the array data vv.print(); // vv's data is no more aliased to v1's VRegexp re_see( "^\\s*see\\s*=\\s*([^, \011]*)\\s*,(.*)$", "i" ); if( re_see.m( "see=*.tgz,tralala" ) ) { VString str; str = str + re_see[1] + re_see[2]; printf( "VRegexp[1+2]=[%s]\n", str.data() ); } printf( "************************ test 3 ends here\n" ); } void test4() { // this is regression test, please ignore it... int i; int ii; VArray va; ii = 20; i = ii; while( i-- ) { va = str_split( ",", "this is, just a simple. but fixed, nonsense test, voila :)" ); printf( "%d%% va count = %d\n", (100*i)/ii, va.count() ); } VString set; VString cat; VString setn; VString catn; VString sete; VString setp; i = 2000; while( i-- ) { set.set( "this is, just a simple. but fixed, nonsense test, voila :)" ); cat.cat( "this is, just a simple. but fixed, nonsense test, voila :)" ); setn.setn( "this is, just a simple. but fixed, nonsense test, voila :)", 20 ); catn.catn( "this is, just a simple. but fixed, nonsense test, voila :)", 20 ); sete = "this is, just a simple. but fixed, nonsense test, voila :)"; setp += "this is, just a simple. but fixed, nonsense test, voila :)"; } printf( "set = %d\n", str_len( set ) ); printf( "cat = %d\n", str_len( cat ) ); printf( "setn = %d\n", str_len( setn ) ); printf( "catn = %d\n", str_len( catn ) ); printf( "sete = %d\n", str_len( sete ) ); printf( "setp = %d\n", str_len( setp ) ); printf( "--------------------\n" ); i = 2000; while( i-- ) { set = "this is, just a simple. but fixed, nonsense test, voila :)"; setn = set; str_del( set, 20, 10 ); str_ins( set, 30, "***opa***" ); str_replace( setn, "i", "[I]" ); } printf( "set = %s\n", set.data() ); printf( "setn = %s\n", setn.data() ); printf( "---array sort-------\n" ); va.undef(); va = str_split( "[, \t]+", "this is, just a simple. but fixed, nonsense test, voila :)" ); va.sort(); va.print(); printf( "--------------------\n" ); va.sort( 1 ); va.print(); printf( "--------------------\n" ); } void test5() { VTrie tr; // hash-like VArray va; // inserting keys and values tr[ "key1" ] = "data1"; tr[ "key2" ] = "data2"; tr[ "key3" ] = "data3"; tr.print(); tr.reverse(); tr.print(); tr.reverse(); tr.print(); VCharSet cs; cs.push( 'a' ); printf( "char_set: %d, %d\n", cs.in( 'a' ), cs.in( 'z' ) ); cs.undef( 'a' ); printf( "char_set: %d, %d\n", cs.in( 'a' ), cs.in( 'z' ) ); cs.undef(); int i = 2000; while( i-- ) { cs.push( i ); } cs.undef(); printf( "************************ test 5 ends here\n" ); } void test6() { VRegexp re; VArray va; re.comp( "^([^!]+)!(.+)=apquxz(.+)$" ); int i = re.m( "abc!pqr=apquxz.ixr.zzz.ac.uk" ); i--; while( i >= 0 ) { va.push( re[i] ); i--; } va.print(); va.undef(); va += "/this/is/samle/file.tail"; va += "/file.tail"; va += "/this/is/./samle/file.tail/"; va += "/this/..../is/../samle/.file.tail"; va += "/.file.tail"; va += "/"; const char* ps; va.reset(); while( ( ps = va.next() ) ) { printf( "------------------------------------\n" ); printf( "file is: %s\n", ps ); printf( "path is: %s\n", (const char*)str_file_path( ps ) ); printf( "name is: %s\n", (const char*)str_file_name( ps ) ); printf( "ext is: %s\n", (const char*)str_file_ext( ps ) ); printf( "n+ex is: %s\n", (const char*)str_file_name_ext( ps ) ); printf( "reduced path is: %s\n", (const char*)str_reduce_path( ps ) ); printf( "dot reduce sample is: %s\n", (const char*)str_dot_reduce( ps, 10 ) ); } va.fsave( "/tmp/a.aaa" ); va.fload( "/tmp/a.aaa" ); va.print(); } void test7() { VTrie tr; // hash-like VTrie tr2; // hash-like VArray va; // inserting keys and values tr[ "key1" ] = "data1"; tr[ "key2" ] = "data2"; tr[ "key3" ] = "data3"; tr.print(); printf( "---------------------------------1---\n" ); tr.reverse(); tr.print(); printf( "---------------------------------2---\n" ); tr.reverse(); tr.print(); printf( "---------------------------------3---\n" ); tr2 = str_split( " ", "this is simple one way test" ); tr2.print(); printf( "---------------------------------4---\n" ); tr2 += tr; tr2.print(); printf( "---------------------------------5---\n" ); va = tr2; va.print(); printf( "---------------------------------6---\n" ); } void test8() { VString v1; VString v2; v1 = "this is simple test "; v1 *= 1024; printf( "v1 len: %d\n", str_len( v1 ) ); v2.compact( 1 ); // makes v2 compact, i.e. it will get as much memory as it // needs. otherwise it will get fixed amount of blocks v2 = v1; // data is shared between v1 and v2. any change to v1 or v2 will // detach this data and both will get own copy v2[0] = ' '; // this will create own data for v2 str_tr( v2, "ti", "TI" ); // capitalize T and I v2 = ""; // this will free all data allocated by v2 printf( "copy 7,6: [%s]", (const char*)str_copy( v2, v1, 8, 6 ) ); printf( "copy 10: [%s]", (const char*)str_copy( v2, v1, -10 ) ); printf( "************************ test 5 ends here\n" ); } int main( int argc, char* argv[] ) { //#define PAT "9892009" #define PAT "MARINOW Uliqn P. prof. dtn kw.Wladaq ul.Witoshki granit 11" //#define PAT "marinow uliqn p. prof. dtn kw.wladaq ul.witoshki granit 11" printf( "found at pos %ld\n", file_pattern_search( PAT, strlen(PAT), "/tmp/ss.txt", "", mem_quick_search ) ); //printf( "expand=[%s]\n", (const char*)tilde_expand( "~root/" ) ); /**/ test1(); test2(); test3(); test4(); test5(); test6(); test7(); //*/ return 0; } vfu-4.10/vslib/makefile0000644000175000001440000001605711172614226013703 0ustar cadeusers ### MAKEMAKE STARTS HERE ####################################################### ### Created by makemake.pl on Wed Dec 29 04:46:52 2004 ######################### ### GLOBAL TARGETS ############################################################# default: all re: rebuild li: link all: modules libvslib.a libvscon.a test clean: clean-modules clean-libvslib.a clean-libvscon.a clean-test rebuild: rebuild-modules rebuild-libvslib.a rebuild-libvscon.a rebuild-test link: link-modules link-libvslib.a link-libvscon.a link-test ### GLOBAL (AND USER) DEFS ##################################################### AR = ar rv CC = g++ LD = g++ MKDIR = mkdir -p RANLIB = ranlib RMDIR = rm -rf RMFILE = rm -f SRC = *.c *.cpp *.cc *.cxx ### TARGET 1: libvslib.a ####################################################### CC_1 = g++ LD_1 = g++ AR_1 = ar rv RANLIB_1 = ranlib CCFLAGS_1 = -I. -O2 $(CCDEF) LDFLAGS_1 = $(LDDEF) DEPFLAGS_1 = ARFLAGS_1 = TARGET_1 = libvslib.a ### SOURCES FOR TARGET 1: libvslib.a ########################################### SRC_1= \ clusters.cpp \ dlog.cpp \ eval.cpp \ fnmatch2.cpp \ getopt2.cpp \ scroll.cpp \ vslib.cpp \ vstring.cpp \ vstrlib.cpp \ vsuti.cpp \ vscrc.cpp \ #### OBJECTS FOR TARGET 1: libvslib.a ########################################## OBJ_1= \ .OBJ.libvslib.a/clusters.o \ .OBJ.libvslib.a/dlog.o \ .OBJ.libvslib.a/eval.o \ .OBJ.libvslib.a/fnmatch2.o \ .OBJ.libvslib.a/getopt2.o \ .OBJ.libvslib.a/scroll.o \ .OBJ.libvslib.a/vslib.o \ .OBJ.libvslib.a/vstring.o \ .OBJ.libvslib.a/vstrlib.o \ .OBJ.libvslib.a/vsuti.o \ .OBJ.libvslib.a/vscrc.o \ ### TARGET DEFINITION FOR TARGET 1: libvslib.a ################################# .OBJ.libvslib.a: $(MKDIR) .OBJ.libvslib.a libvslib.a: .OBJ.libvslib.a $(OBJ_1) $(AR_1) $(ARFLAGS_1) $(TARGET_1) $(OBJ_1) $(RANLIB_1) $(TARGET_1) clean-libvslib.a: $(RMFILE) $(TARGET_1) $(RMDIR) .OBJ.libvslib.a rebuild-libvslib.a: clean-libvslib.a libvslib.a link-libvslib.a: .OBJ.libvslib.a $(OBJ_1) $(RMFILE) libvslib.a $(AR_1) $(ARFLAGS_1) $(TARGET_1) $(OBJ_1) $(RANLIB_1) $(TARGET_1) ### TARGET OBJECTS FOR TARGET 1: libvslib.a #################################### .OBJ.libvslib.a/clusters.o: clusters.cpp clusters.cpp clusters.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c clusters.cpp -o .OBJ.libvslib.a/clusters.o .OBJ.libvslib.a/dlog.o: dlog.cpp dlog.cpp dlog.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c dlog.cpp -o .OBJ.libvslib.a/dlog.o .OBJ.libvslib.a/eval.o: eval.cpp eval.cpp eval.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c eval.cpp -o .OBJ.libvslib.a/eval.o .OBJ.libvslib.a/fnmatch2.o: fnmatch2.cpp fnmatch2.cpp fnmatch2.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c fnmatch2.cpp -o .OBJ.libvslib.a/fnmatch2.o .OBJ.libvslib.a/getopt2.o: getopt2.cpp getopt2.cpp getopt2.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c getopt2.cpp -o .OBJ.libvslib.a/getopt2.o .OBJ.libvslib.a/scroll.o: scroll.cpp scroll.cpp scroll.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c scroll.cpp -o .OBJ.libvslib.a/scroll.o .OBJ.libvslib.a/vslib.o: vslib.cpp vslib.cpp $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c vslib.cpp -o .OBJ.libvslib.a/vslib.o .OBJ.libvslib.a/vstring.o: vstring.cpp vstring.cpp vstring.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c vstring.cpp -o .OBJ.libvslib.a/vstring.o .OBJ.libvslib.a/vstrlib.o: vstrlib.cpp vstrlib.cpp vstrlib.h vstring.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c vstrlib.cpp -o .OBJ.libvslib.a/vstrlib.o .OBJ.libvslib.a/vsuti.o: vsuti.cpp vsuti.cpp vsuti.h target.h vstring.h vstrlib.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c vsuti.cpp -o .OBJ.libvslib.a/vsuti.o .OBJ.libvslib.a/vscrc.o: vscrc.cpp vscrc.cpp vsuti.h target.h vstring.h $(CC_1) $(CFLAGS_1) $(CCFLAGS_1) -c vscrc.cpp -o .OBJ.libvslib.a/vscrc.o ### TARGET 2: libvscon.a ####################################################### CC_2 = g++ LD_2 = g++ AR_2 = ar rv RANLIB_2 = ranlib CCFLAGS_2 = -I. -I/usr/include/ncurses -O2 $(CCDEF) LDFLAGS_2 = $(LDDEF) DEPFLAGS_2 = ARFLAGS_2 = TARGET_2 = libvscon.a ### SOURCES FOR TARGET 2: libvscon.a ########################################### SRC_2= \ ansiterm.cpp \ conmenu.cpp \ form_in.cpp \ unicon.cpp \ #### OBJECTS FOR TARGET 2: libvscon.a ########################################## OBJ_2= \ .OBJ.libvscon.a/ansiterm.o \ .OBJ.libvscon.a/conmenu.o \ .OBJ.libvscon.a/form_in.o \ .OBJ.libvscon.a/unicon.o \ ### TARGET DEFINITION FOR TARGET 2: libvscon.a ################################# .OBJ.libvscon.a: $(MKDIR) .OBJ.libvscon.a libvscon.a: .OBJ.libvscon.a $(OBJ_2) $(AR_2) $(ARFLAGS_2) $(TARGET_2) $(OBJ_2) $(RANLIB_2) $(TARGET_2) clean-libvscon.a: $(RMFILE) $(TARGET_2) $(RMDIR) .OBJ.libvscon.a rebuild-libvscon.a: clean-libvscon.a libvscon.a link-libvscon.a: .OBJ.libvscon.a $(OBJ_2) $(RMFILE) libvscon.a $(AR_2) $(ARFLAGS_2) $(TARGET_2) $(OBJ_2) $(RANLIB_2) $(TARGET_2) ### TARGET OBJECTS FOR TARGET 2: libvscon.a #################################### .OBJ.libvscon.a/ansiterm.o: ansiterm.cpp ansiterm.cpp ansiterm.h $(CC_2) $(CFLAGS_2) $(CCFLAGS_2) -c ansiterm.cpp -o .OBJ.libvscon.a/ansiterm.o .OBJ.libvscon.a/conmenu.o: conmenu.cpp conmenu.cpp conmenu.h $(CC_2) $(CFLAGS_2) $(CCFLAGS_2) -c conmenu.cpp -o .OBJ.libvscon.a/conmenu.o .OBJ.libvscon.a/form_in.o: form_in.cpp form_in.cpp form_in.h unicon.h target.h vstring.h clusters.h \ scroll.h $(CC_2) $(CFLAGS_2) $(CCFLAGS_2) -c form_in.cpp -o .OBJ.libvscon.a/form_in.o .OBJ.libvscon.a/unicon.o: unicon.cpp unicon.cpp unicon.h target.h $(CC_2) $(CFLAGS_2) $(CCFLAGS_2) -c unicon.cpp -o .OBJ.libvscon.a/unicon.o ### TARGET 3: test ############################################################# CC_3 = g++ LD_3 = g++ AR_3 = ar rv RANLIB_3 = ranlib CCFLAGS_3 = -g -I. $(CCDEF) -DTEST LDFLAGS_3 = -g -L. -lvslib -lvscon -lpcre -lncurses $(LDDEF) DEPFLAGS_3 = ARFLAGS_3 = TARGET_3 = test ### SOURCES FOR TARGET 3: test ################################################# SRC_3= \ test.cpp \ #### OBJECTS FOR TARGET 3: test ################################################ OBJ_3= \ .OBJ.test/test.o \ ### TARGET DEFINITION FOR TARGET 3: test ####################################### .OBJ.test: $(MKDIR) .OBJ.test test: libvslib.a .OBJ.test $(OBJ_3) $(LD_3) $(OBJ_3) $(LDFLAGS_3) -o $(TARGET_3) clean-test: $(RMFILE) $(TARGET_3) $(RMDIR) .OBJ.test rebuild-test: clean-test test link-test: .OBJ.test $(OBJ_3) $(RMFILE) test $(LD_3) $(OBJ_3) $(LDFLAGS_3) -o $(TARGET_3) ### TARGET OBJECTS FOR TARGET 3: test ########################################## .OBJ.test/test.o: test.cpp test.cpp vstrlib.h vstring.h $(CC_3) $(CFLAGS_3) $(CCFLAGS_3) -c test.cpp -o .OBJ.test/test.o ### MODULES #################################################################### modules: true clean-modules: true rebuild-modules: true link-modules: true ### MAKEMAKE ENDS HERE ######################################################### vfu-4.10/vslib/mm.conf0000644000175000001440000000203011172614300013436 0ustar cadeusers# # this file is used to create full-featured vslib incl. unicon features # # $Id: mm.conf,v 1.10 2003/05/06 10:57:01 cade Exp $ # CC = g++ LD = g++ ############################################################################ # make vslib (general features that coul'd be used in any context) [libvslib.a] CCFLAGS = -I. -O2 $(CCDEF) LDFLAGS = $(LDDEF) SRC = clusters.cpp dlog.cpp eval.cpp fnmatch2.cpp getopt2.cpp SRC += scroll.cpp vslib.cpp vstring.cpp vstrlib.cpp vsuti.cpp vscrc.cpp ############################################################################ # make vscon library that provides unified console handling for multiple # platforms [libvscon.a] CCFLAGS = -I. -I/usr/include/ncurses -O2 $(CCDEF) LDFLAGS = $(LDDEF) SRC = ansiterm.cpp conmenu.cpp form_in.cpp unicon.cpp ############################################################################ # make test program [test] CCFLAGS = -g -I. $(CCDEF) -DTEST LDFLAGS = -g -L. -lvslib -lvscon -lpcre -lncurses $(LDDEF) DEPS = libvslib.a SRC = test.cpp vfu-4.10/vslib/fnmatch2.h0000644000175000001440000000364311005727400014045 0ustar cadeusers/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. NOTE: The canonical source of this file is maintained with the GNU C Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _FNMATCH_H #define _FNMATCH_H 1 /* We #undef these before defining them because some losing systems (HP-UX A.08.07 for example) define these in . */ #undef FNM_PATHNAME #undef FNM_NOESCAPE #undef FNM_PERIOD /* Bits set in the FLAGS argument to `fnmatch'. */ #define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */ #define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */ #define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */ // #if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_GNU_SOURCE) #define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ #define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ #define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ // #endif /* Value returned by `fnmatch' if STRING does not match PATTERN. */ #define FNM_NOMATCH 1 /* Match STRING against the filename pattern PATTERN, returning zero if it matches, FNM_NOMATCH if not. */ int fnmatch(const char *__pattern, const char *__string, int __flags); #endif /* fnmatch.h */ vfu-4.10/vslib/scroll.h0000644000175000001440000000317611005727400013642 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: scroll.h,v 1.5 2003/02/08 02:48:50 cade Exp $ * */ #ifndef _SCROLL_H_ #define _SCROLL_H_ class ScrollPos { int _min; int _max; int _pos; int _page; int _pagesize; int _pagestep; // step to change page on up/down out of the current page int _size; void fix(); int check(); public: int wrap; // 0 -- none, else -- wrap end/begin; NOTE: works only on up/down ScrollPos() { wrap = _min = _max = _pos = _page = _pagesize = _size = 0; _pagestep = 1; }; void set_min_max( int a_min, int a_max ) { _min = a_min; _max = a_max; _size = _max - _min + 1; } void set_pos( int a_pos ) { _pos = a_pos; } void set_page( int a_page ) { _page = a_page; } void set_pagesize( int a_pagesize ) { _pagesize = a_pagesize; if ( _pagesize < 0 ) _pagesize = 0; } void set_pagestep( int a_pagestep ) { _pagestep = a_pagestep; if ( _pagestep < 1 ) _pagestep = 1; } int min() { return _min; } int max() { return _max; } int pos() { if ( ! _size ) return 0; return _pos; } int page() { if ( ! _size ) return 0; return _page; } int pagesize() { return _pagesize; } int step() { return _pagestep; } void home(); void end(); void up(); void down(); void pageup(); void pagedown(); void ppage() { pageup(); } void npage() { pagedown(); } void go( int new_pos ); }; #endif //_SCROLL_H_ // eof scroll.h vfu-4.10/vslib/vstring.cpp0000644000175000001440000012056211312244766014404 0ustar cadeusers/* * * VSTRING Library * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * Distributed under the GPL license, you should receive copy of GPL! * * SEE vstring.h FOR FURTHER INFORMATION AND CREDITS * * $Id: vstring.cpp,v 1.26 2008/01/18 18:40:46 cade Exp $ * * This file (vstring.h and vstring.cpp) implements plain string-only * manipulations. For further functionality see vstrlib.h and vstrlib.cpp. * */ #include #include #include #include #include #include #include "vstring.h" #ifndef _HAVE_ITOA_ #define itoa(n,s,r) sprintf(s,"%d",n) #endif /**************************************************************************** ** ** VSTRING BOX ** ****************************************************************************/ VStringBox* VStringBox::clone() { VStringBox* box = new VStringBox(); box->resize_buf( size ); box->sl = sl; box->compact = compact; memcpy( box->s, s, size ); return box; } void VStringBox::resize_buf( int new_size ) { /* FIXME: this breaks a lot of things: ==, strcmp, const char*, ... if ( new_size == 0 ) { sl = 0; if ( s ) free( s ); s = NULL; size = 0; return; } */ new_size++; /* for the trailing 0 */ if ( !compact ) { new_size = new_size / STR_BLOCK_SIZE + ( new_size % STR_BLOCK_SIZE != 0 ); new_size *= STR_BLOCK_SIZE; } if( s == NULL ) { /* first time alloc */ s = (char*)malloc( new_size ); ASSERT( s ); s[ 0 ] = 0; size = new_size; sl = 0; } else if ( size != new_size ) { /* expand/shrink */ s = (char*)realloc( s, new_size ); size = new_size; s[ size - 1 ] = 0; if ( sl > size - 1 ) sl = size - 1; } } /**************************************************************************** ** ** VSTRING ** ****************************************************************************/ void VString::detach() { if ( box->refs() == 1 ) return; VStringBox *new_box = box->clone(); box->unref(); box = new_box; } void VString::i( const int n ) { char tmp[64]; itoa( n, tmp, 10 ); set( tmp ); } void VString::l( const long n ) { char tmp[64]; sprintf( tmp, "%ld", n ); set( tmp ); } void VString::f( const double d ) { char tmp[64]; sprintf( tmp, "%.10f", d ); int z = strlen( tmp ); while( tmp[z-1] == '0' ) z--; if ( tmp[z-1] == '.' ) z--; tmp[z] = 0; set( tmp ); } void VString::fi( const double d ) // sets double as int (w/o frac) { char tmp[64]; sprintf( tmp, "%.0f", d ); int z = strlen( tmp ); tmp[z] = 0; set( tmp ); } void VString::set( const char* ps ) { if (ps == NULL || ps[0] == 0) { resize( 0 ); ASSERT( box->s ); box->sl = 0; box->s[ 0 ] = 0; } else { int sl = strlen(ps); resize( sl ); memcpy( box->s, ps, sl ); box->sl = sl; box->s[sl] = 0; } } void VString::cat( const char* ps ) { if (ps == NULL) return; if (ps[0] == 0) return; int psl = strlen( ps ); resize( box->sl + psl ); memcpy( box->s + box->sl, ps, psl ); box->s[ box->sl + psl ] = 0; box->sl += psl; } void VString::setn( const char* ps, int len ) { if ( !ps || len < 1 ) { resize( 0 ); box->sl = 0; box->s[ 0 ] = 0; return; } int z = strlen( ps ); if ( len < z ) z = len; resize( z ); box->sl = z; memcpy( box->s, ps, z ); box->s[z] = 0; } void VString::catn( const char* ps, int len ) { if ( !ps || len < 1 ) return; int z = strlen( ps ); if ( len < z ) z = len; resize( box->sl + z ); memcpy( box->s + box->sl, ps, z ); box->sl += z; box->s[ box->sl ] = 0; } /**************************************************************************** ** ** VString Functions (for class VString) ** ****************************************************************************/ VString &str_mul( VString &target, int n ) // multiplies the VString n times, i.e. `1'*5 = `11111' { target.resize( target.box->sl * n ); str_mul( target.box->s, n ); target.fix(); return target; } VString &str_del( VString &target, int pos, int len ) // deletes `len' chars starting from `pos' { if ( pos > target.box->sl || pos < 0 ) return target; target.detach(); str_del( target.box->s, pos, len ); target.fix(); return target; } VString &str_ins( VString &target, int pos, const char* s ) // inserts `s' in position `pos' { if ( pos > target.box->sl || pos < 0 ) return target; target.resize( target.box->sl + strlen(s) ); str_ins( target.box->s, pos, s ); target.fixlen(); return target; } VString &str_ins_ch( VString &target, int pos, char ch ) // inserts `ch' in position `pos' { if ( pos > target.box->sl || pos < 0 ) return target; target.resize( target.box->sl + 1 ); str_ins_ch( target.box->s, pos, ch ); target.fixlen(); return target; } VString &str_replace( VString &target, const char* out, const char* in ) // replace `out' w. `in' { int outl = strlen( out ); int inl = strlen( in ); int z = str_find( target, out ); while(z != -1) { str_del( target, z, outl ); str_ins( target, z, in ); z = str_find( target, out, z + inl ); } ASSERT(target.check()); return target; } VString &str_copy( VString &target, const char* source, int pos, int len ) // returns `len' chars from `pos' { //FIXME: too many strlen()'s... if ( pos < 0 ) { pos = str_len( source ) + pos; if ( pos < 0 ) pos = 0; } if ( len == -1 ) len = str_len( source ) - pos; if ( len < 1 ) { target = ""; return target; } target.resize( len ); str_copy( target.box->s, source, pos, len ); target.fix(); ASSERT( target.check() ); return target; } VString &str_left( VString &target, const char* source, int len ) // returns `len' chars from the left { return str_copy( target, source, 0, len ); } VString &str_right( VString &target, const char* source, int len ) // returns `len' chars from the right { return str_copy( target, source, strlen( source ) - len, len ); } VString &str_sleft( VString &target, int len ) // SelfLeft -- just as 'Left' but works on `this' { if ( len < target.box->sl ) { target.detach(); target.box->s[len] = 0; target.fix(); } return target; } VString &str_sright( VString &target, int len ) // SelfRight -- just as 'Right' but works on `this' { target.detach(); str_sright( target.box->s, len ); target.fix(); return target; } VString &str_trim_left( VString &target, int len ) // trims `len' chars from the beginning (left) { target.detach(); str_trim_left( target.box->s, len ); target.fix(); return target; } VString &str_trim_right( VString &target, int len ) // trim `len' chars from the end (right) { target.detach(); str_trim_right( target.box->s, len ); target.fix(); return target; } VString &str_cut_left( VString &target, const char* charlist ) // remove all chars `charlist' from the beginning (i.e. from the left) { target.detach(); str_cut_left( target.box->s, charlist ); target.fix(); return target; } VString &str_cut_right( VString &target, const char* charlist ) // remove all chars `charlist' from the end (i.e. from the right) { target.detach(); str_cut_right( target.box->s, charlist ); target.fix(); return target; } VString &str_cut( VString &target, const char* charlist ) // does `CutR(charlist);CutL(charlist);' { target.detach(); str_cut_left( target.box->s, charlist ); str_cut_right( target.box->s, charlist ); target.fix(); return target; } VString &str_cut_spc( VString &target ) // does `Cut(" ");' { return str_cut( target, " " ); } VString &str_pad( VString &target, int len, char ch ) { target.resize( (len > 0) ? len : -len ); str_pad( target.box->s, len, ch ); target.fixlen(); return target; } VString &str_comma( VString &target, char delim ) { int new_size = str_len( target ) / 3 + str_len( target ); target.resize( new_size ); str_comma( target.box->s, delim ); target.fix(); return target; } void str_set_ch( VString &target, int pos, const char ch ) // sets `ch' char at position `pos' { if ( pos < 0 ) pos = target.box->sl + pos; if ( pos < 0 || pos >= target.box->sl ) return; if (target.box->s[pos] != ch) target.detach(); target.box->s[pos] = ch; } char str_get_ch( VString &target, int pos ) // return char at position `pos' { if ( pos < 0 ) pos = target.box->sl + pos; if ( pos < 0 || pos >= target.box->sl ) return 0; return target.box->s[pos]; } void str_add_ch( VString &target, const char ch ) // adds `ch' at the end { int sl = target.box->sl; target.resize( sl+1 ); target.box->s[sl] = ch; target.box->s[sl+1] = 0; target.fix(); } char* str_word( VString &target, const char* delimiters, char* result ) { target.detach(); str_word( target.box->s, delimiters, result ); target.fix(); return result[0] ? result : NULL; } char* str_rword( VString &target, const char* delimiters, char* result ) { target.detach(); str_rword( target.box->s, delimiters, result ); target.fix(); return result; } int sprintf( int init_size, VString &target, const char *format, ... ) { char *tmp = new char[init_size]; va_list vlist; va_start( vlist, format ); int res = vsnprintf( tmp, init_size, format, vlist ); va_end( vlist ); target = tmp; delete [] tmp; return res; } int sprintf( VString &target, const char *format, ... ) { #define VSPRINTF_BUF_SIZE 1024 char tmp[VSPRINTF_BUF_SIZE]; va_list vlist; va_start( vlist, format ); int res = vsnprintf( tmp, VSPRINTF_BUF_SIZE, format, vlist ); va_end( vlist ); target = tmp; return res; } VString& str_tr ( VString& target, const char *from, const char *to ) { target.detach(); str_tr( target.box->s, from, to ); return target; } VString& str_up ( VString& target ) { target.detach(); str_up( target.box->s ); return target; } VString& str_low( VString& target ) { target.detach(); str_low( target.box->s ); return target; } VString& str_flip_case( VString& target ) { target.detach(); str_flip_case( target.box->s ); return target; } VString& str_reverse( VString& target ) { target.detach(); str_reverse( target.box->s ); return target; } VString &str_squeeze( VString &target, const char* sq_chars ) // squeeze repeating chars to one only { target.detach(); str_squeeze( target.box->s, sq_chars ); target.fix(); return target; } /**************************************************************************** ** ** VString Functions (for char*) ** ****************************************************************************/ char* str_mul( char* target, int n ) // multiplies the VString n times, i.e. `1'*5 = `11111' { if ( n < 0 ) return target; if ( n == 0 ) { target[0] = 0; return target; } int sl = strlen( target ); int z = (n - 1) * sl; while( z > 0 ) { strncpy( target + z, target, sl ); z -= sl; } target[sl*n] = 0; return target; } int str_find( const char* target, int c, int startpos ) // returns first zero-based position of char, or -1 if not found { if (startpos < 0) return -1; int sl = strlen( target ); if (startpos >= sl) return -1; const char* pc = strchr( target + startpos, c ); if( ! pc ) return -1; return pc - target; } int str_rfind( const char* target, int c ) // returns last zero-based position of char, or -1 if not found { const char* pc = strrchr( target, c ); if( ! pc ) return -1; return pc - target; } int str_find( const char* target, const char* s, int startpos ) // returns first zero-based position of VString, or -1 if not found { if (startpos < 0) return -1; int sl = strlen( target ); if (startpos >= sl) return -1; const char* pc = strstr( target + startpos, s ); if( ! pc ) return -1; return pc - target; } int str_rfind( const char* target, const char* s ) // returns last zero-based position of VString, or -1 if not found { int sl = strlen( target ); int sls = strlen( s ); int z = sl - sls; while ( z > 0 ) { if ( strncmp( target + z, s, sls ) == 0 ) return z; z--; } return -1; } char* str_del( char* target, int pos, int len ) // deletes `len' chars starting from `pos' { int sl = strlen( target ); if ( pos > sl || pos < 0 ) return target; int z = sl-pos-len; if ( pos + len < sl ) strncpy(target+pos, target+pos+len, z+1); else target[pos] = 0; return target; } char* str_ins( char* target, int pos, const char* s ) // inserts `s' in position `pos' { int sl = strlen( target ); if ( pos > sl || pos < 0 ) return target; int sls = strlen( s ); if ( sls < 1 ) return target; int z = sl - pos; target[pos + z + sls] = 0; while(z) { target[pos + z + sls - 1] = target[pos + z - 1]; z--; } for(z = 0; z < sls; z++) target[pos+z] = s[z]; return target; } char* str_ins_ch( char* target, int pos, char ch ) // inserts `ch' in position `pos' { char tmp[2]; tmp[0] = ch; tmp[1] = 0; str_ins( target, pos, tmp ); return target; } char* str_replace( char* target, const char* out, const char* in ) // replace `out' w. `in' { int outl = strlen( out ); int inl = strlen( in ); int z = str_find( target, out ); while(z != -1) { str_del( target, z, outl ); str_ins( target, z, in ); z = str_find( target, out, z + inl ); } return target; } char* str_copy( char* target, const char* source, int pos, int len ) // returns `len' chars from `pos' { target[0] = 0; int sl = str_len( source ); if ( pos < 0 ) { pos = sl + pos; if ( pos < 0 ) pos = 0; } if ( pos < 0 || pos >= sl ) return target; if ( len == -1 ) len = sl - pos; if ( len < 1 ) return target; if ( pos + len >= sl ) len = sl - pos; strncpy( target, source + pos, len ); target[ len ] = 0; return target; } char* str_left( char* target, const char* source, int len ) // returns `len' chars from the left { return str_copy( target, source, 0, len ); } char* str_right( char* target, const char* source, int len ) // returns `len' chars from the right { return str_copy( target, source, strlen(source) - len, len ); } char* str_sleft( char* target, int len ) // SelfLeft -- just as 'Left' but works on `this' { if ( (size_t)len < strlen(target) ) target[len] = 0; return target; } char* str_sright( char* target, int len ) // SelfRight -- just as 'Right' but works on `this' { int sl = strlen( target ); if ( len < sl ) { strcpy( target, target + ( sl - len )); target[len] = 0; } return target; } char* str_trim_left( char* target, int len ) // trims `len' chars from the beginning (left) { int s = strlen( target ) - len; if ( s > 0 ) strcpy( target, target + len ); else target[0] = 0; return target; } char* str_trim_right( char* target, int len ) // trim `len' chars from the end (right) { int e = strlen(target) - len; if ( e > 0 ) target[e] = 0; else target[0] = 0; return target; } void str_set_ch( char* target, int pos, const char ch ) // sets `ch' char at position `pos' { int sl = str_len( target ); if ( pos < 0 ) pos = sl + pos; if ( pos < 0 || pos >= sl ) return; target[pos] = ch; } char str_get_ch( char* target, int pos ) // return char at position `pos' { int sl = str_len( target ); if ( pos < 0 ) pos = sl + pos; if ( pos < 0 || pos >= sl ) return 0; return target[pos]; } void str_add_ch( char* target, const char ch ) // adds `ch' at the end { int sl = strlen( target ); target[sl] = ch; target[sl+1] = 0; } // return first `word', i.e. from pos 0 to first found delimiter char // after that deletes this `word' from the VString char* str_word( char* target, const char* delimiters, char* result ) { int z = 0; int sl = strlen( target ); while ((strchr(delimiters, target[z]) == NULL) && (target[z] != 0)) z++; strncpy(result, target, z); result[z] = 0; if ( z > 0 ) strncpy( target, target + z + 1, sl - z + 1 ); return result[0] ? result : NULL; } // ...same but `last' word char* str_rword( char* target, const char* delimiters, char* result ) { result[0] = 0; int sl = strlen( target ); int z = sl - 1; while ( strchr( delimiters, target[z] ) == NULL && z > 0 ) z--; if (z < 0) return NULL; strcpy( result, target + z + 1); target[z] = 0; return result; } char* str_cut_left( char* target, const char* charlist ) // remove all chars `charlist' from the beginning (i.e. from the left) { if (strlen(target) == 0) return target; int z = 0; while ((strchr(charlist, target[z]) != NULL) && (target[z] != 0)) z++; if (z == 0) return target; strcpy( target, target + z ); return target; } char* str_cut_right( char* target, const char* charlist ) // remove all chars `charlist' from the end (i.e. from the right) { if (strlen(target) == 0) return target; int z = strlen(target) - 1; while ((strchr(charlist, target[z]) != NULL) && (z > 0)) z--; target[z+1] = 0; return target; } char* str_cut( char* target, const char* charlist ) // does `CutR(charlist);CutL(charlist);' { str_cut_left( target, charlist ); str_cut_right( target, charlist ); return target; } char* str_cut_spc( char* target ) // does `Cut(" ");' { str_cut_left( target, " " ); str_cut_right( target, " " ); return target; } // expand align in a field, filled w. `ch', if len > 0 then right, else left char* str_pad( char* target, int len, char ch ) { int sl = strlen( target ); int _len; _len = (len >= 0) ? len : - len; if ( _len <= sl ) return target; char *tmp = new char[_len + 1]; // result buffer -- need len + 1 tmp[0] = ch; tmp[1] = 0; str_mul( tmp, _len - sl ); if ( len < 0 ) { strcat( target, tmp ); } else { strcat( tmp, target ); strcpy( target, tmp ); } delete [] tmp; return target; } // insert `commas' for 1000's delimiter or use another delimiter // VString supposed to be a integer or real w/o `e' format char* str_comma( char* target, char delim ) { int dot = str_rfind( target, '.' ); if (dot == -1) dot = strlen( target ); dot -= 3; while( dot > 0 ) { str_ins_ch( target, dot , delim ); dot -= 3; } return target; } // translate chars from `from' to `to' // length of `from' MUST be equal to length of `to' char* str_tr( char* target, const char *from, const char *to ) { ASSERT(strlen( from ) == strlen( to )); if (strlen( from ) != strlen( to )) return target; int z = 0; int sl = strlen( target ); for( z = 0; z < sl; z++ ) { const char *pc = strchr( from, target[z] ); if (pc) target[z] = to[ pc - from ]; } return target; } char* str_up( char* target ) { int sl = strlen( target ); for( int z = 0; z < sl; z++ ) target[z] = toupper( target[z] ); return target; } char* str_low( char* target ) { int sl = strlen( target ); for( int z = 0; z < sl; z++ ) target[z] = tolower( target[z] ); return target; } char* str_flip_case( char* target ) // CUTE nali? :) // vladi { int sl = strlen( target ); for( int z = 0; z < sl; z++ ) { if ( target[z] >= 'a' && target[z] <= 'z' ) target[z] -= 32; else if ( target[z] >= 'A' && target[z] <= 'Z' ) target[z] += 32; } return target; } char* str_reverse( char* target ) // reverse the VString: `abcde' becomes `edcba' :) { int z = 0; int x = strlen(target)-1; while( z < x ) { char ch = target[ z ]; target[ z++ ] = target[ x ]; target[ x-- ] = ch; } return target; } char* str_squeeze( char* target, const char* sq_chars ) // squeeze repeating chars to one only { if (!target) return NULL; if (!sq_chars) return NULL; int rc = -1; int pos = 0; while( target[pos] ) { if ( rc == -1 && strchr( sq_chars, target[pos] ) ) { rc = target[pos]; pos++; } else if ( rc != -1 && target[pos] == rc ) { str_del( target, pos, 1 ); } else if ( rc != -1 && target[pos] != rc ) { rc = -1; } else pos++; } return target; } /**************************************************************************** ** ** VString Functions (for const char*) ** ****************************************************************************/ VString str_up ( const char* src ) { VString ret = src; return str_up( ret ); } VString str_low( const char* src ) { VString ret = src; return str_low( ret ); } VString str_flip_case( const char* src ) { VString ret = src; return str_flip_case( ret ); } /**************************************************************************** ** ** VString Functions -- common (VString class will pass transparently) ** ****************************************************************************/ int str_count( const char* target, const char* charlist, int startpos ) // returns match count of all chars from `charlist' { if (!target) return 0; int sl = strlen( target ); if ( startpos >= sl || startpos < 0 ) return 0; int z = startpos; int cnt = 0; for ( z = 0; z < sl; z++ ) cnt += ( strchr( charlist, target[z]) != NULL ); return cnt; } int str_str_count( const char* target, const char* s, int startpos ) // returns match count of `s' VString into target { if (!target) return 0; int cnt = 0; int sl = strlen( s ); const char* pc = target; while( (pc = strstr( pc, s )) ) { pc += sl; cnt++; } return cnt; } int str_is_int( const char* target ) // check if VString is correct int value { if (!target) return 0; char *tmp = strdup( target ); str_cut_spc( tmp ); int dc = str_count( tmp, "0123456789" ); int sl = strlen( tmp ); free( tmp ); return ( dc == sl ); } int str_is_double( const char* target ) // check if VString is correct double (w/o `e' format :( ) { if (!target) return 0; char *tmp = strdup( target ); str_cut_spc( tmp ); int dc = str_count( tmp, "0123456789" ); int cc = str_count( tmp, "." ); int sl = strlen( tmp ); free( tmp ); return ( (dc + cc == sl) && ( cc == 1 ) ); } /*************************************************************************** ** ** VARRAYBOX ** ****************************************************************************/ VArrayBox* VArrayBox::clone() { VArrayBox *new_box = new VArrayBox(); new_box->resize( _size ); new_box->_count = _count; int i; for( i = 0; i < _count; i++ ) { new_box->_data[i] = new VString; *new_box->_data[i] = *_data[i]; } return new_box; } void VArrayBox::resize( int new_size ) { ASSERT( new_size >= 0 ); if ( new_size < 0 ) new_size = 0; while ( new_size < _count ) { ASSERT( _data[ _count - 1 ] ); delete _data[ _count - 1 ]; _data[ _count - 1 ] = NULL; _count--; } if ( new_size == 0 ) { if ( _data ) delete [] _data; _data = NULL; _size = 0; _count = 0; return; } new_size = new_size / VARRAY_BLOCK_SIZE + (new_size % VARRAY_BLOCK_SIZE != 0); new_size *= VARRAY_BLOCK_SIZE; if ( new_size == _size ) return; VString** new_data = new VString*[ new_size ]; ASSERT( new_data ); memset( new_data, 0, new_size * sizeof(VString*) ); if ( _data ) { memcpy( new_data, _data, (_size < new_size ? _size : new_size) * sizeof(VString*) ); delete [] _data; } _size = new_size; _data = new_data; } /*************************************************************************** ** ** VARRAY ** ****************************************************************************/ VArray::VArray() { box = new VArrayBox(); compact = 1; } VArray::VArray( const VArray& arr ) { box = arr.box; box->ref(); compact = 1; } VArray::VArray( const VTrie& tr ) { box = new VArrayBox(); compact = 1; *this = tr; } VArray::~VArray() { box->unref(); } void VArray::detach() { if ( box->refs() == 1 ) return; VArrayBox *new_box = box->clone(); box->unref(); box = new_box; } void VArray::ins( int n, const char* s ) { detach(); ASSERT( n >= 0 && n <= box->_count ); if ( box->_count == box->_size ) box->resize( box->_size + 1 ); memmove( &box->_data[0] + n + 1, &box->_data[0] + n, ( box->_count - n ) * sizeof(VString*) ); box->_count++; box->_data[n] = new VString; box->_data[n]->compact( compact ); box->_data[n]->set( s ); } void VArray::del( int n ) { detach(); if ( n < 0 || n >= box->_count ) return; delete box->_data[n]; memmove( &box->_data[0] + n, &box->_data[0] + n + 1, ( box->_count - n ) * sizeof(VString*) ); box->_count--; if ( box->_size - box->_count > VARRAY_BLOCK_SIZE ) box->resize( box->_count ); } void VArray::set( int n, const char* s ) { detach(); ASSERT( n >= 0 ); if ( n >= box->_count ) { int i = n - box->_count + 1; while ( i-- ) push( "" ); } ASSERT( n < box->_count ); box->_data[n]->set( s ); } const char* VArray::get( int n ) { if ( n < 0 || n >= box->_count ) return NULL; else return box->_data[n]->data(); } int VArray::push( const char* s ) { ins( box->_count, s ); return box->_count; } const char* VArray::pop() { if ( box->_count == 0 ) return NULL; _ret_str = get( box->_count - 1 ); del( box->_count - 1 ); return _ret_str.data(); } int VArray::unshift( const char* s ) { ins( 0, s ); return box->_count; } const char* VArray::shift() { if ( box->_count == 0 ) return NULL; _ret_str = get( 0 ); del( 0 ); return _ret_str.data(); } int VArray::merge( VTrie *tr ) { tr->keys_and_values( this, this ); return box->_count; } int VArray::merge( VArray *arr ) { int cnt = arr->count(); for( int z = 0; z < cnt; z++ ) push( arr->get( z ) ); return box->_count; } int VArray::fload( const char* fname ) { undef(); FILE* f = fopen( fname, "rt" ); if (!f) return 1; int r = fload( f ); fclose(f); return r; } int VArray::fsave( const char* fname ) { FILE* f = fopen( fname, "wt" ); if (!f) return 1; int r = fsave( f ); fclose(f); return r; } int VArray::fload( FILE* f ) { undef(); char buf[1024]; VString str; while( fgets( buf, sizeof(buf)-1, f ) ) { str += buf; if ( str_get_ch( str, -1 ) != '\n' && !feof(f) ) continue; while ( str_get_ch( str, -1 ) == '\n' ) str_trim_right( str, 1 ); push( str ); str = ""; } return 0; } int VArray::fsave( FILE* f ) { for( int z = 0; z < box->_count; z++ ) { size_t len = strlen( get(z) ); if ( fwrite( get(z), 1, len, f ) != len ) return 2; if ( fwrite( "\n", 1, 1, f ) != 1 ) return 2; } return 0; } void VArray::sort( int rev, int (*q_strcmp)(const char *, const char *) ) { if ( count() > 1 ) q_sort( 0, count() - 1, q_strcmp ? q_strcmp : strcmp ); if ( rev ) // FIXME: not optimal... reverse(); } void VArray::q_sort( int lo, int hi, int (*q_strcmp)(const char *, const char *) ) { int m, l, r; const char* v; m = ( hi + lo ) / 2; v = box->_data[m]->data(); l = lo; r = hi; do { while( (l <= hi) && (q_strcmp(box->_data[l]->data(),v) < 0) ) l++; while( (r >= lo) && (q_strcmp(v,box->_data[r]->data()) < 0) ) r--; if ( l <= r ) { VString *t; t = box->_data[l]; box->_data[l] = box->_data[r]; box->_data[r] = t; l++; r--; } } while( l <= r ); if ( lo < r ) q_sort( lo, r, q_strcmp ); if ( l < hi ) q_sort( l, hi, q_strcmp ); } void VArray::reverse() { int m = box->_count / 2; for( int z = 0; z < m; z++ ) { VString *t; t = box->_data[z]; box->_data[z] = box->_data[box->_count-1-z]; box->_data[box->_count-1-z] = t; } } void VArray::shuffle() /* Fisher-Yates shuffle */ { int i = box->_count - 1; while( i >= 0 ) { int j = rand() % ( i + 1 ); VString *t; t = box->_data[i]; box->_data[i] = box->_data[j]; box->_data[j] = t; i--; } } void VArray::print() { int z; for( z = 0; z < count(); z++ ) printf( "%d=%s\n", z, get(z) ); } int VArray::max_len() { if ( count() == 0 ) return 0; int l = 0; int z; for( z = 0; z < count(); z++ ) { int sl = strlen(get(z)); if ( sl > l ) l = sl; } return l; } int VArray::min_len() { if ( count() == 0 ) return 0; int l = strlen(get(0)); int z; for( z = 0; z < count(); z++ ) { int sl = strlen(get(z)); if ( sl < l ) l = sl; } return l; } /*************************************************************************** ** ** VTRIENODE ** ****************************************************************************/ VTrieNode::VTrieNode() { next = NULL; down = NULL; c = 0; data = NULL; } VTrieNode::~VTrieNode() { if ( next ) delete next; if ( down ) delete down; if ( data ) delete data; } void VTrieNode::del_node( const char *key, int branch ) { if ( !key ) return; if ( !key[0] ) return; if ( key[1] == 0 ) { // last char reached if ( key[0] != c ) return; // not found // key found if ( data ) delete data; // release key's value data = NULL; if ( down ) { // there are more keys below if ( branch ) { delete down; // delete all keys below c = 0; // mark current as `not used' } } else { // there is no more keys below c = 0; // mark current as `not used' } } else { // last char is not reached if ( key[0] == c ) { // current char is in the key if ( down ) { // try key down down->del_node( key + 1, branch ); if ( down->c == 0 ) { // down node is not used--remove it ASSERT( down->down == NULL ); VTrieNode *tmp = down; down = down->next; delete tmp; } } else return; // not found } else { if ( next ) // char is not in the key, try next { next->del_node( key, branch ); if ( next->c == 0 ) { // down node is not used--remove it ASSERT( next->down == NULL ); VTrieNode *tmp = next; next = next->next; delete tmp; } } else return; // not found } } } VTrieNode* VTrieNode::find_node( const char* key, int create ) { if ( !key || !key[0] ) return NULL; if ( key[0] == c ) { // char in the current key if ( key[1] == 0 ) { // last char and is in the key--found! return this; } else { // not last char... if ( ! down && create ) { // nothing below but should create down = new VTrieNode(); down->c = key[1]; } if ( down ) return down->find_node( key + 1, create ); // search below else return NULL; // not found } } else { // char not in the current key--try next if ( ! next && create ) { // no next but should create next = new VTrieNode(); next->c = key[0]; } if ( next ) return next->find_node( key, create ); // search next else return NULL; // not found } } VTrieNode *VTrieNode::clone() { VTrieNode *tmp = new VTrieNode(); tmp->c = c; if ( next ) tmp->next = next->clone(); if ( down ) tmp->down = down->clone(); if ( data ) tmp->data = new VString( *data ); return tmp; } void VTrieNode::print() { printf( "---------------------------------\n" ); printf( "this = %p\n", this ); printf( "key = %c\n", c ); printf( "next = %p\n", next ); printf( "down = %p\n", down ); printf( "data = %s\n", data ? data->data() : "(null)" ); if (next) next->print(); if (down) down->print(); } /*************************************************************************** ** ** VTRIEBOX ** ****************************************************************************/ VTrieBox* VTrieBox::clone() { VTrieBox *new_box = new VTrieBox(); delete new_box->root; new_box->root = root->clone(); return new_box; } /*************************************************************************** ** ** VTRIE ** ****************************************************************************/ VTrie::VTrie() { box = new VTrieBox(); } VTrie::VTrie( const VArray& arr ) { box = new VTrieBox(); merge( (VArray*)&arr ); } VTrie::VTrie( const VTrie& tr ) { box = tr.box; box->ref(); } VTrie::~VTrie() { box->unref(); } void VTrie::detach() { if ( box->refs() == 1 ) return; VTrieBox *new_box = box->clone(); box->unref(); box = new_box; } void VTrie::trace_node( VTrieNode *node, VArray* keys, VArray *vals ) { int kl = str_len( temp_key ); if ( node->c ) str_add_ch( temp_key, node->c ); if ( node->data ) { if ( keys ) keys->push( temp_key ); if ( vals ) vals->push( node->data->data() ); } if ( node->down ) trace_node( node->down, keys, vals ); str_sleft( temp_key, kl ); if ( node->next ) trace_node( node->next, keys, vals ); } void VTrie::set( const char* key, const char* value ) { if ( !value || !key || !key[0] ) return; detach(); VTrieNode *node = box->root->find_node( key, 1 ); ASSERT( node ); if ( ! node->data ) node->data = new VString(); node->data->set( value ); } const char* VTrie::get( const char* key ) { if ( !key || !key[0] ) return NULL; VTrieNode *node = box->root->find_node( key ); if ( node && node->data ) return node->data->data(); else return NULL; } void VTrie::del( const char* key ) { if ( !key || !key[0] ) return; detach(); box->root->del_node( key ); } int VTrie::exists( const char* key ) // return != 0 if key exist (with data) { VTrieNode *node = box->root->find_node( key ); if ( node && node->data ) return 1; else return 0; } void VTrie::keys_and_values( VArray *keys, VArray *values ) { trace_node( box->root, keys, values ); } VArray VTrie::keys() { VArray arr; keys_and_values( &arr, NULL ); return arr; } VArray VTrie::values() { VArray arr; keys_and_values( NULL, &arr ); return arr; } void VTrie::reverse() { VArray ka = keys(); VArray va = values(); ASSERT( ka.count() == va.count() ); undef(); int z = ka.count(); while( z-- ) { set( va.get( z ), ka.get( z ) ); } } void VTrie::merge( VTrie *tr ) { VArray ka = tr->keys(); VArray va = tr->values(); ASSERT( ka.count() == va.count() ); int z = ka.count(); while( z-- ) { set( ka.get( z ), va.get( z ) ); } } void VTrie::merge( VArray *arr ) { int z = 0; while( z < arr->count() ) { set( arr->get( z ), arr->get( z + 1 ) ); z += 2; } } int VTrie::fload( const char* fname ) { FILE* f = fopen( fname, "rt" ); if (!f) return 1; int r = fload( f ); fclose(f); return r; } int VTrie::fsave( const char* fname ) { FILE* f = fopen( fname, "wt" ); if (!f) return 1; int r = fsave( f ); fclose(f); return r; } int VTrie::fload( FILE* f ) { VArray arr; int r = arr.fload( f ); if ( r == 0 ) merge( &arr ); return r; } int VTrie::fsave( FILE* f ) { VArray arr; arr.merge( this ); return arr.fsave( f ); } void VTrie::print() { VArray ka = keys(); VArray va = values(); ASSERT( ka.count() == va.count() ); while( ka.count() && va.count() ) { printf( "%s=%s\n", ka.pop(), va.pop() ); } } /**************************************************************************** ** ** VString Utilities -- functions and classes ** ****************************************************************************/ VString str_dot_reduce( const char* s, int width ) { VString dest; dest = s; int sl = str_len( dest ); if ( sl <= width ) return dest; int pos = (width-3) / 2; str_del( dest, pos, sl - width + 3 ); str_ins( dest, pos, "..." ); return dest; } /**************************************************************************** ** ** VString file names utilities -- functions and classes ** NOTE: does not use any external function calls! ** ****************************************************************************/ char* str_fix_path( char* s, int slashtype ) { size_t sl = strlen( s ); if ( s[sl-1] != slashtype ) { s[sl] = slashtype; s[sl+1] = 0; } return s; } const char* str_fix_path( VString &s, int slashtype ) { size_t sl = str_len( s ); if ( s[sl-1] != slashtype ) str_add_ch( s, slashtype ); return (const char*)s; } VString str_file_ext( const char *ps ) { VString ext; int len = strlen(ps); int z = len - 1; while ( ps[z] != '.' && ps[z] != '/' && z > 0 ) z--; if ( ps[z] == '.' ) if ( !(z == 0 || (z > 0 && ps[z-1] == '/')) ) // `.name' has no extension! ext = ps + z + 1; return ext; } VString str_file_name( const char *ps ) { VString name; int len = strlen( ps ); int z = len - 1; while ( z >= 0 && ps[z] != '/' ) z--; name = ps + z + 1; z = str_len( name ) - 1; while ( z > 0 && name[z] != '.' && name[z] != '/' ) z--; if ( z > 0 && name[z] == '.') // `.name' has no extension! str_sleft( name, z ); return name; } VString str_file_name_ext( const char *ps ) { VString name; int len = strlen( ps ); int z = len - 1; while ( z >= 0 && ps[z] != '/' ) z--; name = ps + z + 1; return name; } VString str_file_path( const char *ps ) { VString name; int len = strlen( ps ); int z = len; while ( z >= 0 && ps[z] != '/' ) z--; name = ps; str_sleft( name, z+1 ); return name; } VString str_reduce_path( const char* path ) // removes ".."s { VString dest; dest = path; str_replace( dest, "/./", "/" ); int i = -1; while( (i = str_find( dest, "/../" ) ) != -1 ) { int j = i - 1; while( j >= 0 && dest[j] != '/' ) j--; ASSERT( j >= -1 ); if ( j < 0 ) { if ( dest[0] == '/' ) str_del( dest, 0, 3 ); } else str_del( dest, j+1, i+3-j ); } return dest; } /**************************************************************************** ** ** VString Conversions ** ****************************************************************************/ long hex2long( const char* s ) // hex to long { long P = 1; long C = 0; char tmp[255]; strcpy( tmp, s ); str_up( tmp ); str_cut_spc( tmp ); int sl = strlen(tmp); for( int z=sl-1; z >= 0; z-- ) { int i = -1; if( (i = str_find( "0123456789ABCDEF", tmp[z] )) != -1) C = C + P*i; else C = 0; P = P*16; } return C; } /*************************************************************************** ** ** EOF ** ****************************************************************************/ vfu-4.10/vslib/dlog.h0000644000175000001440000000156211005727400013266 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * * SEE `README',LICENSE' OR COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: dlog.h,v 1.3 2003/01/21 19:56:35 cade Exp $ * */ #ifndef _DLOG_H_ #define _DLOG_H_ #include #define LOG( what ) log( __FILE__, __LINE__, what ) #define LOGN( what, n ) log( __FILE__, __LINE__, what, n ) class TLogFile { FILE *f; char log_fn[255]; int keep_open; public: int on_stdout; int on_stderr; TLogFile(); ~TLogFile(); void create( const char *fname, int pkeep_open ); void open(); void close(); void log( const char *fname, int line, const char *msg ); void log( const char *fname, int line, const char *msg, int n ); void log( const char *msg ); void log( const char *msg, int n ); void log( const char *msg, const char *arg ); }; #endif //_DLOG_H_ vfu-4.10/vslib/eval.h0000644000175000001440000000072311005727400013266 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * * SEE `README',LICENSE' OR COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: eval.h,v 1.3 2003/01/21 19:56:35 cade Exp $ * */ #ifndef _EVAL_H_ #define _EVAL_H_ // // this evaluates math expression with recursive parser etc. // (c) Vladi Belperchinov-Shabanski "Cade" 1996-1998 // extern int EvalResult; double Eval( const char* pExp ); #endif //_EVAL_H_ vfu-4.10/vslib/scroll.cpp0000644000175000001440000000442311310547204014172 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: scroll.cpp,v 1.4 2003/01/29 22:59:27 cade Exp $ * */ #include #ifndef ASSERT #define ASSERT assert #endif #include "scroll.h" void ScrollPos::home() { if ( ! _size ) return; _pos = _min; _page = _min; fix(); } void ScrollPos::end() { if ( ! _size ) return; _pos = _max; fix(); } void ScrollPos::up() { if ( ! _size ) return; ASSERT( check() ); _pos--; if ( _pos < _min ) { if ( wrap ) _pos = _max; else _pos = _min; } if ( _pos < _page ) _page--; fix(); } void ScrollPos::down() { if ( ! _size ) return; ASSERT( check() ); _pos++; if ( _pos > _max ) { if ( wrap ) _pos = _min; else _pos = _max; } if ( _pos > _page + _pagesize - 1 ) _page++; fix(); } void ScrollPos::pageup() { if ( ! _size ) return; ASSERT( check() ); if ( _pos != _page) _pos = _page; else _pos -= _pagesize; fix(); } void ScrollPos::pagedown() { if ( ! _size ) return; ASSERT( check() ); if ( _pos != _page + _pagesize -1 ) _pos = _page + _pagesize - 1; else { _pos += _pagesize; if ( _page + _pagesize <= _max ) _page += _pagesize; } fix(); } void ScrollPos::go( int new_pos ) { _pos = new_pos; fix(); } void ScrollPos::fix() { if ( _pos < _min ) _pos = _min; if ( _pos > _max ) _pos = _max; if ( _page < _min ) _page = _min; if ( _page > _max ) _page = _max; if ( _pos < _page || _pos > _page + _pagesize - 1 ) { if ( _pagesize ) _page = ( _pos / _pagesize ) * _pagesize; else _page = 0; } ASSERT( check() ); } int ScrollPos::check() { if ( ! _size ) return 1; if ( _pos < _min ) return 0; if ( _pos > _max ) return 0; if ( _page < _min ) return 0; if ( _page > _max ) return 0; if ( _pos < _page ) return 0; if ( _pagesize < 0 ) return 0; if ( _pagestep < 1 ) return 0; if ( _pos >= _page + _pagesize ) return 0; return 1; } // eof scroll.cpp vfu-4.10/vslib/eval.cpp0000644000175000001440000000753611005727400013632 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: eval.cpp,v 1.5 2003/01/21 19:56:35 cade Exp $ * */ #include #include #include "eval.h" /* This is *very* old code and I'm not sure if it works at all after the last rewrite :) */ int EvalResult; double Eval( const char* a_exp ) { VString exp = a_exp; str_cut_spc( exp ); int ps = 0; // pos of the +/-/:/* signs int prior = 0; // priority flag int par = 0; // brackets flag int z = 0; // pos counter while ( z < str_len( exp ) ) { switch ( exp[z] ) { case '(': par++; break; case ')': par--; break; case '+': if ((par == 0) && (prior < 20)) { prior = 20; ps = z; } break; case '-': if ((par == 0) && (prior < 20)) { prior = 20; ps = z; } break; case '*': if ((par == 0) && (prior < 10)) { prior = 10; ps = z; } break; case '/': if ((par == 0) && (prior < 10)) { prior = 10; ps = z; } break; case '%': if ((par == 0) && (prior < 10)) { prior = 10; ps = z; } break; } z++; } if (ps != 0) { VString p1; VString p2; str_copy( p1, exp, 0, ps ); str_copy( p1, exp, ps ); double res = 0.0; switch (exp[ps]) { case '+': res = (Eval(p1)+Eval(p2)); break; case '-': res = (Eval(p1)-Eval(p2)); break; case '*': res = (Eval(p1)*Eval(p2)); break; case '/': res = (Eval(p1)/Eval(p2)); break; case '%': res = (fmod(Eval(p1),Eval(p2))); break; } return res; } else { // well ... constant/function/brackets int bp = str_find( exp, '(' ); if ( bp >= 0 ) if ( bp > 0 ) { // function VString fname; str_copy( fname, exp, 0, bp ); VString p1; str_copy( p1, exp, bp+1, str_rfind( exp, ')' ) - bp - 1 ); double res = 0.0; if (strcasecmp(fname, "sin") == 0) {res = sin(Eval(p1));} else if (strcasecmp(fname, "cos") == 0) {res = cos(Eval(p1));} else if (strcasecmp(fname, "tan") == 0) {res = sin(Eval(p1))/cos(Eval(p1));} else if (strcasecmp(fname, "atan") == 0) {res = atan(Eval(p1));} else if (strcasecmp(fname, "asin") == 0) {res = asin(Eval(p1));} else if (strcasecmp(fname, "acos") == 0) {res = acos(Eval(p1));} else // degree/radians/grads conversions... if (strcasecmp(fname, "r2d") == 0) {res = Eval(p1)*180/M_PI;} else if (strcasecmp(fname, "d2r") == 0) {res = Eval(p1)*M_PI/180;} else if (strcasecmp(fname, "r2g") == 0) {res = Eval(p1)*200/M_PI;} else if (strcasecmp(fname, "g2r") == 0) {res = Eval(p1)*M_PI/200;} else if (strcasecmp(fname, "d2g") == 0) {res = Eval(p1)*400/360;} else if (strcasecmp(fname, "g2d") == 0) {res = Eval(p1)*360/400;} else if (strcasecmp(fname, "random") == 0) {res = random() % long(Eval(p1));} else if (strcasecmp(fname, "abs") == 0) {res = fabs(Eval(p1));} else if (strcasecmp(fname, "int") == 0) {res = floor(Eval(p1)+0.5);} else if (strcasecmp(fname, "sqrt") == 0) {res = sqrt(Eval(p1));} else if (strcasecmp(fname, "exp") == 0) {res = ::exp(Eval(p1));} else if (strcasecmp(fname, "ln") == 0) {res = log(Eval(p1));} else if (strcasecmp(fname, "lg") == 0) {res = log10(Eval(p1));} else // if (strcasecmp(fname, "") == 0) {} else EvalResult = 10; if (EvalResult == 10) return 0; else return res; } else { // brackets VString p1; str_copy( p1, exp, 1, str_len( exp ) - 2 ); double res = Eval( p1 ); return res; } else { // constant if ( strcasecmp( exp, "pi" ) == 0 ) { return M_PI; } else if ( strcasecmp( exp, "e" ) == 0 ) { return M_E; } else return atof ( exp ); } } //return 0; } vfu-4.10/vslib/getopt2.h0000644000175000001440000000151711114206650013725 0ustar cadeusers/* * $Header: /cvs/vslib/getopt2.h,v 1.3 2007/12/16 13:53:36 cade Exp $ * * Copyright (C) 1994 Arno Schaefer * * AU: Prototypen und externe Variablen fuer getopt () * * PO: ANSI C * */ /* see getopt.h for changes */ #ifndef GETOPT_H #define GETOPT_H /* next line added by see getopt2.cpp for changes */ #define GETOPT(opts) while((optc = getopt2(argc, argv, opts)) != -1) /* avoid C/C++ linkage declarations conflict with */ extern "C" { extern char *optarg; extern int optind; extern int opterr; extern int optopt; extern int optc; /* * set this to `0' to avoid warning message from getopt when * reach unknown option */ extern int opterr_report; } /* extern "C" */ /* name changed to getopt2 to avoid library function mismatch */ int getopt2(int argc, char *argv[], char *optstring); #endif vfu-4.10/vslib/form_in.h0000644000175000001440000000204011005727400013762 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: form_in.h,v 1.4 2003/01/21 19:56:35 cade Exp $ * */ #ifndef _FORM_IN_H_ #define _FORM_IN_H_ #include "unicon.h" #include "vstring.h" #include "clusters.h" extern BSet FI_LETTERS; extern BSet FI_DIGITS; extern BSet FI_ALPHANUM; extern BSet FI_REALS; extern BSet FI_USERS; extern BSet FI_MASKS; extern int EditStrBF; // bakground/foreground extern int EditStrFH; // first hit color // allows only FI_USERS chars int FormInput( int x, int y, const char *prompt, const char *mask, VString *strres, void (*handlekey)( int key, VString &s, int &pos ) = NULL ); int TextInput( int x, int y, const char *prompt, int maxlen, int fieldlen, VString *strres, void (*handlekey)( int key, VString &s, int &pos ) = NULL ); int TextInput( int x, int y, const char *prompt, int maxlen, int fieldlen, char *strres, void (*handlekey)( int key, VString &s, int &pos ) = NULL ); #endif //_FORM_IN_H_ vfu-4.10/vslib/vstring.h0000644000175000001440000006446611312244766014063 0ustar cadeusers/* * * VSTRING Library * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * Distributed under the GPL license, you should receive copy of GPL! * * VSTRING library provides vast set of string manipulation features * including dynamic string object that can be freely exchanged with * standard char* type, so there is no need to change function calls * nor the implementation when you change from char* to VString (and * vice versa). The main difference from other similar libs is that * the dynamic VString class has no visible methods (except operators) * so you will use it as a plain char* but it will expand/shrink as * needed. * * Thank you for the attention! * If you find bug or you have note about vstring lib, please feel * free to contact me at: * * Vladi Belperchinov-Shabanski "Cade" * * * http://soul.datamax.bg/~cade * * NOTE: vstring was initially (and loosely) based on * `cxstring' lib (c) Ivo Baylov 1998. * NOTE: vstring is distributed standalone as well as a part from vslib. * * This file (vstring.h and vstring.cpp) implements plain string-only * manipulations. For further functionality see vstrlib.h and vstrlib.cpp. * * $Id: vstring.h,v 1.24 2008/01/18 18:40:46 cade Exp $ * */ #ifndef _VSTRING_H_ #define _VSTRING_H_ #include #include #include #include #ifndef ASSERT #define ASSERT assert #endif /*************************************************************************** ** ** GLOBALS ** ****************************************************************************/ #define VARRAY_BLOCK_SIZE 2048 class VTrie; /* forward */ class VArray; /* forward */ class VRegexp; /* forward */ #define VHash VTrie; /* using casual names... */ #define VRegExp VRegexp; /* using casual names... */ /*************************************************************************** ** ** VREF ** ****************************************************************************/ class VRef { int _ref; public: VRef() { _ref = 1; } // creator get first reference virtual ~VRef() { ASSERT( _ref == 0 ); } void ref() { _ref++; } void unref() { ASSERT( _ref > 0 ); _ref--; if ( _ref == 0 ) delete this; } int refs() { return _ref; } }; /**************************************************************************** ** ** VSTRING BOX ** ****************************************************************************/ class VStringBox: public VRef { public: int sl; // string buffer length int size; // internal buffer size char* s; // internal buffer int compact; VStringBox() { s = NULL; sl = size = compact = 0; resize_buf( 0 ); }; ~VStringBox() { undef(); if ( s ) free( s ); }; VStringBox* clone(); void resize_buf( int new_size ); void undef() { resize_buf( 0 ); sl = 0; }; }; /**************************************************************************** ** ** VSTRING ** ****************************************************************************/ #define STR_BLOCK_SIZE 256 class VString { VStringBox* box; char retch; // used to return char& for off-range char index void detach(); public: VString( const VString& str ) { box = str.box; box->ref(); }; VString() { box = new VStringBox(); }; VString( const char* ps ) { box = new VStringBox(); set( ps); }; VString( const int n ) { box = new VStringBox(); i(n); }; VString( const long n ) { box = new VStringBox(); l(n); }; VString( const double n ) { box = new VStringBox(); f(n); }; ~VString() { box->unref(); }; void compact( int a_compact ) // set this != 0 for compact (memory preserving) behaviour { box->compact = a_compact; }; //FIXME: detach() first? void resize( int new_size ) { detach(); box->resize_buf( new_size ); }; void undef() { box->unref(); box = new VStringBox(); }; const VString& operator = ( const VString& str ) { box->unref(); box = str.box; box->ref(); return *this; }; const VString& operator = ( const char* ps ) { set(ps);return *this; }; const VString& operator = ( const int n ) { i(n); return *this; }; const VString& operator = ( const long n ) { l(n); return *this; }; const VString& operator = ( const double n ) { f(n); return *this; }; const VString& operator += ( const VString& str ) { cat( str.box->s ); return *this; }; const VString& operator += ( const char* ps ) { cat( ps ); return *this; }; const VString& operator += ( const int n ) { VString tmp = n; cat(tmp); return *this; }; const VString& operator += ( const long n ) { VString tmp = n; cat(tmp); return *this; }; const VString& operator += ( const double n ) { VString tmp = n; cat(tmp); return *this; }; const VString& operator *= ( const int n ) { return str_mul( *this, n ); }; friend VString operator + ( const VString& str1, const VString& str2 ) { VString res = str1; res += str2; return res; }; friend VString operator + ( const VString& str1, const char* ps ) { VString res = str1; res += ps; return res; }; friend VString operator + ( const char* ps, const VString& str2 ) { VString res = ps; res += str2; return res; }; friend VString operator + ( const VString& str1, const int n ) { VString res = str1; res += n; return res; }; friend VString operator + ( const int n, const VString& str2 ) { VString res = n; res += str2; return res; }; friend VString operator + ( const VString& str1, const long n ) { VString res = str1; res += n; return res; }; friend VString operator + ( const long n, const VString& str2 ) { VString res = n; res += str2; return res; }; friend VString operator + ( const VString& str1, const double n ) { VString res = str1; res += n; return res; }; friend VString operator + ( const double n, const VString& str2 ) { VString res = n; res += str2; return res; }; friend int operator == ( const VString& s1, const VString& s2 ) { return strcmp( s1, s2 ) == 0; }; friend int operator == ( const char* s1, const VString& s2 ) { return strcmp( s1, s2 ) == 0; }; friend int operator == ( const VString& s1, const char* s2 ) { return strcmp( s1, s2 ) == 0; }; friend int operator != ( const VString& s1, const VString& s2 ) { return strcmp( s1, s2 ) != 0; }; friend int operator != ( const char* s1, const VString& s2 ) { return strcmp( s1, s2 ) != 0; }; friend int operator != ( const VString& s1, const char* s2 ) { return strcmp( s1, s2 ) != 0; }; friend int operator > ( const VString& s1, const VString& s2 ) { return strcmp( s1, s2 ) > 0; }; friend int operator > ( const char* s1, const VString& s2 ) { return strcmp( s1, s2 ) > 0; }; friend int operator > ( const VString& s1, const char* s2 ) { return strcmp( s1, s2 ) > 0; }; friend int operator >= ( const VString& s1, const VString& s2 ) { return strcmp( s1, s2 ) >= 0; }; friend int operator >= ( const char* s1, const VString& s2 ) { return strcmp( s1, s2 ) >= 0; }; friend int operator >= ( const VString& s1, const char* s2 ) { return strcmp( s1, s2 ) >= 0; }; friend int operator < ( const VString& s1, const VString& s2 ) { return strcmp( s1, s2 ) < 0; }; friend int operator < ( const char* s1, const VString& s2 ) { return strcmp( s1, s2 ) < 0; }; friend int operator < ( const VString& s1, const char* s2 ) { return strcmp( s1, s2 ) < 0; }; friend int operator <= ( const VString& s1, const VString& s2 ) { return strcmp( s1, s2 ) <= 0; }; friend int operator <= ( const char* s1, const VString& s2 ) { return strcmp( s1, s2 ) <= 0; }; friend int operator <= ( const VString& s1, const char* s2 ) { return strcmp( s1, s2 ) <= 0; }; operator const char* ( ) const { return (const char*)box->s; } const char* data() { return box->s; } char& operator [] ( int n ) { if ( n < 0 ) n = box->sl + n; if ( n < 0 || n >= box->sl ) { retch = 0; return retch; } detach(); return box->s[n]; } void fixlen() { box->sl = strlen(box->s); ASSERT( box->sl < box->size ); } void fix() { box->sl = strlen(box->s); box->resize_buf(box->sl); ASSERT( box->sl < box->size ); } void i( const int n ); void l( const long n ); void f( const double d ); void fi( const double d ); // sets double as int (w/o frac) int i() { return atoi( box->s ); } long l() { return atol( box->s ); } double f() { return atof( box->s ); } double fi() { return atof( box->s ); } void set( const char* ps ); void cat( const char* ps ); void setn( const char* ps, int len ); void catn( const char* ps, int len ); /* for debugging only */ int check() { int len = strlen(box->s); return ((len == box->sl)&&(lensize)); } /**************************************************************************** ** VString Friend Functions (for class VString) ****************************************************************************/ inline friend int str_len( VString& target ) { return target.box->sl; }; inline friend VString& str_set( VString& target, const char* ps ) { target.set( ps ); return target; }; friend VString& str_mul( VString& target, int n ); // multiplies the VString n times, i.e. `1'*5 = `11111' friend VString& str_del ( VString& target, int pos, int len ); // deletes `len' chars starting from `pos' friend VString& str_ins ( VString& target, int pos, const char* s ); // inserts `s' in position `pos' friend VString& str_ins_ch ( VString& target, int pos, char ch ); // inserts `ch' in position `pos' friend VString& str_replace( VString& target, const char* out, const char* in ); // replace `out' w. `in' friend VString& str_copy ( VString& target, const char* source, int pos, int len = -1 ); // returns `len' chars from `pos' friend VString& str_left ( VString& target, const char* source, int len ); // returns `len' chars from the left friend VString& str_right ( VString& target, const char* source, int len ); // returns `len' chars from the right friend VString& str_sleft ( VString& target, int len ); // SelfLeft -- just as 'Left' but works on `this' friend VString& str_sright( VString& target, int len ); // SelfRight -- just as 'Right' but works on `this' friend VString& str_trim_left ( VString& target, int len ); // trims `len' chars from the beginning (left) friend VString& str_trim_right( VString& target, int len ); // trim `len' chars from the end (right) friend VString& str_cut_left ( VString& target, const char* charlist ); // remove all chars `charlist' from the beginning (i.e. from the left) friend VString& str_cut_right( VString& target, const char* charlist ); // remove all chars `charlist' from the end (i.e. from the right) friend VString& str_cut ( VString& target, const char* charlist ); // does `CutR(charlist);CutL(charlist);' friend VString& str_cut_spc ( VString& target ); // does `Cut(" ");' friend VString& str_pad ( VString& target, int len, char ch = ' ' ); friend VString& str_comma( VString& target, char delim = ',' ); // next 3 functions are safe! so if you get/set out f the VString range! friend void str_set_ch( VString& target, int pos, const char ch ); // sets `ch' char at position `pos' friend char str_get_ch( VString& target, int pos ); // return char at position `pos', -1 for the last char etc... friend void str_add_ch( VString& target, const char ch ); // adds `ch' at the end friend char* str_word( VString& target, const char* delimiters, char* result ); friend char* str_rword( VString& target, const char* delimiters, char* result ); // check VArray::split() instead of word() funtions... //FIXME: TODO: str_sprintf() should return VString! // this `sprintf'-like function works as follows: // 1. set `this.VString' length to `init_size' // 2. call `sprintf' with `format' and `...' // NOTE: You have to supply enough `init_size'! sorry... friend int sprintf( int init_size, VString& target, const char *format, ... ); // this is equal to `printf( 1024, format, ... )', i.e. `init_size=1024' friend int sprintf( VString& target, const char *format, ... ); friend VString& str_tr ( VString& target, const char *from, const char *to ); friend VString& str_up ( VString& target ); friend VString& str_low( VString& target ); friend VString& str_flip_case( VString& target ); friend VString& str_reverse ( VString& target ); // reverse the VString: `abcde' becomes `edcba' friend VString& str_squeeze( VString& target, const char* sq_chars ); // squeeze repeating chars to one only }; /* end of VString class */ /**************************************************************************** ** ** VString Functions (for class VString) ** ****************************************************************************/ /**************************************************************************** ** ** VString Functions (for char*) ** ****************************************************************************/ inline int str_len( const char* ps ) { return strlen( ps ); } inline char* str_set( char* target, const char* ps ) { target[0] = 0; if (ps) strcpy( target, ps ); strcpy( target, ps ); return target; } char* str_mul( char* target, int n ); // multiplies the VString n times, i.e. `1'*5 = `11111' char* str_del ( char* target, int pos, int len ); // deletes `len' chars starting from `pos' char* str_ins ( char* target, int pos, const char* s ); // inserts `s' in position `pos' char* str_ins_ch ( char* target, int pos, char ch ); // inserts `ch' in position `pos' char* str_replace( char* target, const char* out, const char* in ); // replace `out' w. `in' char* str_copy ( char* target, const char* source, int pos, int len = -1 ); // returns `len' chars from `pos' char* str_left ( char* target, const char* source, int len ); // returns `len' chars from the left char* str_right ( char* target, const char* source, int len ); // returns `len' chars from the right char* str_sleft ( char* target, int len ); // just as 'left' but works on `target' char* str_sright( char* target, int len ); // just as 'right' but works on `target' char* str_trim_left ( char* target, int len ); // trims `len' chars from the beginning (left) char* str_trim_right( char* target, int len ); // trim `len' chars from the end (right) // next 3 functions are safe! so if you get/set out f the VString range! // (note: that `char*' funcs are slower because of initial strlen() check void str_set_ch( char* target, int pos, const char ch ); // sets `ch' char at position `pos' char str_get_ch( char* target, int pos ); // return char at position `pos', -1 for the last char etc... void str_add_ch( char* target, const char ch ); // adds `ch' at the end // return first `word', i.e. from pos 0 to first found delimiter char // after that deletes this `word' from the VString char* str_word ( char* target, const char* delimiters, char* result ); // ...same but `last' word reverse/rear char* str_rword( char* target, const char* delimiters, char* result ); char* str_cut_left ( char* target, const char* charlist ); // remove all chars `charlist' from the beginning (i.e. from the left) char* str_cut_right( char* target, const char* charlist ); // remove all chars `charlist' from the end (i.e. from the right) char* str_cut ( char* target, const char* charlist ); // does `CutR(charlist);CutL(charlist);' char* str_cut_spc ( char* target ); // does `Cut(" ");' // expand align in a field, filled w. `ch', if len > 0 then right, else left char* str_pad( char* target, int len, char ch = ' ' ); // insert `commas' for 1000's delimiter or use another delimiter // VString supposed to be a integer or real w/o `e' format char* str_comma( char* target, char delim = ',' ); // translate chars from `from' to `to' // length of `from' MUST be equal to length of `to' char* str_tr( char* target, const char *from, const char *to ); char* str_up ( char* target ); char* str_low( char* target ); char* str_flip_case( char* target ); char* str_reverse( char* target ); // reverse the VString: `abcde' becomes `edcba' char* str_squeeze( char* target, const char* sq_chars ); // squeeze repeating chars to one only /**************************************************************************** ** ** VString Functions (for const char*) ** ****************************************************************************/ VString str_up ( const char* src ); VString str_low( const char* src ); VString str_flip_case( const char* src ); /**************************************************************************** ** ** VString Functions -- common (VString class will pass transparently) ** ****************************************************************************/ int str_find ( const char* target, int c, int startpos = 0 ); // returns first zero-based position of char, or -1 if not found int str_rfind( const char* target, int c ); // returns last zero-based position of char, or -1 if not found int str_find ( const char* target, const char* s, int startpos = 0 ); // returns first zero-based position of VString, or -1 if not found int str_rfind( const char* target, const char* s ); // returns last zero-based position of VString, or -1 if not found int str_count( const char* target, const char* charlist, int startpos = 0 ); // returns match count of all chars from `charlist' int str_str_count( const char* target, const char* s, int startpos = 0 ); // returns match count of `s' VString into target int str_is_int ( const char* target ); // check if VString is correct int value int str_is_double( const char* target ); // check if VString is correct double (w/o `e' format :( ) /*************************************************************************** ** ** VARRAYBOX ** ****************************************************************************/ class VArrayBox : public VRef { public: VString** _data; int _size; int _count; VArrayBox() { _data = NULL; _size = 0; _count = 0; }; ~VArrayBox() { undef(); }; VArrayBox* clone(); void resize( int new_size ); void undef() { resize( 0 ); }; }; /*************************************************************************** ** ** VARRAY ** ****************************************************************************/ class VArray { VArrayBox *box; int _fe; // foreach element index VString _ret_str; // return-container void detach(); void q_sort( int lo, int hi, int (*q_strcmp)(const char *, const char *) ); public: int compact; VArray(); VArray( const VArray& arr ); VArray( const VTrie& tr ); ~VArray(); int count() { return box->_count; } // return element count void ins( int n, const char* s ); // insert at position `n' void del( int n ); // delete at position `n' void set( int n, const char* s ); // set/replace at position `n' const char* get( int n ); // get at position `n' void undef() // clear the array (frees all elements) { box->unref(); box = new VArrayBox(); _ret_str = ""; } int push( const char* s ); // add to the end of the array const char* pop(); // get and remove the last element int unshift( const char* s ); // add to the beginning of the array const char* shift(); // get and remove the first element int merge( VTrie *tr ); // return new elements count (same as += ) int merge( VArray *arr ); // return new elements count (same as += ) void print(); // print array data to stdout (console) int fload( const char* fname ); // return 0 for ok int fsave( const char* fname ); // return 0 for ok int fload( FILE* f ); // return 0 for ok int fsave( FILE* f ); // return 0 for ok void sort( int rev = 0, int (*q_strcmp)(const char *, const char *) = NULL ); // sort (optional reverse order) void reverse(); // reverse elements order void shuffle(); // randomize element order with Fisher-Yates shuffle VString& operator []( int n ) { if ( n < 0 ) { _ret_str = ""; return _ret_str; } if ( n >= box->_count ) set( n, "" ); else detach(); // I don't know if user will change returned VString?! return *box->_data[n]; } const VArray& operator = ( const VArray& arr ) { box->unref(); box = arr.box; box->ref(); return *this; }; const VArray& operator = ( const VTrie& tr ) { undef(); merge( (VTrie*)&tr ); return *this; }; const VArray& operator = ( const VString& str ) { undef(); push( str ); return *this; }; const VArray& operator += ( const VArray& arr ) { merge( (VArray*)&arr ); return *this; }; const VArray& operator += ( const VTrie& tr ) { merge( (VTrie*)&tr ); return *this; }; const VArray& operator += ( const VString& str ) { push( str ); return *this; }; /* utilities */ /* implement `foreach'-like interface */ void reset() // reset position to beginning { _fe = -1; }; const char* next() // get next item or NULL for the end { _fe++; return _fe < box->_count ? box->_data[_fe]->data() : NULL; }; const char* current() // get latest item got from next() -- current one { return _fe < box->_count ? box->_data[_fe]->data() : NULL; }; int current_index() // current index { return _fe < box->_count ? _fe : -1; }; int max_len(); // return the length of the longest string in the array int min_len(); // return the length of the shortest string in the array }; /*************************************************************************** ** ** VTRIENODE ** ****************************************************************************/ class VTrieNode { public: VTrieNode(); ~VTrieNode(); VTrieNode *next; VTrieNode *down; char c; VString *data; void detach() { next = down = NULL; } void del_node( const char *key, int branch = 0 ); VTrieNode* find_node( const char* key, int create = 0 ); VTrieNode *clone(); void print(); }; /*************************************************************************** ** ** VTRIEBOX ** ****************************************************************************/ class VTrieBox : public VRef { public: VTrieNode *root; VTrieBox() { root = new VTrieNode(); } ~VTrieBox() { ASSERT( root ); delete root; } VTrieBox* clone(); void undef() { ASSERT( root ); delete root; root = new VTrieNode(); }; }; /*************************************************************************** ** ** VTRIE ** ****************************************************************************/ class VTrie { VTrieBox *box; void detach(); void trace_node( VTrieNode *node, VArray* keys, VArray *vals ); VString temp_key; public: int compact; VTrie(); VTrie( const VArray& arr ); VTrie( const VTrie& tr ); ~VTrie(); void set( const char* key, const char* data ); // set data, same as [] void del( const char* key ); // remove data associated with `key' const char* get( const char* key ); // get data by `key' int exists( const char* key ); // return != 0 if key exist (with data) void undef() // delete all key+data pairs { box->unref(); box = new VTrieBox(); } void keys_and_values( VArray *keys, VArray *values ); VArray keys(); // store keys to `arr', return keys count VArray values(); // store values to `arr', return values count void reverse(); // reverse keys <-> values void merge( VTrie *tr ); // return new keys count (same as +=) void merge( VArray *arr ); // return new keys count (same as +=) //void print_nodes() { print_node( root ); }; // for debug only void print(); // print trie data to stdout (console) int fload( const char* fname ); // return 0 for ok int fsave( const char* fname ); // return 0 for ok int fload( FILE* f ); // return 0 for ok int fsave( FILE* f ); // return 0 for ok VString& operator []( const char* key ) { detach(); // I don't know if user will change returned VString?! VTrieNode *node = box->root->find_node( key, 1 ); ASSERT( node ); if ( ! node->data ) node->data = new VString(); return *(node->data); } const VTrie& operator = ( const VTrie& tr ) { box->unref(); box = tr.box; box->ref(); return *this; }; const VTrie& operator = ( const VArray& arr ) { undef(); merge( (VArray*)&arr ); return *this; }; const VTrie& operator += ( const VArray& arr ) { merge( (VArray*)&arr ); return *this; }; const VTrie& operator += ( const VTrie& tr ) { merge( (VTrie*)&tr ); return *this; }; }; /**************************************************************************** ** ** VString Utility functions ** ****************************************************************************/ /* str_chop() removes last char from a VString (perl-like) */ inline char* str_chop( char* target ) { return str_trim_right( target, 1 ); } inline VString& str_chop( VString& target ) { return str_trim_right( target, 1 ); } /* reduces VString to the given width using dots: `this is long line' -> `this...ine' `s' can be NULL, then target will be reduced */ VString str_dot_reduce( const char* s, int width ); /**************************************************************************** ** ** VString file names utilities -- functions and classes ** NOTE: does not use any external (outside this library) function calls! ** ****************************************************************************/ // adds trailing '/' if not exist char* str_fix_path( char* s, int slashtype = '/' ); const char* str_fix_path( VString& s, int slashtype = '/' ); VString str_file_ext( const char *ps ); /* `ext' */ VString str_file_name( const char *ps ); /* `filename' */ VString str_file_name_ext( const char *ps ); /* `filename.ext' */ VString str_file_path( const char *ps ); /* `/path/' */ /* removes "/../"s, `path' can be NULL, then dest is fixed */ VString str_reduce_path( const char* path ); /**************************************************************************** ** ** VString Conversions ** ****************************************************************************/ long hex2long( const char* s ); // hex to long #endif /* _VSTRING_H_ */ /*************************************************************************** ** ** EOF ** ****************************************************************************/ vfu-4.10/vslib/vstrlib.h0000644000175000001440000002403611005727400014027 0ustar cadeusers/* * * VSTRING Library supporting structures and functions * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * Distributed under the GPL license, you should receive copy of GPL! * * VSTRLIB library provides string data structures which mimic Perl's. * There are several classes: * * VArray -- array of VString elements * VTrie -- associative array (hash) of VString elements * VRegexp -- regular expression helper class * * $Id: vstrlib.h,v 1.22 2008/01/18 18:40:46 cade Exp $ * */ #ifndef _VSTRLIB_H_ #define _VSTRLIB_H_ #include #ifndef ASSERT #define ASSERT assert #endif #include #include #include #include "vstring.h" /*************************************************************************** ** ** GLOBALS ** ****************************************************************************/ #define VCHARSET_BLOCK_SIZE 32 /* max pattern length for file_find_*() and ... */ #define MAX_PATTERN 2048 /* max file_grep() text line input length... :| */ #define MAX_GREP_LINE 4096 /**************************************************************************** ** ** VString aditional functions ** ****************************************************************************/ char* time2str( const time_t tim ); time_t str2time( const char* timstr ); int str_find_regexp( const char* target, const char* pattern, int startpos = 0 ); // warning: str_rfind_regexp() is slow! it can execute pattern matching to `n' // times where n is the target string length... int str_rfind_regexp( const char* target, const char* pattern ); /***************************************************************************** ** ** Hex string to pattern conversion ** ** Converts hex-string to binary pattern (data) ** example: `56 6C 61 64 69' -> ... ** returns pattern length ** *****************************************************************************/ int hex_string_to_pattern( const char *str, char* pattern ); /***************************************************************************** ** ** Next mem* search functions are used to find pattern into memory block ** p is pattern, ps is pattern size, d is data searched and ds is its size ** return found pttern position or -1 for not found ** *****************************************************************************/ int mem_kmp_search( const char *p, int ps, const char *d, int ds ); int mem_quick_search( const char *p, int ps, const char *d, int ds ); int mem_sum_search( const char *p, int ps, const char *d, int ds ); /* no-case versions */ int mem_quick_search_nc( const char *p, int ps, const char *d, int ds ); /***************************************************************************** ** ** Function which return position of pattern into a file ** this uses mem* functions above or defaults to mem_quick_search ** *****************************************************************************/ long file_pattern_search( const char *p, int ps, FILE* f, const char* opt = "", int (*mem_search)( const char *p, int ps, const char *d, int ds ) = NULL ); long file_pattern_search( const char *p, int ps, const char* fn, const char* opt = "", int (*mem_search)( const char *p, int ps, const char *d, int ds ) = NULL ); /***************************************************************************** ** ** This function reads lines from a text file and runs regexp on it. ** file_grep_max_line defines the max line length read (1024) ** file_grep_lines_read reports how many lines are read in during the ** last file_grep() call ** re_string is regexp string, not arbitrary (binary) pattern ** spos defines what file start offset should be accepted ** *****************************************************************************/ extern int file_grep_max_line; extern int file_grep_lines_read; long file_grep( const char *re_string, const char* file_name, int nocase, off_t spos = -1 ); long file_grep( const char *re_string, FILE* f, int nocase, off_t spos = -1 ); /***************************************************************************** ** ** Search interface functions ** ** options are: ** ** i -- ignore case ** r -- regular expression (grep) ** h -- hex pattern search ** *****************************************************************************/ long file_string_search( const char *p, const char* fn, const char* opt ); long file_string_search( const char *p, FILE *f, const char* opt ); int mem_string_search( const char *p, const char* d, const char* opt ); /*************************************************************************** ** ** VREGEXP ** ****************************************************************************/ /* ** options are: ** i -- case insensitive ** m -- multiline matches ** s -- single line (`.' matches and NEWLINE's) ** x -- extended (ifnores whitespace and comments) ** ** f -- plain find (substring) using quick search ** h -- hex search, input pattern is converted from hex string ** ** for more docs see perlre(1) and pcre library docs ** ** ** WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! ** extracting of the captured substring is only possible while subject input ** line which is used as matching target is intact! which means that if you ** change this line between match and substring extraction this will lead to ** segmentation fault! ** */ /* number of subpatterns which can be catched by VRegexp::m() */ #ifndef VREGEXP_MAX_SUBS #define VREGEXP_MAX_SUBS 32 #endif class VRegexp { /* search modes */ enum SearchMode { MODE_REGEXP = 0, MODE_FIND, MODE_HEX }; /* common data */ SearchMode opt_mode; int opt_nocase; // 1 if caseless search needed /* regexp data */ pcre* re; pcre_extra *pe; int sp[VREGEXP_MAX_SUBS*3]; // sub pointers int rc; const char *lp; // last line matched ptr /* no-regexp/hex search pattern */ char* pt; // pattern int pl; // pattern length int pos; // last match found pos /* common data */ //VString substr; VString errstr; int get_options( const char* opt ); public: VRegexp(); VRegexp( const char* pattern, const char *opt = NULL ); // compiles new regexp ~VRegexp(); int comp( const char* pattern, const char *opt = NULL ); // compile re, return > 0 for success // options are: // i -- ignore case // m -- multiline match // s -- match dot against all chars (\n) // x -- extended, ignore whitespace // f -- plain string search (no regexp used) // h -- hex search, converts string ( `56 6C 61 64 69' ) to search pattern // r -- regexp match (default, no need to specify) // last options found are mandatory: "fhr" options sets regexp match int study(); // optimizing regexp for (big-size) multiple matches int ok(); // return 1 if regexp is compiled ok, 0 if not int m( const char* line ); // execute re against line, return 1 for match int m( const char* line, const char* pattern, const char *opt = NULL ); // same as exec, but compiles first VString sub( int n ); // return n-th substring match int sub_sp( int n ); // return n-th substring start position int sub_ep( int n ); // return n-th substring end position VString operator []( int n ) // same as sub() { return sub( n ); } const char* error_str() { return errstr.data(); }; }; /*************************************************************************** ** ** VCHARSET ** ****************************************************************************/ class VCharSet { unsigned char *_data; int _size; // size (in bytes) void resize( int new_size ); public: VCharSet(); ~VCharSet(); void push( int n, int val = 1 ); void undef( int n ); void undef(); int in( int n ); /* push int get ( int pn ); void set_range1( int start, int end ); void set_range0( int start, int end ); void set_str1( const char* str ); void set_str0( const char* str ); int in( const char *str ); // return 1 if all str's chars are in the set int in( int pn ) { if ( pn < 0 || pn >= size ) return 0; else return get( pn ); }; void reverse() { for(int z = 0; z < datasize; z++) data[z] = ~data[z]; }; void set( int pn, int val ) { if ( val ) set1( pn ); else set0( pn ); }; void set_all1() { if ( data ) memset( data, 0xff, datasize ); }; void set_all0() { if ( data ) memset( data, 0x00, datasize ); }; const int operator [] ( int pn ) { ASSERT( pn >= 0 && pn < size ); return get( pn ); }; int resize( int p_size ); VCharSet& operator = ( const VCharSet &b1 ); VCharSet& operator &= ( const VCharSet &b1 ); VCharSet& operator |= ( const VCharSet &b1 ); VCharSet operator ~ (); friend VCharSet operator & ( const VCharSet &b1, const VCharSet &b2 ); friend VCharSet operator | ( const VCharSet &b1, const VCharSet &b2 ); */ }; /*************************************************************************** ** ** UTILITIES ** ****************************************************************************/ // split `source' with `regexp_str' regexp VArray str_split( const char* regexp_str, const char* source, int maxcount = -1 ); // split `source' with exact string `delimiter_str' VArray str_split_simple( const char* delimiter_str, const char* source, int maxcount = -1 ); // join array data to single string with `glue' string // returns the result string or store to optional `dest' VString str_join( VArray array, const char* glue = "" ); /*************************************************************************** ** ** MISC FUNCTIONS ** ****************************************************************************/ #endif /* _VSTRLIB_H_ */ /*************************************************************************** ** ** EOF ** ****************************************************************************/ vfu-4.10/vslib/dlog.cpp0000644000175000001440000000352711005727400013624 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: dlog.cpp,v 1.3 2003/01/21 19:56:35 cade Exp $ * */ #include #include #include "dlog.h" TLogFile::TLogFile() { f = NULL; log_fn[0] = 0; keep_open = 0; on_stdout = 0; on_stderr = 0; } TLogFile::~TLogFile() { close(); } void TLogFile::create( const char *fname, int pkeep_open ) { strcpy( log_fn, fname ); f = NULL; keep_open = pkeep_open; open(); fprintf( f, "\n" ); if (!keep_open) close(); } void TLogFile::open() { if ( f ) fclose( f ); f = fopen( log_fn, "at" ); } void TLogFile::close() { if ( f ) fclose( f ); f = NULL; } void TLogFile::log( const char *fname, int line, const char *msg ) { char tmp[1024]; if (!keep_open) open(); time_t now; time(&now); char stime[32]; strcpy(stime, asctime(localtime(&now))); if (stime[strlen(stime) - 1] == '\n') stime[strlen(stime) - 1] = 0; if ( fname == NULL || line == -1 ) sprintf( tmp, "%s : %s", stime, msg); else sprintf( tmp, "%s [%10s:%-5d] %s", stime, fname, line, msg); while(tmp[strlen(tmp) - 1] == '\n') tmp[strlen(tmp) - 1] = 0; strcat( tmp, "\n" ); fprintf( f, tmp ); if (on_stdout) fprintf( stdout, tmp ); if (on_stderr) fprintf( stderr, tmp ); if (!keep_open && f != NULL) close(); } void TLogFile::log( const char *msg ) { log( NULL, -1, msg ); } void TLogFile::log( const char *msg, int n ) { char tmp[255]; sprintf( tmp, msg, n ); log( NULL, -1, tmp ); } void TLogFile::log( const char *msg, const char *arg ) { char tmp[255]; sprintf( tmp, msg, arg ); log( NULL, -1, tmp ); } void TLogFile::log( const char *fname, int line, const char *msg, int n ) { char tmp[255]; sprintf( tmp, msg, n ); log( fname, line, tmp ); } vfu-4.10/vslib/fnmatch2.cpp0000644000175000001440000001034011005727400014370 0ustar cadeusers/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. NOTE: The canonical source of this file is maintained with the GNU C Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include "fnmatch2.h" /* Match STRING against the filename pattern PATTERN, returning zero if it matches, nonzero if not. */ int fnmatch (const char *pattern, const char *string, int flags) { register const char *p = pattern, *n = string; register char c; /* Note that this evalutes C many times. */ #define FOLD(c) ((flags & FNM_CASEFOLD) && isupper (c) ? tolower (c) : (c)) while ((c = *p++) != '\0') { c = FOLD (c); switch (c) { case '?': if (*n == '\0') return FNM_NOMATCH; else if ((flags & FNM_FILE_NAME) && *n == '/') return FNM_NOMATCH; else if ((flags & FNM_PERIOD) && *n == '.' && (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) return FNM_NOMATCH; break; case '\\': if (!(flags & FNM_NOESCAPE)) { c = *p++; c = FOLD (c); } if (FOLD (*n) != c) return FNM_NOMATCH; break; case '*': if ((flags & FNM_PERIOD) && *n == '.' && (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) return FNM_NOMATCH; for (c = *p++; c == '?' || c == '*'; c = *p++, ++n) if (((flags & FNM_FILE_NAME) && *n == '/') || (c == '?' && *n == '\0')) return FNM_NOMATCH; if (c == '\0') return 0; { char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; c1 = FOLD (c1); for (--p; *n != '\0'; ++n) if ((c == '[' || FOLD (*n) == c1) && fnmatch (p, n, flags & ~FNM_PERIOD) == 0) return 0; return FNM_NOMATCH; } case '[': { /* Nonzero if the sense of the character class is inverted. */ register int notnot; if (*n == '\0') return FNM_NOMATCH; if ((flags & FNM_PERIOD) && *n == '.' && (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) return FNM_NOMATCH; notnot = (*p == '!' || *p == '^'); if (notnot) ++p; c = *p++; for (;;) { register char cstart = c, cend = c; if (!(flags & FNM_NOESCAPE) && c == '\\') cstart = cend = *p++; cstart = cend = FOLD (cstart); if (c == '\0') /* [ (unterminated) loses. */ return FNM_NOMATCH; c = *p++; c = FOLD (c); if ((flags & FNM_FILE_NAME) && c == '/') /* [/] can never match. */ return FNM_NOMATCH; if (c == '-' && *p != ']') { cend = *p++; if (!(flags & FNM_NOESCAPE) && cend == '\\') cend = *p++; if (cend == '\0') return FNM_NOMATCH; cend = FOLD (cend); c = *p++; } if (FOLD (*n) >= cstart && FOLD (*n) <= cend) goto matched; if (c == ']') break; } if (!notnot) return FNM_NOMATCH; break; matched:; /* Skip the rest of the [...] that already matched. */ while (c != ']') { if (c == '\0') /* [... (unterminated) loses. */ return FNM_NOMATCH; c = *p++; if (!(flags & FNM_NOESCAPE) && c == '\\') /* XXX 1003.2d11 is unclear if this is right. */ ++p; } if (notnot) return FNM_NOMATCH; } break; default: if (c != FOLD (*n)) return FNM_NOMATCH; } ++n; } if (*n == '\0') return 0; if ((flags & FNM_LEADING_DIR) && *n == '/') /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ return 0; return FNM_NOMATCH; } // eof vfu-4.10/vslib/ansiterm.cpp0000644000175000001440000001043711310550207014515 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: ansiterm.cpp,v 1.3 2003/01/21 19:56:35 cade Exp $ * */ #include #include #include #include "ansiterm.h" int Ansi_MAXX = 80; int Ansi_MAXY = 25; int Ansi_X = 1; int Ansi_Y = 1; int a_fg; int a_bg; int a_ta; int ansi_o_ta; int ANSI = 0; static int colortab( int color ) // convert normal colors to ANSI ones { switch(color) { case cBLACK : return 0; case cBLUE : return 4; case cGREEN : return 2; case cCYAN : return 6; case cRED : return 1; case cMAGENTA : return 5; case cYELLOW : return 3; case cWHITE : return 7; } return 7; } int AnsiInit( int pANSI ) { if ( pANSI != -1) ANSI = pANSI; else { ANSI = 0; char *buf = getenv( "TERM" ); if ( buf && strcasecmp( buf, "ANSI" ) == 0 ) ANSI = 1; if ( buf && strcasecmp( buf, "vt100" ) == 0 ) ANSI = 1; } if (getenv( "TERMX" )) Ansi_MAXX = atoi( getenv( "TERMX" ) ); if (getenv( "TERMY" )) Ansi_MAXY = atoi( getenv( "TERMY" ) ); if ( Ansi_MAXX == 0 ) Ansi_MAXX = 80; if ( Ansi_MAXY == 0 ) Ansi_MAXY = 25; Ansi_X = 1; Ansi_Y = 1; AnsiTA( cNORMAL ); return 0; } void AnsiDone() { if (!ANSI) return; AnsiTA( cNORMAL ); } void AnsiSuspend() // suspends console (before system() for example) { if (!ANSI) return; ansi_o_ta = a_ta; AnsiTA( cNORMAL ); } void AnsiRestore() // restores console after suspend { if (!ANSI) return; AnsiTA( ansi_o_ta ); } void AnsiCE( int attr ) // clear to end-of-line { if (!ANSI) return; if ( attr != -1 ) { int save_ta = a_ta; AnsiTA( attr ); printf( "\033[K" ); AnsiTA( save_ta ); } else { printf( "\033[K" ); } } void AnsiCS( int attr ) // clear screen { if (!ANSI) return; if ( attr != -1 ) { int save_ta = a_ta; AnsiTA( attr ); printf( "\033[2J" ); AnsiTA( save_ta ); } else { printf( "\033[2J" ); } } void AnsiOut( int x, int y, const char *s ) { AnsiXY( x, y ); AnsiPuts( s ); } void AnsiOut( int x, int y, const char *s, int attr ) { AnsiXY( x, y ); AnsiPuts( s, attr ); } void AnsiPuts( const char *s ) { printf( s ); } void AnsiPuts( const char *s, int attr ) { int _ta = a_ta; AnsiTA( attr ); printf( s ); AnsiTA( _ta ); } void AnsiCHide() { return; } // cursor hide void AnsiCShow() { return; } // cursor show int AnsiMaxX() { return Ansi_MAXX; } int AnsiMaxY() { return Ansi_MAXY; } int AnsiX() { return -1; } int AnsiY() { return -1; } void AnsiFG( int color ) { AnsiTA( CONCOLOR(color, a_bg) ); } void AnsiBG( int color ) { AnsiTA( CONCOLOR( a_fg, color ) ); } void AnsiTA( int attr ) { if (!ANSI) return; a_ta = attr; a_fg = COLORFG( a_ta ); a_bg = COLORBG( a_ta ); int _l = (a_bg>7)?5:0; // blink int _h = (a_fg>7)?1:0; // hi int _f = a_fg; int _b = a_bg; if ( _f > 7 ) _f -= 8; if ( _b > 7 ) _b -= 8; _f = colortab(_f)+30; // fore _b = colortab(_b)+40; // back // hi,blink,fg,bg printf( "\033[0;%s%s%d;%dm", _h?"1;":"", _l?"5;":"", _f, _b ); } void AnsiXY( int x, int y ) // go to x,y { if (!ANSI) return; if ( x < 1 || y < 1 || x > Ansi_MAXX || y > Ansi_MAXY ) return; printf( "\033[%d;%dH", y, x ); } int AnsiKbHit() { return 1; } int AnsiGetch() { return fgetc(stdin); } void AnsiBeep() { printf( "\007" ); } #ifdef TEST3 int main() { AnsiInit(); AnsiCS(); AnsiOut( 1, 1, "<-" ); AnsiXY( 10, 10 ); AnsiTA( 79 ); AnsiPuts( " ANSI terminal Test " ); AnsiXY( 1, 11 ); int z; for ( z = 0; z < 256; z++ ) { char tmp[16]; sprintf( tmp, " %3d ", z ); AnsiTA(z); AnsiPuts( tmp ); } AnsiTA( cNORMAL ); for ( z = 1; z <= AnsiMaxX(); z++ ) AnsiOut( z, 1, "*", z ); for ( z = 1; z <= AnsiMaxX(); z++ ) AnsiOut( z, AnsiMaxY()-1, "*", z ); int c = AnsiGetch(); if (c) c = c; // :) test AnsiDone(); } #endif // eof ansiterm.cpp vfu-4.10/vslib/clusters.cpp0000644000175000001440000002236311310546617014552 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: clusters.cpp,v 1.5 2003/01/21 19:56:35 cade Exp $ * */ #include #include #include "clusters.h" #define RETURN(n) { return status = n; } /**************************************************************************** ** ** FREE-LIST cluster ** ****************************************************************************/ #define FL_EF(n) (((int32*)(data+(n)*es))[0]) // element `free' field #define FL_ED(n) ((char*)(data+(n)*es+sizeof(int32))) // element `data' field #define E_BUSY (-2) #define E_NULL (-1) #define E_FREE ( 0) FLCluster::FLCluster() { base = 0; null = -1; data = NULL; size = 0; used = 0; ff = E_NULL; } void FLCluster::done() { ASSERT( data ); if (data) ::free( data ); } FLCluster::~FLCluster() { done(); } int FLCluster::create( int32 pcnt, int32 pgrow, int32 pes ) { ASSERT( pes > 0 ); ASSERT( pcnt > -1 ); ASSERT( pgrow > -1 ); ASSERT( !(pcnt == 0 && pgrow == 0 ) ); es = pes + sizeof(int32); ds = pes; size = 0; used = 0; growby = pgrow; ff = E_NULL; data = NULL; return Realloc( pcnt ); } int32 FLCluster::add( void* pe ) // insert element { ASSERT( pe ); // if (ff == E_NULL) return -1; if (ff == E_NULL) { int32 res = Realloc( size + growby ); if (res != CE_OK) return null; } int32 ret = ff; ff = FL_EF(ret); ASSERT( FL_EF(ret) != E_BUSY ); FL_EF(ret) = E_BUSY; memcpy( FL_ED(ret), pe, ds ); return ret + base; } int FLCluster::get( int32 pn, void* pe ) // get element { pn -= base; ASSERT( pn >= 0 && pn < size ); ASSERT( pe ); ASSERT( FL_EF(pn) == E_BUSY ); memcpy( pe, FL_ED(pn), ds ); return CE_OK; } char* FLCluster::get( int32 pn ) // get element pointer or NULL if error { pn -= base; ASSERT( pn >= 0 && pn < size ); ASSERT( FL_EF(pn) == E_BUSY ); return (char*)(FL_ED(pn)); } int FLCluster::del( int32 pn ) // get element { pn -= base; ASSERT( pn >= 0 && pn < size ); ASSERT( FL_EF(pn) == E_BUSY ); FL_EF(pn) = ff; ff = pn; return CE_OK; } int FLCluster::is_used( int32 pn ) // 1 if pn element is used { return ( FL_EF(pn - base) == E_BUSY ); } int FLCluster::Realloc( int32 pn ) // expand/shrink data list { pn -= base; ASSERT( pn >= size ); if ( pn == size ) return CE_OK; char *newdata = (char*)realloc( data, pn*es ); if (!newdata) return CE_MEM; data = newdata; memset( data + size*es, 0, (pn - size)*es ); int32 z; int32 base = size > 0; for(z = size+base; z < pn; z++) FL_EF(z) = z - 1; FL_EF(size) = ff; ff = pn - 1; size = pn; return CE_OK; } void FLCluster::dump() { int32 z; printf("size: %d, ff: %d, used: %d\n", size, ff, used); for(z = 0; z < size; z++) { printf("%2d: nextfree: %2d\n", z, FL_EF(z)); } } /**************************************************************************** ** ** BASE Cluster prototype ** ****************************************************************************/ int BaseCluster::create( int p_size, int p_bsize, int p_es ) { cnt = 0; es = p_es; // size = p_size; this should be set by Realloc size = 0; bsize = p_bsize; RETURN(Realloc( p_size )); } void BaseCluster::done() { freeall(); cnt = 0; es = 0; bsize = 0; if (data) ::free(data); data = NULL; } void BaseCluster::del( int pn ) { ASSERT( pn >= 0 && pn < cnt ); if (pn < cnt - 1) memmove( data + ( pn )*es, data + ( pn + 1 )*es, ( cnt - pn )*es ); cnt--; } void BaseCluster::delall() { int z = cnt; while(z) del((z--) - 1); } void BaseCluster::free( int pn ) { ASSERT( pn >= 0 && pn < cnt ); destroy_element( (void*)(data + (pn)*es) ); del( pn ); } void BaseCluster::freeall() { int z = cnt; while(z) free((z--) - 1); } int BaseCluster::Realloc( int pn ) { if ( pn == size ) RETURN(CE_OK); char* newdata = (char*)malloc( pn*es ); if (newdata == NULL) RETURN(CE_MEM); #ifdef DEBUG memset( newdata, '+', pn*es ); #endif if (newdata && data) memcpy( newdata, data, (( pn < size ) ? pn : size)*es ); if (data) ::free(data); data = newdata; size = pn; RETURN(CE_OK); } /**************************************************************************** ** ** DATA cluster ** ****************************************************************************/ int DCluster::add( void* pe ) { RETURN(ins( cnt, pe )); } int DCluster::ins( int pn, void* pe ) { int res = 0; if ( cnt == size ) if ( (res = Realloc( size + bsize )) != 0 ) RETURN(res); if (pn < cnt) memmove( data + (pn+1)*es, data + (pn)*es, (cnt - pn)*es ); memcpy( data + (pn*es), pe, es ); cnt++; RETURN(CE_OK); } void DCluster::put( int pn, void* pe ) { ASSERT( pn >= 0 && pn < cnt ); memcpy( data + pn*es, pe, es ); } void DCluster::get( int pn, void* pe ) { ASSERT( pn >= 0 && pn < cnt ); memcpy( pe, data + pn*es, es ); } /**************************************************************************** ** ** POINTER cluster ** ****************************************************************************/ int PCluster::add( void* pe ) { RETURN(ins( cnt, pe )); } int PCluster::ins( int pn, void* pe ) { int res = 0; if ( cnt == size ) if ( (res = Realloc( size + bsize )) != 0 ) RETURN(res); if (pn < cnt) memmove( data + (pn+1)*es, data + (pn)*es, (cnt - pn)*es ); ((void**)data)[pn] = pe; cnt++; RETURN(CE_OK); } void PCluster::put( int pn, void* pe ) { ASSERT( pn >= 0 && pn < cnt ); ((void**)data)[pn] = pe; } void* PCluster::get( int pn ) { ASSERT( pn >= 0 && pn < cnt ); return ((void**)data)[pn]; } /**************************************************************************** ** ** BIT-SET cluster ** ****************************************************************************/ BSet::BSet() { data = NULL; size = 0; datasize = 0; resize( 256 ); } BSet::BSet( const char* str ) { data = NULL; size = 0; datasize = 0; resize( 256 ); set_str1( str ); } BSet::~BSet() { if( data ) free( data ); } void BSet::set1( int pn ) { if ( pn < 0 ) return; if ( pn >= size ) resize( pn + 1 ); data[pn / 8] |= 1 << (pn % 8); } void BSet::set0( int pn ) { if ( pn < 0 ) return; if ( pn >= size ) resize( pn + 1 ); data[pn / 8] &= ~(1 << (pn % 8)); } int BSet::get( int pn ) { if ( pn < 0 || pn >= size ) return 0; return (data[pn / 8] & (1 << (pn % 8))) != 0; } void BSet::set_range1( int start, int end ) // set range { char s = ( start < end ) ? start : end; char e = ( start > end ) ? start : end; for( int z = s; z <= e; z++) set1( z ); } void BSet::set_range0( int start, int end ) // set range { char s = ( start < end ) ? start : end; char e = ( start > end ) ? start : end; for( int z = s; z <= e; z++) set0( z ); } void BSet::set_str1( const char* str ) { int sl = strlen( str ); for( int z = 0; z < sl; z++ ) set1( str[z] ); } void BSet::set_str0( const char* str ) { int sl = strlen( str ); for( int z = 0; z < sl; z++ ) set0( str[z] ); } int BSet::in( const char *str ) { int sl = strlen( str ); for( int z = 0; z < sl; z++ ) if ( !in( str[z] ) ) return 0; return 1; } int BSet::resize( int p_size ) { ASSERT( p_size > 0 ); int new_size = p_size; int new_datasize = p_size / 8 + (p_size % 8 != 0); char *new_data = (char*)malloc( new_datasize ); if (new_data == NULL) return CE_MEM; memset( new_data, 0, new_datasize ); if (data) { memcpy( new_data, data, datasize < new_datasize ? datasize : new_datasize ); free( data ); data = NULL; } data = new_data; size = new_size; datasize = new_datasize; return CE_OK; } BSet& BSet::operator = ( const BSet &b1 ) { resize( b1.size ); memcpy( data, b1.data, datasize ); return *this; } BSet& BSet::operator &= ( const BSet &b1 ) { int z; for(z = 0; z < (datasize < b1.datasize ? datasize : b1.datasize ); z++) data[z] &= b1.data[z]; return *this; } BSet& BSet::operator |= ( const BSet &b1 ) { int z; for(z = 0; z < (datasize < b1.datasize ? datasize : b1.datasize ); z++) data[z] |= b1.data[z]; return *this; } BSet BSet::operator ~ () { BSet b; b = *this; int z; for(z = 0; z < b.datasize; z++) b.data[z] = ~b.data[z]; return b; } BSet operator & ( const BSet &b1, const BSet &b2 ) { BSet b; b = b1; b &= b2; return b; } BSet operator | ( const BSet &b1, const BSet &b2 ) { BSet b; b = b1; b |= b2; return b; } // eof vfu-4.10/vslib/target.h0000644000175000001440000000453711005727400013634 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: target.h,v 1.6 2004/12/29 02:44:21 cade Exp $ * */ #ifndef _TARGET_H_ #define _TARGET_H_ #define _TARGET_UNKNOWN_ /****************************************** define target OS ***************/ #ifdef _TARGET_UNKNOWN_ #if defined(DJGPP) || defined(_TARGET_DJGPP_) #define _TARGET_GO32_ #define _TARGET_DJGPP_ #define _TARGET_DOS_ #define _TARGET_DESCRIPTION_ "DOS/DJGPP" #undef _TARGET_UNKNOWN_ #endif #endif #ifdef _TARGET_UNKNOWN_ #if defined(__linux__) || defined(__Linux__) || defined(_TARGET_LINUX_) #define _TARGET_LINUX_ #define _TARGET_UNIX_ #define _TARGET_DESCRIPTION_ "UNIX/LINUX" #undef _TARGET_UNKNOWN_ #endif #endif #ifdef _TARGET_UNKNOWN_ #if defined(__NetBSD__) || defined(_TARGET_NETBSD_) #define _TARGET_NETBSD_ #define _TARGET_UNIX_ #define _TARGET_DESCRIPTION_ "UNIX/NETBSD" #undef _TARGET_UNKNOWN_ #endif #endif #ifdef _TARGET_UNKNOWN_ #if defined(WIN32) || defined(_TARGET_WIN32_) #define _TARGET_WIN32_ #define _TARGET_UNIX_ #define _TARGET_DESCRIPTION_ "DOS/WIN32" // sorry :) #undef _TARGET_UNKNOWN_ #endif #endif #ifdef _TARGET_UNKNOWN_ #if defined(MACOSX) || defined(__APPLE__) #define _TARGET_MACOSX_ #define _TARGET_UNIX_ #define _TARGET_DESCRIPTION_ "UNIX/MACOSX" #undef _TARGET_UNKNOWN_ #endif #endif #ifdef _TARGET_UNKNOWN_ #if defined(__GNU__) || defined(_TARGET_GNU_) #define _TARGET_GNU_ #define _TARGET_UNIX_ #define _TARGET_DESCRIPTION_ "GNU" #undef _TARGET_UNKNOWN_ #endif #endif #ifdef _TARGET_UNKNOWN_ #if ((defined(__unix__) || defined(unix)) && !defined(USG)) || defined(_TARGET_UNIX_) #define _TARGET_UNIX_ #define _TARGET_DESCRIPTION_ "UNIX" #undef _TARGET_UNKNOWN_ #endif #endif #ifndef _TARGET_DESCRIPTION_ #define _TARGET_DESCRIPTION_ "UNKNOWN/UNKNOWN" #endif /****************************************** go error unless known :/ *******/ #ifdef _TARGET_UNKNOWN_ #error "Unknown target please define one manually!" #error "Supported are _TARGET_LINUX_, _TARGET_DJGPP_, _TARGET_NETBSD_, _TARGET_GNU_, _TARGET_UNIX_" #error "Read README or COMPILE file(s) for details" #endif /******************************************************************* eof ***/ #endif //_TARGET_H_ vfu-4.10/vslib/vsuti.cpp0000644000175000001440000003502311310547313014047 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * * SEE `README',LICENSE' OR COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vsuti.cpp,v 1.13 2006/08/05 20:15:19 cade Exp $ * */ #include "vsuti.h" #include "vstring.h" #include "vstrlib.h" /*###########################################################################*/ /* adler32.c -- compute the Adler-32 checksum of a data stream * Copyright (C) 1995-1996 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #define BASE 65521L /* largest prime smaller than 65536 */ #define NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ #define DO1(buf,i) {s1 += buf[i]; s2 += s1;} #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); #define DO16(buf) DO8(buf,0); DO8(buf,8); /*---------------------------------------------------------------------------*/ unsigned long adler32(unsigned long adler, const char *buf, unsigned int len) { unsigned long s1 = adler & 0xffff; unsigned long s2 = (adler >> 16) & 0xffff; int k; if (buf == NULL) return 1L; while (len > 0) { k = len < NMAX ? len : NMAX; len -= k; while (k >= 16) { DO16(buf); buf += 16; k -= 16; } if (k != 0) do { s1 += *buf++; s2 += s1; } while (--k); s1 %= BASE; s2 %= BASE; } return (s2 << 16) | s1; } /*---------------------------------------------------------------------------*/ adler32_t mem_adler32( const void* buff, int size ) { return adler32( adler32( 0, NULL, 0 ), (const char *)buff, size ); } /*---------------------------------------------------------------------------*/ adler32_t str_adler32( const char *s ) { return mem_adler32( s, strlen(s) ); } /*---------------------------------------------------------------------------*/ adler32_t file_adler32( FILE *f, long buffsize ) { ASSERT( f ); char *buff = (char*)malloc( buffsize ); if (buff == NULL) return 0; adler32_t adler = adler32( 0, NULL, 0 ); while(42) { long res = fread( buff, 1, buffsize, f ); if (res == -1) { fclose( f ); return 0; } adler = adler32( adler, buff, res ); if ( res != buffsize ) break; } free( buff ); return adler; } /*---------------------------------------------------------------------------*/ adler32_t file_adler32( const char *fname, long buffsize ) { FILE *f = fopen( fname, "rb" ); if (!f) return 0; adler32_t adler = file_adler32( f, buffsize ); fclose(f); return adler; } /*###########################################################################*/ /* FILE functions */ off_t file_size( const char *fname ) { struct stat st; if (stat( fname, &st )) return -1; return st.st_size; } /*---------------------------------------------------------------------------*/ off_t file_size( FILE *f ) { int res = 0; off_t opos = ftello( f ); if (opos == -1) return -1; if (fseeko( f, 0, SEEK_END )) res++; off_t size = ftello( f ); res += (size == -1); if (fseeko( f, opos, SEEK_SET )) res++; if (res) return -1; return size; } /*---------------------------------------------------------------------------*/ int file_load( FILE *f, void *buff, int size ) { return ( fread( buff, 1, size, f ) != (size_t)size); } /*---------------------------------------------------------------------------*/ int file_save( FILE *f, void *buff, int size ) { return (fwrite( buff, 1, size, f ) != (size_t)size); } /*---------------------------------------------------------------------------*/ int file_load( const char* fname, void *buff, int size ) { FILE *f = fopen( fname, "rb" ); if (!f) return 1; int res = file_load( f, buff, size ); fclose( f ); return res; } /*---------------------------------------------------------------------------*/ int file_save( const char* fname, void *buff, int size ) { FILE *f = fopen( fname, "wb" ); if (!f) return 1; int res = file_save( f, buff, size ); fclose( f ); return res; } /*---------------------------------------------------------------------------*/ int file_load_crc32( const char* fname, void *buff, int size ) { crc32_t crc; FILE *f = fopen( fname, "rb" ); if (!f) return 1; int res = 0; res += ( fread( buff, 1, size, f ) != (size_t)size ); res += ( fread( &crc, 1, sizeof(crc), f ) != sizeof(crc) ); fclose(f); res += ( crc != mem_crc32( buff, size ) ); return res; } /*---------------------------------------------------------------------------*/ int file_save_crc32( const char* fname, void *buff, int size ) { crc32_t crc = mem_crc32( buff, size ); FILE *f = fopen( fname, "wb" ); if (!f) return 1; int res = 0; res += ( fwrite( buff, 1, size, f ) != (size_t)size ); res += ( fwrite( &crc, 1, sizeof(crc), f ) != sizeof(crc) ); fclose(f); return res; } int file_is_link( const char* fname ) { #ifdef _TARGET_GO32_ return 0; #else struct stat st; if (lstat( fname, &st )) return 0; /* consider it not link */ return !!( S_ISLNK(st.st_mode) ); #endif } /*---------------------------------------------------------------------------*/ int file_is_dir( const char* fname ) { struct stat st; if (stat( fname, &st )) return 0; /* consider it not link */ return !!( S_ISDIR(st.st_mode) ); } /*---------------------------------------------------------------------------*/ int file_is_dir( struct stat st ) { return !!( S_ISDIR(st.st_mode) ); } int file_exists( const char* fname ) { return access( fname, F_OK ) == 0; } /***************************************************************************** ** ** tilde_expand() expands ~/path and ~name/path to real pathname. ** it uses $HOME environment variable for ~ substitution. ** *****************************************************************************/ VString tilde_expand( const char* a_path ) { #ifdef _TARGET_UNIX_ VString path; struct passwd* pwd; if ( !a_path || !a_path[0] || a_path[0] != '~' ) return VString( a_path ); int z = 1; // first after ~ while( a_path[z] != '/' && a_path[z] != 0 ) str_add_ch( path, a_path[z++] ); if ( path == "" ) path = getenv( "USER" ); if ( path != "" ) { pwd = getpwnam( path ); if (!pwd) return VString( a_path ); path = pwd->pw_dir; } else { char* pw_dir = getenv("HOME"); if (!pw_dir) return VString( a_path ); path = pw_dir; } // get rid of trailing `/' if exists str_fix_path( path ); str_chop( path ); path += a_path + z; return path; #else //_TARGET_UNIX_ VString path = a_path; return path; #endif //_TARGET_UNIX_ } /***************************************************************************** ** ** make_path() create new directory including non-existing path entries. ** It can create /a/b/c/d/e/ without existing of `/a/' for example. ** return 0 for success ** *****************************************************************************/ int make_path( const char *s, long mode ) { char str[MAX_PATH]; char tmp[MAX_PATH]; strcpy( tmp, s ); str_fix_path( tmp ); int l = strlen( tmp ); strcpy( str, tmp ); // to hold original expanded path while(1) { while ( l >= 0 && tmp[l] != '/' ) l--; ASSERT( l < 0 || tmp[l] == '/' ); if ( l < 0 ) break; else tmp[l+1] = 0; if ( access( tmp, F_OK ) == 0 ) break; l--; } while(1) { l++; while ( str[l] != 0 && str[l] != '/' ) l++; if ( str[l] == 0 ) break; strncpy( tmp, str, l ); tmp[l] = 0; int res = mkdir( tmp, mode ); if (res) return res; } return 0; } /***************************************************************************** ** ** expand_path() resolves symlinks etc. ** *****************************************************************************/ char* expand_path( const char *src, char *dest ) { #ifdef _TARGET_UNIX_ realpath( src, dest); #endif #ifdef _TARGET_GO32_ _fixpath( src, dest ); #endif return dest; } VString expand_path( const char* src ) { char temp[MAX_PATH]; VString dest = expand_path( src, temp ); return dest; } /***************************************************************************** ** ** dosstat() is fast stat() designed for DOS FAT filesystems under DJGPP. ** *****************************************************************************/ #ifdef _TARGET_GO32_ /* This is specific to djgpp/libc 2.01 -- if it changes later this must be changed too... */ struct ___DIR { int num_read; char *name; int flags; struct ffblk ff; struct dirent de; int need_fake_dot_dotdot; /* 0=no, 1=.., 2=. */ } /* Convert file date and time to time_t value suitable for struct stat fields. */ time_t _file_time_stamp(unsigned int dos_ftime) { struct tm file_tm; memset(&file_tm, 0, sizeof(struct tm)); file_tm.tm_isdst = -1; /* let mktime() determine if DST is in effect */ file_tm.tm_sec = (dos_ftime & 0x1f) * 2; file_tm.tm_min = (dos_ftime >> 5) & 0x3f; file_tm.tm_hour = (dos_ftime >> 11) & 0x1f; file_tm.tm_mday = (dos_ftime >> 16) & 0x1f; file_tm.tm_mon = ((dos_ftime >> 21) & 0x0f) - 1; /* 0 = January */ file_tm.tm_year = (dos_ftime >> 25) + 80; return mktime(&file_tm); } int dosstat( DIR *dir, struct stat *statbuf ) { #define ff_blk (((___DIR*)(dir))->ff) #define READ_ACCESS (S_IRUSR | S_IRGRP | S_IROTH) #define WRITE_ACCESS S_IWUSR #define EXEC_ACCESS (S_IXUSR | S_IXGRP | S_IXOTH) memset(statbuf, 0, sizeof(struct stat)); unsigned dos_ftime = 0; dos_ftime = ( (unsigned short)ff_blk.ff_fdate << 16 ) + (unsigned short)ff_blk.ff_ftime; statbuf->st_uid = getuid(); statbuf->st_gid = getgid(); statbuf->st_nlink = 1; statbuf->st_size = ff_blk.ff_fsize; statbuf->st_mode |= READ_ACCESS; if ( !(ff_blk.ff_attrib & 0x07) ) /* no R, H or S bits set */ statbuf->st_mode |= WRITE_ACCESS; if (ff_blk.ff_attrib & 0x10) statbuf->st_mode |= (S_IFDIR | EXEC_ACCESS); /* Set regular file bit. */ statbuf->st_mode |= S_IFREG; /* Time fields. */ statbuf->st_atime = statbuf->st_mtime = statbuf->st_ctime = _file_time_stamp(dos_ftime); if ( ! strcmp(ff_blk.lfn_magic,"LFN32") ) { unsigned xtime; xtime = *(unsigned *)&ff_blk.lfn_ctime; if(xtime) /* May be zero if file written w/o lfn active */ statbuf->st_ctime = _file_time_stamp(xtime); xtime = *(unsigned *)&ff_blk.lfn_atime; if(xtime > dos_ftime) /* Accessed time is date only, no time */ statbuf->st_atime = _file_time_stamp(xtime); } return 0; #undef ff_blk } #endif /* _TARGET_GO32_ */ /***************************************************************************** ** ** ftwalk() traverses directory tree and calls func() for every entri it ** encounters. It supports DOS FAT filesystems under DJGPP. ** *****************************************************************************/ int __ftwalk_process( const char *origin, const char *path, int (*func)( const char* origin, /* origin path */ const char* fname, /* full file name */ const struct stat* st, /* stat or NULL */ int is_link, /* 1 if link */ int flag ), int level = -1 ) { DIR *dir; struct dirent *de; struct stat st; int flag; if ( level != -1 && level == 0) return 0; /* required level reqched */ VString this_path = path; int this_path_len = str_len( this_path ); dir = opendir( this_path ); if (!dir) return 0; /* consider it ok */ while( (de = readdir(dir)) ) { if ( strcmp( de->d_name, "." ) == 0 || strcmp(de->d_name, "..") == 0 ) continue; this_path += de->d_name; int is_link = file_is_link( this_path ); #ifdef _TARGET_GO32_ if (dosstat(dir, &st)) /* dosstat() will never return != 0 */ #else if (stat(this_path, &st)) #endif flag = FTWALK_NS; else if (S_ISDIR(st.st_mode)) flag = FTWALK_D; else flag = FTWALK_F; int r = func( origin, this_path, &st, is_link, flag ); if ( r ) { closedir(dir); return r; } if ( flag == FTWALK_D && !is_link ) { this_path += "/"; r = __ftwalk_process( origin, this_path, func, level - 1 ); if ( r ) { closedir(dir); return r; } str_trim_right( this_path, 1 ); /* remove trailing `/' */ int r = func( origin, this_path, &st, is_link, FTWALK_DX ); if ( r ) { closedir(dir); return r; } } str_sleft( this_path, this_path_len ); } /* while readdir(dir) */ closedir(dir); return 0; } int ftwalk( const char *origin, int (*func)( const char* origin, /* origin path */ const char* fname, /* full file name */ const struct stat* st, /* stat struture or NULL */ int is_link, /* 1 if link */ int flag ), int level ) { int r; if ( !origin || !func || !origin[0] ) return 255; VString o = origin; str_fix_path( o ); if ( !file_is_dir( o ) ) return 255; r = __ftwalk_process( o, o, func, level ); return r; } /***************************************************************************** ** ** get_rc_directory() return application rc directory (and possibly create it) ** returned dir is $HOME/.dir_prefix or $HOME/$RC_PREFIX/dir_prefix depending ** on $RC_PREFIX existence. ** *****************************************************************************/ VString get_rc_directory( const char* dir_prefix ) { VString rc_dir; rc_dir = getenv("HOME"); if ( rc_dir == "" ) rc_dir = "/tmp/"; #ifdef _TARGET_GO32_ str_tr( rc_dir, "\\", "/" ); #endif str_fix_path( rc_dir ); int rcprefix = 1; if (getenv("RC_PREFIX")) rc_dir += getenv("RC_PREFIX"); else rcprefix = 0; str_fix_path( rc_dir ); if ( dir_prefix && dir_prefix[0] ) { if ( rcprefix ) rc_dir += dir_prefix; else { #ifdef _TARGET_GO32_ rc_dir += "_"; #else rc_dir += "."; #endif rc_dir += dir_prefix; } str_fix_path( rc_dir ); } make_path( rc_dir ); return rc_dir; } /***************************************************************************** ** ** EOF ** *****************************************************************************/ vfu-4.10/vslib/vstrlib.cpp0000644000175000001440000005315711310547274014400 0ustar cadeusers/* * * VSTRING Library supporting structures and functions * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * Distributed under the GPL license, see end of this file for full text! * * $Id: vstrlib.cpp,v 1.30 2008/01/18 18:40:46 cade Exp $ * */ #ifdef WIN32 #include "stdafx.h" #endif #include #include "vstrlib.h" /**************************************************************************** ** ** VString aditional functions ** ****************************************************************************/ char* time2str( const time_t tim ) { time_t t = tim; return ctime( &t ); } time_t str2time( const char* timstr ) { if (strlen( timstr ) < 24) return 0; char ts[32]; struct tm m; memset( &m, 0, sizeof(m) ); strcpy( ts, timstr ); str_up( ts ); // 0 5 10 5 20 4 // "Wed Jun 30 21:49:08 1993\n" ts[24] = 0; m.tm_year = atoi( ts + 20 ) - 1900; ts[19] = 0; m.tm_sec = atoi( ts + 17 ); ts[16] = 0; m.tm_min = atoi( ts + 14 ); ts[13] = 0; m.tm_hour = atoi( ts + 11 ); ts[10] = 0; m.tm_mday = atoi( ts + 8 ); ts[ 7] = 0; m.tm_mon = str_find( "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC", ts+4 ) / 3; m.tm_yday = 0; m.tm_wday = 0; m.tm_isdst = -1; time_t tim = mktime( &m ); return tim; } int str_find_regexp( const char* target, const char* pattern, int startpos ) { VRegexp re; if ( ! re.comp( pattern ) ) return -1; if ( startpos < 0 ) return -1; int z = 0; while( startpos-- ) { if ( target[z] == 0 ) return -1; z++; } if ( re.m( target + z ) ) return z + re.sub_sp( 0 ); else return -1; } int str_rfind_regexp( const char* target, const char* pattern ) { VRegexp re; if ( ! re.comp( pattern ) ) return -1; int z = str_len( target ); while(4) { z--; if ( re.m( target + z ) ) return z + re.sub_sp( 0 ); if ( z == 0 ) break; } return -1; } /***************************************************************************** ** ** Hex string to pattern conversion ** ** Converts hex-string to binary pattern (data) ** example: `56 6C 61 64 69' -> ... ** returns pattern length ** *****************************************************************************/ int __hex_code( int ch ) { ch = toupper( ch ); if( ch >= '0' && ch <= '9' ) return ch - '0'; if( ch >= 'A' && ch <= 'F' ) return ch - 'A' + 10; return -1; } int hex_string_to_pattern( const char *str, char* pattern ) { const char *pc = pattern; while( *str ) { while( *str == ' ' || *str == '\t' ) str++; int hex = __hex_code( *str++ ); if( hex == -1 ) return 0; int hex2 = __hex_code( *str++ ); if( hex2 == -1 ) return 0; hex <<= 4; hex += hex2; *pattern = hex; pattern ++; } return pattern - pc; } /***************************************************************************** ** ** Knuth-Morris-Pratt search ** *****************************************************************************/ void __kmp_preprocess( const char* p, int ps, int* next ) { int i = 0; int j = next[0] = -1; while (i < ps) { while ((j > -1) && (p[i] != p[j])) j=next[j]; i++; j++; next[i] = p[i] == p[j] ? next[j] : j; } } #define MAX_KMP_PATTERN_SIZE 1024 int mem_kmp_search( const char *p, int ps, const char *d, int ds ) { int i; int j; int next[MAX_KMP_PATTERN_SIZE]; if ( ps > MAX_KMP_PATTERN_SIZE ) return -1; __kmp_preprocess( p, ps, next ); i = j = 0; while (j < ds) { while (i > -1 && p[i] != d[j]) i = next[i]; i++; j++; if (i >= ps) return j - i; } return -1; } /***************************************************************************** ** ** Quick Search (simplified Boyer-Moore) ** ** Note: currently only 256-symbol alphabet supported (ASCII) ** ** The difference from Boyer-Moore is that good-suffix shift is not used. ** Actually this is quick search with Horspool hint which is that rightmost ** char is examined first. ** *****************************************************************************/ #define QS_ASIZE 256 void __qs_preprocess( const char* p, int ps, int* badc ) { int i; for (i = 0; i < QS_ASIZE; i++) badc[i] = ps + 1; for (i = 0; i < ps; i++) badc[(unsigned char)p[i]] = ps - i; } int mem_quick_search( const char *p, int ps, const char *d, int ds ) { int badc[QS_ASIZE]; __qs_preprocess( p, ps, badc); int j = 0; while (j <= ds - ps) { int i; for ( i = ps - 1; i >= 0 && p[i] == d[i + j]; --i ); if ( i < 0 ) return j; j += badc[(unsigned char)d[j + ps]]; } return -1; } /* no-case version */ void __qs_preprocess_nc( const char* p, int ps, int* badc ) { int i; for (i = 0; i < QS_ASIZE; i++) badc[i] = ps + 1; for (i = 0; i < ps; i++) badc[toupper((unsigned char)p[i])] = ps - i; } int mem_quick_search_nc( const char *p, int ps, const char *d, int ds ) { int badc[QS_ASIZE]; __qs_preprocess_nc( p, ps, badc); int j = 0; while (j <= ds - ps) { int i; for ( i = ps - 1; i >= 0 && toupper(p[i]) == toupper(d[i + j]); --i ); if ( i < 0 ) return j; j += badc[toupper((unsigned char)d[j + ps])]; } return -1; } /***************************************************************************** ** ** Sum search ** ** This exact form is made myself. It is not anything new or exceptional :) ** It is Karp-Rabin idea of searching `similar' pattern and if found check ** the actual one. The hash function here is simple sum of bytes in the range ** of pattern size. ** ** Mostly useless since Quick search performs better in almost all cases. ** I wrote it for benchmarking purpose. ** *****************************************************************************/ int mem_sum_search( const char *p, int ps, const char *d, int ds ) { int psum = 0; int i; for( i = 0; i < ps; i++ ) psum += p[i]; int j = 0; int sum = 0; while( j <= ds - ps ) { if ( sum == psum && memcmp( p, d + j, ps ) == 0 ) return j; sum -= d[j]; j++; sum += d[j+ps]; } return -1; } /***************************************************************************** ** ** mem_*_search benchmarks: ** ** For simple benchmark I used ~700MB file and tried to find 10- and 70-chars ** patterns. Results in seconds for both cases (similar to 1-2 seconds) were: ** ** Quick 26 ** KMP 42 ** Sum 39 ** ** Even though KMP returns right result I prefer Quick search for default! ** (last one was joke:)) ** ** Case insensitive search is 2 times slower due to the simple implementation. ** *****************************************************************************/ /***************************************************************************** ** ** file search frontend ** *****************************************************************************/ long file_pattern_search( const char *p, int ps, FILE* f, const char* opt, int (*mem_search)( const char *p, int ps, const char *d, int ds ) ) { #define BUFSIZE (1024*1024) char* buff = new char[BUFSIZE]; int nocase = str_find( opt, 'i' ) > -1; char* np = new char[ps+1]; ASSERT(np); memcpy( np, p, ps ); np[ps] = 0; if ( ! mem_search ) mem_search = mem_quick_search; if ( nocase ) mem_search = mem_quick_search_nc; off_t pos = -1; while(4) { int bs = fread( buff, 1, BUFSIZE, f ); int cpos = mem_search( np, ps, buff, bs ); if ( cpos > -1 ) { pos = ftello(f) - bs + cpos; break; } else { fseeko( f, -ps, SEEK_CUR ); } if ( bs < BUFSIZE ) break; } delete np; delete buff; return pos; } long file_pattern_search( const char *p, int ps, const char* fn, const char* opt, int (*mem_search)( const char *p, int ps, const char *d, int ds ) ) { FILE *f = fopen( fn, "r" ); if ( ! f ) return -1; int res = file_pattern_search( p, ps, f, opt, mem_search ); fclose( f ); return res; } /***************************************************************************** ** ** Grep -- regular expression search ** *****************************************************************************/ /* FGrep -- regular expression search (I know `G' here stands for :)) */ long file_grep( const char *re_string, const char* file_name, int nocase, off_t spos ) { FILE *f = fopen( file_name, "rb" ); if (!f) return -1; long pos = file_grep( re_string, f, nocase, spos ); fclose(f); return pos; } int file_grep_max_line = MAX_GREP_LINE; int file_grep_lines_read = 0; long file_grep( const char *re_string, FILE* f, int nocase, off_t spos ) { if ( strlen(re_string) >= (size_t)file_grep_max_line ) return -2; // just in case, and for now... char newpat[MAX_PATTERN+1]; strcpy( newpat, re_string ); if ( nocase ) str_up( newpat ); VRegexp re; if ( ! re.comp( newpat ) ) return -2; char *line = (char*)malloc( file_grep_max_line+1 ); off_t opos = ftello( f ); ASSERT( spos >= -1 ); if (spos != -1) fseeko( f, spos, SEEK_SET ); off_t cpos = ftello( f ); file_grep_lines_read = 0; int found = 0; while( fgets( line, file_grep_max_line, f ) ) { if ( nocase ) str_up( line ); if ( re.m( line ) ) { found = 1; break; } cpos = ftello( f ); file_grep_lines_read++; if (feof(f)) break; } fseeko( f, opos, SEEK_SET ); if (found) cpos += ( re.sub_sp( 0 ) ); free(line); file_grep_max_line = MAX_GREP_LINE; return found ? cpos : -1; } /***************************************************************************** ** ** Search interface functions ** ** options are: ** ** i -- ignore case ** r -- regular expression (grep) ** h -- hex pattern search ** *****************************************************************************/ long file_string_search( const char *p, const char* fn, const char* opt ) { FILE *f = fopen( fn, "rb" ); if (!f) return -1; long pos = file_string_search( p, f, opt ); fclose(f); return pos; } long file_string_search( const char *p, FILE *f, const char* opt ) { int ps = strlen(p); ASSERT( ps < MAX_PATTERN ); int nocase = str_find( opt, 'i' ) > -1; long pos = -1; if( str_find( opt, 'r' ) > -1 ) { pos = file_grep( p, f, 0, -1 ); } else if( str_find( opt, 'h' ) > -1 ) { char new_p[MAX_PATTERN+1]; int pl = hex_string_to_pattern( p, new_p ); if (pl > 0) pos = file_pattern_search( new_p, pl, f, nocase ? "i" : "" ); } else { pos = file_pattern_search( p, strlen(p), f, nocase ? "i" : "" ); } return pos; } int mem_string_search( const char *p, const char* d, const char* opt ) { int ps = strlen(p); ASSERT( ps < MAX_PATTERN ); int nocase = str_find( opt, 'i' ) > -1; long pos = -1; if( str_find( opt, 'r' ) > -1 ) { VRegexp re; if ( ! re.comp( p ) ) return -1; if ( ! re.m( d ) ) return -1; pos = re.sub_sp( 0 ); } else if( str_find( opt, 'h' ) > -1 ) { char new_p[MAX_PATTERN+1]; int pl = hex_string_to_pattern( p, new_p ); if (pl > 0) { if ( nocase ) pos = mem_quick_search_nc( new_p, pl, d, strlen(d) ); else pos = mem_quick_search( new_p, pl, d, strlen(d) ); } } else { if ( nocase ) pos = mem_quick_search_nc( p, ps, d, strlen(d) ); else pos = mem_quick_search( p, ps, d, strlen(d) ); } return pos; } /*************************************************************************** ** ** VREGEXP ** ****************************************************************************/ VRegexp::VRegexp() { re = NULL; pe = NULL; rc = 0; lp = NULL; pt = NULL; pl = 0; } VRegexp::VRegexp( const char* rs, const char* opt ) { re = NULL; pe = NULL; rc = 0; lp = NULL; pt = NULL; pl = 0; comp( rs, opt ); } VRegexp::~VRegexp() { if ( re ) pcre_free( re ); if ( pt ) delete pt; } int VRegexp::get_options( const char* opt ) { opt_mode = MODE_REGEXP; opt_nocase = 0; if ( ! opt ) return 0; if ( ! opt[0] ) return 0; int options = 0; int sl = strlen( opt ); int z; for( z = 0; z < sl; z++ ) { switch( opt[z] ) { case 'i': options |= PCRE_CASELESS; opt_nocase = 1; break; case 'm': options |= PCRE_MULTILINE; break; case 's': options |= PCRE_DOTALL; break; case 'x': options |= PCRE_EXTENDED; break; case 'f': opt_mode = MODE_FIND; break; case 'h': opt_mode = MODE_HEX; break; case 'r': opt_mode = MODE_REGEXP; break; default: errstr = "invalid option, allowed are: imsxfhr"; return -1; } } return options; } int VRegexp::comp( const char* pattern, const char *opt ) { if ( re ) pcre_free( re ); if ( pt ) delete pt; re = NULL; pt = NULL; pl = 0; int options = get_options( opt ); if( options == -1 ) return 0; if ( opt_mode == MODE_REGEXP ) { const char *error; int erroffset; re = pcre_compile( pattern, options, &error, &erroffset, NULL ); if ( re ) { errstr = ""; return 1; } else { errstr = error; return 0; } } else { pl = strlen( pattern ); pt = new char[pl+1]; if ( opt_mode == MODE_HEX ) pl = hex_string_to_pattern( pattern, pt ); else strcpy( pt, pattern ); pt[pl] = 0; return pl; } } int VRegexp::study() { return 1; } int VRegexp::ok() { if ( opt_mode == MODE_REGEXP ) return re != NULL; else return pt != NULL && pl > 0; } int VRegexp::m( const char* line ) { if ( ! ok() ) { errstr = "no pattern compiled"; return 0; } if ( ! line ) { errstr = "no data to search into"; return 0; } errstr = ""; lp = line; if ( opt_mode == MODE_REGEXP ) { rc = pcre_exec( re, pe, lp, strlen( lp ), 0, 0, sp, VREGEXP_MAX_SUBS*3 ); ASSERT( rc >= -1 && rc != 0 ); if ( rc > VREGEXP_MAX_SUBS ) rc = VREGEXP_MAX_SUBS; if ( rc < 1 ) rc = 0; // fail-safe, should throw exception above in debug mode return rc; } else { if ( opt_nocase ) pos = mem_quick_search_nc( pt, pl, line, strlen(lp) ); else pos = mem_quick_search( pt, pl, line, strlen(lp) ); return pos >= 0; } } int VRegexp::m( const char* line, const char* pattern, const char *opt ) { comp( pattern, opt ); return m( line ); } VString VRegexp::sub( int n ) { VString substr; if ( ! ok() ) return substr; if ( ! lp ) return substr; if ( opt_mode == MODE_REGEXP ) { if ( n < 0 || n >= rc ) return substr; //substr = ""; int s = sp[n*2]; int e = sp[n*2+1]; int l = e - s; substr.setn( lp + s, l ); } else { if ( n != 0 ) return substr; substr.setn( lp + pos, pl ); } return substr; } int VRegexp::sub_sp( int n ) { if ( opt_mode == MODE_REGEXP ) { if ( n < 0 || n >= rc ) return -1; return sp[n*2]; } else { if ( n != 0 ) return -1; return pos; } } int VRegexp::sub_ep( int n ) { if ( opt_mode == MODE_REGEXP ) { if ( n < 0 || n >= rc ) return -1; return sp[n*2+1]; } else { if ( n != 0 ) return -1; return pos+pl; } } /*************************************************************************** ** ** VCHARSET ** ****************************************************************************/ VCharSet::VCharSet() { _data = NULL; _size = 0; } VCharSet::~VCharSet() { _data = NULL; _size = 0; } void VCharSet::resize( int new_size ) { if ( new_size < 1 ) { if ( _data ) delete [] _data; _data = NULL; _size = 0; return; } // calc required mem size in unsigned chars (bytes?) new_size = new_size / sizeof(unsigned char) + (new_size % sizeof(unsigned char) != 0); // pad mem size in blocks of VCHARSET_BLOCK_SIZE new_size = new_size / VCHARSET_BLOCK_SIZE + (new_size % VCHARSET_BLOCK_SIZE != 0); // calc size back to unsigned chars (bytes?) new_size *= VCHARSET_BLOCK_SIZE; unsigned char *new_data = new unsigned char[ new_size ]; memset( new_data, 0, new_size ); if ( _data ) { memcpy( new_data, _data, _size < new_size ? _size : new_size ); delete [] _data; } _data = new_data; _size = new_size; } void VCharSet::push( int n, int val ) { if ( n < 0 ) return; if ( n >= _size * (int)sizeof(unsigned char) ) resize( n + 1 ); if ( val ) _data[ n / sizeof(unsigned char) ] |= 1 << (n % sizeof(unsigned char)); else _data[ n / sizeof(unsigned char) ] &= ~(1 << (n % sizeof(unsigned char))); } void VCharSet::undef( int n ) { push( n, 0 ); } void VCharSet::undef() { resize( 0 ); } int VCharSet::in( int n ) { if ( n < 0 || n >= _size * (int)sizeof(unsigned char) ) return 0; return ( _data[ n / sizeof(unsigned char) ] & ( 1 << ( n % sizeof(unsigned char) ) ) ) != 0; } /* int VCharSet::get( int pn ) { if ( pn < 0 || pn >= size ) return 0; return (data[pn / 8] & (1 << (pn % 8))) != 0; } void VCharSet::set_range1( int start, int end ) // set range { char s = ( start < end ) ? start : end; char e = ( start > end ) ? start : end; for( int z = s; z <= e; z++) set1( z ); } void VCharSet::set_range0( int start, int end ) // set range { char s = ( start < end ) ? start : end; char e = ( start > end ) ? start : end; for( int z = s; z <= e; z++) set0( z ); } void VCharSet::set_str1( const char* str ) { int sl = strlen( str ); for( int z = 0; z < sl; z++ ) set1( str[z] ); } void VCharSet::set_str0( const char* str ) { int sl = strlen( str ); for( int z = 0; z < sl; z++ ) set0( str[z] ); } int VCharSet::in( const char *str ) { int sl = strlen( str ); for( int z = 0; z < sl; z++ ) if ( !in( str[z] ) ) return 0; return 1; } int VCharSet::resize( int p_size ) { ASSERT( p_size > 0 ); int new_size = p_size; int new_datasize = p_size / 8 + (p_size % 8 != 0); char *new_data = (char*)malloc( new_datasize ); if (new_data == NULL) return CE_MEM; memset( new_data, 0, new_datasize ); if (data) { memcpy( new_data, data, datasize < new_datasize ? datasize : new_datasize ); free( data ); data = NULL; } data = new_data; size = new_size; datasize = new_datasize; return CE_OK; } VCharSet& VCharSet::operator = ( const VCharSet &b1 ) { resize( b1.size ); memcpy( data, b1.data, datasize ); return *this; } VCharSet& VCharSet::operator &= ( const VCharSet &b1 ) { int z; for(z = 0; z < (datasize < b1.datasize ? datasize : b1.datasize ); z++) data[z] &= b1.data[z]; return *this; } VCharSet& VCharSet::operator |= ( const VCharSet &b1 ) { int z; for(z = 0; z < (datasize < b1.datasize ? datasize : b1.datasize ); z++) data[z] |= b1.data[z]; return *this; } VCharSet VCharSet::operator ~ () { VCharSet b; b = *this; int z; for(z = 0; z < b.datasize; z++) b.data[z] = ~b.data[z]; return b; } VCharSet operator & ( const VCharSet &b1, const VCharSet &b2 ) { VCharSet b; b = b1; b &= b2; return b; } VCharSet operator | ( const VCharSet &b1, const VCharSet &b2 ) { VCharSet b; b = b1; b |= b2; return b; } */ /*************************************************************************** ** ** UTILITIES ** ****************************************************************************/ // split `source' with `regexp_str' regexp VArray str_split( const char* regexp_str, const char* source, int maxcount ) { VArray arr; VRegexp re; int z = re.comp( regexp_str ); ASSERT( z ); if ( ! z ) return arr; const char* ps = source; while( ps && ps[0] && re.m( ps ) ) { if ( maxcount != -1 ) { maxcount--; if ( maxcount == 0 ) break; } VString s; s.setn( ps, re.sub_sp( 0 ) ); arr.push( s ); ps += re.sub_ep( 0 ); } if ( ps && ps[0] ) arr.push( ps ); return arr; } // split `source' with exact string `delimiter_str' VArray str_split_simple( const char* delimiter_str, const char* source, int maxcount ) { VArray arr; const char* ps = source; const char* fs; int rl = strlen( delimiter_str ); VString s; while( (fs = strstr( ps, delimiter_str )) ) { if ( maxcount != -1 ) { maxcount--; if ( maxcount == 0 ) break; } int l = fs - ps; s.setn( ps, l ); arr.push( s ); ps = (const char *)(ps + l + rl); } if ( ps && ps[0] ) arr.push( ps ); return arr; } // join array data to single string with `glue' string // returns the result string or store to optional `dest' VString str_join( VArray array, const char* glue ) { VString str; for( int z = 0; z < array.count()-1; z++ ) { str += array.get( z ); str += glue; } str += array.get( array.count()-1 ); return str; } /*************************************************************************** ** ** EOF ** ****************************************************************************/ vfu-4.10/vslib/vslib.h0000644000175000001440000000100311005727400013446 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vslib.h,v 1.7 2003/01/21 19:56:35 cade Exp $ * */ #ifndef _VLIB_H_ #define _VLIB_H_ #include #include #include #include #include #include #include #include #include #include #include "target.h" #endif //_VLIB_H_ // eof vlib.h vfu-4.10/vslib/vsuti.h0000644000175000001440000001233211005727400013510 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: vsuti.h,v 1.9 2004/04/04 23:18:20 cade Exp $ * */ #ifndef _VSUTI_H_ #define _VSUTI_H_ #include #include #include #include #include #include #include #include #include "target.h" #ifdef _TARGET_UNIX_ #include #include #include #endif #include #ifndef ASSERT #define ASSERT assert #endif #include "vstring.h" /*###########################################################################*/ /* MISC defines */ /* max filename length */ #ifndef MAX_PATH #define MAX_PATH 512 #endif /*###########################################################################*/ /* CRC functions */ typedef unsigned long int crc32_t; #define CRC32NULL (0xffffffff) /* should start with `0xffffffff' for `crc' and result is crc = ~crc; */ crc32_t update_crc32( const unsigned char octet, const crc32_t crc ); crc32_t mem_crc32( const void* buff, int size ); crc32_t str_crc32( const char *s ); crc32_t file_crc32( FILE *f, long buffsize = 256*1024 ); crc32_t file_crc32( const char *fname, long buffsize = 256*1024 ); /*###########################################################################*/ typedef unsigned long int adler32_t; adler32_t adler32(adler32_t adler, const char *buf, unsigned int len); adler32_t mem_adler32( const void* buff, int size ); adler32_t str_adler32( const char *s ); adler32_t file_adler32( FILE *f, long buffsize = 256*1024 ); adler32_t file_adler32( const char *fname, long buffsize = 256*1024 ); /*###########################################################################*/ /* FILE functions */ off_t file_size( const char *fname ); off_t file_size( FILE *f ); int file_load( FILE *f, void *buff, int size = -1 ); int file_save( FILE *f, void *buff, int size = -1 ); int file_load( const char* fname, void *buff, int size = -1 ); int file_save( const char* fname, void *buff, int size = -1 ); int file_load_crc32( const char* fname, void *buff, int size ); int file_save_crc32( const char* fname, void *buff, int size ); int file_is_link( const char* fname ); int file_is_dir( const char* fname ); int file_is_dir( struct stat st ); int file_exists( const char* fname ); /***************************************************************************** ** ** tilde_expand() expands ~/path and ~name/path to real pathname. ** it uses $HOME environment variable for ~ substitution. ** *****************************************************************************/ VString tilde_expand( const char* a_path ); /***************************************************************************** ** ** make_path() create new directory including non-existing path entries. ** It can create /a/b/c/d/e/ without existing of `/a/' for example. ** return 0 for success ** *****************************************************************************/ int make_path( const char *s, long mode = S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH ); /***************************************************************************** ** ** expand_path() resolves symlinks etc. ** *****************************************************************************/ char* expand_path( const char *src, char *dest ); VString expand_path( const char* src ); /***************************************************************************** ** ** dosstat() is fast stat() designed for DOS FAT filesystems under DJGPP. ** *****************************************************************************/ #ifdef _TARGET_GO32_ #include #include int dosstat( DIR *dir, struct stat *stbuf ); #endif /***************************************************************************** ** ** ftwalk() traverses directory tree and calls func() for every entri it ** encounters. It supports DOS FAT filesystems under DJGPP. ** *****************************************************************************/ #define FTWALK_F 1 /* file (regular) */ #define FTWALK_D 2 /* dir */ #define FTWALK_DX 3 /* call on exit directory */ #define FTWALK_NS 4 /* stat() failed */ /* func() should return 0 for ok, -1 */ int ftwalk( const char *origin_dir, int (*func)( const char* origin, /* origin path */ const char* fname, /* full file name */ const struct stat* st, /* stat struture or NULL */ int is_link, /* 1 if link */ int flag ), int level = -1 ); /***************************************************************************** ** ** get_rc_directory() return application rc directory (and possibly create it) ** returned dir is $HOME/.dir_prefix or $HOME/$RC_PREFIX/dir_prefix depending ** on $RC_PREFIX existence. ** *****************************************************************************/ VString get_rc_directory( const char* dir_prefix ); /***************************************************************************** ** ** EOF ** *****************************************************************************/ #endif /* _VUTILS_H_ */ vfu-4.10/vslib/COPYING0000644000175000001440000004307011005727400013223 0ustar cadeusers GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. vfu-4.10/vslib/form_in.cpp0000644000175000001440000000722711056505404014335 0ustar cadeusers/* * * (c) Vladi Belperchinov-Shabanski "Cade" 1998-2003 * * SEE `README',`LICENSE' OR `COPYING' FILE FOR LICENSE AND OTHER DETAILS! * * $Id: form_in.cpp,v 1.9 2007/01/31 22:34:50 cade Exp $ * */ #include "form_in.h" #include "scroll.h" BSet FI_LETTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; BSet FI_DIGITS = "0123456789"; BSet FI_ALPHANUM = FI_LETTERS & FI_DIGITS; BSet FI_REALS = FI_DIGITS & "Ee+-."; BSet FI_USERS = ""; BSet FI_MASKS = "A#$U"; // A-any, #-int, $-real, U-users int EditStrBF = CONCOLOR( chWHITE, cBLUE ); int EditStrFH = CONCOLOR( cBLACK, cWHITE ); int TextInput( int x, int y, const char *prompt, int maxlen, int fieldlen, VString *strres, void (*handlekey)( int key, VString &s, int &pos ) ) { int res = 0; int insert = 1; VString str = *strres; VString tmp; int ch; ScrollPos scroll; scroll.set_min_max( 0, str_len( str ) ); scroll.set_pagesize( fieldlen ); scroll.go( str_len(str) ); int show = 1; int firsthit = 1; int opage = -1; con_cshow(); while(1) { if (opage != scroll.page()) show = 1; if (show) { str_copy( tmp, str, scroll.page(), scroll.pagesize() ); str_pad( tmp, -scroll.pagesize() ); tmp = " " + tmp + " "; if ( scroll.page() > 0 ) str_set_ch( tmp, 0, '<' ); if ( scroll.page()+scroll.pagesize() < str_len(str) ) str_set_ch( tmp, str_len(tmp)-1, '>' ); con_out(x, y, tmp, firsthit ? EditStrFH : EditStrBF ); show = 0; opage = scroll.page(); } con_xy( x + scroll.pos() - scroll.page() + 1 , y ); ch = con_getch(); if( ch >= 32 && ch <= 255 && str_len(str) < maxlen - 1 ) { if (firsthit) { str = ""; scroll.go(0); firsthit = 0; } if (!insert) str_del( str, scroll.pos(), 1 ); str_ins_ch( str, scroll.pos(), ch ); scroll.set_min_max( 0, str_len( str ) ); scroll.go( scroll.pos() ); scroll.down(); show = 1; }; if (firsthit) { show = 1; firsthit = 0; } if( ch == 27 ) { res = 0; break; } else if( ch == 13 ) { *strres = str; res = 1; break; } else if( ch == KEY_CTRL_U ) { scroll.go(0); str = ""; show = 1; } else if( (ch == KEY_BACKSPACE || ch == 8 ) && (scroll.pos() > 0) ) { scroll.up(); str_del( str, scroll.pos(), 1 ); show = 1; } else if ( ch == KEY_IC ) insert = !insert; else if ( ch == KEY_LEFT ) scroll.up(); else if ( ch == KEY_RIGHT ) scroll.down(); else /* if ( ch == KEY_PPAGE ) scroll.ppage(); else if ( ch == KEY_NPAGE ) scroll.npage(); else */ if ( ch == KEY_HOME || ch == KEY_CTRL_A ) scroll.go(0); else if ( ch == KEY_END || ch == KEY_CTRL_E ) scroll.go(str_len(str)); else if ( ( ch == KEY_DC || ch == KEY_CTRL_D ) && scroll.pos() < str_len(str) ) { str_del( str, scroll.pos(), 1 ); show = 1; } else if ( handlekey ) { int npos = scroll.pos(); handlekey( ch, str, npos ); scroll.set_min_max( 0, str_len( str ) ); scroll.go( scroll.pos() ); if (scroll.pos() != npos) scroll.go( npos ); show = 1; } scroll.set_min_max( 0, str_len( str ) ); scroll.go( scroll.pos() ); } con_chide(); return res; } int TextInput( int x, int y, const char *prompt, int maxlen, int fieldlen, char *strres, void (*handlekey)( int key, VString &s, int &pos ) ) { VString str = strres; int res = TextInput( x, y, prompt, maxlen, fieldlen, &str, handlekey ); strcpy( strres, str.data() ); return res; } // eof form_in.cpp vfu-4.10/README0000644000175000001440000000145611172607331011740 0ustar cadeusers VF File Manager for Unix/Linux ( VFU ) ------------------------------------------------------------------ DISCLAIMER AND LICENSE VFU is distributed under the GPL ( GNU General Public License ). See the `COPYING' for the full GPL text. WARNING Make sure you removed all old personal config and cache files before new version install! Usually this means you have to remove or rename ~/.vfu directory. NOTE This file was a vfu documentation file once, now it is split into separated files ( INSTALL, HISTORY, FAQ, TODO, etc... ) AUTHOR Vladi Belperchinov-Shabanski "Cade". http://cade.datamax.bg/vfu ---eof------------------------------------------------------------ vfu-4.10/THANKS.TO0000644000175000001440000000374311312262307012311 0ustar cadeusers THANKS.TO ---------------------------------------------------------------------------- Yes! There are many people that I should thank... :) Few days ago ( about 1.Apr.2000(!) ) I was accused of not providing appropriate thanks/credits! Wow(?!:)), it was a friend of mine :)) ... anyway, from now on this file will keep track of all the people who did help the VFU project! BIG THANKS TO ALL OF THEM! ( note: the following list is in random order and is *NOT* complete! ) If someone is missing in this list, please inform me! The author of the old F (unknown to me) ( F is an old dos real-mode file manager ) -- for the original F itself Alexander Dimitrov for the extensive vfu testing and sample config file(s) Hubert Feyrer for NetBSD support & packaging Ryan Weaver for RedHat (rpm) support & packaging Mika Fischer for Debian support & packaging Ivaylo Baylov for bits of code (credits in the source) and ideas (*) Charles Hannum for several fixups BIS OnLine [http://www.biscom.net] for hosting the VFU site all these years ePay.bg Plc [http://soul.datamax.bg] for hosting the VFU site since Nov.2002 William Vera for recent Debian support & packaging Ubuntu Community Documentation for VFU wiki docs: https://help.ubuntu.com/community/Vfu/ (current release copied as vfu.wiki here) There are some people that I still not have expressly permission to list here. Some of them are people that has helped the VF project which is indirectly the same thing. The rest are all known and unknown VFU users (and YOU, yes you, reader :)). P! Vladi Belperchinov-Shabanski http://cade.datamax.bg ---eof---------------------------------------------------------------------- vfu-4.10/build.netbsd0000755000175000001440000000115511172606420013355 0ustar cadeusers#!/bin/sh # # note: `-D__NetBSD__' is removed `CCDEF' -- it is defined by default... echo "Compiling VSLIB..." cd vslib make CCDEF="-I${LOCALBASE}/include" LDDEF="-Wl,-R${LOCALBASE}/lib -L${LOCALBASE}/lib" if [ -e libvslib.a ]; then echo "VSLIB compiled ok." else echo "VSLIB compilation failed..." fi cd .. echo "Compiling VFU..." cd vfu make CCDEF="-I${LOCALBASE}/include -DFILENAME_CONF_GLOBAL0=\\\"${PREFIX}/etc/\\\" -DFILENAME_CONF_GLOBAL1=\\\"${PREFIX}/\\\" " LDDEF="-Wl,-R${LOCALBASE}/lib -L${LOCALBASE}/lib" if [ -e vfu ]; then echo "VFU compiled ok." else echo "VFU compilation failed..." fi cd .. vfu-4.10/makefile0000644000175000001440000000171411172606420012553 0ustar cadeusers ### MAKEMAKE STARTS HERE ####################################################### ### Created by makemake.pl on Sun Dec 15 20:23:25 2002 ######################### ### GLOBAL TARGETS ############################################################# default: all re: rebuild li: link all: modules clean: clean-modules rebuild: rebuild-modules link: link-modules ### GLOBAL (AND USER) DEFS ##################################################### AR = ar rv CC = gcc LD = gcc MKDIR = mkdir -p MODULES = vslib vfu RANLIB = ranlib RMDIR = rm -rf RMFILE = rm -f SRC = *.c *.cpp *.cc *.cxx ### MODULES #################################################################### modules: make -C vslib make -C vfu clean-modules: make -C vslib clean make -C vfu clean rebuild-modules: make -C vslib rebuild make -C vfu rebuild link-modules: make -C vslib link make -C vfu link ### MAKEMAKE ENDS HERE ######################################################### vfu-4.10/mm.conf0000644000175000001440000000002411172606420012324 0ustar cadeusersMODULES = vslib vfu vfu-4.10/build.docs0000755000175000001440000000032311172606420013022 0ustar cadeusers#!/bin/sh pod2man --center="VFU File Manager" --release="Version 4.xx" vfu.pod > vfu.1 pod2html vfu.pod > vfu.html rm -f pod2htmd.x~~ pod2htmi.x~~ pod2html-dircache pod2html-itemcache vfu.pod.tmp echo "done." vfu-4.10/XWINDOW.NOTES0000644000175000001440000000254411172607464013037 0ustar cadeusers This file contains some hints for using VFU under XWindow, i.e. in a xterm, rxvt or other compatible(?) terminal. The only solution I come up to use VFU with colors, keys etc. under xterm is to set terminal type to `linux', i.e. console: export TERM=linux or export TERM=rxvt (if you use rxvt like me:)) It works fine here, so try it. I suggest you create script like this: ---cut--- #!/bin/bash # # vfux -- script for starting vfu under xterm # export TERM=linux vfu ---cut--- If you still have problems (wrong keys,missing sequences,etc.) you can try a modified terminfo definition (based on linux-c) which I use. Check the `terminfo' directory in the vfu package. If you want to use keypad for navigation (arrows, +, -, ...) and your keypad is mapped to numbers (KP_1 ... KP_9, etc.) you have to add these lines to your Xmodmap ( usually located at /var/X11R6/lib/xinit/.Xmodmap ) ---cut--- keycode 63 = asterisk keycode 112 = slash keycode 108 = Return keycode 79 = Home keycode 80 = Up keycode 81 = Page_Up keycode 82 = minus keycode 83 = Left keycode 85 = Right keycode 86 = plus keycode 87 = End keycode 88 = Down keycode 89 = Page_Down keycode 90 = Insert keycode 91 = Delete ---cut--- That's all for now... If you have problems contact me at vfu-4.10/HISTORY0000644000175000001440000007022011312261771012137 0ustar cadeusers ---------------------------------------------------------------------- VFU File Manager by Vladi Belperchinov-Shabanski "Cade" http://soul.datamax.bg/~cade/vfu http://cade.datamax.bg/vfu/ ---------------------------------------------------------------------- HISTORY (CHANGE.LOG) + feature add - feature changed x feature removed ! bugfix % note 4.10: 16.Dec.2009 ! 1. Source cleanup for recent gcc/g++/glibc. For Debian Sid. (Greetings Billy! :)) pre-4.10: 29.Jul.2009 - 1. removed 'bookmark1' to 'bookmark9' config file options. now only (repeated) 'bookmark' can be used. ! 2. fixed ALT+1 to ALT+9 bookmarks hotkeys. ! 3. fixed several problems with rx_* tools and some archives filenames. 4.09: 14 Apr 2009 ! 1. fixed 64-bit offset formats under 32-bit platform (SEE). thanks to svilen ! 2. Initially this release was timestamped 05 Aug 2006, but it is not correct. Actually released now :) 14 Apr 2009 + 3. Added option for default target directory to be current working dir. % 4. Moved to git :) cheers! % 5. Cygwin package for vfu is now available! Thanks to Jari Aalto! http://www.cygwin.com/ http://cygwin.com/packages/ http://cygwin.com/packages/vfu/ % 6. Applied patches several from Debian. 4.08: 26 Oct 2005 + 1. %g and %G shell line options added: %g -- same as %f but for each selected filename %G -- same as %F but for each selected filename %g and %G produce list of filenames. each filename is surrounded by ' if filename contains ' then " is used. example: 'file1' "file2's" 'file"3"' ... + 2. %! shell line option added: %! -- request shell line to be shown before execution (debug mode) 4.07: 28.Aug.2005 + 1. Tools/Rename_Tools/Replace_SymLink_w._Original tool added. You can select symlink (file only) then call this tool. It will remove the symlink and rename original file to the place of the symlink: ls sym: sym -> org rm sym mv org sym + 2. Tools/Go_To_Symlink_Target tool added. It can change directory to symlink target's one and go to target name. It is usefull if you want to inspect symlink target. + 3. Tools/Go_Back_To_Last_Target tool added. This can bring you back to the last entry you were before using Tools/Go_To_Symlink_Target tool. This can be used multiple times and will lead to toggling between symlink and its target. 4.06: 06.Jun.2005 ! 1. Sizes above 4GB are now correctly shown/calculated. (needs 'make CCDEF=-D_FILE_OFFSET_BITS=64') 4.05: 05.Jun.2005 ! 1. update of dir size cache is optimized for multiple dirs. + 2. GlobalSelect/Extended/SelectToBegin/End of list added. ! 3. Sizes above 2GB are now correctly shown/calculated. ! 4. Docs updated to offer way to handle ctrl+z, ctrl+c. 4.04: 07.Jun.2003 + 1. "View differences" menu option added for overwrite file (copy). This can be used to preview files before overwriting. 4.03: 15.Jun.2003 ! 1. Various gcc version warnings and problems were solved. ! 2. Old (pre 4.xx version) directories size cache problem fixed. ( ASSERT("|") issue ) - 3. Credits are removed from the console. 4.02: 06.May.2003 ! 1. Compilation problem fixed. 4.01: 28.Apr.2003 % 0. VFU is now recompiled with the new vslib which features strings, arrays and tries (hashes) with referenced data (shared). ! 1. Various small fixes (logic and less memory alloc/dealloc). ! 2. SeeViewer is now fixed for screens larger than 80 columns. ! 3. Fixed Lynx-style navigation. ! 4. New faster directory size cache! - 5. Directory tree is 2 lines bigger and has dir sizes back. :) + 6. VFU now uses pcre library so it can support Perl-like regular. expressions (i.e. in regexp searches, see viewer, etc.). ! 7. Now SeeViewer highlights found strings in the current visible page. ! 8. Hex mode of SeeViewer was rewritten. Now it supports several 8-byte columns for different width terminals. + 9. Clipboard is now functional (key P). -10. bookmark1 .. bookmark9 options in config file are now replaced with single one: `bookmark' which can be used multiple times (note that for some time old ones will work as well). +11. Directory bookmarks are no attached to a key (`) and new option to temporary run-time bookmarking has been added (`A' inside the bookmarks menu). 4.00: 27.Nov.2002 % 0. Hope this is the new next stage in the VFU development :) ! 1. Fixed rxvt emulation BS handling. (actually found why is that... to fix this issue add `Rxvt*backspacekey: ^H' line to your .Xdefaults) + 2. Ctrl+A/E in file list are Home/End. + 3. Ctrl+A/E/D in all input lines are Home/End/Del. + 4. Added octal mode change (key TAB, edit entry menu). + 5. Fixed global select masking for recursive file lists. - 6. Now `Lowercase extensions for configs' is on by default. ! 7. Settings are saved immediately after options change. ! 8. Fixed directory sizes cache cleaning. ! 9. Fixed all input lines to allow full ascii range (32..255). !10. rx_* tools are completely rewritten! -11. rx_ftp now uses Net::FTP instead of external ftparc utility. 3.04: 24.May.2002 % 0. This version should be named over `04' as result of large number of changes (most internal ones)... Still I'll wait next release to be able receive any bug reports before major version change... (there is about 1.5 years since 3.03:)) + 1. Added FastSizeCache option -- turns off directory resolving for directory size cache which means that the cache will act faster but you won't get sizes for symlinked dirs. + 2. Added `Randomize' function to file list arrange menu. ! 3. Rename tools now work on filename only, not on the full pathname (usual bug in recursive scanning -- Ctrl+R) ! 4. Fixed loops on incremental searches in the files list and directory tree. + 5. Actual files size is now reported before copy/move. + 6. Size chache is now auto-cleaned on dir size recalculation. + 7. Now errors on copy/move/symlink/erase can be ignored (always skipped quietly). ! 8. Temporary files used for view filters are now removed. ! 9. Now all temporary files and directories are set owner read/write/traverse permission only. !10. Fixed problem with browsing/user commands for files inside archive. !11. Fixed problem when quit unsaved file that cannot be saved from the internal editor. !12. Fixed `Name###' arrange mode. +13. Now file list can be sorted separately by modify, change and access time. !14. Fixed directory size cache for symlink-ed dirs. !15. Now VFU accepts trigger `.automount' just like `automount'. !16. Now extension colors loaded from DIR_COLORS are added to those from vfu.conf (not overwritten) !17. Internal: changed all PSZCluster+StrSplitter to VArray+VTrie !18. Fixed configuration file problems (missing archives etc.) !19. SIGWINCH finally works, i.e. VFU redraws on terminal resize (please report any problems regarding this one!) 3.03: 31.Dec.2000 ! 1. Documentation fixed to address directory bookmarks in the vfu.conf correctly. ( bookmark#=path ) ! 2. Added option for VFU to handle Ctrl+Z, Ctrl+C, Ctrl+\ as it is expected (suspend,interrupt,quit). To use it you have to export UNICON_NO_RAW environment var with any value. ( for bash: `export UNICON_NO_RAW=1' ) ! 3. User menu is fixed. + 4. Change directory completion menu is now sorted. + 5. Sequential rename function added (Tools/Rename menu) + 6. Now directory sizes cache is removed from the directory tree, so you can have directory sizes saved even if you don't have directory tree built. 3.02: 01.Aug.2000 ! 1. Several DJGPP (DOS/Win9x) portability fixups. ! 2. Fixed problem with input line for long directory names. ! 3. Fixed directory tree sizes calculation. + 4. Added inode size cache for directories that are new to the currently saved directory tree. (unix version only) ! 5. Fixed major bug in file move procedure. ! 6. Fixed extension masking `for all' in user externals. - 7. Now all path lists in vfu.conf (like TrimTree) are `:' separated (or `;' for dos version) 3.01: 07.Jun.2000 ! 1. Fixed SeeEditor bug when editing new files (that does not exist) ! 2. Fixed install script to se correct permissions. ! 3. Fixed build.netbsd to se correct global configuration files locations. + 4. GlobalSelect/HideDotFiles added. ! 5. Fixed build.netbsd. - 6. Now directory tree automation (rescanning etc.) is disabled by default (see Options/AutoDirTree). ! 7. Fixed zero-sized files bug in SeeViewer. ! 8. Alt+B browse/view current file w/o filters. + 9. Now install script set sample config file into /usr/local/etc (to get personal config file you have to copy /usr/local/etc/vfu.conf to ~/.vfu/vfu.conf or ~/$RC_PREFIX/vfu/vfu.conf if you have set $RC_PREFIX ) !10. Ctrl+L refresh/redraw page problem is now fixed. !11. Several little fixups. 3.00: 20.May.2000 % 0. Hello again! :) The VFU development was suspended nearly an year ago. Now it is resumed and a lot of changes took place! First of all -- VFU was completely rewritten/revised(!), so many (internal?) features were added, some removed, other changed. Below I will list some key features in this version, but probably I'll forget some things or else... % 1. There are no big changes in the user interface and feel. - 2. Now reading/extracting archives is removed from inside VFU to external (perl) utilities. This will help adding new archives and debugging existing ones. - 3. Now archives' structure is followed as the local file system, i.e. you will browse directory by directory but not the whole archive content as before. Perhaps option for recursive (whole content) browsing will be added in the future. + 4. Now you can cancel copy/move procedures at stage you want even during single file copy process! (It was not possible in older versions) ! 5. The rare problem of showing total percentages over 100% during copy/move is finally (and hopefully:)) fixed. + 6. Now files in archive can be masked and files mask can be changed inside archive. ! 7. Some access/terminal emulation problems are fixed. ( i.e. some `difficult' key functions are accessible and from menus etc. ) 1.51: 31.May.1999 + 1. Debian `.deb' packages are now supported as archives! ! 2. All paths containing `dir/..' are reduced. ! 3. Now arcive files are recognized by longer extensions like `.tar.gz'. Result is proper handling of `.tar.gz' and `.tar.bz2' archives. + 4. Added SEE Viewer filters. Now you can view gzipped files and or add filters for viewing man pages etc. + 5. Added ready `panelizers' command to the RescanMenu ( key Ctrl+R ) Can be used as menu alternative to external panelize option. ! 6. SEE screen draws improved and `< >' bug is fixed. ! 7. GetDirName function now allows dirs only. + 8. Added UserMenu ( key `U' ). User external commands can be attached not to key but to this menu. + 9. Bash/Unix-style filename completion added! -10. Bash/Unix-style completion is now default one! +11. Now entries in the filelist can be moved ( see ArrangeMenu/MoveEntry ) !12. Now VFU keeps current file postition after change of sort order. !13. Better preserve/copy mode/protection when copy/move directory subtrees. ( from RO media for example ) !14. Fixed erase of own directories without `write' permission/mode. !15. More examples and comments added to the sampe configuration file: vfu.conf. 1.50: 27.Mar.1999 % 0. This is primarily bugfix release, supposed to form final stable release with all planned features. :) ! 1. CR_LF problem in Seed is now solved. ! 2. Total/Free space calculation problem is fixed. ! 3. GlobalSelect/Grep file search problem (finally!) fixed. ! 4. EditEntry/OwnerGroup now accepts `user' format instead of `user.' (i.e. no trailing dot required) ! 5. Fixed problem with Seed and new files (create). ! 6. `/etc/DIR_COLORS' loads properly now, even if vfu.conf doesn't exist. ! 7. Items (files/dirs) colors are changed properly now after mode/protection change. + 8. Now VFU shows and current hostname. + 9. AutoIndent option added to Seed ( key: Ctrl+T ) !10. Fixed problem with free space check before Copy/Move. -11. VFU will not resort files after Ctrl+Z on directory and sort order is `size'. +12. Preliminary man page added. ( vfu.1 ) 1.46: 19.Mar.1999 + 1. Support for /etc/DIR_COLORS (for file-type colorization) See Option/UseEtcDirColors. + 2. Small internal Text editor added! (can be used as emergency editor if no other available) See Option/UseInternalEditor. + 3. Added Lynx-like arrow keys navigation: UpArrow/DownArrow -- scroll list LeftArrow/RightArrow -- enter/exit/cdup See Options/AltArrowsNavigate. + 4. Separate histories to all input lines. Use PageUp/PageDown to recall. + 5. Now SymLink references can be edited in-place. See EditEntry(key TAB)/EditSymLinkReference(key L). + 6. File Find results can be panelized now. ! 7. The usual bugfixes ( not important really ). - 8. Changed location for personal config and other related files, now default place is `$HOME/.vfu'. Changed VFU config file name from `vfurc' to `vfu.conf'. Please read CONFIG file! + 9. Now the internal Viewer and Editor (See/Seed) have separate options files. The `see(d).options' location is `$HOME/$RC_PREFIX/.see(d)/see(d).options'. 1.45: 03.Mar.1999 + 1. `%i' and `%n' macros added. (See abov for details) ! 2. Now VFU won't expand masks if you enter external scan/panelize command in the file mask field. ! 3. Now VFU will remember internal file viewer options during the same session. + 4. GlobalSelect/SelectSame/Type(TP) function added. + 5. HexEditor added! See the help in the internal file viewer ( press `I' in the HEX mode of the internal file viewer ) ! 6. Fixed pattern searching function ( it didn't work before with patterns that contains char codes >128 sometimes ) + 7. FTP support! See above for details. ! 8. Few bugfixes as usual... 1.44: 14.Feb.1999 + 1. Auto mounting on change directory added. ( see Options/AutoMount ) If you chdir to a directory which contains only one file named `automount', then VFU will try to mount this directory automatically. After mounting `automount' file won't be visible. You can create file with `echo > automount' command. + 2. Unmount feature added to the `JumpToMountpoint' menu ( key `j' ). + 3. PreserveSelection option added. If this option is enabled VFU will preserve selected files after rescanning files list. ( see Options menu ) + 4. Added Ctrl+Z key to the Directory Tree View for update the current (under cursor) directory size. ! 5. Fixed tilde `~' expansion -- now standalone `~' or `~username' are expanded properly. + 6. RecursiveRescanning can be canceled with ESC now. ! 7. Options(Toggles) separators bug fixed. ! 8. User External Utilities are enabled in InArchive mode as it should be. (considered bug) ! 9. Dotfiles `.filename' colorization fixed. 1.43: 12.Feb.1999 ! 1. Now VFU supports properly screens >80x25 (fixed bug with 80-columns filename view) - 2. ENTER has priority now for entering into archives than executing user external program. + 3. Added option for handling .TGZ equally to .tgz, i.e. case insensitive archive extension detection. + 4. RenameTools added to the tools menu (key `T') + 5. Added one more location for global vfurc file: `/etc/' it is searched first. Can be changed through VFU_RCPATH0 define. ! 6. Now $HOME/.vfurc is primary if exists ( before global vfurc's as it should be ) considered as bug :) - 7. ENTER key behavior changed: If not defined for user external utility, ENTER works as browse/view. It also assumed equal to '+' or '=' for archives ( i.e. cannot be redefined for archives, there's INSERT and Fx alternatives, however if someone needs ENTER for this I probably can change it ). + 8. MenuBorders option added. It can improve menu visibility on mono/colorless terminals. 1.42: 03.Feb.1999 + 1. External scanning ( panelize ). Just enter `command |' in the files masks input line to use it ( i.e. instead of "*.txt" enter "find / -name '*.txt'" ). ! 2. The problem with files/dirs' sizes >2GB is now fixed! 1.41: 04.Dec.1998 + 1. Added Options/FileCopyPreserveOwner/Group option. If enabled VFU will try to preserve files owner and group id's on copy/move if possible. - 2. Now `dir1' is equal to `presetdir1' etc. in the vfurc meaning. + 3. BZip2 archives now supported NOTE!: you have to get tar-1.2+ patched to support -I option which is BZip2 support. required extensions for such files are `bz2' or `tbz' (second one is mine:)) + 4. `Time/Touch' entry added to the `EditEntry' function (TAB key), i.e. change file(s)'s modify and access times. + 5. Now VFU expands ~ with username (~cade/boo) but only if target directory is started with ~. + 6. Added `Show Real Free Space' toggle to the options. + 7. Recursive rescanning added ( Ctrl+R key menu ). Now you can operate over all files from a tree branch! + 8. A lot of cleanup work done. 0.40 ... 1.41: xx.xxx.xx % 0. FAQ: Why is this? You have skipped these version numbers? Well the answer is something like: The versions 0.xx were meant to be kind of alpha/beta versions and are not supposed to be released to the public in the beginning ( didn't happen :)). Well, the versions after 0.40 are considered `stable' and `official' now, so I've added `1' to them... ( there's 1 year since BETA status was removed :)) 0.40: 31.Sep.1998 + 1. Internal Text/Hex file viewer/browser added! See Options/InternalViewer. Hit `H' to get help inside viewer. (The viewer is available and as standalone utility called `See') + 2. Extended filename completion: now you can enter for example: `/level/next/one[mM]o?r*' and hit TAB to complete! + 3. Everywhere you enter directory path you can use: Ctrl+X -- expand to real path Ctrl+A -- delete back one dir level Ctrl+S -- show list with matching directories (kind of visual tab-completion) + 4. Key-names for `user external commands' are shorter: KEY_F1 is now F1 KEY_SH_F1 is now #F1 (Shift+F1) KEY_ALT_F1 is now @F1 (not available under Linux) KEY_CTRL_F1 is now ^F1 (not available under Linux) KEY_IC is now either INSERT, INS or IC KEY_ENTER is now ENTER + 5. `Tools/Classify move' tool added. + 6. `GlobalSelect/Extended/Find;Scan;Hex;Regexp;String' added! + 7. Extended FileFind menu added (Ctrl+N). FileFind with Find/Scan/Hex/Regexp string added. - 8. New Options/Toggles system (Now it is more flexible for adding/displaying new toggles -- really sorry if you liked old one :( ) + 9. Now file types: `** [] <> () etc...' can be used instead of file extensions in the user external command: ux=EXECUTE,INS,.**.,%w +10. Now VFU has option to zap/erase READ-ONLY files. (see options) +11. Many command line switches added! (run `VFU -h' for help) +12. Find/Scan/Hex/Regexp string search added to the internal file viewer/browser! +13. User External Commands are now available and in InArchive mode! +14. FileMasks expanding added to `files mask' filter and file find tool. ( for more details see `FAQ/What are the mask expansion rules' ) +15. GlobalSelect/Different function added. 0.30: 25.Sep.1998 + 1. Archives support! Now VFU supports the following archives: zip, tar, tgz, uc2, arj, lha, rar (for more details see `Usage notes' section) + 2. Now VFU follows sym-links. 0.22: 30.Aug.1998 % 1. Support VFUSHELL environment variable -- it is used to override SHELL variable (to use login shell for example) + 2. Added `GlobalSelect/All+Dirs' function. + 3. Preserve timestamps on copy. + 4. Report target file status on overwrite (copy/move/etc.). + 5. `Insert/Overstrike' modes in all input lines. + 6. Added `History' to most of the input lines. (try PageUp/PageDown keys in input lines) + 7. Now incremental search can work and with patterns. (for example if you enter `>*.cpp' VFU will track on all *.cpp files -- please note the leading `>'!) - 8. Now options(keywords) in the vfurc file are NOT case sensitive. (for example you can type `BrOwSeR=less %f') + 9. `TrimTree' option added to vfurc. example: TrimTree=/mnt/cdrom/ /proc/ /tmp/ You can use these separators: UNIX: [,:] space and tab. DOS: [,;] space and tab. DOS users note: TrimTree doesn't support driveletters! I mean if you want to trim `c:/tmp/' you should add `TrimTree=/tmp/' but this will cut also `d:/tmp/' -- This is NOT bug but WAD. +10. Now you can use file type identifiers for filename colorization (also `dotfiles' for `.name' dotfiles). For example: cGREEN=.cpp.h.**.(). cRED=.[].txt.dotfiles. cBLUE=.<>. all .cpp, .h, executable files and pipes are GREEN all .txt, dotfiles and directories are RED all links to directories are BLUE 0.21: 02.Aug.1998 % 0. Oops... I forgot -- If someone want to know why I'm trying to support DOS platform: the reason is that I use DJGPP+RHIDE for development environment -- it is more comfortable than gcc+joe :) Well I know that there is RHIDE for Linux but I haven't tried it yet... + 1. New files' attributes/mode set/get engine. Now VFU supports different attrib's under different OS-es transparently: Linux/UNIX: `drwxrwxrwx' DOS: `DV----RHSA' + 2. `VFFilenames' style added for DOS *only*! This means all dirs' names are upper case and all files' names are lower case (but this is only for the screen!) + 3. Added IncrementalSearch to the file list and the directory tree ( key Ctrl+S, and TAB to advance ). + 4. Copy/Move/Erase now work on directories (w. entire substructures)! + 5. `CDTree' option added. This is similar to bash's CDPATH env.variable but the needed path is searched in the directory tree. For example: if you are in the HOME directory and try to ChDir to `rc.d' -- VFU will check for HOME/rc.d, which not exist, then will try to find such dir in the DirTree (if the tree is not built, VFU will try to just to load it from disk), most probably `/etc/rc.d/' will be found and VFU will ChDir to it. + 6. New shell-macros: %e, %E, %s, %R, %c, %C + 7. Added `JumptToMountpoint' function ( key `J' ) + 6. Added `MakeDirectory' to `Tools' menu ( key `T' ) 0.20: 4.Jul.1998 % 0. Changes are too much to list (will try to describe most important ones). The main change is that -- VFU goes portable -- Currently it supports Linux, Solaris, DOS(!). (I mean that I have compiled it for these OS-es myself) Win32 version is on the way... Note that DOS version supports long filenames (LFN's)! To use this support you have to `set LFN=Y' in the environment. + 1. `Options/Toggles' screen added (key `O' or Alt+O) Options menu (key `o') still exists but is empty for now. + 2. Now you can switch off parts of file informations (i.e. mode/attr, owner, group, time, size... see Options/Toggles). + 3. DirectoryTree added (key Ctrl+D) incl. hot key search `a'-`z'. + 4. `DynamicScroll' option added -- it switch all lists scrolling between `page-by-page' or `line-by-line'. 0.15: 15.Mar.1998 + 1. FileFind function added. (key `n') ! 2. Screen redraw after shell fixed. 0.14: 17.Oct.1997 + 1. SymLinks -- `l' key. ! 2. RmDir/Links bug is now fixed. ! 3. Other minor bugfixes. % 4. Since VF/U passed large enough test period without any major problems or any kind of data loss etc., `BETA' status has been removed. 0.13BETA: 17.Oct.1997 There's not such version really. :) trust me... :) 0.12BETA: 06.Oct.1997 + 1. GlobalSelect/+/-/= -- select/deselect by mask. + 2. UserExternals commands added (see vfurc description). + 3. Now vfu will search for environment variables 'EDITOR' and 'PAGER' (or 'BROWSER') to set editor and pager/browser. (if not given in vfurc file) + 4. TAB/chown now accepts 'username.groupname' instead of 'uid.gid'. + 5. GlobalSelect/Same..name/ext/size/owner/group added. + 6. Inline editing caps added. + 7. File masks added. + 8. VFU or VF screen/view styles added. 0.11BETA: 20.Aug.1997 ! 1. Some bugfixes. 0.10BETA: 07.Aug.1997 ! 1. bug with following directory links when calculating directory(ies) size is now removed. ! 2. now vfu shows file type correctly. (links,dir.links) + 3. link realpaths are now shown: "linkname -> realpath". + 4. "Tools/r-realpath" added, shows real path for a link. + 5. "Options" added -- key "o"/"O". ! 6. problem with unknown uid/gid is now fixed. + 7. "ChDirHistory" added -- key "D". 0.09BETA: 01.Apr.1997 + 1. now vfu prompts you before overwriting existing file. (while copy or move files) 0.08BETA: 30.Mar.1997 ! 1. get dir name logic fixed. ( don't worry if you don't know what that means, however it's better now :)) 0.07BETA: 28.Mar.1997 % 0. elf version. - 1. now tab-completion procedure adds '/' at the end. + 2. octal mode chmod (TAB+A+\). + 3. now vfu remembers last copy/move paths. + 4. chdir shows last path you were in. 0.06BETA: history lost... ---------------------------------------------------------------------- vfu-4.10/README.DOS0000644000175000001440000000070311172607364012364 0ustar cadeusers FAR PRELIMINARY :) this file contains some hints how to compile vfu under dos/djgpp 1. you have to edit makefile's in the vslib and vfu directories and change `g++' to `gcc' in `CC' and `LD' fields. 2. remove `-lncurses' from both makefiles `LDFLAGS' field. 3. try to `make' in vslib dir and after this in the vfu dir. NOTE: you must preserve the tabs in the makefile's! if you have problems contact me at vfu-4.10/vfu.conf0000644000175000001440000002411311172607551012526 0ustar cadeusers############################################################################################### # # vfu.conf # VFU File Manager config file # (c) Vladi Belperchinov-Shabaski 1997-2009 # # http://soul.datamax.bg/~cade/vfu # http://cade.datamax.bg/vfu/ # ############################################################################################### # # All lines with first character # or ; are considered comments! # Comments may start on a separated new line only! (i.e. comment chars must be first in line) # This file is read-only! vfu never writes to it. # # Possible locations for this file are: # # $HOME/.vfu/vfu.conf # $HOME/$RC_PREFIX/vfu/vfu.conf ( please read CONFIG file ) # /etc/vfu.conf # /usr/local/etc/vfu.conf # /usr/local/vfu.conf # # comment out folowing lines to use vfu's internal editor and viewer # or you can toggle em run-time if you wish so Browser=less %f Editor=joe %f Diff=diff -u # alternative ones: #Editor=vi %f #Editor=~/apps/zed/zed %f # list of known archive types, these are just for recognizing # handling is done via rx_* scripts! but not by VFU itself Archive=*.zip Archive=*.pk3 Archive=*.maff Archive=*.jar Archive=*.tar.gz Archive=*.tgz Archive=*.tar.Z Archive=*.tar.bz2 Archive=*.tar Archive=*.rar Archive=*.deb Archive=*.ftp Archive=*.rpm # # if you'd like to restrict VFU when walking the directory tree -- list paths # here. Note that you usually should add at least `/tmp/' and `/proc/' # format is `:' separated list of directory prefixes # TrimTree=/dev/:/proc/:/tmp/:/dos/:/a/ ############################################################################################### # user external commands (handlers), format is: # description,keyname,ext.mask,command # # to execute a command VFU will try to match both # key pressed and current file's extension! # # 1. `description' is just free text, keep it small, first letter can be used as menu hotkey # 2. `keyname' is key you want to bind # 3. `ext.mask' is dot-separated list of required extensions and/or file type strings # or `*' to discard file type and run command for all files # (don't be confused with `.**.' which stands for `executable' files) # 4. `command' is the shell line you want to execute (as on the command prompt for example) # # Available keys (keynames) are: # ENTER, INSERT, F1..F10, @F1..@F10, #F1..#F10, ^F1..^F10 # (#=shift, @=alt, ^=ctrl, note: ^KEY and @KEY are not available under Linux) # # NOTE: You can use keyname `MENU' to attach this command to the `UserMenu' (key U in vfu) # NOTE: `file type strings' are the strings that VFU shows in the `TP' column in the file, # list. Here is a list of the file type strings: # ** -- executable file # [] -- directory # -> -- symbolic link # <> -- symbolic link to directory # == -- block device # ++ -- character device # () -- fifo (pipe) # ## -- socket # You can mix file extensions with file type strings in the same mask. # There is a special mask called `dotfiles' which will match dotfiles (wiles named # with leading dot -- `.dotname' ) # NOTE: You cannot mask longer extensions like `.tar.gz' for example. # # `Command' string (shell line) can contain following macros: # # %f -- replaced w. current filename (w/o path) # %F -- replaced w. full pathname of the current file # %g -- same as %f but for each selected filename # %G -- same as %F but for each selected filename # %g and %G produce list of filenames. each filename # is surrounded by ' # if filename contains ' then " is used. # example: 'file1' "file2's" 'file"3"' ... # %e -- current file name without extension # %E -- current file extension # %s -- current file size # %c -- current path ( with slash at the end ) # %C -- startup path ( with slash at the end ) # %R -- re-read directory content after shell # %? -- prompt for user input and replace it in # %i -- simulates DownArrow after execution # %n -- don't clear and redraw screen on user external command # %w -- wait a key after shell. replaced w. `' (i.e. empty string) # %x -- replaced w. `x'. # %_ -- use short file names (SFN) for %f and %F (DOS only) # %\ -- use backslashes for %f and %F (DOS only) # %! -- request shell line to be shown before execution (debug mode) # # view JPEGs and GIFs -- you can move this to the SEE filters below #ux=SEE JPEG,INSERT,.jpg.jpeg.gif.,seejpeg -w -F G640x480x256 -c "%f" ux=SEE JPEG,ENTER,.JPG.jpg.JPEG.jpeg.gif.xpm.png.,qvv "%f" 2> /dev/null & ux=SEE GNUMERIC,ENTER,.xls.gnumeric.,gnumeric "%f" 2> /dev/null & # view HTML documents -- now moved to SEE filters below ux=SEE HTML,ENTER,.htm.html.shtml.,lynx "%F" ux=SEE HTML,INSERT,.htm.html.shtml.,lynx "%F" #ux=PLAY WAV,ENTER ,.au.wav.WAV.,killall mpg123 play 2> /dev/null; play "%f" %i %n 1> /dev/null 2> /dev/null & #ux=PLAY WAV,INSERT,.au.wav.WAV.,play "%f" %i%n 1> /dev/null 2> /dev/null & #ux=PLAYMP3,ENTER,.ogg.mp3.wav.,killall mpg123 play 2> /dev/null; mpg123 -b 1024 "%f" %i 1> /dev/null 2> /dev/null & # run xmms with all selected files ux=PLAY MP3,ENTER,.ogg.mp3.wav.,xmms "%f" %i 1> /dev/null 2> /dev/null & # if you want to run only pointed one, then replace %g with %f like in the next line: # ux=PLAY MP3,ENTER,.ogg.mp3.wav.,xmms "%f" %i 1> /dev/null 2> /dev/null & # run xmms with all mp3/wav files in the current directory ux=PLAY MP3,INSERT,*,xmms *.mp3 *.wav 1> /dev/null 2> /dev/null & # view PDF and PS document ux=VIEW PDF,ENTER,.pdf.PDF.,acroread "%f" 1> /dev/null 2> /dev/null & ux=VIEW PS,ENTER,.ps.,gv "%f"& # ux=VIEW TAR,INS,.gz.,gunzip -c "%f" | tar tvf - | less # view man pages -- note you can add and see filter for this ux=VIEW MAN,ENTER,.1.2.3.4.5.6.7.8.,man "%F" # play mpeg's #ux=PLAY MPEG,ENTER,.mpg.MPG.mpeg.,plaympeg "%f" 1> /dev/null & #ux=PLAY MPEG,INS,.mpg.MPG.mpeg.,plaympeg -2 "%f" 1> /dev/null & ux=PLAY MPEG,ENTER,.mpg.MPG.mpeg.asf.avi.mov.wmv.,mplayer "%f" 1> /dev/null 2> /dev/null & ux=PLAY MPEG,INS,.mpg.mpeg.asf.avi.mov.wmv.,mplayer "%f" 1> /dev/null 2> /dev/null ux=PLAY REAL,ENTER,.rm.,realplay "%f" 1> /dev/null 2> /dev/null & # other applications ux=EDIT GNUMERIC,ENTER,.gnumeric.,gnumeric "%f" 1> /dev/null 2> /dev/null & # # following user commands are bound to the UserMenu -- key `u' # note that instead of keyname there's `menu' string! # first letter is hotkey! # ux=lLocate file,menu,*,locate %? %w ux=---,menu,*, ux=ompg123: Stop,menu,*,killall -TERM mpg123 1> /dev/null 2> /dev/null & ux=smpg123: Suspend,menu,*,killall -STOP mpg123 1> /dev/null 2> /dev/null & ux=cmpg123: Continue,menu,*,killall -CONT mpg123 1> /dev/null 2> /dev/null & ux=vmpg123: View running/queue,menu,*,ps xeo "%%p %%a" | grep mpg123 | grep -v grep | less ux=---,menu,*, ux=GGQView Here,menu,*,gqview . 1> /dev/null 2> /dev/null & # # aditional examples: # # edit with kwrite ( > /dev/null -- all os text messages ) # NOTE: `*' means for any file (regardless type) ux=KWRITE EDIT,F6,*,kwrite "%f" 2> /dev/null 1> /dev/null %n & ux=GIMP EDIT,F7,.gif.jpg.png.xcf.,gimp-remote "%f" 2> /dev/null 1> /dev/null %n & # ux=SLICK EDIT,F7,*,vs '%f' 2> /dev/null 1> /dev/null %n & ux=KATE EDIT,F7,*,e '%f' 2> /dev/null 1> /dev/null %n & # execute all files that have type `**' with ENTER ux=EXEC,ENTER,.**.,"%f" # same as the one before but executes command in background ux=EXEC,INSERT,.**.,"%f"& ############################################################################################### # the `see' file browser/viewer filters # the format is: # file-mask,command # 1. `file-mask' tells which files should be filtered # 2. `command' is executed and it's output is piped to temporary file which is # viewed by the viewer (You have to specify %f in the command) # see=*.html.gz,(gzip -dc "%f" > /tmp/vfu.temp.000.html; lynx -dump /tmp/vfu.temp.000.html; rm /tmp/vfu.temp.000.html ) see=*.[1234567890].gz,man "%F" see=*.gz,gzip -dc "%f" see=*.bz2,bzip2 -dc "%f" see=*.Z,gzip -dc "%f" see=*.[1234567890],man "%F" see=*.htm,lynx -dump "%f" see=*.html,lynx -dump "%f" see=*.shtml,lynx -dump "%f" see=*.dbf,dbfdump -2 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 "%f" see=*.jpg,exiftags '%f' see=*.JPG,exiftags '%f' # this is a hack to view Qt man pages see=*.[1234567890][a-zA-Z]t?,man "%F" ############################################################################################### # external panelizers -- added to RescanMenu ( key ALT+R ) # first letter is hotkey! # format is: # description,command # 1. `description' is free text describing panelizer command # 2. `command' is processed just like any other external command, so # you can use the shell-macros described above. Note that # first letter of description is used for menu hotkey! # panelize=xExternal panelize command,%? panelize=yFind all symlink files...,find . -type l panelize=lLocate file,locate %? ############################################################################################### # directory bookmarks -- press ALT+2 to change current dir to `/tmp' etc... # bookmark1=/home/cade/ bookmark2=/tmp/ bookmark3=/usr/src/ bookmark4=/usr/local/lib/X11/icewm/ # :) ############################################################################################### # file extensions colors, format is .ext.ext.ext....ext. # NOTE: this is extensions list, use dots to separate and at the end # cMAGENTA=.**.txt.rc. cGREEN=.jpeg.jpg.lbm.xpm.tif.gif.png. cCYAN=.[].<>.h.c.cpp.cc.cxx.pas.pl. cRED=.dotfiles. cYELLOW=.uc2.zip.arj.tgz.tar.rar.lzh.j.ha.lim.gz.Z.bz2.deb. cBLUE=.==.++.().##. ############################################################################################### # high colors # NOTE: this mode currently is not available! # #chMAGENTA= #chGREEN= #chCYAN= #chYELLOW=.1.2.3.4.5.6.7.8. #chBLUE= ############################################################################################### # EOF vfu.conf ############################################################################################### vfu-4.10/vfu.html0000644000175000001440000001231211172611246012537 0ustar cadeusers vfu - VFU is console file manager for UNIX/Linux

NAME

vfu - VFU is console (text-mode) file manager for UNIX/Linux


SYNOPSIS

vfu [options]


DESCRIPTION

vfu has following features:

 - Fast one-key commands
 - Extended completition and wildcard expansion
 - Directory tree with sizes (incl. sizes cache)
 - File-type colorization (extension and type)
 - Archives support (TAR, TGZ, BZ2, and many more)
 - Simple FTP support through archive-like interface
 - Internal text/hex file viewer and editor (optional)
 - Extensive user-defined external support/utils
 - Regular expressions selection and search
 - Multiple file masks
 - and much more...


OPTIONS

 -h
prints help for command line options
 -i
runs vfu in interactive mode (can be used with \-d)
 -d path
changes working directory to `path'
 -r
rebuild directory tree
 -t
view directory tree only

These options are for using vfu in partial non-interactive mode.

 example: vfu -d /usr/local -i


CONFIGURATION

vfu configuration is divided in two parts (files):

vfu.conf

This file contains configuration for external editor and pager, favorite directories, file-type colorization. This is plain text file which format is described below. vfu only reads vfu.conf, it never writes in it!

vfu.options

This file contains all Options/Toggles which can be changed from inside vfu -- Options menu. vfu.options is binary file and is overwritten on vfu exit or on change option event! Deleting this file will reset vfu toggles to default values. vfu.options is not portable between vfu versions!

Location of vfu.conf

vfu.conf can be placed as any of:

 $HOME/.vfu/vfu.conf

 $HOME/$RC_PREFIX/vfu/vfu.conf  (if $RC_PREFIX is exported)

 /etc/vfu.conf

 /usr/local/etc/vfu.conf

 /usr/local/vfu.conf

Other files location

All other files including vfu.options are placed in:

 $HOME/.vfu/

 $HOME/$RC_PREFIX/vfu/

What is $RC_PREFIX and why to use it? Some more information for this can be found in the CONFIG file which is supplied with vfu package.


VFU.CONF

This is a sample copy of vfu.conf with appropriate comments:


DISTRIBUTION

It is supposed that only source packages will be distributed. However sometimes binary packages will be released, but not often. VFU packages are named in this way:

 vfu-X.xx.src.tgz

source package for version X.xx
 vfu-X.xx.bin.platform.tgz

binary package for version X.xx for `platform' platform

examples:

 vfu-4.00.src.tgz
 vfu-4.00.bin.linux.glibc.tgz
 vfu-4.00.bin.linux.libc5.tgz
 vfu-4.00.bin.dos.tgz

All packages are TAR+GZIP .tgz, bz2 and zip are available on request.

NOTE: Always check HISTORY document -- it often contains some usefull notes!


FILES

 $HOME/$RC_PREFIX/vfu/vfu.conf

configuration, explained above

 $HOME/$RC_PREFIX/vfu/vfu.options

options, explained above

 $HOME/$RC_PREFIX/vfu/vfu.history

contains history lines

 $HOME/$RC_PREFIX/vfu/vfu.tree

contains directory tree

If you don't set $RC_PREFIX configuration files are:

 $HOME/.vfu/vfu.conf
 $HOME/.vfu/vfu.options
 $HOME/.vfu/vfu.history
 $HOME/.vfu/vfu.tree


TODO

see the TODO file


BUGS

unknown


AUTHOR

 Vladi Belperchinov-Shabanski "Cade"
 <cade@biscom.net> <cade@datamax.bg>
 http://soul.datamax.bg/~cade/
 http://soul.datamax.bg/~cade/vfu
vfu-4.10/vfu.wiki0000644000175000001440000002364511172613707012555 0ustar cadeusersvfu ia a nifty little text-based file-manager which can be run from a terminal. <> == Helpful Commands: == * '''h''' - help * '''q''' - exit to the (VFU) current directory (using optional shell script, see below) * '''x''' - exit to the last working directory * '''ENTER''' - view file or enter folder * '''BKSPACE''' - up a level * '''a''' - arrange (sort) files list * '''e''' - erase file/folder * '''c''' - copy files * '''m''' - move files * '''l''' - symlink files (lower L) * '''b''' - browse (view) files * '''g''' - global select files by criteria. also modifies files list (hide entries for example) * '''s''' - search for filename, wildcards are available (advance with '''TAB''' during search) * '''i''' - edit file * '''1'''..'''9''' - toggle display of files details (mode, time, size...) * '''0''' - switch between simple and detailed listings (full info or just filenames) * '''~''' - to home directory * '''.''' - show/hide hidden files (.dot files) * '''f''' - mask files (CTRL+f resets mask back to '''*''') * '''d''' - change working directory * '''ALT+d''' - change directory history * '''`''' - directory bookmarks * '''u''' - user menu * '''TAB''' - edit file name/properties * '''o''' - runtime options (those are not saved/read from the config file) * '''p''' - files clipboard (copy, move files from several locations...) * '''v''' - edit VFU config file VFU will execute actions either on the currently pointed file (if no selection exists) or on the currently selected entries. Using ALT+key exacutes action only on the currently pointed file, regardless selection. Those rules apply to '''copy''' (ALT+c), '''move''' (ALT+m), '''symlink''' (ALT+l), '''browse''' (ALT+b) operations. == Changing location of config file: == To change where the configuration file is stored ( such as moving it to .config so that it does not clutter the home folder) add {{{ # to get vfu to put config file into ~/.conf # have to export $RC_PREFIX as .conf export RC_PREFIX=.config }}} into the file {{{.bashrc}}}. The configiuraton file can now be found in {{{~/.config/vfu/vfu.conf}}} If you decide not to change the location of the config file, it will be stored in {{{~/.vfu/vfu.conf}}} == Quit To Current (VFU) Working Directory == VFU offers two exits. One to the last working directory ('''x''' key) and the other is to the directory VFU is currently in ('''q''' key). To use the latter you need to start VFU with shell function. Here is example for bash(1): {{{ function vfu() { /usr/local/bin/vfu $*; cd "`cat /tmp/vfu.exit.$USER`"; rm -f /tmp/vfu.exit.$USER; } alias vf="vfu" # you need to add this to your ~/.profile or ~/.bash_profile }}} == Custom File Editor: == To change the text editor used by vfu find, within the {{{vfu.conf}}} file, the line (near the top): {{{ Editor=vim %f }}} and change it so that `vim` is the editor of your choice, such as `gedit`, `kwrite`, `mousepad`, `vi`, `vim`, `nano`, `emacs`. You may have to turn off the 'use internal editor' option in the options menu (press `o` to bring up menu and `SPACE` to turn off option). It is also possible to use a different viewer if you so wish. == Custom File Associations: == Vfu can be customised to open different files with different programs; Entrys are put in the comma separated format such as: {{{ ux=SEE DOC,ENTER,.doc.DOC.odt.sxw.,ooffice2 -writer "%f" & }}} Where: * '''SEE DOC''' is just a short descriptive name * '''ENTER''' is the action on the file * '''.ext.ext.ext.ext.''' the file extentions to which the actions apply (dot separated list) * '''ooffice2 -writer "%f"''' is the command to use on the file, "%f" is the location of the file * '''&''' indicates that you wish to continue using vfu whist the file is open Thus, vfu will open ooffice2 -writer when I press ENTER on a .odt file (or .doc , .sxw etc). If you don't add '''&''' at the end, VFU will wait ooffice2 to exit before returning back to files list. General syntax is: {{{ description,keyname,ext.mask,command }}} * '''description''' is just free text, keep it small, first letter can be used as menu hotkey * '''keyname''' is key you want to bind * '''ext.mask''' is dot-separated list of required extensions and/or file type strings (extension mask) * '''command''' is the shell line you want to execute (as on the command prompt for example) Available keys (keynames) are: {{{ ENTER, INSERT, F1..F10, @F1..@F10, #F1..#F10, ^F1..^F10 Modifiers are: #=shift @=alt ^=ctrl note: ^KEY and @KEY may not always work, try pressing ESC then Fx as alternative to @Fx }}} Extension mask can be '''*''' to discard file type and run command for any/all files. It may also contain file types: {{{ ** -- executable file [] -- directory -> -- symbolic link <> -- symbolic link to directory == -- block device ++ -- character device () -- fifo (pipe) ## -- socket }}} You can mix file extensions with file type strings in the same mask. Don't confuse '''*''' (any/all files) with '''**''' (executables). In any '''command''' string (shell exec lines) you can use those placeholders: {{{ %f -- replaced with current filename (w/o path) %F -- replaced with full pathname of the current file %g -- same as %f but for each selected filename %G -- same as %F but for each selected filename %g and %G produce list of filenames. each filename is surrounded by ' if filename contains ' then " is used. example: 'file1' "file2's" 'file"3"' ... %e -- current file name without extension %E -- current file extension %s -- current file size %c -- current path ( with slash at the end ) %C -- startup path ( with slash at the end ) %R -- re-read directory content after shell %? -- prompt for user input and replace it in %i -- simulates DownArrow after execution (advances file pointer to the next file in the list) %n -- don't clear and redraw screen on user external command %w -- wait a key after shell. replaced with empty string %x -- replaced with `x' (i.e. if '''x''' is not recognised as placeholder) %! -- request shell line to be shown before execution (debug mode) }}} Example section: {{{ # view pictures ux=SEE JPEG,ENTER,.JPG.jpg.JPEG.jpeg.gif.xpm.png.,feh "%f" 2> /dev/null & # view HTML documents -- now moved to SEE filters below ux=SEE HTML,ENTER,.htm.html.shtml.,firefox "%F" & #ux=SEE HTM,ENTER,.htm.html.,w3m "%F" ux=SEE HTML,INSERT,.htm.html.shtml.,w3m "%F" # office document viewing ux=SEE DOC,ENTER,.doc.DOC.odt.sxw.,ooffice2 -writer "%f" & ux=SEE SHEET,ENTER,.ods.sxc.xls.,ooffice2 -calc "%f" & ux=SEE PRESENTATION,ENTER,.odp.ppt.sxi.,ooffice2 -impress "%f" & ux=SEE DRAW,ENTER,.odg.sxd.sda.sdd.,ooffice2 -draw "%f" & #music x=PLAY MP3,ENTER,.ogg.mp3.wav.wma.,vlc -I skins2 "%f" %i 1> /dev/null 2> /dev/null & ux=PLAY MP3,INSERT,*,xmms *.mp3 *.wav 1> /dev/null 2> /dev/null & # view PDF and PS document ux=VIEW PDF,ENTER,.pdf.PDF.,acroread "%f"& ux=VIEW PS,ENTER,.ps.,gv "%f"& # ux=VIEW TAR,INS,.gz.,gunzip -c "%f" | tar tvf - | less # view man pages -- note you can add and see filter for this ux=VIEW MAN,ENTER,.1.2.3.4.5.6.7.8.,man "%F" # play mpeg's ux=PLAY MPEG,ENTER,.mpg.MPG.mpeg.asf.avi.mov.wmv.,vlc -I skins2 "%f" 1> /dev/null 2> /dev/null & ux=PLAY MPEG,INS,.mpg.MPG.mpeg.asf.avi.mov.wmv.,vlc -I skins2 "%f" 1> /dev/null 2> /dev/null & }}} == Custom User Menu: == The user menu is reached by pressing the `u` key. Custom options in this menu can be added by finding the section; {{{ # # following user commands are bound to the UserMenu -- key `u' # note that instead of keyname there's `menu' string! # first letter is hotkey! # ux=lLocate file,menu,*,locate %? %w ux=---,menu,*, ux=ompg123: Stop,menu,*,killall -TERM mpg123 1> /dev/null 2> /dev/null & ux=smpg123: Suspend,menu,*,killall -STOP mpg123 1> /dev/null 2> /dev/null & ux=cmpg123: Continue,menu,*,killall -CONT mpg123 1> /dev/null 2> /dev/null & ux=vmpg123: View running/queue,menu,*,ps xeo "%%p %%a" | grep mpg123 | grep -v grep | less }}} The format is of comma separated fields: {{{ ux=kname,menu,*,command }}} where: * `k` is the shortcut key in the menu. * `name` is the name of the entry in the menu. * `menu` states that it is a menu item. * `*` is the filetype filter - leave it as an asterix to enable it to be performed on all files/folders. * `command` is the command to be performed the variable "%f" is used to add in the location of the file/folder. An '&' can be added on at the end if you want to continue using vfu whilst the action is being performed. Example menu section: {{{ # # following user commands are bound to the UserMenu -- key `u` # note that instead of keyname there's `menu` string! # first letter is hotkey! # ux=lLocate file,menu,*,locate %? %w ux=---,menu,*, ux=ffeh: show pics in feh,menu,*,feh "%f" & ux=gfeh: show pics fullscreen,menu,*,feh -F "%f" ux=pplay: play in xfmedia,menu,*,xfmedia "%f" & ux=wwatch: play in vlc,menu,*,vlc -I skins2 "%f" 1> /dev/null 2> /dev/null & ux=---,menu,*, ux=ompg123: Stop,menu,*,killall -TERM mpg123 1> /dev/null 2> /dev/null & ux=smpg123: Suspend,menu,*,killall -STOP mpg123 1> /dev/null 2> /dev/null & ux=cmpg123: Continue,menu,*,killall -CONT mpg123 1> /dev/null 2> /dev/null & ux=vmpg123: View running/queue,menu,*,ps xeo "%%p %%a" | grep mpg123 | grep -v grep | less }}} Where extra options have been added to play music/videos in xfmedia or vlc and to show pictures in feh. i.e. It is now possible to open a folder of pictures using feh or a folder of music using vlc (with the options for a nice skin) But the best way to find out about vfu (and most other programs) is to make a backup of the file and then play arround with it to see what you can get it to do. == Links == [[http://cade.datamax.bg/vfu/|vfu homepage]] CategoryDocumentation vfu-4.10/vfu.lsm0000644000175000001440000000237111172607616012400 0ustar cadeusersBegin3 Title: VFU File Manager Version: 4.09 Entered-date: 14APR2009 Description: VFU is console (text mode) file manager for UNIX. It has all usual file oprations plus more: - extended completition and wildcard expansion - directory tree with sizes (incl. sizes cache) - file-type colorization (extension and type) - archives support (TAR, TGZ, BZ2, and many more) - simple FTP support through archive-like interface - internal text/hex file viewer and editor (optional) - extensive user-defined external support/utils - regular expressions selection and search - multiple file masks - one-key commands - session saving - more... Keywords: console file manager unix portable Author: cade@datamax.bg (Vladi Belperchinov-Shabanski) Maintained-by: cade@biscom.net (Vladi Belperchinov-Shabanski) Primary-site: metalab.unc.edu /pub/Linux/utils/file/managers 450kB vfu-4.09.tar.gz Original-site: http://soul.datamax.bg/~cade/vfu Platforms: UNIX (Linux, Solaris, NetBSD, ...), DOS/Win9X Copying-policy: GPL End vfu-4.10/vfu.pod0000644000175000001440000000645011172606420012361 0ustar cadeusers=head1 NAME vfu - VFU is console (text-mode) file manager for UNIX/Linux =head1 SYNOPSIS vfu [options] =head1 DESCRIPTION B has following features: - Fast one-key commands - Extended completition and wildcard expansion - Directory tree with sizes (incl. sizes cache) - File-type colorization (extension and type) - Archives support (TAR, TGZ, BZ2, and many more) - Simple FTP support through archive-like interface - Internal text/hex file viewer and editor (optional) - Extensive user-defined external support/utils - Regular expressions selection and search - Multiple file masks - and much more... =head1 OPTIONS -h prints help for command line options -i runs vfu in interactive mode (can be used with \-d) -d path changes working directory to `path' -r rebuild directory tree -t view directory tree only These options are for using vfu in partial non-interactive mode. example: vfu -d /usr/local -i =head1 CONFIGURATION B configuration is divided in two parts (files): B This file contains configuration for external editor and pager, favorite directories, file-type colorization. This is plain text file which format is described below. vfu only reads vfu.conf, it never writes in it! B This file contains all Options/Toggles which can be changed from inside vfu -- Options menu. vfu.options is binary file and is overwritten on vfu exit or on change option event! Deleting this file will reset vfu toggles to default values. vfu.options is not portable between vfu versions! =head2 Location of vfu.conf B can be placed as any of: $HOME/.vfu/vfu.conf $HOME/$RC_PREFIX/vfu/vfu.conf (if $RC_PREFIX is exported) /etc/vfu.conf /usr/local/etc/vfu.conf /usr/local/vfu.conf =head2 Other files location All other files including vfu.options are placed in: $HOME/.vfu/ $HOME/$RC_PREFIX/vfu/ What is B> and why to use it? Some more information for this can be found in the B file which is supplied with B package. =head1 VFU.CONF This is a sample copy of vfu.conf with appropriate comments: =begin text #include "vfu.conf" =end text =head1 DISTRIBUTION It is supposed that only source packages will be distributed. However sometimes binary packages will be released, but not often. VFU packages are named in this way: vfu-X.xx.src.tgz source package for version X.xx vfu-X.xx.bin.platform.tgz binary package for version X.xx for `platform' platform examples: vfu-4.00.src.tgz vfu-4.00.bin.linux.glibc.tgz vfu-4.00.bin.linux.libc5.tgz vfu-4.00.bin.dos.tgz All packages are TAR+GZIP .tgz, bz2 and zip are available on request. B: Always check HISTORY document -- it often contains some usefull notes! =head1 FILES $HOME/$RC_PREFIX/vfu/vfu.conf configuration, explained above $HOME/$RC_PREFIX/vfu/vfu.options options, explained above $HOME/$RC_PREFIX/vfu/vfu.history contains history lines $HOME/$RC_PREFIX/vfu/vfu.tree contains directory tree If you don't set $RC_PREFIX configuration files are: $HOME/.vfu/vfu.conf $HOME/.vfu/vfu.options $HOME/.vfu/vfu.history $HOME/.vfu/vfu.tree =head1 TODO see the TODO file =head1 BUGS unknown =head1 AUTHOR Vladi Belperchinov-Shabanski "Cade" http://soul.datamax.bg/~cade/ http://soul.datamax.bg/~cade/vfu vfu-4.10/INSTALL0000644000175000001440000000570611231161125012103 0ustar cadeusers 1. how to compile vfu run `make' from vfu base directory this should compile everything to compile each part of vfu manually do this: -- go to `vslib' directory -- run `make' -- go to `vfu' directory -- run `make' if something goes wrong, check these: -- if your `curses.h' file locations is not `/usr/include/ncurses' you have to change this in the Makefile. -- if vslib library is not in the `../vslib' directory you also have to change this in the Makefile. to get file sizes above 4GB shown properly you need to make this way: export CCDEF="-D_FILE_OFFSET_BITS=64" make or make CCDEF="-D_FILE_OFFSET_BITS=64" 2. how to install vfu run `install' script from vfu base directory install script checks if all required files are available/built and then does this: cp vfu/vfu rx/rx_* /usr/local/bin cp vfu.1 /usr/local/man/man1 cp vfu.conf /usr/local/etc 3. how to install vfu manually -- you have to copy `vfu' in the `/usr/local/bin' or `/usr/bin' directory and set mode to 755 `rwxr-xr-x' the owner is not significant ( root is also possible ). -- there is preliminary man page ( vfu.1 ) which could be copied to /usr/man/man1. -- copy all `rx/rx_*' tools to /usr/local/bin -- install Net::FTP perl module if needed. (this is used for FTP support) 4. requirements: VFU uses pcre perl-like regexp library. If you get error messages like these: > ~/src/vfu-4.09$ make > make -C vslib > make[1]: Entering directory `/home/cade/src/vfu-4.09/vslib' > true > g++ -I. -O2 -c vstrlib.cpp -o .OBJ.libvslib.a/vstrlib.o > In file included from vstrlib.cpp:17: > vstrlib.h:28:18: error: pcre.h: No such file or directory > In file included from vstrlib.cpp:17: > vstrlib.h:178: error: ISO C++ forbids declaration of ‘pcre’ with no type > vstrlib.h:178: error: expected ‘;’ before ‘*’ token > vstrlib.h:179: error: ISO C++ forbids declaration of ‘pcre_extra’ with then you need pcre library. you should have package named something like: libpcre-dev in debian, for example, the correct package name is: libpcre3-dev apt-get install libpcre3-dev if you dont have this package or do not want to install it, you can try VFU internal pcre library (i.e. pcre shanshot, used with permission): tar xzvf vfu-4.09.tar.gz cd vfu-4.09 make -C vslib/pcre export CCDEF="-Ipcre -I../vslib/pcre" export LDDEF="-Lpcre -l../vslib/pcre pcre" make this should help. WARNING: make sure to remove all old personal cache files! If you still have problems feel free to contact me anytime. P! Vladi. -- Vladi Belperchinov-Shabanski http://cade.datamax.bg/vfu vfu-4.10/install0000755000175000001440000000113211204631441012436 0ustar cadeusers#!/bin/bash if [ ! -e vfu/vfu ]; then echo "vfu/vfu cannot be found, try to build it first..." exit; fi # this is not completely correct, it should check for all rx_* tools if [ ! -e rx/rx_auto ]; then echo "rx/rx_* cannot be found, check distribution/docs..." exit; fi echo "Press ENTER to install vfu in /usr/local/bin and rx_* in /usr/lib/vfu" echo "Or press Ctrl+C to cancel" read cp vfu/vfu /usr/local/bin mkdir /usr/lib/vfu cp rx/rx_* /usr/lib/vfu cp vfu.1 /usr/local/man/man1 cp vfu.conf /usr/lib/vfu cd /usr/local/bin chmod 755 vfu cd /usr/lib/vfu chmod 755 rx_* echo "done." vfu-4.10/COPYING0000644000175000001440000004307011172606420012107 0ustar cadeusers GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. vfu-4.10/CONFIG0000644000175000001440000000374011172606420011744 0ustar cadeusers VFU CONFIGURATION, OPTIONS AND CACHE FILES LOCATIONS ------------------------------------------------------------------------ By default VFU searches these locations for `vfu.conf' config file: 1. personal vfu.conf ( explained below ) 2. /etc/ 3. /usr/local/etc/ 4. /usr/local/ The personal vfu.conf is located in `$HOME/.vfu/' directory and it is created if not exist. The same directory is used for keeping options and cache files ( directory tree, history, options, etc. ) Well, More than 1/3 of all files in my home directory are various configuration ( dotfiles -> `.name' ) files for many applications ( and directories as well ). I think that if all these files/dirs are moved to `$HOME/etc/' or `$HOME/.conf/' or similar directory, the home directory will look a lot more clean. I know that dotfiles are considered `hidden' but I'd like to see all files w/o such restrictions. I also know that keeping configs in `$HOME/.name' files is usual since the beginning, but it doesn't help. So a simple solution to this problem is to check for exported environment variable called `RC_PREFIX' and if found to check for config files in `$HOME/$RC_PREFIX/.name' ( where `.name' is the config file or dir ). Is $RC_PREFIX is not defined all configs will go as usual in the `$HOME/.name'. VFU works in this way and I have got always $RC_PREFIX defined to `etc' ( i.e. vfu.conf goes in `$HOME/etc/.vfu/' ). I don't know if there is similar idea already, but if you like it it would be nice if your own programs support this option. Of cource if you don't like the name RC_PREFIX you can use other like CONFIG_PREFIX for example. Thanx for the attention! Vladi Belperchinov-Shabanski http://soul.datamax.bg/~cade/vfu ------------------------------------------------------------------------