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.33 1993/12/21 11:58:41 bostic Exp $ (Berkeley) $Date: 1993/12/21 11:58:41 $";
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 {"nundo", NULL
, OPT_0BOOL
, 0},
95 {"open", NULL
, OPT_1BOOL
, 0},
97 {"optimize", f_optimize
, OPT_1BOOL
, 0},
98 /* O_PARAGRAPHS 4BSD */
99 {"paragraphs", f_paragraph
, OPT_STR
, 0},
101 {"prompt", NULL
, OPT_1BOOL
, 0},
102 /* O_READONLY 4BSD (undocumented) */
103 {"readonly", f_readonly
, OPT_0BOOL
, 0},
104 /* O_RECDIR 4.4BSD */
105 {"recdir", NULL
, OPT_STR
, 0},
107 {"redraw", NULL
, OPT_0BOOL
, 0},
109 {"remap", NULL
, OPT_1BOOL
, 0},
111 {"report", NULL
, OPT_NUM
, OPT_NOSTR
},
113 {"ruler", f_ruler
, OPT_0BOOL
, 0},
115 {"scroll", NULL
, OPT_NUM
, 0},
116 /* O_SECTIONS 4BSD */
117 {"sections", f_section
, OPT_STR
, 0},
119 {"shell", NULL
, OPT_STR
, 0},
120 /* O_SHIFTWIDTH 4BSD */
121 {"shiftwidth", f_shiftwidth
, OPT_NUM
, 0},
122 /* O_SHOWDIRTY 4.4BSD */
123 {"showdirty", NULL
, OPT_0BOOL
, 0},
124 /* O_SHOWMATCH 4BSD */
125 {"showmatch", NULL
, OPT_0BOOL
, 0},
126 /* O_SHOWMODE 4.4BSD */
127 {"showmode", NULL
, OPT_0BOOL
, 0},
128 /* O_SIDESCROLL 4.4BSD */
129 {"sidescroll", f_sidescroll
, OPT_NUM
, 0},
130 /* O_SLOWOPEN 4BSD */
131 {"slowopen", NULL
, OPT_0BOOL
, 0},
132 /* O_SOURCEANY 4BSD (undocumented) */
133 {"sourceany", f_sourceany
, OPT_0BOOL
, 0},
135 {"tabstop", f_tabstop
, OPT_NUM
, 0},
136 /* O_TAGLENGTH 4BSD */
137 {"taglength", NULL
, OPT_NUM
, OPT_NOSTR
},
139 {"tags", f_tags
, OPT_STR
, 0},
141 {"term", f_term
, OPT_STR
, OPT_NOSAVE
},
143 {"terse", NULL
, OPT_0BOOL
, 0},
144 /* O_TIMEOUT 4BSD (undocumented) */
145 {"timeout", NULL
, OPT_1BOOL
, 0},
146 /* O_TTYWERASE 4.4BSD */
147 {"ttywerase", f_ttywerase
, OPT_0BOOL
, 0},
148 /* O_VERBOSE 4.4BSD */
149 {"verbose", NULL
, OPT_0BOOL
, 0},
151 {"w1200", f_w1200
, OPT_NUM
, OPT_NEVER
},
153 {"w300", f_w300
, OPT_NUM
, OPT_NEVER
},
155 {"w9600", f_w9600
, OPT_NUM
, OPT_NEVER
},
157 {"warn", NULL
, OPT_1BOOL
, 0},
159 {"window", f_window
, OPT_NUM
, 0},
160 /* O_WRAPMARGIN 4BSD */
161 {"wrapmargin", f_wrapmargin
, OPT_NUM
, OPT_NOSTR
},
162 /* O_WRAPSCAN 4BSD */
163 {"wrapscan", NULL
, OPT_1BOOL
, 0},
164 /* O_WRITEANY 4BSD */
165 {"writeany", NULL
, OPT_0BOOL
, 0},
169 typedef struct abbrev
{
174 static OABBREV
const abbrev
[] = {
175 {"ai", O_AUTOINDENT
}, /* 4BSD */
176 {"ap", O_AUTOPRINT
}, /* 4BSD */
177 {"aw", O_AUTOWRITE
}, /* 4BSD */
178 {"bf", O_BEAUTIFY
}, /* 4BSD */
179 {"co", O_COLUMNS
}, /* 4.4BSD */
180 {"dir", O_DIRECTORY
}, /* 4BSD */
181 {"eb", O_ERRORBELLS
}, /* 4BSD */
182 {"ed", O_EDCOMPATIBLE
}, /* 4BSD (undocumented) */
183 {"ex", O_EXRC
}, /* System V (undocumented) */
184 {"ht", O_HARDTABS
}, /* 4BSD */
185 {"ic", O_IGNORECASE
}, /* 4BSD */
186 {"li", O_LINES
}, /* 4.4BSD */
187 {"modelines", O_MODELINE
}, /* HPUX */
188 {"nu", O_NUMBER
}, /* 4BSD */
189 {"opt", O_OPTIMIZE
}, /* 4BSD */
190 {"para", O_PARAGRAPHS
}, /* 4BSD */
191 {"re", O_REDRAW
}, /* O'Reilly */
192 {"ro", O_READONLY
}, /* 4BSD (undocumented) */
193 {"scr", O_SCROLL
}, /* 4BSD (undocumented) */
194 {"sect", O_SECTIONS
}, /* O'Reilly */
195 {"sh", O_SHELL
}, /* 4BSD */
196 {"slow", O_SLOWOPEN
}, /* 4BSD */
197 {"sm", O_SHOWMATCH
}, /* 4BSD */
198 {"sw", O_SHIFTWIDTH
}, /* 4BSD */
199 {"tag", O_TAGS
}, /* 4BSD (undocumented) */
200 {"tl", O_TAGLENGTH
}, /* 4BSD */
201 {"to", O_TIMEOUT
}, /* 4BSD (undocumented) */
202 {"ts", O_TABSTOP
}, /* 4BSD */
203 {"tty", O_TERM
}, /* 4BSD (undocumented) */
204 {"ttytype", O_TERM
}, /* 4BSD (undocumented) */
205 {"w", O_WINDOW
}, /* O'Reilly */
206 {"wa", O_WRITEANY
}, /* 4BSD */
207 {"wi", O_WINDOW
}, /* 4BSD (undocumented) */
208 {"wm", O_WRAPMARGIN
}, /* 4BSD */
209 {"ws", O_WRAPSCAN
}, /* 4BSD */
215 * Initialize some of the options. Since the user isn't really
216 * "setting" these variables, don't set their OPT_SET bits.
235 #define SET_DEF(opt, str) { \
236 if (str != b1) /* GCC puts strings in text-space. */ \
237 (void)strcpy(b1, str); \
238 a.len = strlen(b1); \
239 if (opts_set(sp, argv)) { \
241 "Unable to set default %s option", optlist[opt]); \
244 F_CLR(&sp->opts[opt], OPT_SET); \
246 /* Set default values. */
247 for (op
= optlist
, cnt
= 0; op
->name
!= NULL
; ++op
, ++cnt
)
248 if (op
->type
== OPT_0BOOL
)
250 else if (op
->type
== OPT_1BOOL
)
255 * Vi historically stored temporary files in /var/tmp. We store them
256 * in /tmp by default, hoping it's a memory based file system. There
257 * are two ways to change this -- the user can set either the directory
258 * option or the TMPDIR environmental variable.
260 (void)snprintf(b1
, sizeof(b1
), "directory=%s",
261 (s
= getenv("TMPDIR")) == NULL
? _PATH_TMP
: s
);
262 SET_DEF(O_DIRECTORY
, b1
);
263 SET_DEF(O_KEYTIME
, "keytime=6");
264 SET_DEF(O_MATCHTIME
, "matchtime=7");
265 SET_DEF(O_REPORT
, "report=5");
266 SET_DEF(O_PARAGRAPHS
, "paragraphs=IPLPPPQPP LIpplpipbp");
267 (void)snprintf(b1
, sizeof(b1
), "recdir=%s", _PATH_PRESERVE
);
268 SET_DEF(O_RECDIR
, b1
);
269 (void)snprintf(b1
, sizeof(b1
), "scroll=%ld", O_VAL(sp
, O_LINES
) / 2);
270 SET_DEF(O_SCROLL
, b1
);
271 SET_DEF(O_SECTIONS
, "sections=NHSHH HUnhsh");
272 (void)snprintf(b1
, sizeof(b1
),
273 "shell=%s", (s
= getenv("SHELL")) == NULL
? _PATH_BSHELL
: s
);
274 SET_DEF(O_SHELL
, b1
);
275 SET_DEF(O_SHIFTWIDTH
, "shiftwidth=8");
276 SET_DEF(O_SIDESCROLL
, "sidescroll=16");
277 SET_DEF(O_TABSTOP
, "tabstop=8");
278 (void)snprintf(b1
, sizeof(b1
), "tags=%s", _PATH_TAGS
);
280 (void)snprintf(b1
, sizeof(b1
),
281 "term=%s", (s
= getenv("TERM")) == NULL
? "unknown" : s
);
285 * The default window option values are:
286 * 8 if baud rate <= 600
287 * 16 if baud rate <= 1200
288 * LINES - 1 if baud rate > 1200
290 v
= baud_from_bval(sp
);
296 v
= O_VAL(sp
, O_LINES
) - 1;
297 (void)snprintf(b1
, sizeof(b1
), "window=%lu", v
);
298 SET_DEF(O_WINDOW
, b1
);
300 SET_DEF(O_WRAPMARGIN
, "wrapmargin=0");
303 * By default, the historic vi always displayed information
304 * about two options, redraw and term. Term seems sufficient.
306 F_SET(&sp
->opts
[O_TERM
], OPT_SET
);
312 * Change the values of one or more options.
324 u_long value
, turnoff
;
325 int ch
, offset
, rval
;
326 char *endp
, *equals
, *name
, *p
;
329 for (rval
= 0; (*argv
)->len
!= 0; ++argv
) {
331 * The historic vi dumped the options for each occurrence of
332 * "all" in the set list. Puhleeze.
334 if (!strcmp(argv
[0]->bp
, "all")) {
339 /* Find equals sign or end of set, skipping backquoted chars. */
340 for (p
= name
= argv
[0]->bp
, equals
= NULL
; ch
= *p
; ++p
)
346 /* Historic vi just used the backslash. */
358 /* Check list of abbreviations. */
360 if ((ap
= bsearch(&atmp
, abbrev
,
361 sizeof(abbrev
) / sizeof(OABBREV
) - 1,
362 sizeof(OABBREV
), opts_abbcmp
)) != NULL
) {
363 op
= optlist
+ ap
->offset
;
367 /* Check list of options. */
369 if ((op
= bsearch(&otmp
, optlist
,
370 sizeof(optlist
) / sizeof(OPTLIST
) - 1,
371 sizeof(OPTLIST
), opts_cmp
)) != NULL
)
374 /* Try the name without any leading "no". */
375 if (name
[0] == 'n' && name
[1] == 'o') {
381 /* Check list of abbreviations. */
383 if ((ap
= bsearch(&atmp
, abbrev
,
384 sizeof(abbrev
) / sizeof(OABBREV
) - 1,
385 sizeof(OABBREV
), opts_abbcmp
)) != NULL
) {
386 op
= optlist
+ ap
->offset
;
390 /* Check list of options. */
392 if ((op
= bsearch(&otmp
, optlist
,
393 sizeof(optlist
) / sizeof(OPTLIST
) - 1,
394 sizeof(OPTLIST
), opts_cmp
)) != NULL
)
397 /* Check for prefix match. */
398 prefix
: op
= opts_prefix(name
);
400 found
: if (op
== NULL
) {
402 "no %s option: 'set all' gives all option values",
407 /* Find current option values. */
408 offset
= op
- optlist
;
409 spo
= sp
->opts
+ offset
;
411 /* Set name, value. */
417 "set: [no]%s option doesn't take a value",
421 if (op
->func
!= NULL
) {
422 if (op
->func(sp
, spo
, NULL
, turnoff
)) {
434 * Extension to historic vi. If the OPT_NOSTR flag is
435 * set, a numeric option may be turned off by using a
436 * "no" prefix, e.g. "nowrapmargin". (We assume that
437 * setting the value to 0 turns a numeric option off.)
440 if (F_ISSET(op
, OPT_NOSTR
)) {
445 "set: %s option isn't a boolean", name
);
450 disp
= SELECT_DISPLAY
;
451 F_SET(spo
, OPT_SELECTED
);
454 value
= strtol(equals
, &endp
, 10);
455 if (*endp
&& !isblank(*endp
)) {
457 "set %s: illegal number %s", name
, equals
);
460 nostr
: if (op
->func
!= NULL
) {
461 if (op
->func(sp
, spo
, equals
, value
)) {
466 O_VAL(sp
, offset
) = value
;
471 "set: %s option isn't a boolean", name
);
476 disp
= SELECT_DISPLAY
;
477 F_SET(spo
, OPT_SELECTED
);
480 if (op
->func
!= NULL
) {
481 if (op
->func(sp
, spo
, equals
, (u_long
)0)) {
486 if (F_ISSET(&sp
->opts
[offset
], OPT_ALLOCATED
))
487 free(O_STR(sp
, offset
));
488 if ((O_STR(sp
, offset
) =
489 strdup(equals
)) == NULL
) {
490 msgq(sp
, M_SYSERR
, NULL
);
494 F_SET(&sp
->opts
[offset
], OPT_ALLOCATED
);
496 change
: if (sp
->s_optchange
!= NULL
)
497 (void)sp
->s_optchange(sp
, offset
);
498 F_SET(&sp
->opts
[offset
], OPT_SET
);
511 * List the current values of selected options.
519 int base
, b_num
, chcnt
, cnt
, col
, colwidth
, curlen
, endcol
, s_num
;
520 int numcols
, numrows
, row
, tablen
, termwidth
;
521 int b_op
[O_OPTIONCOUNT
], s_op
[O_OPTIONCOUNT
];
525 * Options are output in two groups -- those that fit at least two to
526 * a line and those that don't. We do output on tab boundaries for no
527 * particular reason. First get the set of options to list, keeping
528 * track of the length of each. No error checking, because we know
529 * that O_TERM was set so at least one option has the OPT_SET bit on.
530 * Termwidth is the tab stop before half of the line in the first loop,
531 * and the full line length later on.
534 tablen
= O_VAL(sp
, O_TABSTOP
);
535 termwidth
= (sp
->cols
- 1) / 2 & ~(tablen
- 1);
536 for (b_num
= s_num
= 0, op
= optlist
; op
->name
; ++op
) {
539 /* If OPT_NEVER set, it's never displayed. */
540 if (F_ISSET(op
, OPT_NEVER
))
544 case ALL_DISPLAY
: /* Display all. */
546 case CHANGED_DISPLAY
: /* Display changed. */
547 if (!F_ISSET(&sp
->opts
[cnt
], OPT_SET
))
550 case SELECT_DISPLAY
: /* Display selected. */
551 if (!F_ISSET(&sp
->opts
[cnt
], OPT_SELECTED
))
559 F_CLR(&sp
->opts
[cnt
], OPT_SELECTED
);
561 curlen
= strlen(op
->name
);
565 if (!O_ISSET(sp
, cnt
))
570 sizeof(nbuf
), "%ld", O_VAL(sp
, cnt
));
571 curlen
+= strlen(nbuf
);
574 curlen
+= strlen(O_STR(sp
, cnt
)) + 3;
577 if (curlen
< termwidth
) {
578 if (colwidth
< curlen
)
585 colwidth
= (colwidth
+ tablen
) & ~(tablen
- 1);
586 termwidth
= sp
->cols
- 1;
587 numcols
= termwidth
/ colwidth
;
588 if (s_num
> numcols
) {
589 numrows
= s_num
/ numcols
;
595 for (row
= 0; row
< numrows
;) {
597 for (base
= row
, chcnt
= col
= 0; col
< numcols
; ++col
) {
598 chcnt
+= opts_print(sp
,
599 &optlist
[s_op
[base
]], &sp
->opts
[s_op
[base
]]);
600 if ((base
+= numrows
) >= s_num
)
603 (chcnt
+ tablen
& ~(tablen
- 1))) <= endcol
) {
604 (void)ex_printf(EXCOOKIE
, "\t");
609 if (++row
< numrows
|| b_num
)
610 (void)ex_printf(EXCOOKIE
, "\n");
613 for (row
= 0; row
< b_num
;) {
614 (void)opts_print(sp
, &optlist
[b_op
[row
]], &sp
->opts
[b_op
[row
]]);
616 (void)ex_printf(EXCOOKIE
, "\n");
618 (void)ex_printf(EXCOOKIE
, "\n");
623 * Print out an option.
626 opts_print(sp
, op
, spo
)
634 offset
= op
- optlist
;
638 curlen
+= ex_printf(EXCOOKIE
,
639 "%s%s", O_ISSET(sp
, offset
) ? "" : "no", op
->name
);
642 curlen
+= ex_printf(EXCOOKIE
,
643 "%s=%ld", op
->name
, O_VAL(sp
, offset
));
646 curlen
+= ex_printf(EXCOOKIE
,
647 "%s=\"%s\"", op
->name
, O_STR(sp
, offset
));
655 * Write the current configuration to a file.
667 for (spo
= sp
->opts
, op
= optlist
; op
->name
; ++op
) {
668 if (F_ISSET(op
, OPT_NOSAVE
))
674 if (O_ISSET(sp
, cnt
))
675 (void)fprintf(fp
, "set %s\n", op
->name
);
677 (void)fprintf(fp
, "set no%s\n", op
->name
);
681 "set %s=%-3d\n", op
->name
, O_VAL(sp
, cnt
));
684 (void)fprintf(fp
, "set ");
685 for (p
= op
->name
; (ch
= *p
) != '\0'; ++p
) {
687 (void)putc('\\', fp
);
691 for (p
= O_STR(sp
, cnt
); (ch
= *p
) != '\0'; ++p
) {
693 (void)putc('\\', fp
);
696 (void)putc('\n', fp
);
700 msgq(sp
, M_ERR
, "I/O error: %s", strerror(errno
));
709 * Check to see if the name is the prefix of one (and only one)
710 * option. If so, return the option.
712 static OPTLIST
const *
716 OPTLIST
const *op
, *save_op
;
721 for (op
= optlist
; op
->name
!= NULL
; ++op
) {
722 if (op
->name
[0] < name
[0])
724 if (op
->name
[0] > name
[0])
726 if (!memcmp(op
->name
, name
, len
)) {
739 return(strcmp(((OABBREV
*)a
)->name
, ((OABBREV
*)b
)->name
));
746 return(strcmp(((OPTLIST
*)a
)->name
, ((OPTLIST
*)b
)->name
));
751 * Free all option strings
760 for (cnt
= 0; cnt
< O_OPTIONCOUNT
; ++cnt
)
761 if (F_ISSET(&sp
->opts
[cnt
], OPT_ALLOCATED
)) {
763 FREE(p
, strlen(p
) + 1);
769 * Copy a screen's OPTION array.
778 /* Copy most everything without change. */
779 memmove(sp
->opts
, orig
->opts
, sizeof(orig
->opts
));
782 * Allocate copies of the strings -- keep trying to reallocate
783 * after ENOMEM failure, otherwise end up with more than one
784 * screen referencing the original memory.
786 for (op
= sp
->opts
, cnt
= 0; cnt
< O_OPTIONCOUNT
; ++cnt
, ++op
)
787 if (F_ISSET(&sp
->opts
[cnt
], OPT_ALLOCATED
) &&
788 (O_STR(sp
, cnt
) = strdup(O_STR(sp
, cnt
))) == NULL
) {
789 msgq(orig
, M_SYSERR
, NULL
);