home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-387-Vol-3of3.iso
/
x
/
xvisrc.zoo
/
param.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-07-28
|
23KB
|
892 lines
/* Copyright (c) 1990,1991,1992 Chris and John Downey */
#ifndef lint
static char *sccsid = "@(#)param.c 2.1 (Chris & John Downey) 7/29/92";
#endif
/***
* program name:
xvi
* function:
PD version of UNIX "vi" editor, with extensions.
* module name:
param.c
* module function:
Code to handle user-settable parameters. This is all pretty much
table-driven. To add a new parameter, put it in the params array,
and add a macro for it in param.h.
The idea of the parameter table is that access to any particular
parameter has to be fast, so it is done with a table lookup. This
unfortunately means that the index of each parameter is recorded
as a macro in param.h, so that file must be changed at the same
time as the table below, and in the same way.
When a parameter is changed, a function is called to do the actual
work; this function is part of the parameter structure. For many
parameters, it's just a simple function that prints "not implemented";
for most others, there are "standard" functions to set bool, numeric
and string parameters, with a certain amount of checking.
No bounds checking is done here; we should really include limits
to numeric parameters in the table. Maybe this will come later.
The data structures will be changed again shortly to enable
buffer- and window-local parameters to be implemented.
One problem with numeric parameters is that they are of type "int";
this obviously places some restrictions on the sort of things they
may be used for, and it may be necessary at some point to change
this type to something like "unsigned long".
* history:
STEVIE - ST Editor for VI Enthusiasts, Version 3.10
Originally by Tim Thompson (twitch!tjt)
Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
Heavily modified by Chris & John Downey
***/
#include "xvi.h"
#define nofunc PFUNCADDR(NULL)
/*
* Default settings for string parameters.
* These are set by the exported function init_params(),
* which must be called before any parameters are accessed.
*/
#define DEF_TAGS "tags,/usr/lib/tags"
#define DEF_PARA "^($|\\.([ILPQ]P|LI|[plib]p))"
#define DEF_SECTIONS "^({|\\.([NS]H|HU|nh|sh))"
#define DEF_SENTENCES "\\<[A-Z]"
/*
* Default setting for roscolour parameter is the same
* as the statuscolour if not specified otherwise.
*/
#ifndef DEF_ROSCOLOUR
#define DEF_ROSCOLOUR DEF_STCOLOUR
#endif
/*
* Default settings for showing control- and meta-characters are
* as for "normal" vi, i.e. "old" xvi without SHOW_META_CHARS set.
*/
#ifndef DEF_CCHARS
# define DEF_CCHARS FALSE
#endif
#ifndef DEF_MCHARS
# define DEF_MCHARS FALSE
#endif
/*
* Internal functions.
*/
static int strtoi P((char **));
static bool_t _do_set P((Xviwin *, char *, bool_t));
static char *parmstring P((Param *, int));
static void enum_usage P((Xviwin*, Param *));
static bool_t not_imp P((Xviwin *, Paramval, bool_t));
static bool_t set_magic P((Xviwin *, Paramval, bool_t));
static bool_t set_rt P((Xviwin *, Paramval, bool_t));
static char *par_show P((void));
/*
* These are the available parameters. The following are non-standard:
*
* autosplit format helpfile jumpscroll preserve
* preservetime regextype vbell edit
* colour statuscolour roscolour systemcolour
*/
Param params[] = {
/* fullname shortname flags value function ... */
{ "ada", "ada", P_BOOL, 0, not_imp, },
{ "adapath", "adapath", P_STRING, 0, not_imp, },
{ "autoindent", "ai", P_BOOL, 0, nofunc, },
{ "autoprint", "ap", P_BOOL, 0, not_imp, },
{ "autosplit", "as", P_NUM, 2, nofunc, },
{ "autowrite", "aw", P_BOOL, 0, not_imp, },
{ "beautify", "bf", P_BOOL, 0, not_imp, },
{ "cchars", "cchars", P_BOOL, DEF_CCHARS, nofunc, },
{ "colour", "co", P_NUM, DEF_COLOUR, nofunc, },
{ "directory", "dir", P_STRING, 0, not_imp, },
{ "edcompatible", "edcompatible", P_BOOL, 0, not_imp, },
{ "edit", "edit", P_BOOL, TRUE, set_edit, },
{ "errorbells", "eb", P_BOOL, 0, nofunc, },
{ "format", "fmt", P_ENUM, 0, set_format,},
{ "hardtabs", "ht", P_NUM, 0, not_imp, },
{ "helpfile", "hf", P_STRING, 0, nofunc, },
{ "ignorecase", "ic", P_BOOL, 0, nofunc, },
{ "jumpscroll", "js", P_ENUM, 0, nofunc, },
{ "lisp", "lisp", P_BOOL, 0, not_imp, },
{ "list", "ls", P_BOOL, 0, nofunc, },
{ "magic", "magic", P_BOOL, TRUE, set_magic, },
{ "mchars", "mchars", P_BOOL, DEF_MCHARS, nofunc, },
{ "mesg", "mesg", P_BOOL, 0, not_imp, },
{ "minrows", "min", P_NUM, 2, nofunc, },
{ "modeline", "modeline", P_BOOL, 0, not_imp, },
{ "number", "nu", P_BOOL, 0, nofunc, },
{ "open", "open", P_BOOL, 0, not_imp, },
{ "optimize", "opt", P_BOOL, 0, not_imp, },
{ "paragraphs", "para", P_STRING, 0, nofunc, },
{ "preserve", "psv", P_ENUM, 0, nofunc, },
{ "preservetime", "psvt", P_NUM, 5, nofunc, },
{ "prompt", "prompt", P_BOOL, 0, not_imp, },
{ "readonly", "ro", P_BOOL, 0, nofunc, },
{ "redraw", "redraw", P_BOOL, 0, not_imp, },
{ "regextype", "rt", P_ENUM, 0, set_rt, },
{ "remap", "remap", P_BOOL, 0, nofunc, },
{ "report", "report", P_NUM, 5, nofunc, },
{ "roscolour", "rst", P_NUM, DEF_ROSCOLOUR, nofunc, },
{ "scroll", "scroll", P_NUM, 0, not_imp, },
{ "sections", "sections", P_STRING, 0, nofunc, },
{ "sentences", "sentences", P_STRING, 0, nofunc, },
{ "shell", "sh", P_STRING, 0, nofunc, },
{ "shiftwidth", "sw", P_NUM, 8, nofunc, },
{ "showmatch", "sm", P_BOOL, 0, nofunc, },
{ "slowopen", "slowopen", P_BOOL, 0, not_imp, },
{ "sourceany", "sourceany", P_BOOL, 0, not_imp, },
{ "statuscolour", "st", P_NUM, DEF_STCOLOUR, nofunc, },
{ "systemcolour", "sy", P_NUM, DEF_SYSCOLOUR, nofunc, },
{ "tabs", "tabs", P_BOOL, TRUE, nofunc, },
{ "tabstop", "ts", P_NUM, 8, nofunc, },
{ "taglength", "tlh", P_NUM, 0, nofunc, },
{ "tags", "tags", P_LIST, 0, nofunc, },
{ "term", "term", P_STRING, 0, not_imp, },
{ "terse", "terse", P_BOOL, 0, not_imp, },
{ "timeout", "timeout", P_NUM, DEF_TIMEOUT, nofunc, },
{ "ttytype", "ttytype", P_STRING, 0, not_imp, },
{ "vbell", "vb", P_BOOL, 0, nofunc, },
{ "warn", "warn", P_BOOL, 0, not_imp, },
{ "window", "window", P_NUM, 0, not_imp, },
{ "wrapmargin", "wm", P_NUM, 0, nofunc, },
{ "wrapscan", "ws", P_BOOL, TRUE, nofunc, },
{ "writeany", "wa", P_BOOL, 0, not_imp, },
{ (char *) NULL, (char *) NULL, 0, 0, nofunc, },
};
/*
* Special initialisations for string, list and enum parameters,
* which we cannot put in the table above because C does not
* allow the initialisation of unions.
*/
static struct {
int index;
char *value;
} init_str[] = { /* strings and lists */
P_helpfile, HELPFILE,
P_paragraphs, DEF_PARA,
P_sections, DEF_SECTIONS,
P_sentences, DEF_SENTENCES,
P_tags, DEF_TAGS,
};
#define NSTRS (sizeof(init_str) / sizeof(init_str[0]))
/*
* Names of values for the P_jumpscroll enumerated parameter.
*
* It is essential that these are in the same order as the js_...
* symbolic constants defined in xvi.h.
*/
static char *js_strings[] =
{
"off", /* js_OFF */
"auto", /* js_AUTO */
"on", /* js_ON */
NULL
};
static struct {
int index;
int value;
char **elist;
} init_enum[] = { /* enumerations */
P_format, DEF_TFF, fmt_strings,
P_jumpscroll, js_AUTO, js_strings,
P_preserve, psv_STANDARD, psv_strings,
P_regextype, rt_GREP, rt_strings,
};
#define NENUMS (sizeof(init_enum) / sizeof(init_enum[0]))
/*
* These are used by par_show().
*/
static bool_t show_all;
static Param *curparam;
/*
* Initialise parameters.
*
* This function is called once from startup().
*/
void
init_params()
{
Paramval pv;
Param *pp;
int i;
/*
* First go through the special string and enum initialisation
* tables, setting the values into the union field in the
* parameter structures.
*/
for (i = 0; i < NSTRS; i++) {
set_param(init_str[i].index, init_str[i].value);
}
for (i = 0; i < NENUMS; i++) {
set_param(init_enum[i].index, init_enum[i].value,
init_enum[i].elist);
}
/*
* Call any special functions that have been set up for
* any parameters, using the default values included in
* the parameter table.
*/
for (pp = ¶ms[0]; pp->p_fullname != NULL; pp++) {
if (pp->p_func != nofunc && pp->p_func != PFUNCADDR(not_imp)) {
switch (pp->p_flags & P_TYPE) {
case P_NUM:
case P_ENUM:
pv.pv_i = pp->p_value;
break;
case P_BOOL:
pv.pv_b = pp->p_value;
break;
case P_STRING:
pv.pv_s = pp->p_str;
break;
case P_LIST:
pv.pv_l = pp->p_list;
}
(void) (*pp->p_func)(curwin, pv, FALSE);
}
}
}
void
do_set(window, argc, argv, inter)
Xviwin *window;
int argc; /* number of parameters to set */
char *argv[]; /* vector of parameter strings */
bool_t inter; /* TRUE if called interactively */
{
int count;
/*
* First check to see if there were any parameters to set,
* or if the user just wants us to display the parameters.
*/
if (argc == 0 || (argc == 1 && (argv[0][0] == '\0' ||
strncmp(argv[0], "all", 3) == 0))) {
if (inter) {
int pcwidth;
show_all = (argc != 0 && argv[0][0] != '\0');
curparam = ¶ms[0];
pcwidth = (window->w_ncols < 90 ?
window->w_ncols :
(window->w_ncols < 135 ?
window->w_ncols / 2 :
window->w_ncols / 3));
disp_init(window, par_show, pcwidth, FALSE);
}
return;
}
for (count = 0; count < argc; count++) {
if (!_do_set(window, argv[count], inter)) {
break;
}
}
if (inter) {
/*
* Finally, update the screen in case we changed
* something like "tabstop" or "list" that will change
* its appearance. We don't always have to do this,
* but it's easier for now.
*/
update_all();
}
}
/*
* Convert a string to an integer. The string may encode the integer
* in octal, decimal or hexadecimal form, in the same style as C. On
* return, make the string pointer, which is passed to us by
* reference, point to the first character which isn't valid for the
* base the number seems to be in.
*/
static int
strtoi(sp)
char **sp;
{
register char *s;
register int i, c;
bool_t neg;
i = 0;
neg = FALSE;
s = *sp;
c = *s;
while (is_space(c)) {
c = *++s;
}
if (c == '-') {
neg = TRUE;
c = *++s;
}
while (is_space(c)) {
c = *++s;
}
if (c == '0') {
switch (c = *++s) {
case 'x': case 'X':
/*
* We've got 0x ... or 0X ..., so it
* looks like a hex. number.
*/
while ((c = *++s) != '\0' && is_xdigit(c)) {
i = (i * 16) + hex_to_bin(c);
}
break;
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
/*
* It looks like an octal number.
*/
do {
i = (i * 8) + c - '0';
} while ((c = *++s) != '\0' && is_octdigit(c));
break;
default:
*sp = s;
return(0);
}
} else {
/*
* Assume it's decimal.
*/
while (c != '\0' && is_digit(c)) {
i = (i * 10) + c - '0';
c = *++s;
}
}
*sp = s;
return(neg ? -i : i);
}
/*
* Internal version of do_set(). Returns TRUE if set of specified
* parameter was successful, otherwise FALSE.
*/
static bool_t
_do_set(window, arg, inter)
Xviwin *window;
char *arg; /* parameter string */
bool_t inter; /* TRUE if called interactively */
{
int settype = 0; /* type they want to set */
bool_t bool_value; /* value they want to set */
char *str_value; /* value they want to set */
Param *pp;
Paramval val;
char *cp;
char **ep;
/*
* "arg" points at the parameter we are going to try to set.
* Spot "no" and "=" keys.
*/
/*
* Note that we will have to change this later if we
* want to implement "nomatch" and "nonomatch". :-(
*/
if (strncmp(arg, "no", 2) == 0) {
settype = P_BOOL;
bool_value = FALSE;
arg += 2;
} else {
bool_value = TRUE;
}
str_value = strchr(arg, '=');
if (str_value != NULL) {
if (settype == P_BOOL) {
if (inter) {
show_error(window, "Can't give \"no\" and a value");
return(FALSE);
}
}
/*
* Null-terminate the parameter name
* and point str_value at the value to
* the right of the '='.
*/
*str_value++ = '\0';
settype = P_STRING;
} else if (settype != P_BOOL) {
/*
* Not already set to P_BOOL, so we haven't seen a "no".
* No '=' sign, so assume we are setting a boolean
* parameter to TRUE.
*/
settype = P_BOOL;
bool_value = TRUE;
}
/*
* Now search for a complete match of the parameter
* name with either the full or short name in the
* parameter table.
*/
for (pp = ¶ms[0]; pp->p_fullname != NULL; pp++) {
if (strcmp(arg, pp->p_fullname) == 0 ||
strcmp(arg, pp->p_shortname) == 0)
break;
}
if (pp->p_fullname == NULL) { /* no match found */
if (inter) {
show_error(window, "No such parameter");
return(FALSE);
}
}
/*
* Check the passed type is appropriate for the
* parameter's type. If it isn't, winge and return.
*/
switch (pp->p_flags & P_TYPE) {
case P_STRING:
case P_LIST:
case P_NUM:
if (settype != P_STRING) {
if (inter) {
show_error(window,
(pp->p_flags & P_STRING) ?
"Invalid set of string parameter"
: (pp->p_flags & P_NUM) ?
"Invalid set of numeric parameter"
: /* else */
"Invalid set of list parameter");
}
return(FALSE);
}
break;
case P_ENUM:
if (settype != P_STRING) {
if (inter) {
enum_usage(window, pp);
}
return(FALSE);
}
break;
case P_BOOL:
if (settype != P_BOOL) {
if (inter) {
show_error(window, "Invalid set of boolean parameter");
}
return(FALSE);
}
}
/*
* Do any type-specific checking, and set up the
* "val" union to contain the (decoded) value.
*/
switch (pp->p_flags & P_TYPE) {
case P_NUM:
{
int i;
cp = str_value;
i = strtoi(&cp);
/*
* If there are extra characters after the number,
* don't accept it.
*/
if (*cp != '\0') {
if (inter) {
show_error(window, "Invalid numeric parameter");
}
return(FALSE);
}
val.pv_i = i;
break;
}
case P_ENUM:
for (ep = pp->p_elist; *ep != NULL; ep++) {
if (strcmp(*ep, str_value) == 0)
break;
}
if (*ep == NULL) {
if (inter) {
enum_usage(window, pp);
}
return(FALSE);
}
val.pv_i = ep - pp->p_elist;
break;
case P_STRING:
case P_LIST:
val.pv_s = str_value;
break;
case P_BOOL:
val.pv_b = bool_value;
break;
}
/*
* Call the check function if there is one.
*/
if (pp->p_func != nofunc && (*pp->p_func)(window, val, inter) == FALSE) {
return(FALSE);
}
/*
* Set the value.
*/
switch (pp->p_flags & P_TYPE) {
case P_NUM:
case P_ENUM:
pp->p_value = val.pv_i;
break;
case P_BOOL:
pp->p_value = bool_value;
break;
case P_STRING:
case P_LIST:
set_param(pp - params, str_value);
break;
}
pp->p_flags |= P_CHANGED;
/*
* Check the bounds for numeric parameters here.
* We will have to make this table-driven later.
*/
if (Pn(P_tabstop) <= 0 || Pn(P_tabstop) > MAX_TABSTOP) {
if (inter) {
show_error(window, "Invalid tab size specified");
}
set_param(P_tabstop, 8);
return(FALSE);
}
/*
* Got through all the bounds checking, so we're okay.
*/
return TRUE;
}
/*
* Internal parameter setting - parameters are not considered
* to have been changed unless they are set by the user.
*
* All types of parameter are handled by this function.
* Enumerated types are special, because two arguments
* are expected: the first, always present, is the index,
* but the second may be either a valid list of strings
* a NULL pointer, the latter indicating that the list
* of strings is not to be changed.
*
* The P_LIST type accepts a string argument and converts
* it to a vector of strings which is then stored.
*/
/*VARARGS1*/
void
#ifdef __STDC__
set_param(int n, ...)
#else
set_param(n, va_alist)
int n;
va_dcl
#endif
{
va_list argp;
Param *pp;
char *cp;
char **elist;
pp = ¶ms[n];
VA_START(argp, n);
switch (pp->p_flags & P_TYPE) {
case P_ENUM:
pp->p_value = va_arg(argp, int);
/*
* If the second argument is a non-NULL list of
* strings, set it into the parameter structure.
* Note that this is not dependent on the return
* value from the check function being TRUE,
* since the check cannot be made until the
* array of strings is in place.
*/
elist = va_arg(argp, char **);
if (elist != NULL) {
pp->p_elist = elist;
}
break;
case P_BOOL:
case P_NUM:
pp->p_value = va_arg(argp, int);
break;
case P_LIST:
{
int argc;
char **argv;
cp = strsave(va_arg(argp, char *));
if (cp == NULL) {
/*
* This is not necessarily a good idea.
*/
show_error(curwin, "Can't allocate memory for parameter");
return;
}
makeargv(cp, &argc, &argv, " \t,");
if (argc == 0 || argv == NULL) {
free(cp);
return;
}
if (pp->p_list != NULL) {
if (pp->p_list[0] != NULL) {
free(pp->p_list[0]);
}
free((char *) pp->p_list);
}
pp->p_list = argv;
}
break;
case P_STRING:
cp = strsave(va_arg(argp, char *));
if (cp == NULL) {
/*
* This is not necessarily a good idea.
*/
show_error(curwin, "Can't allocate memory for parameter");
} else {
/*
* We always free up the old string, because
* it must have been allocated at some point.
*/
if (pp->p_str != NULL) {
free(pp->p_str);
}
pp->p_str = cp;
}
break;
}
va_end(argp);
}
/*
* Display helpful usage message for an enumerated parameter, listing
* the legal values for it.
*/
static void
enum_usage(w, pp)
Xviwin *w;
Param *pp;
{
Flexbuf s;
char **sp;
flexnew(&s);
(void) lformat(&s, "Must be one of:");
for (sp = (char **) pp->p_str; *sp != NULL; sp++) {
(void) lformat(&s, " %s", *sp);
}
show_error(w, "%s", flexgetstr(&s));
flexdelete(&s);
}
/*
* Return a string representation for a single parameter.
*/
static char *
parmstring(pp, leading)
Param *pp; /* parameter */
int leading; /* number of leading spaces in string */
{
static Flexbuf b;
flexclear(&b);
while (leading-- > 0) {
(void) flexaddch(&b, ' ');
}
switch (pp->p_flags & P_TYPE) {
case P_BOOL:
(void) lformat(&b, "%s%s", (pp->p_value ? "" : "no"), pp->p_fullname);
break;
case P_NUM:
(void) lformat(&b, "%s=%d", pp->p_fullname, pp->p_value);
break;
case P_ENUM:
{
int n;
char *estr;
for (n = 0; ; n++) {
if ((estr = ((char **) pp->p_str)[n]) == NULL) {
estr = "INTERNAL ERROR";
break;
}
if (n == pp->p_value)
break;
}
(void) lformat(&b, "%s=%s", pp->p_fullname, estr);
break;
}
case P_STRING:
(void) lformat(&b, "%s=%s", pp->p_fullname,
(pp->p_str != NULL) ? pp->p_str : "");
break;
case P_LIST:
{
register char **cpp;
(void) lformat(&b, "%s=%s", pp->p_fullname, pp->p_list[0]);
for (cpp = pp->p_list + 1; *cpp != NULL; cpp++) {
(void) lformat(&b, " %s", *cpp);
}
}
break;
}
return(flexgetstr(&b));
}
static char *
par_show()
{
static bool_t started = FALSE;
if (!started) {
started = TRUE;
return("Parameters:");
}
for ( ; curparam->p_fullname != NULL; curparam++) {
/*
* Ignore unimplemented parameters.
*/
if (curparam->p_func != PFUNCADDR(not_imp)) {
/*
* Display all parameters if show_all is set;
* otherwise, just display changed parameters.
*/
if (show_all || (curparam->p_flags & P_CHANGED) != 0) {
break;
}
}
}
if (curparam->p_fullname == NULL) {
started = FALSE; /* reset for next time */
return(NULL);
} else {
char *retval;
retval = parmstring(curparam, 3);
curparam++;
return(retval);
}
}
/*ARGSUSED*/
static bool_t
not_imp(window, new_value, interactive)
Xviwin *window;
Paramval new_value;
bool_t interactive;
{
if (interactive) {
show_message(window, "That parameter is not implemented!");
}
return(TRUE);
}
/*ARGSUSED*/
static bool_t
set_magic(window, new_value, interactive)
Xviwin *window;
Paramval new_value;
bool_t interactive;
{
static int prev_rt = rt_GREP;
if (new_value.pv_b) {
/*
* Turn magic on.
*/
if (Pn(P_regextype) == rt_TAGS) {
set_param(P_regextype, prev_rt, (char **) NULL);
}
} else {
/*
* Turn magic off.
*/
if (Pn(P_regextype) != rt_TAGS) {
prev_rt = Pn(P_regextype);
set_param(P_regextype, rt_TAGS, (char **) NULL);
}
}
return(TRUE);
}
/*ARGSUSED*/
static bool_t
set_rt(window, new_value, interactive)
Xviwin *window;
Paramval new_value;
bool_t interactive;
{
switch (new_value.pv_i) {
case rt_TAGS:
case rt_GREP:
case rt_EGREP:
set_param(P_magic, (new_value.pv_i != rt_TAGS));
return(TRUE);
default:
return(FALSE);
}
}