make abbreviations work on the command line
[nvi.git] / common / options.c
blob2806974f098a85f035642390c9219854f3994ea2
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.33 1993/12/21 11:58:41 bostic Exp $ (Berkeley) $Date: 1993/12/21 11:58:41 $";
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_NUNDO 4.4BSD */
93 {"nundo", NULL, OPT_0BOOL, 0},
94 /* O_OPEN 4BSD */
95 {"open", NULL, OPT_1BOOL, 0},
96 /* O_OPTIMIZE 4BSD */
97 {"optimize", f_optimize, OPT_1BOOL, 0},
98 /* O_PARAGRAPHS 4BSD */
99 {"paragraphs", f_paragraph, OPT_STR, 0},
100 /* O_PROMPT 4BSD */
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},
106 /* O_REDRAW 4BSD */
107 {"redraw", NULL, OPT_0BOOL, 0},
108 /* O_REMAP 4BSD */
109 {"remap", NULL, OPT_1BOOL, 0},
110 /* O_REPORT 4BSD */
111 {"report", NULL, OPT_NUM, OPT_NOSTR},
112 /* O_RULER 4.4BSD */
113 {"ruler", f_ruler, OPT_0BOOL, 0},
114 /* O_SCROLL 4BSD */
115 {"scroll", NULL, OPT_NUM, 0},
116 /* O_SECTIONS 4BSD */
117 {"sections", f_section, OPT_STR, 0},
118 /* O_SHELL 4BSD */
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},
134 /* O_TABSTOP 4BSD */
135 {"tabstop", f_tabstop, OPT_NUM, 0},
136 /* O_TAGLENGTH 4BSD */
137 {"taglength", NULL, OPT_NUM, OPT_NOSTR},
138 /* O_TAGS 4BSD */
139 {"tags", f_tags, OPT_STR, 0},
140 /* O_TERM 4BSD */
141 {"term", f_term, OPT_STR, OPT_NOSAVE},
142 /* O_TERSE 4BSD */
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},
150 /* O_W1200 4BSD */
151 {"w1200", f_w1200, OPT_NUM, OPT_NEVER},
152 /* O_W300 4BSD */
153 {"w300", f_w300, OPT_NUM, OPT_NEVER},
154 /* O_W9600 4BSD */
155 {"w9600", f_w9600, OPT_NUM, OPT_NEVER},
156 /* O_WARN 4BSD */
157 {"warn", NULL, OPT_1BOOL, 0},
158 /* O_WINDOW 4BSD */
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},
166 {NULL},
169 typedef struct abbrev {
170 char *name;
171 int offset;
172 } OABBREV;
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 */
210 {NULL},
214 * opts_init --
215 * Initialize some of the options. Since the user isn't really
216 * "setting" these variables, don't set their OPT_SET bits.
219 opts_init(sp)
220 SCR *sp;
222 ARGS *argv[2], a, b;
223 OPTLIST const *op;
224 u_long v;
225 int cnt;
226 char *s, b1[1024];
228 a.bp = b1;
229 a.len = 0;
230 b.bp = NULL;
231 b.len = 0;
232 argv[0] = &a;
233 argv[1] = &b;
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)) { \
240 msgq(sp, M_ERR, \
241 "Unable to set default %s option", optlist[opt]); \
242 return (1); \
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)
249 O_CLR(sp, cnt);
250 else if (op->type == OPT_1BOOL)
251 O_SET(sp, cnt);
254 * !!!
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);
279 SET_DEF(O_TAGS, b1);
280 (void)snprintf(b1, sizeof(b1),
281 "term=%s", (s = getenv("TERM")) == NULL ? "unknown" : s);
282 SET_DEF(O_TERM, b1);
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);
291 if (v <= 600)
292 v = 8;
293 else if (v <= 1200)
294 v = 16;
295 else
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);
307 return (0);
311 * opts_set --
312 * Change the values of one or more options.
315 opts_set(sp, argv)
316 SCR *sp;
317 ARGS *argv[];
319 enum optdisp disp;
320 OABBREV atmp, *ap;
321 OPTLIST const *op;
322 OPTLIST otmp;
323 OPTION *spo;
324 u_long value, turnoff;
325 int ch, offset, rval;
326 char *endp, *equals, *name, *p;
328 disp = NO_DISPLAY;
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")) {
335 disp = ALL_DISPLAY;
336 continue;
339 /* Find equals sign or end of set, skipping backquoted chars. */
340 for (p = name = argv[0]->bp, equals = NULL; ch = *p; ++p)
341 switch(ch) {
342 case '=':
343 equals = p;
344 break;
345 case '\\':
346 /* Historic vi just used the backslash. */
347 if (p[1] == '\0')
348 break;
349 ++p;
350 break;
353 turnoff = 0;
354 op = NULL;
355 if (equals)
356 *equals++ = '\0';
358 /* Check list of abbreviations. */
359 atmp.name = name;
360 if ((ap = bsearch(&atmp, abbrev,
361 sizeof(abbrev) / sizeof(OABBREV) - 1,
362 sizeof(OABBREV), opts_abbcmp)) != NULL) {
363 op = optlist + ap->offset;
364 goto found;
367 /* Check list of options. */
368 otmp.name = name;
369 if ((op = bsearch(&otmp, optlist,
370 sizeof(optlist) / sizeof(OPTLIST) - 1,
371 sizeof(OPTLIST), opts_cmp)) != NULL)
372 goto found;
374 /* Try the name without any leading "no". */
375 if (name[0] == 'n' && name[1] == 'o') {
376 turnoff = 1;
377 name += 2;
378 } else
379 goto prefix;
381 /* Check list of abbreviations. */
382 atmp.name = name;
383 if ((ap = bsearch(&atmp, abbrev,
384 sizeof(abbrev) / sizeof(OABBREV) - 1,
385 sizeof(OABBREV), opts_abbcmp)) != NULL) {
386 op = optlist + ap->offset;
387 goto found;
390 /* Check list of options. */
391 otmp.name = name;
392 if ((op = bsearch(&otmp, optlist,
393 sizeof(optlist) / sizeof(OPTLIST) - 1,
394 sizeof(OPTLIST), opts_cmp)) != NULL)
395 goto found;
397 /* Check for prefix match. */
398 prefix: op = opts_prefix(name);
400 found: if (op == NULL) {
401 msgq(sp, M_ERR,
402 "no %s option: 'set all' gives all option values",
403 name);
404 continue;
407 /* Find current option values. */
408 offset = op - optlist;
409 spo = sp->opts + offset;
411 /* Set name, value. */
412 switch (op->type) {
413 case OPT_0BOOL:
414 case OPT_1BOOL:
415 if (equals) {
416 msgq(sp, M_ERR,
417 "set: [no]%s option doesn't take a value",
418 name);
419 break;
421 if (op->func != NULL) {
422 if (op->func(sp, spo, NULL, turnoff)) {
423 rval = 1;
424 break;
426 } else if (turnoff)
427 O_CLR(sp, offset);
428 else
429 O_SET(sp, offset);
430 goto change;
431 case OPT_NUM:
433 * !!!
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.)
439 if (turnoff) {
440 if (F_ISSET(op, OPT_NOSTR)) {
441 value = 0;
442 goto nostr;
444 msgq(sp, M_ERR,
445 "set: %s option isn't a boolean", name);
446 break;
448 if (!equals) {
449 if (!disp)
450 disp = SELECT_DISPLAY;
451 F_SET(spo, OPT_SELECTED);
452 break;
454 value = strtol(equals, &endp, 10);
455 if (*endp && !isblank(*endp)) {
456 msgq(sp, M_ERR,
457 "set %s: illegal number %s", name, equals);
458 break;
460 nostr: if (op->func != NULL) {
461 if (op->func(sp, spo, equals, value)) {
462 rval = 1;
463 break;
465 } else
466 O_VAL(sp, offset) = value;
467 goto change;
468 case OPT_STR:
469 if (turnoff) {
470 msgq(sp, M_ERR,
471 "set: %s option isn't a boolean", name);
472 break;
474 if (!equals) {
475 if (!disp)
476 disp = SELECT_DISPLAY;
477 F_SET(spo, OPT_SELECTED);
478 break;
480 if (op->func != NULL) {
481 if (op->func(sp, spo, equals, (u_long)0)) {
482 rval = 1;
483 break;
485 } else {
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);
491 rval = 1;
492 break;
493 } else
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);
499 break;
500 default:
501 abort();
504 if (disp)
505 opts_dump(sp, disp);
506 return (rval);
510 * opts_dump --
511 * List the current values of selected options.
513 void
514 opts_dump(sp, type)
515 SCR *sp;
516 enum optdisp type;
518 OPTLIST const *op;
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];
522 char nbuf[20];
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.
533 colwidth = -1;
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) {
537 cnt = op - optlist;
539 /* If OPT_NEVER set, it's never displayed. */
540 if (F_ISSET(op, OPT_NEVER))
541 continue;
543 switch (type) {
544 case ALL_DISPLAY: /* Display all. */
545 break;
546 case CHANGED_DISPLAY: /* Display changed. */
547 if (!F_ISSET(&sp->opts[cnt], OPT_SET))
548 continue;
549 break;
550 case SELECT_DISPLAY: /* Display selected. */
551 if (!F_ISSET(&sp->opts[cnt], OPT_SELECTED))
552 continue;
553 break;
554 default:
555 case NO_DISPLAY:
556 abort();
557 /* NOTREACHED */
559 F_CLR(&sp->opts[cnt], OPT_SELECTED);
561 curlen = strlen(op->name);
562 switch (op->type) {
563 case OPT_0BOOL:
564 case OPT_1BOOL:
565 if (!O_ISSET(sp, cnt))
566 curlen += 2;
567 break;
568 case OPT_NUM:
569 (void)snprintf(nbuf,
570 sizeof(nbuf), "%ld", O_VAL(sp, cnt));
571 curlen += strlen(nbuf);
572 break;
573 case OPT_STR:
574 curlen += strlen(O_STR(sp, cnt)) + 3;
575 break;
577 if (curlen < termwidth) {
578 if (colwidth < curlen)
579 colwidth = curlen;
580 s_op[s_num++] = cnt;
581 } else
582 b_op[b_num++] = cnt;
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;
590 if (s_num % numcols)
591 ++numrows;
592 } else
593 numrows = 1;
595 for (row = 0; row < numrows;) {
596 endcol = colwidth;
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)
601 break;
602 while ((cnt =
603 (chcnt + tablen & ~(tablen - 1))) <= endcol) {
604 (void)ex_printf(EXCOOKIE, "\t");
605 chcnt = cnt;
607 endcol += colwidth;
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]]);
615 if (++row < b_num)
616 (void)ex_printf(EXCOOKIE, "\n");
618 (void)ex_printf(EXCOOKIE, "\n");
622 * opts_print --
623 * Print out an option.
625 static int
626 opts_print(sp, op, spo)
627 SCR *sp;
628 OPTLIST const *op;
629 OPTION *spo;
631 int curlen, offset;
633 curlen = 0;
634 offset = op - optlist;
635 switch (op->type) {
636 case OPT_0BOOL:
637 case OPT_1BOOL:
638 curlen += ex_printf(EXCOOKIE,
639 "%s%s", O_ISSET(sp, offset) ? "" : "no", op->name);
640 break;
641 case OPT_NUM:
642 curlen += ex_printf(EXCOOKIE,
643 "%s=%ld", op->name, O_VAL(sp, offset));
644 break;
645 case OPT_STR:
646 curlen += ex_printf(EXCOOKIE,
647 "%s=\"%s\"", op->name, O_STR(sp, offset));
648 break;
650 return (curlen);
654 * opts_save --
655 * Write the current configuration to a file.
658 opts_save(sp, fp)
659 SCR *sp;
660 FILE *fp;
662 OPTION *spo;
663 OPTLIST const *op;
664 int ch, cnt;
665 char *p;
667 for (spo = sp->opts, op = optlist; op->name; ++op) {
668 if (F_ISSET(op, OPT_NOSAVE))
669 continue;
670 cnt = op - optlist;
671 switch (op->type) {
672 case OPT_0BOOL:
673 case OPT_1BOOL:
674 if (O_ISSET(sp, cnt))
675 (void)fprintf(fp, "set %s\n", op->name);
676 else
677 (void)fprintf(fp, "set no%s\n", op->name);
678 break;
679 case OPT_NUM:
680 (void)fprintf(fp,
681 "set %s=%-3d\n", op->name, O_VAL(sp, cnt));
682 break;
683 case OPT_STR:
684 (void)fprintf(fp, "set ");
685 for (p = op->name; (ch = *p) != '\0'; ++p) {
686 if (isblank(ch))
687 (void)putc('\\', fp);
688 (void)putc(ch, fp);
690 (void)putc('=', fp);
691 for (p = O_STR(sp, cnt); (ch = *p) != '\0'; ++p) {
692 if (isblank(ch))
693 (void)putc('\\', fp);
694 (void)putc(ch, fp);
696 (void)putc('\n', fp);
697 break;
699 if (ferror(fp)) {
700 msgq(sp, M_ERR, "I/O error: %s", strerror(errno));
701 return (1);
704 return (0);
708 * opts_prefix --
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 *
713 opts_prefix(name)
714 char *name;
716 OPTLIST const *op, *save_op;
717 size_t len;
719 save_op = NULL;
720 len = strlen(name);
721 for (op = optlist; op->name != NULL; ++op) {
722 if (op->name[0] < name[0])
723 continue;
724 if (op->name[0] > name[0])
725 break;
726 if (!memcmp(op->name, name, len)) {
727 if (save_op != NULL)
728 return (NULL);
729 save_op = op;
732 return (save_op);
735 static int
736 opts_abbcmp(a, b)
737 const void *a, *b;
739 return(strcmp(((OABBREV *)a)->name, ((OABBREV *)b)->name));
742 static int
743 opts_cmp(a, b)
744 const void *a, *b;
746 return(strcmp(((OPTLIST *)a)->name, ((OPTLIST *)b)->name));
750 * opts_free --
751 * Free all option strings
753 void
754 opts_free(sp)
755 SCR *sp;
757 int cnt;
758 char *p;
760 for (cnt = 0; cnt < O_OPTIONCOUNT; ++cnt)
761 if (F_ISSET(&sp->opts[cnt], OPT_ALLOCATED)) {
762 p = O_STR(sp, cnt);
763 FREE(p, strlen(p) + 1);
768 * opts_copy --
769 * Copy a screen's OPTION array.
772 opts_copy(orig, sp)
773 SCR *orig, *sp;
775 OPTION *op;
776 int cnt;
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);
790 return (1);
792 return (0);