update to 1.01
[nvi.git] / common / options.c
blob46e70236e1e2b136b2a1ac80cfe538cbdbf80e27
1 /*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
5 * %sccs.include.redist.c%
6 */
8 #ifndef lint
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 $";
10 #endif /* not lint */
12 #include <sys/types.h>
13 #include <sys/stat.h>
15 #include <ctype.h>
16 #include <curses.h>
17 #include <errno.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
22 #include "vi.h"
23 #include "excmd.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
34 * actually from.
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},
48 /* O_BEAUTIFY 4BSD */
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},
66 /* O_FLASH HPUX */
67 {"flash", NULL, OPT_1BOOL, 0},
68 /* O_HARDTABS 4BSD */
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},
76 /* O_LINES 4.4BSD */
77 {"lines", f_lines, OPT_NUM, OPT_NOSAVE},
78 /* O_LISP 4BSD */
79 {"lisp", f_lisp, OPT_0BOOL, 0},
80 /* O_LIST 4BSD */
81 {"list", f_list, OPT_0BOOL, 0},
82 /* O_MAGIC 4BSD */
83 {"magic", NULL, OPT_1BOOL, 0},
84 /* O_MATCHTIME 4.4BSD */
85 {"matchtime", f_matchtime, OPT_NUM, 0},
86 /* O_MESG 4BSD */
87 {"mesg", f_mesg, OPT_1BOOL, 0},
88 /* O_MODELINE 4BSD */
89 {"modeline", f_modeline, OPT_0BOOL, 0},
90 /* O_NUMBER 4BSD */
91 {"number", f_number, OPT_0BOOL, 0},
92 /* O_OPEN 4BSD */
93 {"open", NULL, OPT_1BOOL, 0},
94 /* O_OPTIMIZE 4BSD */
95 {"optimize", f_optimize, OPT_1BOOL, 0},
96 /* O_PARAGRAPHS 4BSD */
97 {"paragraphs", f_paragraph, OPT_STR, 0},
98 /* O_PROMPT 4BSD */
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},
104 /* O_REDRAW 4BSD */
105 {"redraw", NULL, OPT_0BOOL, 0},
106 /* O_REMAP 4BSD */
107 {"remap", NULL, OPT_1BOOL, 0},
108 /* O_REPORT 4BSD */
109 {"report", NULL, OPT_NUM, OPT_NOSTR},
110 /* O_RULER 4.4BSD */
111 {"ruler", f_ruler, OPT_0BOOL, 0},
112 /* O_SCROLL 4BSD */
113 {"scroll", NULL, OPT_NUM, 0},
114 /* O_SECTIONS 4BSD */
115 {"sections", f_section, OPT_STR, 0},
116 /* O_SHELL 4BSD */
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},
132 /* O_TABSTOP 4BSD */
133 {"tabstop", f_tabstop, OPT_NUM, 0},
134 /* O_TAGLENGTH 4BSD */
135 {"taglength", NULL, OPT_NUM, OPT_NOSTR},
136 /* O_TAGS 4BSD */
137 {"tags", f_tags, OPT_STR, 0},
138 /* O_TERM 4BSD */
139 {"term", f_term, OPT_STR, OPT_NOSAVE},
140 /* O_TERSE 4BSD */
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},
148 /* O_W1200 4BSD */
149 {"w1200", f_w1200, OPT_NUM, OPT_NEVER},
150 /* O_W300 4BSD */
151 {"w300", f_w300, OPT_NUM, OPT_NEVER},
152 /* O_W9600 4BSD */
153 {"w9600", f_w9600, OPT_NUM, OPT_NEVER},
154 /* O_WARN 4BSD */
155 {"warn", NULL, OPT_1BOOL, 0},
156 /* O_WINDOW 4BSD */
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},
164 {NULL},
167 typedef struct abbrev {
168 char *name;
169 int offset;
170 } OABBREV;
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 */
208 {NULL},
212 * opts_init --
213 * Initialize some of the options. Since the user isn't really
214 * "setting" these variables, don't set their OPT_SET bits.
217 opts_init(sp)
218 SCR *sp;
220 ARGS *argv[2], a, b;
221 OPTLIST const *op;
222 u_long v;
223 int cnt;
224 char *s, b1[1024];
226 a.bp = b1;
227 a.len = 0;
228 b.bp = NULL;
229 b.len = 0;
230 argv[0] = &a;
231 argv[1] = &b;
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)) { \
238 msgq(sp, M_ERR, \
239 "Unable to set default %s option", optlist[opt]); \
240 return (1); \
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)
247 O_CLR(sp, cnt);
248 else if (op->type == OPT_1BOOL)
249 O_SET(sp, cnt);
252 * !!!
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);
277 SET_DEF(O_TAGS, b1);
278 (void)snprintf(b1, sizeof(b1),
279 "term=%s", (s = getenv("TERM")) == NULL ? "unknown" : s);
280 SET_DEF(O_TERM, b1);
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);
289 if (v <= 600)
290 v = 8;
291 else if (v <= 1200)
292 v = 16;
293 else
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);
305 return (0);
309 * opts_set --
310 * Change the values of one or more options.
313 opts_set(sp, argv)
314 SCR *sp;
315 ARGS *argv[];
317 enum optdisp disp;
318 OABBREV atmp, *ap;
319 OPTLIST const *op;
320 OPTLIST otmp;
321 OPTION *spo;
322 u_long value, turnoff;
323 int ch, offset, rval;
324 char *endp, *equals, *name, *p;
326 disp = NO_DISPLAY;
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")) {
333 disp = ALL_DISPLAY;
334 continue;
337 /* Find equals sign or end of set, skipping backquoted chars. */
338 for (p = name = argv[0]->bp, equals = NULL; ch = *p; ++p)
339 switch(ch) {
340 case '=':
341 equals = p;
342 break;
343 case '\\':
344 /* Historic vi just used the backslash. */
345 if (p[1] == '\0')
346 break;
347 ++p;
348 break;
351 turnoff = 0;
352 op = NULL;
353 if (equals)
354 *equals++ = '\0';
356 /* Check list of abbreviations. */
357 atmp.name = name;
358 if ((ap = bsearch(&atmp, abbrev,
359 sizeof(abbrev) / sizeof(OABBREV) - 1,
360 sizeof(OABBREV), opts_abbcmp)) != NULL) {
361 op = optlist + ap->offset;
362 goto found;
365 /* Check list of options. */
366 otmp.name = name;
367 if ((op = bsearch(&otmp, optlist,
368 sizeof(optlist) / sizeof(OPTLIST) - 1,
369 sizeof(OPTLIST), opts_cmp)) != NULL)
370 goto found;
372 /* Try the name without any leading "no". */
373 if (name[0] == 'n' && name[1] == 'o') {
374 turnoff = 1;
375 name += 2;
376 } else
377 goto prefix;
379 /* Check list of abbreviations. */
380 atmp.name = name;
381 if ((ap = bsearch(&atmp, abbrev,
382 sizeof(abbrev) / sizeof(OABBREV) - 1,
383 sizeof(OABBREV), opts_abbcmp)) != NULL) {
384 op = optlist + ap->offset;
385 goto found;
388 /* Check list of options. */
389 otmp.name = name;
390 if ((op = bsearch(&otmp, optlist,
391 sizeof(optlist) / sizeof(OPTLIST) - 1,
392 sizeof(OPTLIST), opts_cmp)) != NULL)
393 goto found;
395 /* Check for prefix match. */
396 prefix: op = opts_prefix(name);
398 found: if (op == NULL) {
399 msgq(sp, M_ERR,
400 "no %s option: 'set all' gives all option values",
401 name);
402 continue;
405 /* Find current option values. */
406 offset = op - optlist;
407 spo = sp->opts + offset;
409 /* Set name, value. */
410 switch (op->type) {
411 case OPT_0BOOL:
412 case OPT_1BOOL:
413 if (equals) {
414 msgq(sp, M_ERR,
415 "set: [no]%s option doesn't take a value",
416 name);
417 break;
419 if (op->func != NULL) {
420 if (op->func(sp, spo, NULL, turnoff)) {
421 rval = 1;
422 break;
424 } else if (turnoff)
425 O_CLR(sp, offset);
426 else
427 O_SET(sp, offset);
428 goto change;
429 case OPT_NUM:
431 * !!!
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.)
437 if (turnoff) {
438 if (F_ISSET(op, OPT_NOSTR)) {
439 value = 0;
440 goto nostr;
442 msgq(sp, M_ERR,
443 "set: %s option isn't a boolean", name);
444 break;
446 if (!equals) {
447 if (!disp)
448 disp = SELECT_DISPLAY;
449 F_SET(spo, OPT_SELECTED);
450 break;
452 value = strtol(equals, &endp, 10);
453 if (*endp && !isblank(*endp)) {
454 msgq(sp, M_ERR,
455 "set %s: illegal number %s", name, equals);
456 break;
458 nostr: if (op->func != NULL) {
459 if (op->func(sp, spo, equals, value)) {
460 rval = 1;
461 break;
463 } else
464 O_VAL(sp, offset) = value;
465 goto change;
466 case OPT_STR:
467 if (turnoff) {
468 msgq(sp, M_ERR,
469 "set: %s option isn't a boolean", name);
470 break;
472 if (!equals) {
473 if (!disp)
474 disp = SELECT_DISPLAY;
475 F_SET(spo, OPT_SELECTED);
476 break;
478 if (op->func != NULL) {
479 if (op->func(sp, spo, equals, (u_long)0)) {
480 rval = 1;
481 break;
483 } else {
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);
489 rval = 1;
490 break;
491 } else
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);
497 break;
498 default:
499 abort();
502 if (disp)
503 opts_dump(sp, disp);
504 return (rval);
508 * opts_dump --
509 * List the current values of selected options.
511 void
512 opts_dump(sp, type)
513 SCR *sp;
514 enum optdisp type;
516 OPTLIST const *op;
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];
520 char nbuf[20];
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.
529 #define BOUND 6
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);
536 break;
538 colwidth = 0;
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
545 * set.
547 for (b_num = s_num = 0, op = optlist; op->name; ++op) {
548 cnt = op - optlist;
550 /* If OPT_NEVER set, it's never displayed. */
551 if (F_ISSET(op, OPT_NEVER))
552 continue;
554 switch (type) {
555 case ALL_DISPLAY: /* Display all. */
556 break;
557 case CHANGED_DISPLAY: /* Display changed. */
558 if (!F_ISSET(&sp->opts[cnt], OPT_SET))
559 continue;
560 break;
561 case SELECT_DISPLAY: /* Display selected. */
562 if (!F_ISSET(&sp->opts[cnt], OPT_SELECTED))
563 continue;
564 break;
565 default:
566 case NO_DISPLAY:
567 abort();
568 /* NOTREACHED */
570 F_CLR(&sp->opts[cnt], OPT_SELECTED);
572 curlen = strlen(op->name);
573 switch (op->type) {
574 case OPT_0BOOL:
575 case OPT_1BOOL:
576 if (!O_ISSET(sp, cnt))
577 curlen += 2;
578 break;
579 case OPT_NUM:
580 (void)snprintf(nbuf,
581 sizeof(nbuf), "%ld", O_VAL(sp, cnt));
582 curlen += strlen(nbuf);
583 break;
584 case OPT_STR:
585 curlen += strlen(O_STR(sp, cnt)) + 3;
586 break;
588 /* Offset by two so there's a gap. */
589 if (curlen < colwidth - 2)
590 s_op[s_num++] = cnt;
591 else
592 b_op[b_num++] = cnt;
595 numcols = (sp->cols - 1) / colwidth;
596 if (s_num > numcols) {
597 numrows = s_num / numcols;
598 if (s_num % numcols)
599 ++numrows;
600 } else
601 numrows = 1;
603 for (row = 0; row < numrows;) {
604 for (base = row, col = 0; col < numcols; ++col) {
605 cnt = opts_print(sp,
606 &optlist[s_op[base]], &sp->opts[s_op[base]]);
607 if ((base += numrows) >= s_num)
608 break;
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]]);
618 if (++row < b_num)
619 (void)ex_printf(EXCOOKIE, "\n");
621 (void)ex_printf(EXCOOKIE, "\n");
625 * opts_print --
626 * Print out an option.
628 static int
629 opts_print(sp, op, spo)
630 SCR *sp;
631 OPTLIST const *op;
632 OPTION *spo;
634 int curlen, offset;
636 curlen = 0;
637 offset = op - optlist;
638 switch (op->type) {
639 case OPT_0BOOL:
640 case OPT_1BOOL:
641 curlen += ex_printf(EXCOOKIE,
642 "%s%s", O_ISSET(sp, offset) ? "" : "no", op->name);
643 break;
644 case OPT_NUM:
645 curlen += ex_printf(EXCOOKIE,
646 "%s=%ld", op->name, O_VAL(sp, offset));
647 break;
648 case OPT_STR:
649 curlen += ex_printf(EXCOOKIE,
650 "%s=\"%s\"", op->name, O_STR(sp, offset));
651 break;
653 return (curlen);
657 * opts_save --
658 * Write the current configuration to a file.
661 opts_save(sp, fp)
662 SCR *sp;
663 FILE *fp;
665 OPTION *spo;
666 OPTLIST const *op;
667 int ch, cnt;
668 char *p;
670 for (spo = sp->opts, op = optlist; op->name; ++op) {
671 if (F_ISSET(op, OPT_NOSAVE))
672 continue;
673 cnt = op - optlist;
674 switch (op->type) {
675 case OPT_0BOOL:
676 case OPT_1BOOL:
677 if (O_ISSET(sp, cnt))
678 (void)fprintf(fp, "set %s\n", op->name);
679 else
680 (void)fprintf(fp, "set no%s\n", op->name);
681 break;
682 case OPT_NUM:
683 (void)fprintf(fp,
684 "set %s=%-3d\n", op->name, O_VAL(sp, cnt));
685 break;
686 case OPT_STR:
687 (void)fprintf(fp, "set ");
688 for (p = op->name; (ch = *p) != '\0'; ++p) {
689 if (isblank(ch))
690 (void)putc('\\', fp);
691 (void)putc(ch, fp);
693 (void)putc('=', fp);
694 for (p = O_STR(sp, cnt); (ch = *p) != '\0'; ++p) {
695 if (isblank(ch))
696 (void)putc('\\', fp);
697 (void)putc(ch, fp);
699 (void)putc('\n', fp);
700 break;
702 if (ferror(fp)) {
703 msgq(sp, M_ERR, "I/O error: %s", strerror(errno));
704 return (1);
707 return (0);
711 * opts_prefix --
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 *
716 opts_prefix(name)
717 char *name;
719 OPTLIST const *op, *save_op;
720 size_t len;
722 save_op = NULL;
723 len = strlen(name);
724 for (op = optlist; op->name != NULL; ++op) {
725 if (op->name[0] < name[0])
726 continue;
727 if (op->name[0] > name[0])
728 break;
729 if (!memcmp(op->name, name, len)) {
730 if (save_op != NULL)
731 return (NULL);
732 save_op = op;
735 return (save_op);
738 static int
739 opts_abbcmp(a, b)
740 const void *a, *b;
742 return(strcmp(((OABBREV *)a)->name, ((OABBREV *)b)->name));
745 static int
746 opts_cmp(a, b)
747 const void *a, *b;
749 return(strcmp(((OPTLIST *)a)->name, ((OPTLIST *)b)->name));
753 * opts_free --
754 * Free all option strings
756 void
757 opts_free(sp)
758 SCR *sp;
760 int cnt;
761 char *p;
763 for (cnt = 0; cnt < O_OPTIONCOUNT; ++cnt)
764 if (F_ISSET(&sp->opts[cnt], OPT_ALLOCATED)) {
765 p = O_STR(sp, cnt);
766 FREE(p, strlen(p) + 1);
771 * opts_copy --
772 * Copy a screen's OPTION array.
775 opts_copy(orig, sp)
776 SCR *orig, *sp;
778 OPTION *op;
779 int cnt;
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);
793 return (1);
795 return (0);