mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Add a /while loop.
This commit is contained in:
parent
fd5e7d44f3
commit
eda26e299f
@ -1197,11 +1197,20 @@ entire arguments right behind the delimiting space of the function
|
||||
name. @code{unpercent+} also maps plus signs to a spaces.
|
||||
|
||||
@item percent @var{args}
|
||||
@item percent+ @var{args}
|
||||
@itemx percent+ @var{args}
|
||||
Escape the @var{args} using percent style ecaping. Tabs, formfeeds,
|
||||
linefeeds, carriage returns and colons are escaped. @code{percent+} also
|
||||
maps spaces to plus signs.
|
||||
|
||||
@item +
|
||||
@itemx -
|
||||
@item *
|
||||
@item /
|
||||
@item %
|
||||
Evaluate all arguments as long integers using @code{strtol} and apply
|
||||
this operator. A division by zero yields an empty string.
|
||||
|
||||
|
||||
@end table
|
||||
|
||||
|
||||
@ -1248,6 +1257,9 @@ Show a listy of open files.
|
||||
Send the Assuan command @command{GETINFO pid} to the server and store
|
||||
the returned PID for internal purposes.
|
||||
|
||||
@item /sleep
|
||||
Sleep for a second.
|
||||
|
||||
@item /hex
|
||||
@itemx /nohex
|
||||
Same as the command line option @option{--hex}.
|
||||
@ -1260,6 +1272,26 @@ Same as the command line option @option{--decode}.
|
||||
@itemx /nosubst
|
||||
Enable and disable variable substitution. It defaults to disabled
|
||||
unless the command line option @option{--subst} has been used.
|
||||
If /subst as been enabled once, leading white spaces are removed from
|
||||
input lines which makes scripts easier to read.
|
||||
|
||||
@item /while @var{condition}
|
||||
@itemx /end
|
||||
These commands provide a way for executing loops. All lines between the
|
||||
@code{while} and the corresponding @code{end} are executed as long as
|
||||
the evaluation of @var{condition} yields a non-zero value. The
|
||||
evaluation is done by passing @var{condition} to the @code{strtol}
|
||||
function. Example:
|
||||
|
||||
@smallexample
|
||||
/subst
|
||||
/let i 3
|
||||
/while $i
|
||||
/echo loop couter is $i
|
||||
/let i $@{- $i 1@}
|
||||
/end
|
||||
@end smallexample
|
||||
|
||||
|
||||
@item /run @var{file}
|
||||
Run commands from @var{file}.
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
* gpg-connect-agent.c (substitute_line): Restore temporary nul
|
||||
marker.
|
||||
(main): Add /while command.
|
||||
|
||||
2007-10-23 Werner Koch <wk@g10code.com>
|
||||
|
||||
|
@ -79,10 +79,9 @@ watchgnupg_LDADD = $(NETLIBS)
|
||||
|
||||
gpg_connect_agent_SOURCES = gpg-connect-agent.c no-libgcrypt.c
|
||||
# FIXME: remove PTH_LIBS (why do we need them at all?)
|
||||
gpg_connect_agent_LDADD = $(common_libs) $(LIBASSUAN_LIBS) $(PTH_LIBS) \
|
||||
$(GPG_ERROR_LIBS) \
|
||||
../common/libgpgrl.a $(LIBREADLINE) \
|
||||
$(LIBINTL) $(NETLIBS) $(LIBICONV)
|
||||
gpg_connect_agent_LDADD = ../common/libgpgrl.a $(common_libs) \
|
||||
$(LIBASSUAN_LIBS) $(PTH_LIBS) $(GPG_ERROR_LIBS) \
|
||||
$(LIBREADLINE) $(LIBINTL) $(NETLIBS) $(LIBICONV)
|
||||
|
||||
gpgkey2ssh_SOURCES = gpgkey2ssh.c
|
||||
gpgkey2ssh_CFLAGS = $(LIBGCRYPT_CFLAGS) $(GPG_ERROR_CFLAGS)
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <ctype.h>
|
||||
#include <assuan.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "i18n.h"
|
||||
#include "../common/util.h"
|
||||
@ -91,6 +92,7 @@ struct
|
||||
int exec; /* Run the pgm given on the command line. */
|
||||
unsigned int connect_flags; /* Flags used for connecting. */
|
||||
int enable_varsubst; /* Set if variable substitution is enabled. */
|
||||
int trim_leading_spaces;
|
||||
} opt;
|
||||
|
||||
|
||||
@ -122,6 +124,16 @@ typedef struct variable_s *variable_t;
|
||||
|
||||
static variable_t variable_table;
|
||||
|
||||
|
||||
/* To implement loops we store entire lines in a linked list. */
|
||||
struct loopline_s
|
||||
{
|
||||
struct loopline_s *next;
|
||||
char line[1];
|
||||
};
|
||||
typedef struct loopline_s *loopline_t;
|
||||
|
||||
|
||||
/* This is used to store the pid of the server. */
|
||||
static pid_t server_pid = (pid_t)(-1);
|
||||
|
||||
@ -389,6 +401,56 @@ get_var (const char *name)
|
||||
}
|
||||
|
||||
|
||||
/* Perform some simple arithmentic operations. Caller must release
|
||||
the return value. On error the return value is NULL. */
|
||||
static char *
|
||||
arithmetic_op (int operator, const char *operands)
|
||||
{
|
||||
long result, value;
|
||||
char numbuf[35];
|
||||
|
||||
while ( spacep (operands) )
|
||||
operands++;
|
||||
if (!*operands)
|
||||
return NULL;
|
||||
result = strtol (operands, NULL, 0);
|
||||
while (*operands && !spacep (operands) )
|
||||
operands++;
|
||||
while (*operands)
|
||||
{
|
||||
while ( spacep (operands) )
|
||||
operands++;
|
||||
if (!*operands)
|
||||
break;
|
||||
value = strtol (operands, NULL, 0);
|
||||
while (*operands && !spacep (operands) )
|
||||
operands++;
|
||||
switch (operator)
|
||||
{
|
||||
case '+': result += value; break;
|
||||
case '-': result -= value; break;
|
||||
case '*': result *= value; break;
|
||||
case '/':
|
||||
if (!value)
|
||||
return NULL;
|
||||
result /= value;
|
||||
break;
|
||||
case '%':
|
||||
if (!value)
|
||||
return NULL;
|
||||
result %= value;
|
||||
break;
|
||||
default:
|
||||
log_error ("unknown arithmetic operator `%c'\n", operator);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
snprintf (numbuf, sizeof numbuf, "%ld", result);
|
||||
return xstrdup (numbuf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Extended version of get_var. This returns a malloced string and
|
||||
understand the fucntion syntax: "func args".
|
||||
|
||||
@ -412,7 +474,7 @@ get_var (const char *name)
|
||||
|
||||
unpercent ARGS
|
||||
unpercent+ ARGS
|
||||
Remove percent style ecaping from string. NOte that "%00
|
||||
Remove percent style ecaping from string. Note that "%00
|
||||
terminates the string implicitly. Use "%7d" to represetn
|
||||
the closing brace. The args start right after the first
|
||||
space after the function name. "unpercent+" also maps '+'
|
||||
@ -517,6 +579,10 @@ get_var_ext (const char *name)
|
||||
if (*p == ' ')
|
||||
*p = '+';
|
||||
}
|
||||
else if ( (s - name) == 1 && strchr ("+-*/%", *name))
|
||||
{
|
||||
result = arithmetic_op (*name, s+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error ("unknown variable function `%.*s'\n", (int)(s-name), name);
|
||||
@ -1025,8 +1091,16 @@ main (int argc, char **argv)
|
||||
int cmderr;
|
||||
const char *opt_run = NULL;
|
||||
FILE *script_fp = NULL;
|
||||
int use_tty, last_was_tty;
|
||||
|
||||
int use_tty, keep_line;
|
||||
struct {
|
||||
int collecting;
|
||||
loopline_t head;
|
||||
loopline_t *tail;
|
||||
loopline_t current;
|
||||
unsigned int nestlevel;
|
||||
char *condition;
|
||||
} loopstack[20];
|
||||
int loopidx;
|
||||
|
||||
gnupg_rl_initialize ();
|
||||
set_strusage (my_strusage);
|
||||
@ -1060,7 +1134,10 @@ main (int argc, char **argv)
|
||||
case oExec: opt.exec = 1; break;
|
||||
case oNoExtConnect: opt.connect_flags &= ~(1); break;
|
||||
case oRun: opt_run = pargs.r.ret_str; break;
|
||||
case oSubst: opt.enable_varsubst = 1; break;
|
||||
case oSubst:
|
||||
opt.enable_varsubst = 1;
|
||||
opt.trim_leading_spaces = 1;
|
||||
break;
|
||||
|
||||
default: pargs.err = 2; break;
|
||||
}
|
||||
@ -1143,18 +1220,36 @@ main (int argc, char **argv)
|
||||
}
|
||||
|
||||
|
||||
for (loopidx=0; loopidx < DIM (loopstack); loopidx++)
|
||||
loopstack[loopidx].collecting = 0;
|
||||
loopidx = -1;
|
||||
line = NULL;
|
||||
linesize = 0;
|
||||
last_was_tty = 0;
|
||||
keep_line = 1;
|
||||
for (;;)
|
||||
{
|
||||
int n;
|
||||
size_t maxlength;
|
||||
size_t maxlength = 2048;
|
||||
|
||||
maxlength = 2048;
|
||||
if (use_tty && !script_fp)
|
||||
assert (loopidx < (int)DIM (loopstack));
|
||||
if (loopidx >= 0 && loopstack[loopidx].current)
|
||||
{
|
||||
last_was_tty = 1;
|
||||
keep_line = 0;
|
||||
xfree (line);
|
||||
line = xstrdup (loopstack[loopidx].current->line);
|
||||
n = strlen (line);
|
||||
/* Never go beyond of the final /end. */
|
||||
if (loopstack[loopidx].current->next)
|
||||
loopstack[loopidx].current = loopstack[loopidx].current->next;
|
||||
else if (!strncmp (line, "/end", 4) && (!line[4]||spacep(line+4)))
|
||||
;
|
||||
else
|
||||
log_fatal ("/end command vanished\n");
|
||||
}
|
||||
else if (use_tty && !script_fp)
|
||||
{
|
||||
keep_line = 0;
|
||||
xfree (line);
|
||||
line = tty_get ("> ");
|
||||
n = strlen (line);
|
||||
if (n==1 && *line == CONTROL_D)
|
||||
@ -1164,12 +1259,12 @@ main (int argc, char **argv)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (last_was_tty)
|
||||
if (!keep_line)
|
||||
{
|
||||
xfree (line);
|
||||
line = NULL;
|
||||
linesize = 0;
|
||||
last_was_tty = 0;
|
||||
keep_line = 1;
|
||||
}
|
||||
n = read_line (script_fp? script_fp:stdin,
|
||||
&line, &linesize, &maxlength);
|
||||
@ -1208,6 +1303,44 @@ main (int argc, char **argv)
|
||||
log_info (_("line shortened due to embedded Nul character\n"));
|
||||
if (line[n-1] == '\n')
|
||||
line[n-1] = 0;
|
||||
|
||||
if (opt.trim_leading_spaces)
|
||||
{
|
||||
const char *s = line;
|
||||
|
||||
while (spacep (s))
|
||||
s++;
|
||||
if (s != line)
|
||||
{
|
||||
for (p=line; *s;)
|
||||
*p++ = *s++;
|
||||
*p = 0;
|
||||
n = p - line;
|
||||
}
|
||||
}
|
||||
|
||||
if (loopidx+1 >= 0 && loopstack[loopidx+1].collecting)
|
||||
{
|
||||
loopline_t ll;
|
||||
|
||||
ll = xmalloc (sizeof *ll + strlen (line));
|
||||
ll->next = NULL;
|
||||
strcpy (ll->line, line);
|
||||
*loopstack[loopidx+1].tail = ll;
|
||||
loopstack[loopidx+1].tail = &ll->next;
|
||||
|
||||
if (!strncmp (line, "/end", 4) && (!line[4]||spacep(line+4)))
|
||||
loopstack[loopidx+1].nestlevel--;
|
||||
else if (!strncmp (line, "/while", 6) && (!line[6]||spacep(line+6)))
|
||||
loopstack[loopidx+1].nestlevel++;
|
||||
|
||||
if (loopstack[loopidx+1].nestlevel)
|
||||
continue;
|
||||
/* We reached the corresponding /end. */
|
||||
loopstack[loopidx+1].collecting = 0;
|
||||
loopidx++;
|
||||
}
|
||||
|
||||
if (*line == '/')
|
||||
{
|
||||
/* Handle control commands. */
|
||||
@ -1347,12 +1480,16 @@ main (int argc, char **argv)
|
||||
else if (!strcmp (cmd, "nodecode"))
|
||||
opt.decode = 0;
|
||||
else if (!strcmp (cmd, "subst"))
|
||||
{
|
||||
opt.enable_varsubst = 1;
|
||||
opt.trim_leading_spaces = 1;
|
||||
}
|
||||
else if (!strcmp (cmd, "nosubst"))
|
||||
opt.enable_varsubst = 0;
|
||||
else if (!strcmp (cmd, "run"))
|
||||
{
|
||||
char *p2;
|
||||
|
||||
for (p2=p; *p2 && !spacep (p2); p2++)
|
||||
;
|
||||
if (*p2)
|
||||
@ -1382,10 +1519,75 @@ main (int argc, char **argv)
|
||||
else if (opt.verbose)
|
||||
log_info ("running commands from `%s'\n", p);
|
||||
}
|
||||
else if (!strcmp (cmd, "while"))
|
||||
{
|
||||
if (loopidx+2 >= (int)DIM(loopstack))
|
||||
{
|
||||
log_error ("loops are nested too deep\n");
|
||||
/* We should better die or break all loop in this
|
||||
case as recovering from this error won't be
|
||||
easy. */
|
||||
}
|
||||
else
|
||||
{
|
||||
loopstack[loopidx+1].head = NULL;
|
||||
loopstack[loopidx+1].tail = &loopstack[loopidx+1].head;
|
||||
loopstack[loopidx+1].current = NULL;
|
||||
loopstack[loopidx+1].nestlevel = 1;
|
||||
loopstack[loopidx+1].condition = xstrdup (p);
|
||||
loopstack[loopidx+1].collecting = 1;
|
||||
}
|
||||
}
|
||||
else if (!strcmp (cmd, "end"))
|
||||
{
|
||||
if (loopidx < 0)
|
||||
log_error ("stray /end command encountered - ignored\n");
|
||||
else
|
||||
{
|
||||
char *tmpcond;
|
||||
const char *value;
|
||||
long condition;
|
||||
|
||||
/* Evaluate the condition. */
|
||||
tmpcond = xstrdup (loopstack[loopidx].condition);
|
||||
tmpline = substitute_line (tmpcond);
|
||||
value = tmpline? tmpline : tmpcond;
|
||||
condition = strtol (value, NULL, 0);
|
||||
xfree (tmpline);
|
||||
xfree (tmpcond);
|
||||
|
||||
if (condition)
|
||||
{
|
||||
/* Run loop. */
|
||||
loopstack[loopidx].current = loopstack[loopidx].head;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Cleanup. */
|
||||
while (loopstack[loopidx].head)
|
||||
{
|
||||
loopline_t tmp = loopstack[loopidx].head->next;
|
||||
xfree (loopstack[loopidx].head);
|
||||
loopstack[loopidx].head = tmp;
|
||||
}
|
||||
loopstack[loopidx].tail = NULL;
|
||||
loopstack[loopidx].current = NULL;
|
||||
loopstack[loopidx].nestlevel = 0;
|
||||
loopstack[loopidx].collecting = 0;
|
||||
xfree (loopstack[loopidx].condition);
|
||||
loopstack[loopidx].condition = NULL;
|
||||
loopidx--;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strcmp (cmd, "bye"))
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (!strcmp (cmd, "sleep"))
|
||||
{
|
||||
gnupg_sleep (1);
|
||||
}
|
||||
else if (!strcmp (cmd, "help"))
|
||||
{
|
||||
puts (
|
||||
@ -1408,6 +1610,8 @@ main (int argc, char **argv)
|
||||
"/[no]decode Enable decoding of received data lines.\n"
|
||||
"/[no]subst Enable varibale substitution.\n"
|
||||
"/run FILE Run commands from FILE.\n"
|
||||
"/while VAR Begin loop controlled by VAR.\n"
|
||||
"/end End loop.\n"
|
||||
"/bye Terminate gpg-connect-agent.\n"
|
||||
"/help Print this help.");
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user