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.25 1993/11/15 08:42:12 bostic Exp $ (Berkeley) $Date: 1993/11/15 08:42:12 $";
12 #include <sys/types.h>
14 #include <sys/ioctl.h>
25 #include "pathnames.h"
27 static int opts_abbcmp
__P((const void *, const void *));
28 static int opts_cmp
__P((const void *, const void *));
29 static OPTLIST
const *opts_prefix
__P((char *));
30 static int opts_print
__P((SCR
*, OPTLIST
const *, OPTION
*));
32 static OPTLIST
const optlist
[] = {
34 {"altwerase", f_altwerase
, OPT_0BOOL
, 0},
36 {"autoindent", NULL
, OPT_0BOOL
, 0},
38 {"autoprint", NULL
, OPT_1BOOL
, 0},
40 {"autowrite", NULL
, OPT_0BOOL
, 0},
42 {"beautify", NULL
, OPT_0BOOL
, 0},
44 {"columns", f_columns
, OPT_NUM
, OPT_NOSAVE
},
46 {"comment", NULL
, OPT_0BOOL
, 0},
48 {"digraph", NULL
, OPT_0BOOL
, 0},
50 {"directory", NULL
, OPT_STR
, OPT_NOSAVE
},
52 {"edcompatible",NULL
, OPT_0BOOL
, 0},
54 {"errorbells", NULL
, OPT_0BOOL
, 0},
56 {"exrc", NULL
, OPT_0BOOL
, 0},
58 {"extended", NULL
, OPT_0BOOL
, 0},
60 {"flash", NULL
, OPT_1BOOL
, 0},
62 {"ignorecase", NULL
, OPT_0BOOL
, 0},
64 {"keytime", f_keytime
, OPT_NUM
, 0},
66 {"leftright", f_leftright
, OPT_0BOOL
, 0},
68 {"lines", f_lines
, OPT_NUM
, OPT_NOSAVE
},
70 {"lisp", f_lisp
, OPT_0BOOL
, 0},
72 {"list", f_list
, OPT_0BOOL
, 0},
74 {"magic", NULL
, OPT_1BOOL
, 0},
76 {"matchtime", f_matchtime
, OPT_NUM
, 0},
78 {"mesg", f_mesg
, OPT_1BOOL
, 0},
80 {"modeline", f_modelines
, OPT_0BOOL
, 0},
82 {"modelines", f_modelines
, OPT_0BOOL
, 0},
84 {"number", f_number
, OPT_0BOOL
, 0},
86 {"nundo", NULL
, OPT_0BOOL
, 0},
88 {"open", NULL
, OPT_1BOOL
, 0},
90 {"optimize", f_optimize
, OPT_1BOOL
, 0},
92 {"paragraphs", f_paragraph
, OPT_STR
, 0},
94 {"prompt", NULL
, OPT_1BOOL
, 0},
96 {"readonly", f_readonly
, OPT_0BOOL
, 0},
98 {"redraw", NULL
, OPT_0BOOL
, 0},
100 {"remap", NULL
, OPT_1BOOL
, 0},
102 {"report", NULL
, OPT_NUM
, OPT_NOSTR
},
104 {"ruler", f_ruler
, OPT_0BOOL
, 0},
106 {"scroll", NULL
, OPT_NUM
, 0},
108 {"sections", f_section
, OPT_STR
, 0},
110 {"shell", NULL
, OPT_STR
, 0},
112 {"shiftwidth", f_shiftwidth
, OPT_NUM
, 0},
114 {"showdirty", NULL
, OPT_0BOOL
, 0},
116 {"showmatch", NULL
, OPT_0BOOL
, 0},
118 {"showmode", NULL
, OPT_0BOOL
, 0},
120 {"sidescroll", f_sidescroll
, OPT_NUM
, 0},
122 {"tabstop", f_tabstop
, OPT_NUM
, 0},
124 {"taglength", NULL
, OPT_NUM
, OPT_NOSTR
},
126 {"tags", f_tags
, OPT_STR
, 0},
128 {"term", f_term
, OPT_STR
, OPT_NOSAVE
},
130 {"terse", NULL
, OPT_0BOOL
, 0},
132 {"timeout", NULL
, OPT_0BOOL
, 0},
134 {"ttywerase", f_ttywerase
, OPT_0BOOL
, 0},
136 {"verbose", NULL
, OPT_0BOOL
, 0},
138 {"w300", f_w300
, OPT_NUM
, OPT_NEVER
},
140 {"w1200", f_w1200
, OPT_NUM
, OPT_NEVER
},
142 {"w9600", f_w9600
, OPT_NUM
, OPT_NEVER
},
144 {"warn", NULL
, OPT_1BOOL
, 0},
146 {"window", f_window
, OPT_NUM
, 0},
148 {"wrapmargin", f_wrapmargin
, OPT_NUM
, OPT_NOSTR
},
150 {"wrapscan", NULL
, OPT_1BOOL
, 0},
152 {"writeany", NULL
, OPT_0BOOL
, 0},
156 typedef struct abbrev
{
161 static OABBREV
const abbrev
[] = {
162 {"ai", O_AUTOINDENT
},
167 {"dir", O_DIRECTORY
},
168 {"eb", O_ERRORBELLS
},
169 {"ed", O_EDCOMPATIBLE
},
171 {"ic", O_IGNORECASE
},
177 {"modeline", O_MODELINES
},
180 {"pa", O_PARAGRAPHS
},
189 {"ss", O_SIDESCROLL
},
190 {"sw", O_SHIFTWIDTH
},
196 {"wm", O_WRAPMARGIN
},
204 * Initialize some of the options. Since the user isn't really
205 * "setting" these variables, don't set their OPT_SET bits.
214 char *s
, *argv
[2], b1
[1024];
219 #define SET_DEF(opt, str) { \
220 if (str != b1) /* GCC puts strings in text-space. */ \
221 (void)strcpy(b1, str); \
222 if (opts_set(sp, argv)) { \
224 "Unable to set default %s option", optlist[opt]); \
227 F_CLR(&sp->opts[opt], OPT_SET); \
229 /* Set default values. */
230 for (op
= optlist
, cnt
= 0; op
->name
!= NULL
; ++op
, ++cnt
)
231 if (op
->type
== OPT_0BOOL
)
233 else if (op
->type
== OPT_1BOOL
)
236 (void)snprintf(b1
, sizeof(b1
), "directory=%s",
237 (s
= getenv("TMPDIR")) == NULL
? _PATH_PRESERVE
: s
);
238 SET_DEF(O_DIRECTORY
, b1
);
239 SET_DEF(O_KEYTIME
, "keytime=6");
240 SET_DEF(O_MATCHTIME
, "matchtime=7");
241 SET_DEF(O_REPORT
, "report=5");
242 SET_DEF(O_PARAGRAPHS
, "paragraphs=IPLPPPQPP LIpplpipbp");
243 (void)snprintf(b1
, sizeof(b1
), "scroll=%ld", O_VAL(sp
, O_LINES
) / 2);
244 SET_DEF(O_SCROLL
, b1
);
245 SET_DEF(O_SECTIONS
, "sections=NHSHH HUnhsh");
246 (void)snprintf(b1
, sizeof(b1
),
247 "shell=%s", (s
= getenv("SHELL")) == NULL
? _PATH_BSHELL
: s
);
248 SET_DEF(O_SHELL
, b1
);
249 SET_DEF(O_SHIFTWIDTH
, "shiftwidth=8");
250 SET_DEF(O_SIDESCROLL
, "sidescroll=16");
251 SET_DEF(O_TABSTOP
, "tabstop=8");
252 (void)snprintf(b1
, sizeof(b1
), "tags=%s", _PATH_TAGS
);
254 (void)snprintf(b1
, sizeof(b1
),
255 "term=%s", (s
= getenv("TERM")) == NULL
? "unknown" : s
);
259 * The default window option values are:
260 * 8 if baud rate <= 600
261 * 16 if baud rate <= 1200
262 * LINES - 1 if baud rate > 1200
264 v
= baud_from_bval(sp
);
270 v
= O_VAL(sp
, O_LINES
) - 1;
271 (void)snprintf(b1
, sizeof(b1
), "window=%lu", v
);
272 SET_DEF(O_WINDOW
, b1
);
274 SET_DEF(O_WRAPMARGIN
, "wrapmargin=0");
277 * By default, the historic vi always displayed information
278 * about two options, redraw and term. Term seems sufficient.
280 F_SET(&sp
->opts
[O_TERM
], OPT_SET
);
286 * Change the values of one or more options.
298 u_long value
, turnoff
;
299 int ch
, offset
, rval
;
300 char *endp
, *equals
, *name
, *p
;
303 for (rval
= 0; *argv
; ++argv
) {
305 * The historic vi dumped the options for each occurrence of
306 * "all" in the set list. Puhleeze.
308 if (!strcmp(*argv
, "all")) {
313 /* Find equals sign or end of set, skipping backquoted chars. */
314 for (p
= name
= *argv
, equals
= NULL
; ch
= *p
; ++p
)
320 /* Historic vi just used the backslash. */
332 /* Check list of abbreviations. */
334 if ((ap
= bsearch(&atmp
, abbrev
,
335 sizeof(abbrev
) / sizeof(OABBREV
) - 1,
336 sizeof(OABBREV
), opts_abbcmp
)) != NULL
) {
337 op
= optlist
+ ap
->offset
;
341 /* Check list of options. */
343 if ((op
= bsearch(&otmp
, optlist
,
344 sizeof(optlist
) / sizeof(OPTLIST
) - 1,
345 sizeof(OPTLIST
), opts_cmp
)) != NULL
)
348 /* Try the name without any leading "no". */
349 if (name
[0] == 'n' && name
[1] == 'o') {
355 /* Check list of abbreviations. */
357 if ((ap
= bsearch(&atmp
, abbrev
,
358 sizeof(abbrev
) / sizeof(OABBREV
) - 1,
359 sizeof(OABBREV
), opts_abbcmp
)) != NULL
) {
360 op
= optlist
+ ap
->offset
;
364 /* Check list of options. */
366 if ((op
= bsearch(&otmp
, optlist
,
367 sizeof(optlist
) / sizeof(OPTLIST
) - 1,
368 sizeof(OPTLIST
), opts_cmp
)) != NULL
)
371 /* Check for prefix match. */
372 prefix
: op
= opts_prefix(name
);
374 found
: if (op
== NULL
) {
376 "no %s option: 'set all' gives all option values",
381 /* Find current option values. */
382 offset
= op
- optlist
;
383 spo
= sp
->opts
+ offset
;
385 /* Set name, value. */
391 "set: [no]%s option doesn't take a value",
395 if (op
->func
!= NULL
) {
396 if (op
->func(sp
, spo
, NULL
, turnoff
)) {
408 * Extension to historic vi. If the OPT_NOSTR flag is
409 * set, a numeric option may be turned off by using a
410 * "no" prefix, e.g. "nowrapmargin". (We assume that
411 * setting the value to 0 turns a numeric option off.)
414 if (F_ISSET(op
, OPT_NOSTR
)) {
419 "set: %s option isn't a boolean", name
);
424 disp
= SELECT_DISPLAY
;
425 F_SET(spo
, OPT_SELECTED
);
428 value
= strtol(equals
, &endp
, 10);
429 if (*endp
&& !isblank(*endp
)) {
431 "set %s: illegal number %s", name
, equals
);
434 nostr
: if (op
->func
!= NULL
) {
435 if (op
->func(sp
, spo
, equals
, value
)) {
440 O_VAL(sp
, offset
) = value
;
445 "set: %s option isn't a boolean", name
);
450 disp
= SELECT_DISPLAY
;
451 F_SET(spo
, OPT_SELECTED
);
454 if (op
->func
!= NULL
) {
455 if (op
->func(sp
, spo
, equals
, (u_long
)0)) {
460 if (F_ISSET(&sp
->opts
[offset
], OPT_ALLOCATED
))
461 free(O_STR(sp
, offset
));
462 if ((O_STR(sp
, offset
) =
463 strdup(equals
)) == NULL
) {
464 msgq(sp
, M_SYSERR
, NULL
);
468 F_SET(&sp
->opts
[offset
], OPT_ALLOCATED
);
470 change
: if (sp
->s_optchange
!= NULL
)
471 (void)sp
->s_optchange(sp
, offset
);
472 F_SET(&sp
->opts
[offset
], OPT_SET
);
485 * List the current values of selected options.
493 int base
, b_num
, chcnt
, cnt
, col
, colwidth
, curlen
, endcol
, s_num
;
494 int numcols
, numrows
, row
, tablen
, termwidth
;
495 int b_op
[O_OPTIONCOUNT
], s_op
[O_OPTIONCOUNT
];
499 * Options are output in two groups -- those that fit at least two to
500 * a line and those that don't. We do output on tab boundaries for no
501 * particular reason. First get the set of options to list, keeping
502 * track of the length of each. No error checking, because we know
503 * that O_TERM was set so at least one option has the OPT_SET bit on.
504 * Termwidth is the tab stop before half of the line in the first loop,
505 * and the full line length later on.
508 tablen
= O_VAL(sp
, O_TABSTOP
);
509 termwidth
= (sp
->cols
- 1) / 2 & ~(tablen
- 1);
510 for (b_num
= s_num
= 0, op
= optlist
; op
->name
; ++op
) {
513 /* If OPT_NEVER set, it's never displayed. */
514 if (F_ISSET(op
, OPT_NEVER
))
518 case ALL_DISPLAY
: /* Display all. */
520 case CHANGED_DISPLAY
: /* Display changed. */
521 if (!F_ISSET(&sp
->opts
[cnt
], OPT_SET
))
524 case SELECT_DISPLAY
: /* Display selected. */
525 if (!F_ISSET(&sp
->opts
[cnt
], OPT_SELECTED
))
533 F_CLR(&sp
->opts
[cnt
], OPT_SELECTED
);
535 curlen
= strlen(op
->name
);
539 if (!O_ISSET(sp
, cnt
))
544 sizeof(nbuf
), "%ld", O_VAL(sp
, cnt
));
545 curlen
+= strlen(nbuf
);
548 curlen
+= strlen(O_STR(sp
, cnt
)) + 3;
551 if (curlen
< termwidth
) {
552 if (colwidth
< curlen
)
559 colwidth
= (colwidth
+ tablen
) & ~(tablen
- 1);
560 termwidth
= sp
->cols
- 1;
561 numcols
= termwidth
/ colwidth
;
562 if (s_num
> numcols
) {
563 numrows
= s_num
/ numcols
;
569 for (row
= 0; row
< numrows
;) {
571 for (base
= row
, chcnt
= col
= 0; col
< numcols
; ++col
) {
572 chcnt
+= opts_print(sp
,
573 &optlist
[s_op
[base
]], &sp
->opts
[s_op
[base
]]);
574 if ((base
+= numrows
) >= s_num
)
577 (chcnt
+ tablen
& ~(tablen
- 1))) <= endcol
) {
578 (void)ex_printf(EXCOOKIE
, "\t");
583 if (++row
< numrows
|| b_num
)
584 (void)ex_printf(EXCOOKIE
, "\n");
587 for (row
= 0; row
< b_num
;) {
588 (void)opts_print(sp
, &optlist
[b_op
[row
]], &sp
->opts
[b_op
[row
]]);
590 (void)ex_printf(EXCOOKIE
, "\n");
592 (void)ex_printf(EXCOOKIE
, "\n");
597 * Print out an option.
600 opts_print(sp
, op
, spo
)
608 offset
= op
- optlist
;
612 curlen
+= ex_printf(EXCOOKIE
,
613 "%s%s", O_ISSET(sp
, offset
) ? "" : "no", op
->name
);
616 curlen
+= ex_printf(EXCOOKIE
,
617 "%s=%ld", op
->name
, O_VAL(sp
, offset
));
620 curlen
+= ex_printf(EXCOOKIE
,
621 "%s=\"%s\"", op
->name
, O_STR(sp
, offset
));
629 * Write the current configuration to a file.
641 for (spo
= sp
->opts
, op
= optlist
; op
->name
; ++op
) {
642 if (F_ISSET(op
, OPT_NOSAVE
))
648 if (O_ISSET(sp
, cnt
))
649 (void)fprintf(fp
, "set %s\n", op
->name
);
651 (void)fprintf(fp
, "set no%s\n", op
->name
);
655 "set %s=%-3d\n", op
->name
, O_VAL(sp
, cnt
));
658 for (p
= op
->name
; (ch
= *p
) != '\0'; ++p
) {
660 (void)putc('\\', fp
);
664 for (p
= O_STR(sp
, cnt
); (ch
= *p
) != '\0'; ++p
) {
666 (void)putc('\\', fp
);
669 (void)putc('\n', fp
);
673 msgq(sp
, M_ERR
, "I/O error: %s", strerror(errno
));
682 * Check to see if the name is the prefix of one (and only one)
683 * option. If so, return the option.
685 static OPTLIST
const *
689 OPTLIST
const *op
, *save_op
;
694 for (op
= optlist
; op
->name
!= NULL
; ++op
) {
695 if (op
->name
[0] < name
[0])
697 if (op
->name
[0] > name
[0])
699 if (!memcmp(op
->name
, name
, len
)) {
712 return(strcmp(((OABBREV
*)a
)->name
, ((OABBREV
*)b
)->name
));
719 return(strcmp(((OPTLIST
*)a
)->name
, ((OPTLIST
*)b
)->name
));
724 * Free all option strings
733 for (cnt
= 0; cnt
< O_OPTIONCOUNT
; ++cnt
)
734 if (F_ISSET(&sp
->opts
[cnt
], OPT_ALLOCATED
)) {
736 FREE(p
, strlen(p
) + 1);
742 * Copy a screen's OPTION array.
751 /* Copy most everything without change. */
752 memmove(sp
->opts
, orig
->opts
, sizeof(orig
->opts
));
755 * Allocate copies of the strings -- keep trying to reallocate
756 * after ENOMEM failure, otherwise end up with more than one
757 * screen referencing the original memory.
759 for (op
= sp
->opts
, cnt
= 0; cnt
< O_OPTIONCOUNT
; ++cnt
, ++op
)
760 if (F_ISSET(&sp
->opts
[cnt
], OPT_ALLOCATED
) &&
761 (O_STR(sp
, cnt
) = strdup(O_STR(sp
, cnt
))) == NULL
) {
762 msgq(orig
, M_SYSERR
, NULL
);