]> git.pld-linux.org Git - packages/exixpand.git/blob - exixpand.pl
- drop obsolete and outdated manual inclusion of rpm macros
[packages/exixpand.git] / exixpand.pl
1 #!/usr/bin/perl
2
3 # SET THIS TO THE PATH TO YOUR EXIM BINARY!
4 my $exim  = '/usr/bin/exim';
5
6 # wrap 'exim -be' string expansion:
7 #   up and down arrows for history and history editing
8 #   ability to substitute certain variables so whole expansions can be tested
9
10 use strict;
11 use Term::ReadLine;
12
13 my($p_name)   = $0 =~ m|/?([^/]+)$|;
14 my $p_version = "20050922.1";
15 my $p_usage   = "Usage: $p_name [--help|--version] (see --help for details)";
16 my $p_cp      = <<EOM;
17         Copyright (c) 2004-2005 John Jetmore <jj33\@pobox.com>
18
19     This program is free software; you can redistribute it and/or modify
20     it under the terms of the GNU General Public License as published by
21     the Free Software Foundation; either version 2 of the License, or
22     (at your option) any later version.
23
24     This program is distributed in the hope that it will be useful,
25     but WITHOUT ANY WARRANTY; without even the implied warranty of
26     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27     GNU General Public License for more details.
28
29     You should have received a copy of the GNU General Public License
30     along with this program; if not, write to the Free Software
31     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
32 EOM
33 ext_usage(); # before we do anything else, check for --help
34
35 my $term  = Term::ReadLine->new('Exim Expansion Tester');
36 my $OUT   = $term->OUT() || *STDOUT;
37 my %track = ();
38 my $pr1   = 'expand> ';
39 my $pr2   = '> ';
40 my $cpr   = $pr1;
41 my $clear = 1;
42 my $wstr;
43 my $istr;
44
45 #$SIG{INT} = sub { $wstr = ''; $istr = ''; $clear = 1};
46 #$SIG{INT} = sub { $clear = 1; print STDERR "foo!\n"; };
47
48 while (defined ($istr = $term->readline($cpr, ""))) {
49   #if ($clear) {
50   #  $clear = 0;
51   #  $wstr = '';
52   #  $istr = '';
53   #}
54   next if (!$istr);
55   if ($istr =~ /^\./) {
56     if ($istr =~ /^\.(quit|exit)\b/) {
57       exit;
58     } elsif ($istr =~ /^\.clear\b/) {
59       $wstr = '';
60       $cpr  = $pr1;
61       next;
62     } elsif ($istr =~ /^\.track (\S+)(?: (.*))?$/) {
63       my $var = $1;
64       my $val = $2;
65       $track{$var}{on} = 1;
66       if (!$val && !$track{$var}{val}) {
67         $track{$var}{val} = "";
68       } else {
69         $track{$var}{val} = $val;
70       }
71     } elsif ($istr =~ /^\.untrack (\S+)/) {
72       $track{$1}{on} = 0;
73     } elsif ($istr =~ /^\.unset (\S+)/) {
74       delete($track{$1});
75     } elsif ($istr =~ /^\.showvar(?: (\S+))?/) {
76       my $var = $1;
77       if ($var && !$track{$var}) {
78         print $OUT "The variable $var is not set\n";
79       } elsif (!scalar(keys(%track))) {
80         print $OUT "No variables are being tracked\n";
81       } else {
82         printf $OUT "%3s %-20s \"%s\"\n", "On?", "Name", "Value";
83         my @keys = $var ? ($var) : (sort keys %track);
84         foreach my $k (@keys) {
85           printf $OUT "%3s %-20s \"%s\"\n", $track{$k}{on} ? 'Y' : 'N',
86                                            $k, $track{$k}{val};
87         }
88       }
89     } else {
90       print $OUT "command unrecognized\n";
91     }
92     next;
93   }
94   $wstr .= $istr;
95   if ($istr =~ m|\\$| && $istr !~ m|^\\\\| && $istr !~ m|[^\\]\\\\|) {
96     $cpr = $pr2;
97     #$wstr =~ s|\\$|\\\n|g;
98     $wstr =~ s|\\$||g;
99   } else {
100     $cpr = $pr1;
101     my $eval = $wstr;
102     # XXX header expansion (ending in :) is missing here
103     foreach my $var (keys %track) {
104       next if (!$track{$var}{on});
105       if ($var =~ /^r?h(eader)?_/) {
106         #print STDERR "header hit on $var\n";
107         $eval =~ s|\$$var:|$track{$var}{val}|g;
108       }
109       $eval =~ s|\$$var\b|$track{$var}{val}|g;
110       $eval =~ s|\${$var}|$track{$var}{val}|g;
111     }
112     print $OUT "Evaluating: $eval\n";
113     system($exim, '-be', $eval);
114     $term->addhistory($wstr);
115     $wstr = '';
116   }
117 }
118
119 print "\n";
120
121 exit;
122
123 sub ext_usage {
124   if ($ARGV[0] =~ /^--help$/i) {
125     require Config;
126     $ENV{PATH} .= ":" unless $ENV{PATH} eq "";
127     $ENV{PATH} = "$ENV{PATH}$Config::Config{'installscript'}";
128     #exec("perldoc", "-F", "-U", $0) || exit 1;
129     $< = $> = 1 if ($> == 0 || $< == 0);
130     exec("perldoc", $0) || exit 1;
131     # make parser happy
132     %Config::Config = ();
133   } elsif ($ARGV[0] =~ /^--version$/i) {
134     print "$p_name version $p_version\n\n$p_cp\n";
135   } else {
136     return;
137   }
138
139   exit(0);
140 }
141
142 __END__
143
144 =head1 NAME
145
146 exixpand - Wrap exim -be, providing readline and variable substitution
147
148 =head1 USAGE
149
150 exixpand [--help|--version]
151
152 =head1 DESCRIPTION
153
154 exixpand (pronounced exi-spand) is a wrapper for exim's expansion testing function (-be).  It provides readline support via perl's Term::ReadLine module and also provides variable interpolations.  The main intention of being able to track variables is to be able to test different values for variables without modifying the expansion string.  The idea is to be able to test expansion strings that can be copied verbatim into a config file with different variable values.
155
156 Any text that starts with a "." is a command that is handled by exixpand itself.  These commands are explained in more detail below.  Any other text is passed to 'exim -be' and the result is displayed.
157
158 =head1 COMMANDS
159
160 =over 4
161
162 =item .track <variable> [<value>]
163
164 This causes exixpand to mark <variable> for interpolation in passed in strings.  <variable> should not contain any spaces and should not start with a dollar sign (though it should when used in an expansion string).  <variable> does not need to be the same as an internal exim expansion variable.
165
166 <value> is optional.  Leaving it blank will either set an empty variable or cause a previously set but untracked variable to be tracked (see .untrack below for details).
167
168 =item .untrack <variable>
169
170 .untrack causes exixpand to save the value for <variable> but stop interpolating it in strings.  It can be reactivated using .track.  This functionality is provided so that interpolation can be turned off without having to lose potentially complex or lengthy values.
171
172 =item .unset <variable>
173
174 .unset causes exixpand to completely forget about <variable>.
175
176 =item .showvar [<variable>]
177
178 .showvar shows the value of a tracked variable and whether it is currently active or not.  If no <variable> is provided all variables are displayed.
179
180 =item .exit, .quit, ^D
181
182 Exit exixpand.  Note that some bug seems to cause EOF not to be received properly in some perl versions.  I've tried multiple versions of perl on Linux, Solaris, and Darwin, and 5.6.1 consistantly fails to recognize EOF.
183
184 =item .clear, ^C
185
186 Reset internal state (empty multiline buffers).
187
188 =back
189
190 =head1 EXAMPLES
191
192 Test an ${if test against $sender_helo_name.  Use of $GOODHELO and $BADHELO is done to demonstrate nested variable interpolation.
193
194   expand> .track BADHELO host_name.domain.com
195   expand> .track GOODHELO hostname.domain.com
196   expand> .track sender_helo_name $GOODHELO
197   expand> $sender_helo_name
198   Evaluating: hostname.domain.com
199   hostname.domain.com
200   expand> ${if match{$sender_helo_name}{^.*_}{yes}fail}
201   Evaluating: ${if match{hostname.domain.com}{^.*_}{yes}fail}
202   Failed: "if" failed and "fail" requested
203   expand> .track sender_helo_name $BADHELO
204   expand> ${if match{$sender_helo_name}{^.*_}{yes}fail}
205   Evaluating: ${if match{host_name.domain.com}{^.*_}{yes}fail}
206   yes
207   expand> 
208
209 This is a contrived example showing how you can use variable interpolation to make complicated expansions more simple.  It uses small pieces to build up to a failry complicated expansion string which can be paste directly into a configuration file.  (This specific example finds the number of seconds since midnight localtime.)
210
211   expand> .track HOUR ${substr{11}{2}{$tod_log}}
212   expand> $HOUR
213   Evaluating: ${substr{11}{2}{$tod_log}}
214   21
215   expand> .track SECS_IN_HOUR ${eval:$HOUR*3600}
216   expand> $SECS_IN_HOUR
217   Evaluating: ${eval:${substr{11}{2}{$tod_log}}*3600}
218   75600
219   expand> .track BASE_SECS ${eval:3600*${eval:$tod_epoch/3600}}
220   expand> $BASE_SECS
221   Evaluating: ${eval:3600*${eval:$tod_epoch/3600}}
222   1101438000
223   expand> .track REMAINING_SECS ${eval:$tod_epoch-$BASE_SECS}
224   expand> .showvar
225   On? Name                 "Value"
226     Y BASE_SECS            "${eval:3600*${eval:$tod_epoch/3600}}"
227     Y HOUR                 "${substr{11}{2}{$tod_log}}"
228     Y REMAINING_SECS       "${eval:$tod_epoch-$BASE_SECS}"
229     Y SECS_IN_HOUR         "${eval:$HOUR*3600}"
230   expand> ${eval:$SECS_IN_HOUR + $REMAINING_SECS}
231   Evaluating: ${eval:${eval:${substr{11}{2}{$tod_log}}*3600} + ${eval:$tod_epoch-${eval:3600*${eval:$tod_epoch/3600}}}}
232   77742
233   expand>
234
235 =cut
This page took 0.073687 seconds and 3 git commands to generate.