2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
5 * %sccs.include.redist.c%
9 static char sccsid
[] = "$Id: options.c,v 8.26 1993/11/15 09:15:45 bostic Exp $ (Berkeley) $Date: 1993/11/15 09:15:45 $";
12 #include <sys/types.h>
24 #include "pathnames.h"
26 static int opts_abbcmp
__P((const void *, const void *));
27 static int opts_cmp
__P((const void *, const void *));
28 static OPTLIST
const *opts_prefix
__P((char *));
29 static int opts_print
__P((SCR
*, OPTLIST
const *, OPTION
*));
31 static OPTLIST
const optlist
[] = {
33 {"altwerase", f_altwerase
, OPT_0BOOL
, 0},
35 {"autoindent", NULL
, OPT_0BOOL
, 0},
37 {"autoprint", NULL
, OPT_1BOOL
, 0},
39 {"autowrite", NULL
, OPT_0BOOL
, 0},
41 {"beautify", NULL
, OPT_0BOOL
, 0},
43 {"columns", f_columns
, OPT_NUM
, OPT_NOSAVE
},
45 {"comment", NULL
, OPT_0BOOL
, 0},
47 {"digraph", NULL
, OPT_0BOOL
, 0},
49 {"directory", NULL
, OPT_STR
, OPT_NOSAVE
},
51 {"edcompatible",NULL
, OPT_0BOOL
, 0},
53 {"errorbells", NULL
, OPT_0BOOL
, 0},
55 {"exrc", NULL
, OPT_0BOOL
, 0},
57 {"extended", NULL
, OPT_0BOOL
, 0},
59 {"flash", NULL
, OPT_1BOOL
, 0},
61 {"ignorecase", NULL
, OPT_0BOOL
, 0},
63 {"keytime", f_keytime
, OPT_NUM
, 0},
65 {"leftright", f_leftright
, OPT_0BOOL
, 0},
67 {"lines", f_lines
, OPT_NUM
, OPT_NOSAVE
},
69 {"lisp", f_lisp
, OPT_0BOOL
, 0},
71 {"list", f_list
, OPT_0BOOL
, 0},
73 {"magic", NULL
, OPT_1BOOL
, 0},
75 {"matchtime", f_matchtime
, OPT_NUM
, 0},
77 {"mesg", f_mesg
, OPT_1BOOL
, 0},
79 {"modeline", f_modelines
, OPT_0BOOL
, 0},
81 {"modelines", f_modelines
, OPT_0BOOL
, 0},
83 {"number", f_number
, OPT_0BOOL
, 0},
85 {"nundo", NULL
, OPT_0BOOL
, 0},
87 {"open", NULL
, OPT_1BOOL
, 0},
89 {"optimize", f_optimize
, OPT_1BOOL
, 0},
91 {"paragraphs", f_paragraph
, OPT_STR
, 0},
93 {"prompt", NULL
, OPT_1BOOL
, 0},
95 {"readonly", f_readonly
, OPT_0BOOL
, 0},
97 {"redraw", NULL
, OPT_0BOOL
, 0},
99 {"remap", NULL
, OPT_1BOOL
, 0},
101 {"report", NULL
, OPT_NUM
, OPT_NOSTR
},
103 {"ruler", f_ruler
, OPT_0BOOL
, 0},
105 {"scroll", NULL
, OPT_NUM
, 0},
107 {"sections", f_section
, OPT_STR
, 0},
109 {"shell", NULL
, OPT_STR
, 0},
111 {"shiftwidth", f_shiftwidth
, OPT_NUM
, 0},
113 {"showdirty", NULL
, OPT_0BOOL
, 0},
115 {"showmatch", NULL
, OPT_0BOOL
, 0},
117 {"showmode", NULL
, OPT_0BOOL
, 0},
119 {"sidescroll", f_sidescroll
, OPT_NUM
, 0},
121 {"tabstop", f_tabstop
, OPT_NUM
, 0},
123 {"taglength", NULL
, OPT_NUM
, OPT_NOSTR
},
125 {"tags", f_tags
, OPT_STR
, 0},
127 {"term", f_term
, OPT_STR
, OPT_NOSAVE
},
129 {"terse", NULL
, OPT_0BOOL
, 0},
131 {"timeout", NULL
, OPT_0BOOL
, 0},
133 {"ttywerase", f_ttywerase
, OPT_0BOOL
, 0},
135 {"verbose", NULL
, OPT_0BOOL
, 0},
137 {"w300", f_w300
, OPT_NUM
, OPT_NEVER
},
139 {"w1200", f_w1200
, OPT_NUM
, OPT_NEVER
},
141 {"w9600", f_w9600
, OPT_NUM
, OPT_NEVER
},
143 {"warn", NULL
, OPT_1BOOL
, 0},
145 {"window", f_window
, OPT_NUM
, 0},
147 {"wrapmargin", f_wrapmargin
, OPT_NUM
, OPT_NOSTR
},
149 {"wrapscan", NULL
, OPT_1BOOL
, 0},
151 {"writeany", NULL
, OPT_0BOOL
, 0},
155 typedef struct abbrev
{
160 static OABBREV
const abbrev
[] = {
161 {"ai", O_AUTOINDENT
},
166 {"dir", O_DIRECTORY
},
167 {"eb", O_ERRORBELLS
},
168 {"ed", O_EDCOMPATIBLE
},
170 {"ic", O_IGNORECASE
},
176 {"modeline", O_MODELINES
},
179 {"pa", O_PARAGRAPHS
},
188 {"ss", O_SIDESCROLL
},
189 {"sw", O_SHIFTWIDTH
},
195 {"wm", O_WRAPMARGIN
},
203 * Initialize some of the options. Since the user isn't really
204 * "setting" these variables, don't set their OPT_SET bits.
213 char *s
, *argv
[2], b1
[1024];
218 #define SET_DEF(opt, str) { \
219 if (str != b1) /* GCC puts strings in text-space. */ \
220 (void)strcpy(b1, str); \
221 if (opts_set(sp, argv)) { \
223 "Unable to set default %s option", optlist[opt]); \
226 F_CLR(&sp->opts[opt], OPT_SET); \
228 /* Set default values. */
229 for (op
= optlist
, cnt
= 0; op
->name
!= NULL
; ++op
, ++cnt
)
230 if (op
->type
== OPT_0BOOL
)
232 else if (op
->type
== OPT_1BOOL
)
235 (void)snprintf(b1
, sizeof(b1
), "directory=%s",
236 (s
= getenv("TMPDIR")) == NULL
? _PATH_PRESERVE
: s
);
237 SET_DEF(O_DIRECTORY
, b1
);
238 SET_DEF(O_KEYTIME
, "keytime=6");
239 SET_DEF(O_MATCHTIME
, "matchtime=7");
240 SET_DEF(O_REPORT
, "report=5");
241 SET_DEF(O_PARAGRAPHS
, "paragraphs=IPLPPPQPP LIpplpipbp");
242 (void)snprintf(b1
, sizeof(b1
), "scroll=%ld", O_VAL(sp
, O_LINES
) / 2);
243 SET_DEF(O_SCROLL
, b1
);
244 SET_DEF(O_SECTIONS
, "sections=NHSHH HUnhsh");
245 (void)snprintf(b1
, sizeof(b1
),
246 "shell=%s", (s
= getenv("SHELL")) == NULL
? _PATH_BSHELL
: s
);
247 SET_DEF(O_SHELL
, b1
);
248 SET_DEF(O_SHIFTWIDTH
, "shiftwidth=8");
249 SET_DEF(O_SIDESCROLL
, "sidescroll=16");
250 SET_DEF(O_TABSTOP
, "tabstop=8");
251 (void)snprintf(b1
, sizeof(b1
), "tags=%s", _PATH_TAGS
);
253 (void)snprintf(b1
, sizeof(b1
),
254 "term=%s", (s
= getenv("TERM")) == NULL
? "unknown" : s
);
258 * The default window option values are:
259 * 8 if baud rate <= 600
260 * 16 if baud rate <= 1200
261 * LINES - 1 if baud rate > 1200
263 v
= baud_from_bval(sp
);
269 v
= O_VAL(sp
, O_LINES
) - 1;
270 (void)snprintf(b1
, sizeof(b1
), "window=%lu", v
);
271 SET_DEF(O_WINDOW
, b1
);
273 SET_DEF(O_WRAPMARGIN
, "wrapmargin=0");
276 * By default, the historic vi always displayed information
277 * about two options, redraw and term. Term seems sufficient.
279 F_SET(&sp
->opts
[O_TERM
], OPT_SET
);
285 * Change the values of one or more options.
297 u_long value
, turnoff
;
298 int ch
, offset
, rval
;
299 char *endp
, *equals
, *name
, *p
;
302 for (rval
= 0; *argv
; ++argv
) {
304 * The historic vi dumped the options for each occurrence of
305 * "all" in the set list. Puhleeze.
307 if (!strcmp(*argv
, "all")) {
312 /* Find equals sign or end of set, skipping backquoted chars. */
313 for (p
= name
= *argv
, equals
= NULL
; ch
= *p
; ++p
)
319 /* Historic vi just used the backslash. */
331 /* Check list of abbreviations. */
333 if ((ap
= bsearch(&atmp
, abbrev
,
334 sizeof(abbrev
) / sizeof(OABBREV
) - 1,
335 sizeof(OABBREV
), opts_abbcmp
)) != NULL
) {
336 op
= optlist
+ ap
->offset
;
340 /* Check list of options. */
342 if ((op
= bsearch(&otmp
, optlist
,
343 sizeof(optlist
) / sizeof(OPTLIST
) - 1,
344 sizeof(OPTLIST
), opts_cmp
)) != NULL
)
347 /* Try the name without any leading "no". */
348 if (name
[0] == 'n' && name
[1] == 'o') {
354 /* Check list of abbreviations. */
356 if ((ap
= bsearch(&atmp
, abbrev
,
357 sizeof(abbrev
) / sizeof(OABBREV
) - 1,
358 sizeof(OABBREV
), opts_abbcmp
)) != NULL
) {
359 op
= optlist
+ ap
->offset
;
363 /* Check list of options. */
365 if ((op
= bsearch(&otmp
, optlist
,
366 sizeof(optlist
) / sizeof(OPTLIST
) - 1,
367 sizeof(OPTLIST
), opts_cmp
)) != NULL
)
370 /* Check for prefix match. */
371 prefix
: op
= opts_prefix(name
);
373 found
: if (op
== NULL
) {
375 "no %s option: 'set all' gives all option values",
380 /* Find current option values. */
381 offset
= op
- optlist
;
382 spo
= sp
->opts
+ offset
;
384 /* Set name, value. */
390 "set: [no]%s option doesn't take a value",
394 if (op
->func
!= NULL
) {
395 if (op
->func(sp
, spo
, NULL
, turnoff
)) {
407 * Extension to historic vi. If the OPT_NOSTR flag is
408 * set, a numeric option may be turned off by using a
409 * "no" prefix, e.g. "nowrapmargin". (We assume that
410 * setting the value to 0 turns a numeric option off.)
413 if (F_ISSET(op
, OPT_NOSTR
)) {
418 "set: %s option isn't a boolean", name
);
423 disp
= SELECT_DISPLAY
;
424 F_SET(spo
, OPT_SELECTED
);
427 value
= strtol(equals
, &endp
, 10);
428 if (*endp
&& !isblank(*endp
)) {
430 "set %s: illegal number %s", name
, equals
);
433 nostr
: if (op
->func
!= NULL
) {
434 if (op
->func(sp
, spo
, equals
, value
)) {
439 O_VAL(sp
, offset
) = value
;
444 "set: %s option isn't a boolean", name
);
449 disp
= SELECT_DISPLAY
;
450 F_SET(spo
, OPT_SELECTED
);
453 if (op
->func
!= NULL
) {
454 if (op
->func(sp
, spo
, equals
, (u_long
)0)) {
459 if (F_ISSET(&sp
->opts
[offset
], OPT_ALLOCATED
))
460 free(O_STR(sp
, offset
));
461 if ((O_STR(sp
, offset
) =
462 strdup(equals
)) == NULL
) {
463 msgq(sp
, M_SYSERR
, NULL
);
467 F_SET(&sp
->opts
[offset
], OPT_ALLOCATED
);
469 change
: if (sp
->s_optchange
!= NULL
)
470 (void)sp
->s_optchange(sp
, offset
);
471 F_SET(&sp
->opts
[offset
], OPT_SET
);
484 * List the current values of selected options.
492 int base
, b_num
, chcnt
, cnt
, col
, colwidth
, curlen
, endcol
, s_num
;
493 int numcols
, numrows
, row
, tablen
, termwidth
;
494 int b_op
[O_OPTIONCOUNT
], s_op
[O_OPTIONCOUNT
];
498 * Options are output in two groups -- those that fit at least two to
499 * a line and those that don't. We do output on tab boundaries for no
500 * particular reason. First get the set of options to list, keeping
501 * track of the length of each. No error checking, because we know
502 * that O_TERM was set so at least one option has the OPT_SET bit on.
503 * Termwidth is the tab stop before half of the line in the first loop,
504 * and the full line length later on.
507 tablen
= O_VAL(sp
, O_TABSTOP
);
508 termwidth
= (sp
->cols
- 1) / 2 & ~(tablen
- 1);
509 for (b_num
= s_num
= 0, op
= optlist
; op
->name
; ++op
) {
512 /* If OPT_NEVER set, it's never displayed. */
513 if (F_ISSET(op
, OPT_NEVER
))
517 case ALL_DISPLAY
: /* Display all. */
519 case CHANGED_DISPLAY
: /* Display changed. */
520 if (!F_ISSET(&sp
->opts
[cnt
], OPT_SET
))
523 case SELECT_DISPLAY
: /* Display selected. */
524 if (!F_ISSET(&sp
->opts
[cnt
], OPT_SELECTED
))
532 F_CLR(&sp
->opts
[cnt
], OPT_SELECTED
);
534 curlen
= strlen(op
->name
);
538 if (!O_ISSET(sp
, cnt
))
543 sizeof(nbuf
), "%ld", O_VAL(sp
, cnt
));
544 curlen
+= strlen(nbuf
);
547 curlen
+= strlen(O_STR(sp
, cnt
)) + 3;
550 if (curlen
< termwidth
) {
551 if (colwidth
< curlen
)
558 colwidth
= (colwidth
+ tablen
) & ~(tablen
- 1);
559 termwidth
= sp
->cols
- 1;
560 numcols
= termwidth
/ colwidth
;
561 if (s_num
> numcols
) {
562 numrows
= s_num
/ numcols
;
568 for (row
= 0; row
< numrows
;) {
570 for (base
= row
, chcnt
= col
= 0; col
< numcols
; ++col
) {
571 chcnt
+= opts_print(sp
,
572 &optlist
[s_op
[base
]], &sp
->opts
[s_op
[base
]]);
573 if ((base
+= numrows
) >= s_num
)
576 (chcnt
+ tablen
& ~(tablen
- 1))) <= endcol
) {
577 (void)ex_printf(EXCOOKIE
, "\t");
582 if (++row
< numrows
|| b_num
)
583 (void)ex_printf(EXCOOKIE
, "\n");
586 for (row
= 0; row
< b_num
;) {
587 (void)opts_print(sp
, &optlist
[b_op
[row
]], &sp
->opts
[b_op
[row
]]);
589 (void)ex_printf(EXCOOKIE
, "\n");
591 (void)ex_printf(EXCOOKIE
, "\n");
596 * Print out an option.
599 opts_print(sp
, op
, spo
)
607 offset
= op
- optlist
;
611 curlen
+= ex_printf(EXCOOKIE
,
612 "%s%s", O_ISSET(sp
, offset
) ? "" : "no", op
->name
);
615 curlen
+= ex_printf(EXCOOKIE
,
616 "%s=%ld", op
->name
, O_VAL(sp
, offset
));
619 curlen
+= ex_printf(EXCOOKIE
,
620 "%s=\"%s\"", op
->name
, O_STR(sp
, offset
));
628 * Write the current configuration to a file.
640 for (spo
= sp
->opts
, op
= optlist
; op
->name
; ++op
) {
641 if (F_ISSET(op
, OPT_NOSAVE
))
647 if (O_ISSET(sp
, cnt
))
648 (void)fprintf(fp
, "set %s\n", op
->name
);
650 (void)fprintf(fp
, "set no%s\n", op
->name
);
654 "set %s=%-3d\n", op
->name
, O_VAL(sp
, cnt
));
657 for (p
= op
->name
; (ch
= *p
) != '\0'; ++p
) {
659 (void)putc('\\', fp
);
663 for (p
= O_STR(sp
, cnt
); (ch
= *p
) != '\0'; ++p
) {
665 (void)putc('\\', fp
);
668 (void)putc('\n', fp
);
672 msgq(sp
, M_ERR
, "I/O error: %s", strerror(errno
));
681 * Check to see if the name is the prefix of one (and only one)
682 * option. If so, return the option.
684 static OPTLIST
const *
688 OPTLIST
const *op
, *save_op
;
693 for (op
= optlist
; op
->name
!= NULL
; ++op
) {
694 if (op
->name
[0] < name
[0])
696 if (op
->name
[0] > name
[0])
698 if (!memcmp(op
->name
, name
, len
)) {
711 return(strcmp(((OABBREV
*)a
)->name
, ((OABBREV
*)b
)->name
));
718 return(strcmp(((OPTLIST
*)a
)->name
, ((OPTLIST
*)b
)->name
));
723 * Free all option strings
732 for (cnt
= 0; cnt
< O_OPTIONCOUNT
; ++cnt
)
733 if (F_ISSET(&sp
->opts
[cnt
], OPT_ALLOCATED
)) {
735 FREE(p
, strlen(p
) + 1);
741 * Copy a screen's OPTION array.
750 /* Copy most everything without change. */
751 memmove(sp
->opts
, orig
->opts
, sizeof(orig
->opts
));
754 * Allocate copies of the strings -- keep trying to reallocate
755 * after ENOMEM failure, otherwise end up with more than one
756 * screen referencing the original memory.
758 for (op
= sp
->opts
, cnt
= 0; cnt
< O_OPTIONCOUNT
; ++cnt
, ++op
)
759 if (F_ISSET(&sp
->opts
[cnt
], OPT_ALLOCATED
) &&
760 (O_STR(sp
, cnt
) = strdup(O_STR(sp
, cnt
))) == NULL
) {
761 msgq(orig
, M_SYSERR
, NULL
);