Added no_histsubst option and related fixes

This commit is contained in:
Jim Monte 2019-12-05 14:38:57 -05:00 committed by Holger Vogt
parent 4bd4a6e9be
commit 873e4a8db0
5 changed files with 264 additions and 116 deletions

View File

@ -9,25 +9,36 @@
wordlist* readifile(wordlist*);
/* The set command. Syntax is set [opt ...] [opt = val ...]. Val may
* be a string, an int, a float, or a list of the form (elt1 elt2
* ...). */
void
com_set(wordlist *wl)
/* The set command.
*
* Syntax is set [var [= val] ...]
*
* var is the name of the variable to be defined. Quoting allows special
* characters such as = to be included as part of the name.
* val may be a string, an int, a float, a bool, or a list of the form
* ( elt1 ... ).
*
* With no var value, all variables that are currently defined are printed
* Without the "= val" portion, the variable becomes a Boolean set to true.
* Lists must have spaces both after the leading '(' and before the
* trailing ')'. Individual elements may be of any type.
* Quoted expressions are taken to be strings in all cases and quoting a
* grouping character ("(" or ")") suppresses its special properties.
* Further, words "(" and ")" within a list are ordinary words.
*
* This function may alter the input wordlist, but on return its resources
* can be freed in the normal manner.
*/
void com_set(wordlist *wl)
{
struct variable *vars, *oldvar;
if (wl == NULL) {
/* Handle case of printing defined variables */
if (wl == (wordlist *) NULL) {
cp_vprint();
return;
}
/* special case input redirection*/
wordlist *ww = wl->wl_next;
if (ww && eq(ww->wl_word, "<"))
wl = readifile(wl);
vars = cp_setparse(wl);
struct variable *oldvar;
struct variable *vars = cp_setparse(wl);
/* This is sort of a hassle... */
while (vars) {
@ -54,12 +65,14 @@ com_set(wordlist *wl)
cp_vset(vars->va_name, vars->va_type, s);
oldvar = vars;
vars = vars->va_next;
/* va: avoid memory leak: free oldvar carefully */
tfree(oldvar->va_name);
if (oldvar->va_type == CP_STRING)
tfree(oldvar->va_string); /* copied in cp_vset */
/* Free allocations associated with the current variable */
txfree(oldvar->va_name);
if (oldvar->va_type == CP_STRING){
txfree(oldvar->va_string); /* copied in cp_vset */
}
/* don't free oldvar->va_list! This structure is used furthermore! */
tfree(oldvar);
txfree(oldvar);
}
}

View File

@ -140,7 +140,8 @@ cp_usrvars(void)
}
return v;
}
} /* end of function cp_usrvars */
/* Extract the .option lines from the deck */
@ -226,8 +227,6 @@ cp_usrset(struct variable *var, bool isset)
fprintf(cp_err, "Warning: %s compiled without debug messages\n",
cp_program);
#endif
} else if (eq(var->va_name, "program")) {
cp_program = var->va_string;
} else if (eq(var->va_name, "rawfile")) {
ft_rawfile = copy(var->va_string);
} else if (eq(var->va_name, "acct")) {

View File

@ -38,6 +38,8 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
#endif
bool cp_no_histsubst = FALSE; /* perform history substitution by default */
/* Things go as follows:
* (1) Read the line and do some initial quoting (by setting the 8th bit),
* and command ignoring. Also deal with command completion.
@ -54,29 +56,48 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
static void pwlist(wordlist *wlist, char *name);
wordlist *
cp_parse(char *string)
wordlist *cp_parse(char *string)
{
wordlist *wlist;
wlist = cp_lexer(string);
if (!string)
cp_event++;
/* Test for valid wordlist */
if (!wlist) {
return (wordlist *) NULL;
}
if (!wlist->wl_word) {
wl_free(wlist);
return (wordlist *) NULL;
}
if (!wlist || !wlist->wl_word)
return (wlist);
if (!string) { /* cp_lexer read user data */
cp_event++;
}
pwlist(wlist, "Initial parse");
wlist = cp_histsubst(wlist);
if (!wlist || !wlist->wl_word)
return (wlist);
pwlist(wlist, "After history substitution");
if (cp_didhsubst) {
wl_print(wlist, stdout);
putc('\n', stdout);
}
/* Do history substitution (!1, etc.) if enabled */
if (!cp_no_histsubst) {
wlist = cp_histsubst(wlist);
/* Test for valid wordlist */
if (!wlist) {
return (wordlist *) NULL;
}
if (!wlist->wl_word) {
wl_free(wlist);
return (wordlist *) NULL;
}
pwlist(wlist, "After history substitution");
if (cp_didhsubst) {
wl_print(wlist, stdout);
putc('\n', stdout);
}
} /* end of case that history substitutions are allowed */
/* Add the word list to the history. */
/* MW. If string==NULL we do not have to do this, and then play
@ -87,8 +108,9 @@ cp_parse(char *string)
wlist = cp_doalias(wlist);
pwlist(wlist, "After alias substitution");
pwlist(wlist, "Returning ");
return (wlist);
}
return wlist;
} /* end of function cp_parse */
static void

View File

@ -29,8 +29,13 @@ bool cp_echo = FALSE; /* CDHW */
struct variable *variables = NULL;
wordlist *
cp_varwl(struct variable *var)
static void update_option_variables(const char *sz_var_name,
struct variable *p_v);
wordlist *cp_varwl(struct variable *var)
{
wordlist *wl = NULL, *w, *wx = NULL;
char *buf;
@ -49,25 +54,26 @@ cp_varwl(struct variable *var)
buf = tprintf("%G", var->va_real);
break;
case CP_STRING:
buf = cp_unquote(var->va_string);
buf = copy(var->va_string);
break;
case CP_LIST: /* The tricky case. */
for (vt = var->va_vlist; vt; vt = vt->va_next) {
w = cp_varwl(vt);
w = cp_varwl(vt); /* recursive call */
if (wl == NULL) {
wl = wx = w;
} else {
}
else {
wx->wl_next = w;
w->wl_prev = wx;
wx = w;
}
}
return (wl);
return wl;
default:
fprintf(cp_err,
"cp_varwl: Internal Error: bad variable type %d\n",
var->va_type);
return (NULL);
return NULL;
}
return wl_cons(buf, NULL);
@ -75,8 +81,7 @@ cp_varwl(struct variable *var)
/* Set a variable. */
void
cp_vset(char *varname, enum cp_types type, void *value)
void cp_vset(const char *varname, enum cp_types type, const void *value)
{
struct variable *v, *u, *w;
int i;
@ -118,7 +123,9 @@ cp_vset(char *varname, enum cp_types type, void *value)
}
tfree(copyvarname);
return;
} else {
}
else {
/* The variable only exists in TRUE state */
var_set_bool(v, TRUE);
}
break;
@ -147,39 +154,8 @@ cp_vset(char *varname, enum cp_types type, void *value)
return;
}
/* Now, see if there is anything interesting going on. We
* recognise these special variables: noglob, nonomatch, history,
* echo, noclobber, prompt, and verbose. cp_remvar looks for these
* variables too. The host program will get any others. */
if (eq(copyvarname, "noglob"))
cp_noglob = TRUE;
else if (eq(copyvarname, "nonomatch"))
cp_nonomatch = TRUE;
else if (eq(copyvarname, "history") && (type == CP_NUM))
cp_maxhistlength = v->va_num;
else if (eq(copyvarname, "history") && (type == CP_REAL))
cp_maxhistlength = (int)floor(v->va_real + 0.5);
else if (eq(copyvarname, "noclobber"))
cp_noclobber = TRUE;
else if (eq(varname, "echo")) /*CDHW*/
cp_echo = TRUE; /*CDHW*/
else if (eq(copyvarname, "prompt")) {
if (type == CP_STRING) {
cp_promptstring = v->va_string;
}
else { /* use a default string since prompt is not a string */
cp_promptstring = "-> ";
}
}
else if (eq(copyvarname, "ignoreeof"))
cp_ignoreeof = TRUE;
else if (eq(copyvarname, "cpdebug")) {
cp_debug = TRUE;
#ifndef CPDEBUG
fprintf(cp_err,
"Warning: program not compiled with cshpar debug messages\n");
#endif
}
/* Update variables controlling options */
update_option_variables(copyvarname, v);
switch (i = cp_usrset(v, TRUE)) {
@ -260,7 +236,148 @@ cp_vset(char *varname, enum cp_types type, void *value)
}
tfree(copyvarname);
}
} /* end of function cp_vset */
/* Process special variables: noglob, nonomatch, history,
* noclobber, echo, prompt, ignoreeof, cpdebug, and no_histsubst
* by setting the values of associated option variables.
*
* Parmeters
* sz_var_name: Name of variable
* p_v: Variable if it is being added or NULL if being removed.
*/
static void update_option_variables(const char *sz_var_name,
struct variable *p_v)
{
static const unsigned char p_ch0['p' - 'a' + 1] = {
['n' - 'a'] = 1, /* noglob, nonomatch, noclobber, no_histsubst */
['h' - 'a'] = 2, /* history */
['e' - 'a'] = 3, /* echo */
['p' - 'a'] = 4, /* prompt, program */
['i' - 'a'] = 5, /* ignoreeof */
['c' - 'a'] = 6 /* cpdebug */
};
unsigned int index0 = (unsigned int) sz_var_name[0] - 'a';
/* Check if first char of is in range of interest.
* Note that if < 0, as unsigned, it will be very large so this
* single compare checks both < 'a' and > 'p' */
if (index0 >= sizeof p_ch0) {
return;
}
unsigned int id0 = (unsigned int) p_ch0[index0];
if (id0 == 0) { /* not of interest */
return;
}
/* Flag that bool values should be set is based on if the
* variable is being added (via a set) or removed */
const bool f_set = p_v != (struct variable *) NULL;
switch (id0) {
case 1:
/* noglob, nonomatch, noclobber, no_histsubst */
if (sz_var_name[1] != 'o') {
return;
}
{
bool *p_var;
const char *sz_rest = sz_var_name + 2;
if (eq(sz_rest, "glob")) {
p_var = &cp_noglob;
}
else if (eq(sz_rest, "nomatch")) {
p_var = &cp_nonomatch;
}
else if (eq(sz_rest, "clobber")) {
p_var = &cp_noclobber;
}
else if (eq(sz_rest, "_histsubst")) {
p_var = &cp_no_histsubst;
}
else { /* not a variable of interest */
return;
}
*p_var = f_set;
}
return;
case 2: /* history */
if (eq(sz_var_name + 1, "istory")) {
if (f_set) {
int n = -1;
enum cp_types type = p_v->va_type;
if (type == CP_NUM) {
n = p_v->va_num;
}
else if (type == CP_REAL) {
n = (int) round(p_v->va_real);
}
if (n >= 0) {
cp_maxhistlength = n;
}
}
/* Note that 'unset history' doesn't do anything here... Causes
* trouble... */
}
return;
case 3: /* echo */
if (eq(sz_var_name + 1, "cho")) {
cp_echo = f_set;
}
return;
case 4: /* prompt, program */
if (sz_var_name[1] != 'r') {
return;
}
if (sz_var_name[2] != 'o') {
return;
}
const char *sz_rest = sz_var_name + 3;
if (eq(sz_rest, "mpt")) { /* prompt */
if (f_set && p_v->va_type == CP_STRING) {
cp_promptstring = p_v->va_string;
}
else {
/* Use a default string since prompt is not a string or the
* previous prompt string was freed */
cp_promptstring = "-> ";
}
return;
}
if (eq(sz_rest, "gram")) { /* program */
if (f_set && p_v->va_type == CP_STRING) {
cp_program = p_v->va_string;
}
else {
/* Use a default string since program is not a string or the
* previous program string was freed */
cp_program = "";
}
return;
}
return; /* not of interest */
case 5:
if (eq(sz_var_name + 1, "gnoreeof")) { /* ignoreeof */
cp_ignoreeof = f_set;
}
return;
case 6:
if (eq(sz_var_name + 1, "pdebug")) { /* cpdebug */
cp_debug = f_set;
#ifndef CPDEBUG
if (cp_debug) {
fprintf(cp_err, "Warning: program not compiled "
"with cshpar debug messages\n");
}
#endif
}
} /* end of switch over index for first char */
} /* end of function update_option_variables */
/* Read a wordlist, e.g. from the options or set commands
@ -437,8 +554,7 @@ free_struct_variable(struct variable *v)
}
void
cp_remvar(char *varname)
void cp_remvar(char *varname)
{
struct variable *v, **p;
struct variable *uv1;
@ -446,49 +562,45 @@ cp_remvar(char *varname)
uv1 = cp_usrvars();
for (p = &variables; *p; p = &(*p)->va_next)
if (eq((*p)->va_name, varname))
for (p = &variables; *p; p = &(*p)->va_next) {
if (eq((*p)->va_name, varname)) {
break;
}
}
if (*p == NULL)
for (p = &uv1; *p; p = &(*p)->va_next)
if (eq((*p)->va_name, varname))
if (*p == NULL) {
for (p = &uv1; *p; p = &(*p)->va_next) {
if (eq((*p)->va_name, varname)) {
break;
}
}
}
if (*p == NULL && plot_cur)
for (p = &plot_cur->pl_env; *p; p = &(*p)->va_next)
if (eq((*p)->va_name, varname))
if (*p == NULL && plot_cur) {
for (p = &plot_cur->pl_env; *p; p = &(*p)->va_next) {
if (eq((*p)->va_name, varname)) {
break;
}
}
}
if (*p == NULL && ft_curckt)
for (p = &ft_curckt->ci_vars; *p; p = &(*p)->va_next)
if (eq((*p)->va_name, varname))
if (*p == NULL && ft_curckt) {
for (p = &ft_curckt->ci_vars; *p; p = &(*p)->va_next) {
if (eq((*p)->va_name, varname)) {
break;
}
}
}
v = *p;
/* make up an auxiliary struct variable for cp_usrset() */
if (!v)
if (!v) {
v = var_alloc_num(copy(varname), 0, NULL);
}
/* Note that 'unset history' doesn't do anything here... Causes
* trouble... */
if (eq(varname, "noglob"))
cp_noglob = FALSE;
else if (eq(varname, "nonomatch"))
cp_nonomatch = FALSE;
else if (eq(varname, "noclobber"))
cp_noclobber = FALSE;
else if (eq(varname, "echo")) /*CDHW*/
cp_echo = FALSE; /*CDHW*/
else if (eq(varname, "prompt"))
cp_promptstring = NULL;
else if (eq(varname, "cpdebug"))
cp_debug = FALSE;
else if (eq(varname, "ignoreeof"))
cp_ignoreeof = FALSE;
else if (eq(varname, "program"))
cp_program = "";
/* Update options that depend on variables */
update_option_variables(varname, (struct variable *) NULL);
switch (i = cp_usrset(v, FALSE)) {
@ -540,7 +652,8 @@ cp_remvar(char *varname)
free_struct_variable(v);
free_struct_variable(uv1);
}
} /* end of function cp_remvar */
/* Determine the value of a variable. Fail if the variable is unset,

View File

@ -57,6 +57,7 @@ extern FILE *cp_curin;
extern FILE *cp_curout;
extern FILE *cp_curerr;
extern bool cp_debug;
extern bool cp_no_histsubst; /* controlled by "no_histsubst" true/false */
extern char cp_amp;
extern char cp_gt;
extern char cp_lt;
@ -162,7 +163,7 @@ extern bool cp_noglob;
extern bool cp_nonomatch;
extern char cp_dol;
extern void cp_remvar(char *varname);
extern void cp_vset(char *varname, enum cp_types type, void *value);
void cp_vset(const char *varname, enum cp_types type, const void *value);
extern struct variable *cp_setparse(wordlist *wl);
extern wordlist *vareval(char *string);
extern char *span_var_expr(char *t);