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.30 1993/12/10 16:31:23 bostic Exp $ (Berkeley) $Date: 1993/12/10 16:31:23 $";
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
, OPT_NOSAVE
},
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 */
103 {"readonly", f_readonly
, OPT_0BOOL
, 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", NULL
, 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},
143 {"timeout", NULL
, OPT_0BOOL
, 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
)
251 (void)snprintf(b1
, sizeof(b1
), "directory=%s",
252 (s
= getenv("TMPDIR")) == NULL
? _PATH_PRESERVE
: s
);
253 SET_DEF(O_DIRECTORY
, b1
);
254 SET_DEF(O_KEYTIME
, "keytime=6");
255 SET_DEF(O_MATCHTIME
, "matchtime=7");
256 SET_DEF(O_REPORT
, "report=5");
257 SET_DEF(O_PARAGRAPHS
, "paragraphs=IPLPPPQPP LIpplpipbp");
258 (void)snprintf(b1
, sizeof(b1
), "scroll=%ld", O_VAL(sp
, O_LINES
) / 2);
259 SET_DEF(O_SCROLL
, b1
);
260 SET_DEF(O_SECTIONS
, "sections=NHSHH HUnhsh");
261 (void)snprintf(b1
, sizeof(b1
),
262 "shell=%s", (s
= getenv("SHELL")) == NULL
? _PATH_BSHELL
: s
);
263 SET_DEF(O_SHELL
, b1
);
264 SET_DEF(O_SHIFTWIDTH
, "shiftwidth=8");
265 SET_DEF(O_SIDESCROLL
, "sidescroll=16");
266 SET_DEF(O_TABSTOP
, "tabstop=8");
267 (void)snprintf(b1
, sizeof(b1
), "tags=%s", _PATH_TAGS
);
269 (void)snprintf(b1
, sizeof(b1
),
270 "term=%s", (s
= getenv("TERM")) == NULL
? "unknown" : s
);
274 * The default window option values are:
275 * 8 if baud rate <= 600
276 * 16 if baud rate <= 1200
277 * LINES - 1 if baud rate > 1200
279 v
= baud_from_bval(sp
);
285 v
= O_VAL(sp
, O_LINES
) - 1;
286 (void)snprintf(b1
, sizeof(b1
), "window=%lu", v
);
287 SET_DEF(O_WINDOW
, b1
);
289 SET_DEF(O_WRAPMARGIN
, "wrapmargin=0");
292 * By default, the historic vi always displayed information
293 * about two options, redraw and term. Term seems sufficient.
295 F_SET(&sp
->opts
[O_TERM
], OPT_SET
);
301 * Change the values of one or more options.
313 u_long value
, turnoff
;
314 int ch
, offset
, rval
;
315 char *endp
, *equals
, *name
, *p
;
318 for (rval
= 0; (*argv
)->len
!= 0; ++argv
) {
320 * The historic vi dumped the options for each occurrence of
321 * "all" in the set list. Puhleeze.
323 if (!strcmp(argv
[0]->bp
, "all")) {
328 /* Find equals sign or end of set, skipping backquoted chars. */
329 for (p
= name
= argv
[0]->bp
, equals
= NULL
; ch
= *p
; ++p
)
335 /* Historic vi just used the backslash. */
347 /* Check list of abbreviations. */
349 if ((ap
= bsearch(&atmp
, abbrev
,
350 sizeof(abbrev
) / sizeof(OABBREV
) - 1,
351 sizeof(OABBREV
), opts_abbcmp
)) != NULL
) {
352 op
= optlist
+ ap
->offset
;
356 /* Check list of options. */
358 if ((op
= bsearch(&otmp
, optlist
,
359 sizeof(optlist
) / sizeof(OPTLIST
) - 1,
360 sizeof(OPTLIST
), opts_cmp
)) != NULL
)
363 /* Try the name without any leading "no". */
364 if (name
[0] == 'n' && name
[1] == 'o') {
370 /* Check list of abbreviations. */
372 if ((ap
= bsearch(&atmp
, abbrev
,
373 sizeof(abbrev
) / sizeof(OABBREV
) - 1,
374 sizeof(OABBREV
), opts_abbcmp
)) != NULL
) {
375 op
= optlist
+ ap
->offset
;
379 /* Check list of options. */
381 if ((op
= bsearch(&otmp
, optlist
,
382 sizeof(optlist
) / sizeof(OPTLIST
) - 1,
383 sizeof(OPTLIST
), opts_cmp
)) != NULL
)
386 /* Check for prefix match. */
387 prefix
: op
= opts_prefix(name
);
389 found
: if (op
== NULL
) {
391 "no %s option: 'set all' gives all option values",
396 /* Find current option values. */
397 offset
= op
- optlist
;
398 spo
= sp
->opts
+ offset
;
400 /* Set name, value. */
406 "set: [no]%s option doesn't take a value",
410 if (op
->func
!= NULL
) {
411 if (op
->func(sp
, spo
, NULL
, turnoff
)) {
423 * Extension to historic vi. If the OPT_NOSTR flag is
424 * set, a numeric option may be turned off by using a
425 * "no" prefix, e.g. "nowrapmargin". (We assume that
426 * setting the value to 0 turns a numeric option off.)
429 if (F_ISSET(op
, OPT_NOSTR
)) {
434 "set: %s option isn't a boolean", name
);
439 disp
= SELECT_DISPLAY
;
440 F_SET(spo
, OPT_SELECTED
);
443 value
= strtol(equals
, &endp
, 10);
444 if (*endp
&& !isblank(*endp
)) {
446 "set %s: illegal number %s", name
, equals
);
449 nostr
: if (op
->func
!= NULL
) {
450 if (op
->func(sp
, spo
, equals
, value
)) {
455 O_VAL(sp
, offset
) = value
;
460 "set: %s option isn't a boolean", name
);
465 disp
= SELECT_DISPLAY
;
466 F_SET(spo
, OPT_SELECTED
);
469 if (op
->func
!= NULL
) {
470 if (op
->func(sp
, spo
, equals
, (u_long
)0)) {
475 if (F_ISSET(&sp
->opts
[offset
], OPT_ALLOCATED
))
476 free(O_STR(sp
, offset
));
477 if ((O_STR(sp
, offset
) =
478 strdup(equals
)) == NULL
) {
479 msgq(sp
, M_SYSERR
, NULL
);
483 F_SET(&sp
->opts
[offset
], OPT_ALLOCATED
);
485 change
: if (sp
->s_optchange
!= NULL
)
486 (void)sp
->s_optchange(sp
, offset
);
487 F_SET(&sp
->opts
[offset
], OPT_SET
);
500 * List the current values of selected options.
508 int base
, b_num
, chcnt
, cnt
, col
, colwidth
, curlen
, endcol
, s_num
;
509 int numcols
, numrows
, row
, tablen
, termwidth
;
510 int b_op
[O_OPTIONCOUNT
], s_op
[O_OPTIONCOUNT
];
514 * Options are output in two groups -- those that fit at least two to
515 * a line and those that don't. We do output on tab boundaries for no
516 * particular reason. First get the set of options to list, keeping
517 * track of the length of each. No error checking, because we know
518 * that O_TERM was set so at least one option has the OPT_SET bit on.
519 * Termwidth is the tab stop before half of the line in the first loop,
520 * and the full line length later on.
523 tablen
= O_VAL(sp
, O_TABSTOP
);
524 termwidth
= (sp
->cols
- 1) / 2 & ~(tablen
- 1);
525 for (b_num
= s_num
= 0, op
= optlist
; op
->name
; ++op
) {
528 /* If OPT_NEVER set, it's never displayed. */
529 if (F_ISSET(op
, OPT_NEVER
))
533 case ALL_DISPLAY
: /* Display all. */
535 case CHANGED_DISPLAY
: /* Display changed. */
536 if (!F_ISSET(&sp
->opts
[cnt
], OPT_SET
))
539 case SELECT_DISPLAY
: /* Display selected. */
540 if (!F_ISSET(&sp
->opts
[cnt
], OPT_SELECTED
))
548 F_CLR(&sp
->opts
[cnt
], OPT_SELECTED
);
550 curlen
= strlen(op
->name
);
554 if (!O_ISSET(sp
, cnt
))
559 sizeof(nbuf
), "%ld", O_VAL(sp
, cnt
));
560 curlen
+= strlen(nbuf
);
563 curlen
+= strlen(O_STR(sp
, cnt
)) + 3;
566 if (curlen
< termwidth
) {
567 if (colwidth
< curlen
)
574 colwidth
= (colwidth
+ tablen
) & ~(tablen
- 1);
575 termwidth
= sp
->cols
- 1;
576 numcols
= termwidth
/ colwidth
;
577 if (s_num
> numcols
) {
578 numrows
= s_num
/ numcols
;
584 for (row
= 0; row
< numrows
;) {
586 for (base
= row
, chcnt
= col
= 0; col
< numcols
; ++col
) {
587 chcnt
+= opts_print(sp
,
588 &optlist
[s_op
[base
]], &sp
->opts
[s_op
[base
]]);
589 if ((base
+= numrows
) >= s_num
)
592 (chcnt
+ tablen
& ~(tablen
- 1))) <= endcol
) {
593 (void)ex_printf(EXCOOKIE
, "\t");
598 if (++row
< numrows
|| b_num
)
599 (void)ex_printf(EXCOOKIE
, "\n");
602 for (row
= 0; row
< b_num
;) {
603 (void)opts_print(sp
, &optlist
[b_op
[row
]], &sp
->opts
[b_op
[row
]]);
605 (void)ex_printf(EXCOOKIE
, "\n");
607 (void)ex_printf(EXCOOKIE
, "\n");
612 * Print out an option.
615 opts_print(sp
, op
, spo
)
623 offset
= op
- optlist
;
627 curlen
+= ex_printf(EXCOOKIE
,
628 "%s%s", O_ISSET(sp
, offset
) ? "" : "no", op
->name
);
631 curlen
+= ex_printf(EXCOOKIE
,
632 "%s=%ld", op
->name
, O_VAL(sp
, offset
));
635 curlen
+= ex_printf(EXCOOKIE
,
636 "%s=\"%s\"", op
->name
, O_STR(sp
, offset
));
644 * Write the current configuration to a file.
656 for (spo
= sp
->opts
, op
= optlist
; op
->name
; ++op
) {
657 if (F_ISSET(op
, OPT_NOSAVE
))
663 if (O_ISSET(sp
, cnt
))
664 (void)fprintf(fp
, "set %s\n", op
->name
);
666 (void)fprintf(fp
, "set no%s\n", op
->name
);
670 "set %s=%-3d\n", op
->name
, O_VAL(sp
, cnt
));
673 (void)fprintf(fp
, "set ");
674 for (p
= op
->name
; (ch
= *p
) != '\0'; ++p
) {
676 (void)putc('\\', fp
);
680 for (p
= O_STR(sp
, cnt
); (ch
= *p
) != '\0'; ++p
) {
682 (void)putc('\\', fp
);
685 (void)putc('\n', fp
);
689 msgq(sp
, M_ERR
, "I/O error: %s", strerror(errno
));
698 * Check to see if the name is the prefix of one (and only one)
699 * option. If so, return the option.
701 static OPTLIST
const *
705 OPTLIST
const *op
, *save_op
;
710 for (op
= optlist
; op
->name
!= NULL
; ++op
) {
711 if (op
->name
[0] < name
[0])
713 if (op
->name
[0] > name
[0])
715 if (!memcmp(op
->name
, name
, len
)) {
728 return(strcmp(((OABBREV
*)a
)->name
, ((OABBREV
*)b
)->name
));
735 return(strcmp(((OPTLIST
*)a
)->name
, ((OPTLIST
*)b
)->name
));
740 * Free all option strings
749 for (cnt
= 0; cnt
< O_OPTIONCOUNT
; ++cnt
)
750 if (F_ISSET(&sp
->opts
[cnt
], OPT_ALLOCATED
)) {
752 FREE(p
, strlen(p
) + 1);
758 * Copy a screen's OPTION array.
767 /* Copy most everything without change. */
768 memmove(sp
->opts
, orig
->opts
, sizeof(orig
->opts
));
771 * Allocate copies of the strings -- keep trying to reallocate
772 * after ENOMEM failure, otherwise end up with more than one
773 * screen referencing the original memory.
775 for (op
= sp
->opts
, cnt
= 0; cnt
< O_OPTIONCOUNT
; ++cnt
, ++op
)
776 if (F_ISSET(&sp
->opts
[cnt
], OPT_ALLOCATED
) &&
777 (O_STR(sp
, cnt
) = strdup(O_STR(sp
, cnt
))) == NULL
) {
778 msgq(orig
, M_SYSERR
, NULL
);