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.36 1993/12/29 16:11:34 bostic Exp $ (Berkeley) $Date: 1993/12/29 16:11:34 $";
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
*));
32 * O'Reilly noted options and abbreviations are from "Learning the VI Editor",
33 * Fifth Edition, May 1992. There's no way of knowing what systems they are
36 * HPUX noted options and abbreviations are from "The Ultimate Guide to the
37 * VI and EX Text Editors", 1990.
39 static OPTLIST
const optlist
[] = {
40 /* O_ALTWERASE 4.4BSD */
41 {"altwerase", f_altwerase
, OPT_0BOOL
, 0},
42 /* O_AUTOINDENT 4BSD */
43 {"autoindent", NULL
, OPT_0BOOL
, 0},
44 /* O_AUTOPRINT 4BSD */
45 {"autoprint", NULL
, OPT_1BOOL
, 0},
46 /* O_AUTOWRITE 4BSD */
47 {"autowrite", NULL
, OPT_0BOOL
, 0},
49 {"beautify", NULL
, OPT_0BOOL
, 0},
50 /* O_COLUMNS 4.4BSD */
51 {"columns", f_columns
, OPT_NUM
, OPT_NOSAVE
},
52 /* O_COMMENT 4.4BSD */
53 {"comment", NULL
, OPT_0BOOL
, 0},
54 /* O_DIGRAPH XXX: Elvis */
55 {"digraph", NULL
, OPT_0BOOL
, 0},
56 /* O_DIRECTORY 4BSD */
57 {"directory", NULL
, OPT_STR
, 0},
58 /* O_EDCOMPATIBLE 4BSD */
59 {"edcompatible",NULL
, OPT_0BOOL
, 0},
60 /* O_ERRORBELLS 4BSD */
61 {"errorbells", NULL
, OPT_0BOOL
, 0},
62 /* O_EXRC System V (undocumented) */
63 {"exrc", NULL
, OPT_0BOOL
, 0},
64 /* O_EXTENDED 4.4BSD */
65 {"extended", NULL
, OPT_0BOOL
, 0},
67 {"flash", NULL
, OPT_1BOOL
, 0},
69 {"hardtabs", NULL
, OPT_NUM
, 0},
70 /* O_IGNORECASE 4BSD */
71 {"ignorecase", NULL
, OPT_0BOOL
, 0},
72 /* O_KEYTIME 4.4BSD */
73 {"keytime", f_keytime
, OPT_NUM
, 0},
74 /* O_LEFTRIGHT 4.4BSD */
75 {"leftright", f_leftright
, OPT_0BOOL
, 0},
77 {"lines", f_lines
, OPT_NUM
, OPT_NOSAVE
},
79 {"lisp", f_lisp
, OPT_0BOOL
, 0},
81 {"list", f_list
, OPT_0BOOL
, 0},
83 {"magic", NULL
, OPT_1BOOL
, 0},
84 /* O_MATCHTIME 4.4BSD */
85 {"matchtime", f_matchtime
, OPT_NUM
, 0},
87 {"mesg", f_mesg
, OPT_1BOOL
, 0},
89 {"modeline", f_modeline
, OPT_0BOOL
, 0},
91 {"number", f_number
, OPT_0BOOL
, 0},
93 {"open", NULL
, OPT_1BOOL
, 0},
95 {"optimize", f_optimize
, OPT_1BOOL
, 0},
96 /* O_PARAGRAPHS 4BSD */
97 {"paragraphs", f_paragraph
, OPT_STR
, 0},
99 {"prompt", NULL
, OPT_1BOOL
, 0},
100 /* O_READONLY 4BSD (undocumented) */
101 {"readonly", f_readonly
, OPT_0BOOL
, 0},
102 /* O_RECDIR 4.4BSD */
103 {"recdir", NULL
, OPT_STR
, 0},
105 {"redraw", NULL
, OPT_0BOOL
, 0},
107 {"remap", NULL
, OPT_1BOOL
, 0},
109 {"report", NULL
, OPT_NUM
, OPT_NOSTR
},
111 {"ruler", f_ruler
, OPT_0BOOL
, 0},
113 {"scroll", NULL
, OPT_NUM
, 0},
114 /* O_SECTIONS 4BSD */
115 {"sections", f_section
, OPT_STR
, 0},
117 {"shell", NULL
, OPT_STR
, 0},
118 /* O_SHIFTWIDTH 4BSD */
119 {"shiftwidth", f_shiftwidth
, OPT_NUM
, 0},
120 /* O_SHOWDIRTY 4.4BSD */
121 {"showdirty", NULL
, OPT_0BOOL
, 0},
122 /* O_SHOWMATCH 4BSD */
123 {"showmatch", NULL
, OPT_0BOOL
, 0},
124 /* O_SHOWMODE 4.4BSD */
125 {"showmode", NULL
, OPT_0BOOL
, 0},
126 /* O_SIDESCROLL 4.4BSD */
127 {"sidescroll", f_sidescroll
, OPT_NUM
, 0},
128 /* O_SLOWOPEN 4BSD */
129 {"slowopen", NULL
, OPT_0BOOL
, 0},
130 /* O_SOURCEANY 4BSD (undocumented) */
131 {"sourceany", f_sourceany
, OPT_0BOOL
, 0},
133 {"tabstop", f_tabstop
, OPT_NUM
, 0},
134 /* O_TAGLENGTH 4BSD */
135 {"taglength", NULL
, OPT_NUM
, OPT_NOSTR
},
137 {"tags", f_tags
, OPT_STR
, 0},
139 {"term", f_term
, OPT_STR
, OPT_NOSAVE
},
141 {"terse", NULL
, OPT_0BOOL
, 0},
142 /* O_TIMEOUT 4BSD (undocumented) */
143 {"timeout", NULL
, OPT_1BOOL
, 0},
144 /* O_TTYWERASE 4.4BSD */
145 {"ttywerase", f_ttywerase
, OPT_0BOOL
, 0},
146 /* O_VERBOSE 4.4BSD */
147 {"verbose", NULL
, OPT_0BOOL
, 0},
149 {"w1200", f_w1200
, OPT_NUM
, OPT_NEVER
},
151 {"w300", f_w300
, OPT_NUM
, OPT_NEVER
},
153 {"w9600", f_w9600
, OPT_NUM
, OPT_NEVER
},
155 {"warn", NULL
, OPT_1BOOL
, 0},
157 {"window", f_window
, OPT_NUM
, 0},
158 /* O_WRAPMARGIN 4BSD */
159 {"wrapmargin", f_wrapmargin
, OPT_NUM
, OPT_NOSTR
},
160 /* O_WRAPSCAN 4BSD */
161 {"wrapscan", NULL
, OPT_1BOOL
, 0},
162 /* O_WRITEANY 4BSD */
163 {"writeany", NULL
, OPT_0BOOL
, 0},
167 typedef struct abbrev
{
172 static OABBREV
const abbrev
[] = {
173 {"ai", O_AUTOINDENT
}, /* 4BSD */
174 {"ap", O_AUTOPRINT
}, /* 4BSD */
175 {"aw", O_AUTOWRITE
}, /* 4BSD */
176 {"bf", O_BEAUTIFY
}, /* 4BSD */
177 {"co", O_COLUMNS
}, /* 4.4BSD */
178 {"dir", O_DIRECTORY
}, /* 4BSD */
179 {"eb", O_ERRORBELLS
}, /* 4BSD */
180 {"ed", O_EDCOMPATIBLE
}, /* 4BSD (undocumented) */
181 {"ex", O_EXRC
}, /* System V (undocumented) */
182 {"ht", O_HARDTABS
}, /* 4BSD */
183 {"ic", O_IGNORECASE
}, /* 4BSD */
184 {"li", O_LINES
}, /* 4.4BSD */
185 {"modelines", O_MODELINE
}, /* HPUX */
186 {"nu", O_NUMBER
}, /* 4BSD */
187 {"opt", O_OPTIMIZE
}, /* 4BSD */
188 {"para", O_PARAGRAPHS
}, /* 4BSD */
189 {"re", O_REDRAW
}, /* O'Reilly */
190 {"ro", O_READONLY
}, /* 4BSD (undocumented) */
191 {"scr", O_SCROLL
}, /* 4BSD (undocumented) */
192 {"sect", O_SECTIONS
}, /* O'Reilly */
193 {"sh", O_SHELL
}, /* 4BSD */
194 {"slow", O_SLOWOPEN
}, /* 4BSD */
195 {"sm", O_SHOWMATCH
}, /* 4BSD */
196 {"sw", O_SHIFTWIDTH
}, /* 4BSD */
197 {"tag", O_TAGS
}, /* 4BSD (undocumented) */
198 {"tl", O_TAGLENGTH
}, /* 4BSD */
199 {"to", O_TIMEOUT
}, /* 4BSD (undocumented) */
200 {"ts", O_TABSTOP
}, /* 4BSD */
201 {"tty", O_TERM
}, /* 4BSD (undocumented) */
202 {"ttytype", O_TERM
}, /* 4BSD (undocumented) */
203 {"w", O_WINDOW
}, /* O'Reilly */
204 {"wa", O_WRITEANY
}, /* 4BSD */
205 {"wi", O_WINDOW
}, /* 4BSD (undocumented) */
206 {"wm", O_WRAPMARGIN
}, /* 4BSD */
207 {"ws", O_WRAPSCAN
}, /* 4BSD */
213 * Initialize some of the options. Since the user isn't really
214 * "setting" these variables, don't set their OPT_SET bits.
233 #define SET_DEF(opt, str) { \
234 if (str != b1) /* GCC puts strings in text-space. */ \
235 (void)strcpy(b1, str); \
236 a.len = strlen(b1); \
237 if (opts_set(sp, argv)) { \
239 "Unable to set default %s option", optlist[opt]); \
242 F_CLR(&sp->opts[opt], OPT_SET); \
244 /* Set default values. */
245 for (op
= optlist
, cnt
= 0; op
->name
!= NULL
; ++op
, ++cnt
)
246 if (op
->type
== OPT_0BOOL
)
248 else if (op
->type
== OPT_1BOOL
)
253 * Vi historically stored temporary files in /var/tmp. We store them
254 * in /tmp by default, hoping it's a memory based file system. There
255 * are two ways to change this -- the user can set either the directory
256 * option or the TMPDIR environmental variable.
258 (void)snprintf(b1
, sizeof(b1
), "directory=%s",
259 (s
= getenv("TMPDIR")) == NULL
? _PATH_TMP
: s
);
260 SET_DEF(O_DIRECTORY
, b1
);
261 SET_DEF(O_KEYTIME
, "keytime=6");
262 SET_DEF(O_MATCHTIME
, "matchtime=7");
263 SET_DEF(O_REPORT
, "report=5");
264 SET_DEF(O_PARAGRAPHS
, "paragraphs=IPLPPPQPP LIpplpipbp");
265 (void)snprintf(b1
, sizeof(b1
), "recdir=%s", _PATH_PRESERVE
);
266 SET_DEF(O_RECDIR
, b1
);
267 (void)snprintf(b1
, sizeof(b1
), "scroll=%ld", O_VAL(sp
, O_LINES
) / 2);
268 SET_DEF(O_SCROLL
, b1
);
269 SET_DEF(O_SECTIONS
, "sections=NHSHH HUnhsh");
270 (void)snprintf(b1
, sizeof(b1
),
271 "shell=%s", (s
= getenv("SHELL")) == NULL
? _PATH_BSHELL
: s
);
272 SET_DEF(O_SHELL
, b1
);
273 SET_DEF(O_SHIFTWIDTH
, "shiftwidth=8");
274 SET_DEF(O_SIDESCROLL
, "sidescroll=16");
275 SET_DEF(O_TABSTOP
, "tabstop=8");
276 (void)snprintf(b1
, sizeof(b1
), "tags=%s", _PATH_TAGS
);
278 (void)snprintf(b1
, sizeof(b1
),
279 "term=%s", (s
= getenv("TERM")) == NULL
? "unknown" : s
);
283 * The default window option values are:
284 * 8 if baud rate <= 600
285 * 16 if baud rate <= 1200
286 * LINES - 1 if baud rate > 1200
288 v
= baud_from_bval(sp
);
294 v
= O_VAL(sp
, O_LINES
) - 1;
295 (void)snprintf(b1
, sizeof(b1
), "window=%lu", v
);
296 SET_DEF(O_WINDOW
, b1
);
298 SET_DEF(O_WRAPMARGIN
, "wrapmargin=0");
301 * By default, the historic vi always displayed information
302 * about two options, redraw and term. Term seems sufficient.
304 F_SET(&sp
->opts
[O_TERM
], OPT_SET
);
310 * Change the values of one or more options.
322 u_long value
, turnoff
;
323 int ch
, offset
, rval
;
324 char *endp
, *equals
, *name
, *p
;
327 for (rval
= 0; (*argv
)->len
!= 0; ++argv
) {
329 * The historic vi dumped the options for each occurrence of
330 * "all" in the set list. Puhleeze.
332 if (!strcmp(argv
[0]->bp
, "all")) {
337 /* Find equals sign or end of set, skipping backquoted chars. */
338 for (p
= name
= argv
[0]->bp
, equals
= NULL
; ch
= *p
; ++p
)
344 /* Historic vi just used the backslash. */
356 /* Check list of abbreviations. */
358 if ((ap
= bsearch(&atmp
, abbrev
,
359 sizeof(abbrev
) / sizeof(OABBREV
) - 1,
360 sizeof(OABBREV
), opts_abbcmp
)) != NULL
) {
361 op
= optlist
+ ap
->offset
;
365 /* Check list of options. */
367 if ((op
= bsearch(&otmp
, optlist
,
368 sizeof(optlist
) / sizeof(OPTLIST
) - 1,
369 sizeof(OPTLIST
), opts_cmp
)) != NULL
)
372 /* Try the name without any leading "no". */
373 if (name
[0] == 'n' && name
[1] == 'o') {
379 /* Check list of abbreviations. */
381 if ((ap
= bsearch(&atmp
, abbrev
,
382 sizeof(abbrev
) / sizeof(OABBREV
) - 1,
383 sizeof(OABBREV
), opts_abbcmp
)) != NULL
) {
384 op
= optlist
+ ap
->offset
;
388 /* Check list of options. */
390 if ((op
= bsearch(&otmp
, optlist
,
391 sizeof(optlist
) / sizeof(OPTLIST
) - 1,
392 sizeof(OPTLIST
), opts_cmp
)) != NULL
)
395 /* Check for prefix match. */
396 prefix
: op
= opts_prefix(name
);
398 found
: if (op
== NULL
) {
400 "no %s option: 'set all' gives all option values",
405 /* Find current option values. */
406 offset
= op
- optlist
;
407 spo
= sp
->opts
+ offset
;
409 /* Set name, value. */
415 "set: [no]%s option doesn't take a value",
419 if (op
->func
!= NULL
) {
420 if (op
->func(sp
, spo
, NULL
, turnoff
)) {
432 * Extension to historic vi. If the OPT_NOSTR flag is
433 * set, a numeric option may be turned off by using a
434 * "no" prefix, e.g. "nowrapmargin". (We assume that
435 * setting the value to 0 turns a numeric option off.)
438 if (F_ISSET(op
, OPT_NOSTR
)) {
443 "set: %s option isn't a boolean", name
);
448 disp
= SELECT_DISPLAY
;
449 F_SET(spo
, OPT_SELECTED
);
452 value
= strtol(equals
, &endp
, 10);
453 if (*endp
&& !isblank(*endp
)) {
455 "set %s: illegal number %s", name
, equals
);
458 nostr
: if (op
->func
!= NULL
) {
459 if (op
->func(sp
, spo
, equals
, value
)) {
464 O_VAL(sp
, offset
) = value
;
469 "set: %s option isn't a boolean", name
);
474 disp
= SELECT_DISPLAY
;
475 F_SET(spo
, OPT_SELECTED
);
478 if (op
->func
!= NULL
) {
479 if (op
->func(sp
, spo
, equals
, (u_long
)0)) {
484 if (F_ISSET(&sp
->opts
[offset
], OPT_ALLOCATED
))
485 free(O_STR(sp
, offset
));
486 if ((O_STR(sp
, offset
) =
487 strdup(equals
)) == NULL
) {
488 msgq(sp
, M_SYSERR
, NULL
);
492 F_SET(&sp
->opts
[offset
], OPT_ALLOCATED
);
494 change
: if (sp
->s_optchange
!= NULL
)
495 (void)sp
->s_optchange(sp
, offset
);
496 F_SET(&sp
->opts
[offset
], OPT_SET
);
509 * List the current values of selected options.
517 int base
, b_num
, cnt
, col
, colwidth
, curlen
, s_num
;
518 int numcols
, numrows
, row
;
519 int b_op
[O_OPTIONCOUNT
], s_op
[O_OPTIONCOUNT
];
523 * Options are output in two groups -- those that fit in a column and
524 * those that don't. Output is done on 6 character "tab" boundaries
525 * for no particular reason. (Since we don't output tab characters,
526 * we can ignore the terminal's tab settings.) Ignore the user's tab
527 * setting because we have no idea how reasonable it is.
531 /* Find a column width we can live with. */
532 for (cnt
= 6; cnt
> 1; --cnt
) {
533 colwidth
= (sp
->cols
- 1) / cnt
& ~(BOUND
- 1);
534 if (colwidth
>= 10) {
535 colwidth
= (colwidth
+ BOUND
) & ~(BOUND
- 1);
542 * Two passes. First, get the set of options to list, entering them
543 * into the column list or the overflow list. No error checking,
544 * since we know that at least one option (O_TERM) has the OPT_SET bit
547 for (b_num
= s_num
= 0, op
= optlist
; op
->name
; ++op
) {
550 /* If OPT_NEVER set, it's never displayed. */
551 if (F_ISSET(op
, OPT_NEVER
))
555 case ALL_DISPLAY
: /* Display all. */
557 case CHANGED_DISPLAY
: /* Display changed. */
558 if (!F_ISSET(&sp
->opts
[cnt
], OPT_SET
))
561 case SELECT_DISPLAY
: /* Display selected. */
562 if (!F_ISSET(&sp
->opts
[cnt
], OPT_SELECTED
))
570 F_CLR(&sp
->opts
[cnt
], OPT_SELECTED
);
572 curlen
= strlen(op
->name
);
576 if (!O_ISSET(sp
, cnt
))
581 sizeof(nbuf
), "%ld", O_VAL(sp
, cnt
));
582 curlen
+= strlen(nbuf
);
585 curlen
+= strlen(O_STR(sp
, cnt
)) + 3;
588 /* Offset by two so there's a gap. */
589 if (curlen
< colwidth
- 2)
595 numcols
= (sp
->cols
- 1) / colwidth
;
596 if (s_num
> numcols
) {
597 numrows
= s_num
/ numcols
;
603 for (row
= 0; row
< numrows
;) {
604 for (base
= row
, col
= 0; col
< numcols
; ++col
) {
606 &optlist
[s_op
[base
]], &sp
->opts
[s_op
[base
]]);
607 if ((base
+= numrows
) >= s_num
)
609 (void)ex_printf(EXCOOKIE
,
610 "%*s", (int)(colwidth
- cnt
), "");
612 if (++row
< numrows
|| b_num
)
613 (void)ex_printf(EXCOOKIE
, "\n");
616 for (row
= 0; row
< b_num
;) {
617 (void)opts_print(sp
, &optlist
[b_op
[row
]], &sp
->opts
[b_op
[row
]]);
619 (void)ex_printf(EXCOOKIE
, "\n");
621 (void)ex_printf(EXCOOKIE
, "\n");
626 * Print out an option.
629 opts_print(sp
, op
, spo
)
637 offset
= op
- optlist
;
641 curlen
+= ex_printf(EXCOOKIE
,
642 "%s%s", O_ISSET(sp
, offset
) ? "" : "no", op
->name
);
645 curlen
+= ex_printf(EXCOOKIE
,
646 "%s=%ld", op
->name
, O_VAL(sp
, offset
));
649 curlen
+= ex_printf(EXCOOKIE
,
650 "%s=\"%s\"", op
->name
, O_STR(sp
, offset
));
658 * Write the current configuration to a file.
670 for (spo
= sp
->opts
, op
= optlist
; op
->name
; ++op
) {
671 if (F_ISSET(op
, OPT_NOSAVE
))
677 if (O_ISSET(sp
, cnt
))
678 (void)fprintf(fp
, "set %s\n", op
->name
);
680 (void)fprintf(fp
, "set no%s\n", op
->name
);
684 "set %s=%-3d\n", op
->name
, O_VAL(sp
, cnt
));
687 (void)fprintf(fp
, "set ");
688 for (p
= op
->name
; (ch
= *p
) != '\0'; ++p
) {
690 (void)putc('\\', fp
);
694 for (p
= O_STR(sp
, cnt
); (ch
= *p
) != '\0'; ++p
) {
696 (void)putc('\\', fp
);
699 (void)putc('\n', fp
);
703 msgq(sp
, M_ERR
, "I/O error: %s", strerror(errno
));
712 * Check to see if the name is the prefix of one (and only one)
713 * option. If so, return the option.
715 static OPTLIST
const *
719 OPTLIST
const *op
, *save_op
;
724 for (op
= optlist
; op
->name
!= NULL
; ++op
) {
725 if (op
->name
[0] < name
[0])
727 if (op
->name
[0] > name
[0])
729 if (!memcmp(op
->name
, name
, len
)) {
742 return(strcmp(((OABBREV
*)a
)->name
, ((OABBREV
*)b
)->name
));
749 return(strcmp(((OPTLIST
*)a
)->name
, ((OPTLIST
*)b
)->name
));
754 * Free all option strings
763 for (cnt
= 0; cnt
< O_OPTIONCOUNT
; ++cnt
)
764 if (F_ISSET(&sp
->opts
[cnt
], OPT_ALLOCATED
)) {
766 FREE(p
, strlen(p
) + 1);
772 * Copy a screen's OPTION array.
781 /* Copy most everything without change. */
782 memmove(sp
->opts
, orig
->opts
, sizeof(orig
->opts
));
785 * Allocate copies of the strings -- keep trying to reallocate
786 * after ENOMEM failure, otherwise end up with more than one
787 * screen referencing the original memory.
789 for (op
= sp
->opts
, cnt
= 0; cnt
< O_OPTIONCOUNT
; ++cnt
, ++op
)
790 if (F_ISSET(&sp
->opts
[cnt
], OPT_ALLOCATED
) &&
791 (O_STR(sp
, cnt
) = strdup(O_STR(sp
, cnt
))) == NULL
) {
792 msgq(orig
, M_SYSERR
, NULL
);