* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
static char sccsid
[] = "@(#)options.c 8.1 (Berkeley) 6/9/93";
static int opts_abbcmp
__P((const void *, const void *));
static int opts_cmp
__P((const void *, const void *));
static OPTLIST
const *opts_prefix
__P((char *));
static int opts_print
__P((SCR
*, OPTLIST
const *, OPTION
*));
static OPTLIST
const optlist
[] = {
{"autoindent", NULL
, OPT_0BOOL
, 0},
{"autoprint", NULL
, OPT_1BOOL
, 0},
{"autowrite", NULL
, OPT_0BOOL
, 0},
{"beautify", NULL
, OPT_0BOOL
, 0},
{"cc", NULL
, OPT_STR
, 0},
{"columns", f_columns
, OPT_NUM
, OPT_NOSAVE
},
{"comment", NULL
, OPT_0BOOL
, 0},
{"digraph", NULL
, OPT_0BOOL
, 0},
{"directory", NULL
, OPT_STR
, OPT_NOSAVE
},
{"edcompatible",NULL
, OPT_0BOOL
, 0},
{"errorbells", NULL
, OPT_0BOOL
, 0},
{"exrc", NULL
, OPT_0BOOL
, 0},
{"extended", NULL
, OPT_0BOOL
, 0},
{"flash", f_flash
, OPT_1BOOL
, 0},
{"ignorecase", NULL
, OPT_0BOOL
, 0},
{"keytime", f_keytime
, OPT_NUM
, 0},
{"leftright", f_leftright
, OPT_0BOOL
, 0},
{"lines", f_lines
, OPT_NUM
, OPT_NOSAVE
},
{"list", f_list
, OPT_0BOOL
, 0},
{"magic", NULL
, OPT_1BOOL
, 0},
{"make", NULL
, OPT_STR
, 0},
{"mesg", f_mesg
, OPT_1BOOL
, 0},
{"modelines", f_modelines
, OPT_0BOOL
, 0},
{"number", f_number
, OPT_0BOOL
, 0},
{"nundo", NULL
, OPT_0BOOL
, 0},
{"optimize", NULL
, OPT_1BOOL
, 0},
{"paragraphs", f_paragraph
, OPT_STR
, 0},
{"prompt", NULL
, OPT_1BOOL
, 0},
{"readonly", f_readonly
, OPT_0BOOL
, 0},
{"redraw", NULL
, OPT_0BOOL
, 0},
{"remap", NULL
, OPT_1BOOL
, 0},
{"report", NULL
, OPT_NUM
, 0},
{"ruler", f_ruler
, OPT_0BOOL
, 0},
{"scroll", NULL
, OPT_NUM
, 0},
{"sections", f_section
, OPT_STR
, 0},
{"shell", NULL
, OPT_STR
, 0},
{"shiftwidth", f_shiftwidth
, OPT_NUM
, 0},
{"showmatch", NULL
, OPT_0BOOL
, 0},
{"showmode", NULL
, OPT_0BOOL
, 0},
{"sidescroll", f_sidescroll
, OPT_NUM
, 0},
{"tabstop", f_tabstop
, OPT_NUM
, 0},
{"taglength", NULL
, OPT_NUM
, 0},
{"tags", f_tags
, OPT_STR
, 0},
{"term", f_term
, OPT_STR
, OPT_NOSAVE
},
{"terse", NULL
, OPT_0BOOL
, 0},
{"timeout", NULL
, OPT_0BOOL
, 0},
{"verbose", NULL
, OPT_0BOOL
, 0},
{"warn", NULL
, OPT_1BOOL
, 0},
{"wrapmargin", f_wrapmargin
, OPT_NUM
, 0},
{"wrapscan", NULL
, OPT_1BOOL
, 0},
{"writeany", NULL
, OPT_0BOOL
, 0},
static OABBREV
const abbrev
[] = {
{"modeline", O_MODELINES
},
* Initialize some of the options. Since the user isn't really
* "setting" these variables, don't set their OPT_SET bits.
char *s
, *argv
[2], b1
[1024];
#define SET_DEF(opt, str) { \
if (str != b1) /* GCC puts strings in text-space. */ \
if (opts_set(sp, argv)) { \
"Unable to set default %s option", optlist[opt]); \
F_CLR(&sp->opts[opt], OPT_SET); \
/* Set default values. */
for (op
= optlist
, cnt
= 0; op
->name
!= NULL
; ++op
, ++cnt
)
if (op
->type
== OPT_0BOOL
)
else if (op
->type
== OPT_1BOOL
)
SET_DEF(O_CC
, "cc=cc -c");
(void)snprintf(b1
, sizeof(b1
), "directory=%s", _PATH_TMP
);
SET_DEF(O_DIRECTORY
, b1
);
SET_DEF(O_KEYTIME
, "keytime=2");
SET_DEF(O_MAKE
, "make=make");
SET_DEF(O_REPORT
, "report=5");
SET_DEF(O_PARAGRAPHS
, "paragraphs=IPLPPPQPP LIpplpipbp");
(void)snprintf(b1
, sizeof(b1
), "scroll=%ld", O_VAL(sp
, O_LINES
) / 2);
SET_DEF(O_SECTIONS
, "sections=NHSHH HUnhsh");
(void)snprintf(b1
, sizeof(b1
),
"shell=%s", (s
= getenv("SHELL")) == NULL
? _PATH_BSHELL
: s
);
SET_DEF(O_SHIFTWIDTH
, "shiftwidth=8");
SET_DEF(O_SIDESCROLL
, "sidescroll=16");
SET_DEF(O_TABSTOP
, "tabstop=8");
(void)snprintf(b1
, sizeof(b1
), "tags=%s", _PATH_TAGS
);
(void)snprintf(b1
, sizeof(b1
),
"term=%s", (s
= getenv("TERM")) == NULL
? "unknown" : s
);
SET_DEF(O_WRAPMARGIN
, "wrapmargin=0");
* By default, the historic vi displayed information about
* two options, redraw and term. Term seems sufficient.
F_SET(&sp
->opts
[O_TERM
], OPT_SET
);
* Change the values of one or more options.
int all
, ch
, offset
, rval
;
char *endp
, *equals
, *name
;
for (all
= rval
= 0; *argv
; ++argv
) {
* The historic vi dumped the options for each occurrence of
* "all" in the set list. Puhleeze.
if (!strcmp(*argv
, "all")) {
/* Find equals sign or end of set, skipping backquoted chars. */
for (p
= name
= *argv
, equals
= NULL
; ch
= *p
; ++p
)
/* Historic vi just used the backslash. */
/* Check list of abbreviations. */
if ((ap
= bsearch(&atmp
, abbrev
,
sizeof(abbrev
) / sizeof(OABBREV
) - 1,
sizeof(OABBREV
), opts_abbcmp
)) != NULL
) {
op
= optlist
+ ap
->offset
;
/* Check list of options. */
if ((op
= bsearch(&otmp
, optlist
,
sizeof(optlist
) / sizeof(OPTLIST
) - 1,
sizeof(OPTLIST
), opts_cmp
)) != NULL
)
/* Try the name without any leading "no". */
if (name
[0] == 'n' && name
[1] == 'o') {
/* Check list of abbreviations. */
if ((ap
= bsearch(&atmp
, abbrev
,
sizeof(abbrev
) / sizeof(OABBREV
) - 1,
sizeof(OABBREV
), opts_abbcmp
)) != NULL
) {
op
= optlist
+ ap
->offset
;
/* Check list of options. */
if ((op
= bsearch(&otmp
, optlist
,
sizeof(optlist
) / sizeof(OPTLIST
) - 1,
sizeof(OPTLIST
), opts_cmp
)) != NULL
)
/* Check for prefix match. */
prefix
: op
= opts_prefix(name
);
"no %s option: 'set all' gives all option values",
/* Find current option values. */
"set: [no]%s option doesn't take a value",
if (op
->func(sp
, spo
, NULL
, turnoff
)) {
F_SET(&sp
->opts
[offset
], OPT_SET
);
"set: %s option isn't a boolean", name
);
"set: %s option requires a value", name
);
value
= strtol(equals
, &endp
, 10);
if (*endp
&& !isspace(*endp
)) {
"set %s: illegal number %s", name
, equals
);
if (op
->func(sp
, spo
, equals
, value
)) {
O_VAL(sp
, offset
) = value
;
F_SET(&sp
->opts
[offset
], OPT_SET
);
"set: %s option isn't a boolean", name
);
"set: %s option requires a value", name
);
if (op
->func(sp
, spo
, equals
, (u_long
)0)) {
if (F_ISSET(&sp
->opts
[offset
], OPT_ALLOCATED
))
strdup(equals
)) == NULL
) {
"Error: %s", strerror(errno
));
F_SET(&sp
->opts
[offset
], OPT_ALLOCATED
);
F_SET(&sp
->opts
[offset
], OPT_SET
);
* List the current values of selected options.
int base
, b_num
, chcnt
, cnt
, col
, colwidth
, curlen
, endcol
, s_num
;
int numcols
, numrows
, row
, tablen
, termwidth
;
int b_op
[O_OPTIONCOUNT
], s_op
[O_OPTIONCOUNT
];
* Options are output in two groups -- those that fit at least two to
* a line and those that don't. We do output on tab boundaries for no
* particular reason. First get the set of options to list, keeping
* track of the length of each. No error checking, because we know
* that O_TERM was set so at least one option has the OPT_SET bit on.
* Termwidth is the tab stop before half of the line in the first loop,
* and the full line length later on.
tablen
= O_VAL(sp
, O_TABSTOP
);
termwidth
= (sp
->cols
- 1) / 2 & ~(tablen
- 1);
for (b_num
= s_num
= 0, op
= optlist
; op
->name
; ++op
) {
if (!all
&& !F_ISSET(&sp
->opts
[cnt
], OPT_SET
))
curlen
= strlen(op
->name
);
sizeof(nbuf
), "%ld", O_VAL(sp
, cnt
));
curlen
+= strlen(O_STR(sp
, cnt
)) + 3;
if (curlen
< termwidth
) {
colwidth
= (colwidth
+ tablen
) & ~(tablen
- 1);
termwidth
= sp
->cols
- 1;
numcols
= termwidth
/ colwidth
;
numrows
= s_num
/ numcols
;
for (row
= 0; row
< numrows
;) {
for (base
= row
, chcnt
= col
= 0; col
< numcols
; ++col
) {
&optlist
[s_op
[base
]], &sp
->opts
[s_op
[base
]]);
if ((base
+= numrows
) >= s_num
)
(chcnt
+ tablen
& ~(tablen
- 1))) <= endcol
) {
(void)putc('\t', sp
->stdfp
);
if (++row
< numrows
|| b_num
)
(void)putc('\n', sp
->stdfp
);
for (row
= 0; row
< b_num
;) {
(void)opts_print(sp
, &optlist
[b_op
[row
]], &sp
->opts
[b_op
[row
]]);
(void)putc('\n', sp
->stdfp
);
(void)putc('\n', sp
->stdfp
);
* Write the current configuration to a file.
for (spo
= sp
->opts
, op
= optlist
; op
->name
; ++op
) {
if (F_ISSET(op
, OPT_NOSAVE
))
(void)fprintf(fp
, "set %s\n", op
->name
);
(void)fprintf(fp
, "set no%s\n", op
->name
);
"set %s=%-3d\n", op
->name
, O_VAL(sp
, cnt
));
"set %s=\"%s\"\n", op
->name
, O_STR(sp
, cnt
));
msgq(sp
, M_ERR
, "I/O error: %s", strerror(errno
));
if (!O_ISSET(sp
, offset
)) {
(void)putc('n', sp
->stdfp
);
(void)putc('o', sp
->stdfp
);
curlen
+= fprintf(sp
->stdfp
, "%s", op
->name
);
curlen
+= fprintf(sp
->stdfp
, "%s", op
->name
);
(void)putc('=', sp
->stdfp
);
curlen
+= fprintf(sp
->stdfp
, "%ld", O_VAL(sp
, offset
));
curlen
+= fprintf(sp
->stdfp
, "%s", op
->name
);
(void)putc('=', sp
->stdfp
);
(void)putc('"', sp
->stdfp
);
curlen
+= fprintf(sp
->stdfp
, "%s", O_STR(sp
, offset
));
(void)putc('"', sp
->stdfp
);
* Check to see if the name is the prefix of one (and only one)
* option. If so, return the option.
OPTLIST
const *op
, *save_op
;
for (op
= optlist
; op
->name
!= NULL
; ++op
) {
if (op
->name
[0] < name
[0])
if (op
->name
[0] > name
[0])
if (!memcmp(op
->name
, name
, len
)) {
return(strcmp(((OABBREV
*)a
)->name
, ((OABBREV
*)b
)->name
));
return(strcmp(((OPTLIST
*)a
)->name
, ((OPTLIST
*)b
)->name
));