mirror of
git://git.gnupg.org/gnupg.git
synced 2025-03-11 22:52:47 +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.
|
name. @code{unpercent+} also maps plus signs to a spaces.
|
||||||
|
|
||||||
@item percent @var{args}
|
@item percent @var{args}
|
||||||
@item percent+ @var{args}
|
@itemx percent+ @var{args}
|
||||||
Escape the @var{args} using percent style ecaping. Tabs, formfeeds,
|
Escape the @var{args} using percent style ecaping. Tabs, formfeeds,
|
||||||
linefeeds, carriage returns and colons are escaped. @code{percent+} also
|
linefeeds, carriage returns and colons are escaped. @code{percent+} also
|
||||||
maps spaces to plus signs.
|
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
|
@end table
|
||||||
|
|
||||||
|
|
||||||
@ -1248,6 +1257,9 @@ Show a listy of open files.
|
|||||||
Send the Assuan command @command{GETINFO pid} to the server and store
|
Send the Assuan command @command{GETINFO pid} to the server and store
|
||||||
the returned PID for internal purposes.
|
the returned PID for internal purposes.
|
||||||
|
|
||||||
|
@item /sleep
|
||||||
|
Sleep for a second.
|
||||||
|
|
||||||
@item /hex
|
@item /hex
|
||||||
@itemx /nohex
|
@itemx /nohex
|
||||||
Same as the command line option @option{--hex}.
|
Same as the command line option @option{--hex}.
|
||||||
@ -1260,6 +1272,26 @@ Same as the command line option @option{--decode}.
|
|||||||
@itemx /nosubst
|
@itemx /nosubst
|
||||||
Enable and disable variable substitution. It defaults to disabled
|
Enable and disable variable substitution. It defaults to disabled
|
||||||
unless the command line option @option{--subst} has been used.
|
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}
|
@item /run @var{file}
|
||||||
Run commands from @var{file}.
|
Run commands from @var{file}.
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
* gpg-connect-agent.c (substitute_line): Restore temporary nul
|
* gpg-connect-agent.c (substitute_line): Restore temporary nul
|
||||||
marker.
|
marker.
|
||||||
|
(main): Add /while command.
|
||||||
|
|
||||||
2007-10-23 Werner Koch <wk@g10code.com>
|
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
|
gpg_connect_agent_SOURCES = gpg-connect-agent.c no-libgcrypt.c
|
||||||
# FIXME: remove PTH_LIBS (why do we need them at all?)
|
# FIXME: remove PTH_LIBS (why do we need them at all?)
|
||||||
gpg_connect_agent_LDADD = $(common_libs) $(LIBASSUAN_LIBS) $(PTH_LIBS) \
|
gpg_connect_agent_LDADD = ../common/libgpgrl.a $(common_libs) \
|
||||||
$(GPG_ERROR_LIBS) \
|
$(LIBASSUAN_LIBS) $(PTH_LIBS) $(GPG_ERROR_LIBS) \
|
||||||
../common/libgpgrl.a $(LIBREADLINE) \
|
$(LIBREADLINE) $(LIBINTL) $(NETLIBS) $(LIBICONV)
|
||||||
$(LIBINTL) $(NETLIBS) $(LIBICONV)
|
|
||||||
|
|
||||||
gpgkey2ssh_SOURCES = gpgkey2ssh.c
|
gpgkey2ssh_SOURCES = gpgkey2ssh.c
|
||||||
gpgkey2ssh_CFLAGS = $(LIBGCRYPT_CFLAGS) $(GPG_ERROR_CFLAGS)
|
gpgkey2ssh_CFLAGS = $(LIBGCRYPT_CFLAGS) $(GPG_ERROR_CFLAGS)
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <assuan.h>
|
#include <assuan.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
#include "../common/util.h"
|
#include "../common/util.h"
|
||||||
@ -91,6 +92,7 @@ struct
|
|||||||
int exec; /* Run the pgm given on the command line. */
|
int exec; /* Run the pgm given on the command line. */
|
||||||
unsigned int connect_flags; /* Flags used for connecting. */
|
unsigned int connect_flags; /* Flags used for connecting. */
|
||||||
int enable_varsubst; /* Set if variable substitution is enabled. */
|
int enable_varsubst; /* Set if variable substitution is enabled. */
|
||||||
|
int trim_leading_spaces;
|
||||||
} opt;
|
} opt;
|
||||||
|
|
||||||
|
|
||||||
@ -122,6 +124,16 @@ typedef struct variable_s *variable_t;
|
|||||||
|
|
||||||
static variable_t variable_table;
|
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. */
|
/* This is used to store the pid of the server. */
|
||||||
static pid_t server_pid = (pid_t)(-1);
|
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
|
/* Extended version of get_var. This returns a malloced string and
|
||||||
understand the fucntion syntax: "func args".
|
understand the fucntion syntax: "func args".
|
||||||
|
|
||||||
@ -412,7 +474,7 @@ get_var (const char *name)
|
|||||||
|
|
||||||
unpercent ARGS
|
unpercent ARGS
|
||||||
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
|
terminates the string implicitly. Use "%7d" to represetn
|
||||||
the closing brace. The args start right after the first
|
the closing brace. The args start right after the first
|
||||||
space after the function name. "unpercent+" also maps '+'
|
space after the function name. "unpercent+" also maps '+'
|
||||||
@ -517,6 +579,10 @@ get_var_ext (const char *name)
|
|||||||
if (*p == ' ')
|
if (*p == ' ')
|
||||||
*p = '+';
|
*p = '+';
|
||||||
}
|
}
|
||||||
|
else if ( (s - name) == 1 && strchr ("+-*/%", *name))
|
||||||
|
{
|
||||||
|
result = arithmetic_op (*name, s+1);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log_error ("unknown variable function `%.*s'\n", (int)(s-name), name);
|
log_error ("unknown variable function `%.*s'\n", (int)(s-name), name);
|
||||||
@ -1025,8 +1091,16 @@ main (int argc, char **argv)
|
|||||||
int cmderr;
|
int cmderr;
|
||||||
const char *opt_run = NULL;
|
const char *opt_run = NULL;
|
||||||
FILE *script_fp = 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 ();
|
gnupg_rl_initialize ();
|
||||||
set_strusage (my_strusage);
|
set_strusage (my_strusage);
|
||||||
@ -1060,7 +1134,10 @@ main (int argc, char **argv)
|
|||||||
case oExec: opt.exec = 1; break;
|
case oExec: opt.exec = 1; break;
|
||||||
case oNoExtConnect: opt.connect_flags &= ~(1); break;
|
case oNoExtConnect: opt.connect_flags &= ~(1); break;
|
||||||
case oRun: opt_run = pargs.r.ret_str; 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;
|
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;
|
line = NULL;
|
||||||
linesize = 0;
|
linesize = 0;
|
||||||
last_was_tty = 0;
|
keep_line = 1;
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
size_t maxlength;
|
size_t maxlength = 2048;
|
||||||
|
|
||||||
maxlength = 2048;
|
assert (loopidx < (int)DIM (loopstack));
|
||||||
if (use_tty && !script_fp)
|
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 ("> ");
|
line = tty_get ("> ");
|
||||||
n = strlen (line);
|
n = strlen (line);
|
||||||
if (n==1 && *line == CONTROL_D)
|
if (n==1 && *line == CONTROL_D)
|
||||||
@ -1164,12 +1259,12 @@ main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (last_was_tty)
|
if (!keep_line)
|
||||||
{
|
{
|
||||||
xfree (line);
|
xfree (line);
|
||||||
line = NULL;
|
line = NULL;
|
||||||
linesize = 0;
|
linesize = 0;
|
||||||
last_was_tty = 0;
|
keep_line = 1;
|
||||||
}
|
}
|
||||||
n = read_line (script_fp? script_fp:stdin,
|
n = read_line (script_fp? script_fp:stdin,
|
||||||
&line, &linesize, &maxlength);
|
&line, &linesize, &maxlength);
|
||||||
@ -1208,6 +1303,44 @@ main (int argc, char **argv)
|
|||||||
log_info (_("line shortened due to embedded Nul character\n"));
|
log_info (_("line shortened due to embedded Nul character\n"));
|
||||||
if (line[n-1] == '\n')
|
if (line[n-1] == '\n')
|
||||||
line[n-1] = 0;
|
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 == '/')
|
if (*line == '/')
|
||||||
{
|
{
|
||||||
/* Handle control commands. */
|
/* Handle control commands. */
|
||||||
@ -1347,12 +1480,16 @@ main (int argc, char **argv)
|
|||||||
else if (!strcmp (cmd, "nodecode"))
|
else if (!strcmp (cmd, "nodecode"))
|
||||||
opt.decode = 0;
|
opt.decode = 0;
|
||||||
else if (!strcmp (cmd, "subst"))
|
else if (!strcmp (cmd, "subst"))
|
||||||
opt.enable_varsubst = 1;
|
{
|
||||||
|
opt.enable_varsubst = 1;
|
||||||
|
opt.trim_leading_spaces = 1;
|
||||||
|
}
|
||||||
else if (!strcmp (cmd, "nosubst"))
|
else if (!strcmp (cmd, "nosubst"))
|
||||||
opt.enable_varsubst = 0;
|
opt.enable_varsubst = 0;
|
||||||
else if (!strcmp (cmd, "run"))
|
else if (!strcmp (cmd, "run"))
|
||||||
{
|
{
|
||||||
char *p2;
|
char *p2;
|
||||||
|
|
||||||
for (p2=p; *p2 && !spacep (p2); p2++)
|
for (p2=p; *p2 && !spacep (p2); p2++)
|
||||||
;
|
;
|
||||||
if (*p2)
|
if (*p2)
|
||||||
@ -1382,10 +1519,75 @@ main (int argc, char **argv)
|
|||||||
else if (opt.verbose)
|
else if (opt.verbose)
|
||||||
log_info ("running commands from `%s'\n", p);
|
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"))
|
else if (!strcmp (cmd, "bye"))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
else if (!strcmp (cmd, "sleep"))
|
||||||
|
{
|
||||||
|
gnupg_sleep (1);
|
||||||
|
}
|
||||||
else if (!strcmp (cmd, "help"))
|
else if (!strcmp (cmd, "help"))
|
||||||
{
|
{
|
||||||
puts (
|
puts (
|
||||||
@ -1408,6 +1610,8 @@ main (int argc, char **argv)
|
|||||||
"/[no]decode Enable decoding of received data lines.\n"
|
"/[no]decode Enable decoding of received data lines.\n"
|
||||||
"/[no]subst Enable varibale substitution.\n"
|
"/[no]subst Enable varibale substitution.\n"
|
||||||
"/run FILE Run commands from FILE.\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"
|
"/bye Terminate gpg-connect-agent.\n"
|
||||||
"/help Print this help.");
|
"/help Print this help.");
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user