source: trunk/third/nvi/common/options.c @ 14302

Revision 14302, 27.8 KB checked in by ghudson, 25 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r14301, which included commits to RCS files with non-trunk default branches.
Line 
1/*-
2 * Copyright (c) 1991, 1993, 1994
3 *      The Regents of the University of California.  All rights reserved.
4 * Copyright (c) 1991, 1993, 1994, 1995, 1996
5 *      Keith Bostic.  All rights reserved.
6 *
7 * See the LICENSE file for redistribution information.
8 */
9
10#include "config.h"
11
12#ifndef lint
13static const char sccsid[] = "@(#)options.c     10.51 (Berkeley) 10/14/96";
14#endif /* not lint */
15
16#include <sys/types.h>
17#include <sys/queue.h>
18#include <sys/stat.h>
19#include <sys/time.h>
20
21#include <bitstring.h>
22#include <ctype.h>
23#include <errno.h>
24#include <limits.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29
30#include "common.h"
31#include "../vi/vi.h"
32#include "pathnames.h"
33
34static int               opts_abbcmp __P((const void *, const void *));
35static int               opts_cmp __P((const void *, const void *));
36static int               opts_print __P((SCR *, OPTLIST const *));
37
38/*
39 * O'Reilly noted options and abbreviations are from "Learning the VI Editor",
40 * Fifth Edition, May 1992.  There's no way of knowing what systems they are
41 * actually from.
42 *
43 * HPUX noted options and abbreviations are from "The Ultimate Guide to the
44 * VI and EX Text Editors", 1990.
45 */
46OPTLIST const optlist[] = {
47/* O_ALTWERASE    4.4BSD */
48        {"altwerase",   f_altwerase,    OPT_0BOOL,      0},
49/* O_AUTOINDENT     4BSD */
50        {"autoindent",  NULL,           OPT_0BOOL,      0},
51/* O_AUTOPRINT      4BSD */
52        {"autoprint",   NULL,           OPT_1BOOL,      0},
53/* O_AUTOWRITE      4BSD */
54        {"autowrite",   NULL,           OPT_0BOOL,      0},
55/* O_BACKUP       4.4BSD */
56        {"backup",      NULL,           OPT_STR,        0},
57/* O_BEAUTIFY       4BSD */
58        {"beautify",    NULL,           OPT_0BOOL,      0},
59/* O_CDPATH       4.4BSD */
60        {"cdpath",      NULL,           OPT_STR,        0},
61/* O_CEDIT        4.4BSD */
62        {"cedit",       NULL,           OPT_STR,        0},
63/* O_COLUMNS      4.4BSD */
64        {"columns",     f_columns,      OPT_NUM,        OPT_NOSAVE},
65/* O_COMMENT      4.4BSD */
66        {"comment",     NULL,           OPT_0BOOL,      0},
67/* O_DIRECTORY      4BSD */
68        {"directory",   NULL,           OPT_STR,        0},
69/* O_EDCOMPATIBLE   4BSD */
70        {"edcompatible",NULL,           OPT_0BOOL,      0},
71/* O_ESCAPETIME   4.4BSD */
72        {"escapetime",  NULL,           OPT_NUM,        0},
73/* O_ERRORBELLS     4BSD */
74        {"errorbells",  NULL,           OPT_0BOOL,      0},
75/* O_EXRC       System V (undocumented) */
76        {"exrc",        NULL,           OPT_0BOOL,      0},
77/* O_EXTENDED     4.4BSD */
78        {"extended",    f_recompile,    OPT_0BOOL,      0},
79/* O_FILEC        4.4BSD */
80        {"filec",       NULL,           OPT_STR,        0},
81/* O_FLASH          HPUX */
82        {"flash",       NULL,           OPT_1BOOL,      0},
83/* O_HARDTABS       4BSD */
84        {"hardtabs",    NULL,           OPT_NUM,        0},
85/* O_ICLOWER      4.4BSD */
86        {"iclower",     f_recompile,    OPT_0BOOL,      0},
87/* O_IGNORECASE     4BSD */
88        {"ignorecase",  f_recompile,    OPT_0BOOL,      0},
89/* O_KEYTIME      4.4BSD */
90        {"keytime",     NULL,           OPT_NUM,        0},
91/* O_LEFTRIGHT    4.4BSD */
92        {"leftright",   f_reformat,     OPT_0BOOL,      0},
93/* O_LINES        4.4BSD */
94        {"lines",       f_lines,        OPT_NUM,        OPT_NOSAVE},
95/* O_LISP           4BSD
96 *      XXX
97 *      When the lisp option is implemented, delete the OPT_NOSAVE flag,
98 *      so that :mkexrc dumps it.
99 */
100        {"lisp",        f_lisp,         OPT_0BOOL,      OPT_NOSAVE},
101/* O_LIST           4BSD */
102        {"list",        f_reformat,     OPT_0BOOL,      0},
103/* O_LOCKFILES    4.4BSD
104 *      XXX
105 *      Locking isn't reliable enough over NFS to require it, in addition,
106 *      it's a serious startup performance problem over some remote links.
107 */
108        {"lock",        NULL,           OPT_1BOOL,      0},
109/* O_MAGIC          4BSD */
110        {"magic",       NULL,           OPT_1BOOL,      0},
111/* O_MATCHTIME    4.4BSD */
112        {"matchtime",   NULL,           OPT_NUM,        0},
113/* O_MESG           4BSD */
114        {"mesg",        NULL,           OPT_1BOOL,      0},
115/* O_MODELINE       4BSD
116 *      !!!
117 *      This has been documented in historical systems as both "modeline"
118 *      and as "modelines".  Regardless of the name, this option represents
119 *      a security problem of mammoth proportions, not to mention a stunning
120 *      example of what your intro CS professor referred to as the perils of
121 *      mixing code and data.  Don't add it, or I will kill you.
122 */
123        {"modeline",    NULL,           OPT_0BOOL,      OPT_NOSET},
124/* O_MSGCAT       4.4BSD */
125        {"msgcat",      f_msgcat,       OPT_STR,        0},
126/* O_NOPRINT      4.4BSD */
127        {"noprint",     f_print,        OPT_STR,        0},
128/* O_NUMBER         4BSD */
129        {"number",      f_reformat,     OPT_0BOOL,      0},
130/* O_OCTAL        4.4BSD */
131        {"octal",       f_print,        OPT_0BOOL,      0},
132/* O_OPEN           4BSD */
133        {"open",        NULL,           OPT_1BOOL,      0},
134/* O_OPTIMIZE       4BSD */
135        {"optimize",    NULL,           OPT_1BOOL,      0},
136/* O_PARAGRAPHS     4BSD */
137        {"paragraphs",  f_paragraph,    OPT_STR,        0},
138/* O_PATH         4.4BSD */
139        {"path",        NULL,           OPT_STR,        0},
140/* O_PRINT        4.4BSD */
141        {"print",       f_print,        OPT_STR,        0},
142/* O_PROMPT         4BSD */
143        {"prompt",      NULL,           OPT_1BOOL,      0},
144/* O_READONLY       4BSD (undocumented) */
145        {"readonly",    f_readonly,     OPT_0BOOL,      OPT_ALWAYS},
146/* O_RECDIR       4.4BSD */
147        {"recdir",      NULL,           OPT_STR,        0},
148/* O_REDRAW         4BSD */
149        {"redraw",      NULL,           OPT_0BOOL,      0},
150/* O_REMAP          4BSD */
151        {"remap",       NULL,           OPT_1BOOL,      0},
152/* O_REPORT         4BSD */
153        {"report",      NULL,           OPT_NUM,        0},
154/* O_RULER        4.4BSD */
155        {"ruler",       NULL,           OPT_0BOOL,      0},
156/* O_SCROLL         4BSD */
157        {"scroll",      NULL,           OPT_NUM,        0},
158/* O_SEARCHINCR   4.4BSD */
159        {"searchincr",  NULL,           OPT_0BOOL,      0},
160/* O_SECTIONS       4BSD */
161        {"sections",    f_section,      OPT_STR,        0},
162/* O_SECURE       4.4BSD */
163        {"secure",      NULL,           OPT_0BOOL,      OPT_NOUNSET},
164/* O_SHELL          4BSD */
165        {"shell",       NULL,           OPT_STR,        0},
166/* O_SHELLMETA    4.4BSD */
167        {"shellmeta",   NULL,           OPT_STR,        0},
168/* O_SHIFTWIDTH     4BSD */
169        {"shiftwidth",  NULL,           OPT_NUM,        OPT_NOZERO},
170/* O_SHOWMATCH      4BSD */
171        {"showmatch",   NULL,           OPT_0BOOL,      0},
172/* O_SHOWMODE     4.4BSD */
173        {"showmode",    NULL,           OPT_0BOOL,      0},
174/* O_SIDESCROLL   4.4BSD */
175        {"sidescroll",  NULL,           OPT_NUM,        OPT_NOZERO},
176/* O_SLOWOPEN       4BSD  */
177        {"slowopen",    NULL,           OPT_0BOOL,      0},
178/* O_SOURCEANY      4BSD (undocumented)
179 *      !!!
180 *      Historic vi, on startup, source'd $HOME/.exrc and ./.exrc, if they
181 *      were owned by the user.  The sourceany option was an undocumented
182 *      feature of historic vi which permitted the startup source'ing of
183 *      .exrc files the user didn't own.  This is an obvious security problem,
184 *      and we ignore the option.
185 */
186        {"sourceany",   NULL,           OPT_0BOOL,      OPT_NOSET},
187/* O_TABSTOP        4BSD */
188        {"tabstop",     f_reformat,     OPT_NUM,        OPT_NOZERO},
189/* O_TAGLENGTH      4BSD */
190        {"taglength",   NULL,           OPT_NUM,        0},
191/* O_TAGS           4BSD */
192        {"tags",        NULL,           OPT_STR,        0},
193/* O_TERM           4BSD
194 *      !!!
195 *      By default, the historic vi always displayed information about two
196 *      options, redraw and term.  Term seems sufficient.
197 */
198        {"term",        NULL,           OPT_STR,        OPT_ADISP|OPT_NOSAVE},
199/* O_TERSE          4BSD */
200        {"terse",       NULL,           OPT_0BOOL,      0},
201/* O_TILDEOP      4.4BSD */
202        {"tildeop",     NULL,           OPT_0BOOL,      0},
203/* O_TIMEOUT        4BSD (undocumented) */
204        {"timeout",     NULL,           OPT_1BOOL,      0},
205/* O_TTYWERASE    4.4BSD */
206        {"ttywerase",   f_ttywerase,    OPT_0BOOL,      0},
207/* O_VERBOSE      4.4BSD */
208        {"verbose",     NULL,           OPT_0BOOL,      0},
209/* O_W1200          4BSD */
210        {"w1200",       f_w1200,        OPT_NUM,        OPT_NDISP|OPT_NOSAVE},
211/* O_W300           4BSD */
212        {"w300",        f_w300,         OPT_NUM,        OPT_NDISP|OPT_NOSAVE},
213/* O_W9600          4BSD */
214        {"w9600",       f_w9600,        OPT_NUM,        OPT_NDISP|OPT_NOSAVE},
215/* O_WARN           4BSD */
216        {"warn",        NULL,           OPT_1BOOL,      0},
217/* O_WINDOW         4BSD */
218        {"window",      f_window,       OPT_NUM,        0},
219/* O_WINDOWNAME     4BSD */
220        {"windowname",  NULL,           OPT_0BOOL,      0},
221/* O_WRAPLEN      4.4BSD */
222        {"wraplen",     NULL,           OPT_NUM,        0},
223/* O_WRAPMARGIN     4BSD */
224        {"wrapmargin",  NULL,           OPT_NUM,        0},
225/* O_WRAPSCAN       4BSD */
226        {"wrapscan",    NULL,           OPT_1BOOL,      0},
227/* O_WRITEANY       4BSD */
228        {"writeany",    NULL,           OPT_0BOOL,      0},
229        {NULL},
230};
231
232typedef struct abbrev {
233        char *name;
234        int offset;
235} OABBREV;
236
237static OABBREV const abbrev[] = {
238        {"ai",          O_AUTOINDENT},          /*     4BSD */
239        {"ap",          O_AUTOPRINT},           /*     4BSD */
240        {"aw",          O_AUTOWRITE},           /*     4BSD */
241        {"bf",          O_BEAUTIFY},            /*     4BSD */
242        {"co",          O_COLUMNS},             /*   4.4BSD */
243        {"dir",         O_DIRECTORY},           /*     4BSD */
244        {"eb",          O_ERRORBELLS},          /*     4BSD */
245        {"ed",          O_EDCOMPATIBLE},        /*     4BSD */
246        {"ex",          O_EXRC},                /* System V (undocumented) */
247        {"ht",          O_HARDTABS},            /*     4BSD */
248        {"ic",          O_IGNORECASE},          /*     4BSD */
249        {"li",          O_LINES},               /*   4.4BSD */
250        {"modelines",   O_MODELINE},            /*     HPUX */
251        {"nu",          O_NUMBER},              /*     4BSD */
252        {"opt",         O_OPTIMIZE},            /*     4BSD */
253        {"para",        O_PARAGRAPHS},          /*     4BSD */
254        {"re",          O_REDRAW},              /* O'Reilly */
255        {"ro",          O_READONLY},            /*     4BSD (undocumented) */
256        {"scr",         O_SCROLL},              /*     4BSD (undocumented) */
257        {"sect",        O_SECTIONS},            /* O'Reilly */
258        {"sh",          O_SHELL},               /*     4BSD */
259        {"slow",        O_SLOWOPEN},            /*     4BSD */
260        {"sm",          O_SHOWMATCH},           /*     4BSD */
261        {"smd",         O_SHOWMODE},            /*     4BSD */
262        {"sw",          O_SHIFTWIDTH},          /*     4BSD */
263        {"tag",         O_TAGS},                /*     4BSD (undocumented) */
264        {"tl",          O_TAGLENGTH},           /*     4BSD */
265        {"to",          O_TIMEOUT},             /*     4BSD (undocumented) */
266        {"ts",          O_TABSTOP},             /*     4BSD */
267        {"tty",         O_TERM},                /*     4BSD (undocumented) */
268        {"ttytype",     O_TERM},                /*     4BSD (undocumented) */
269        {"w",           O_WINDOW},              /* O'Reilly */
270        {"wa",          O_WRITEANY},            /*     4BSD */
271        {"wi",          O_WINDOW},              /*     4BSD (undocumented) */
272        {"wl",          O_WRAPLEN},             /*   4.4BSD */
273        {"wm",          O_WRAPMARGIN},          /*     4BSD */
274        {"ws",          O_WRAPSCAN},            /*     4BSD */
275        {NULL},
276};
277
278/*
279 * opts_init --
280 *      Initialize some of the options.
281 *
282 * PUBLIC: int opts_init __P((SCR *, int *));
283 */
284int
285opts_init(sp, oargs)
286        SCR *sp;
287        int *oargs;
288{
289        ARGS *argv[2], a, b;
290        OPTLIST const *op;
291        u_long v;
292        int cnt, optindx;
293        char *s, b1[1024];
294
295        a.bp = b1;
296        b.bp = NULL;
297        a.len = b.len = 0;
298        argv[0] = &a;
299        argv[1] = &b;
300
301        /* Set numeric and string default values. */
302#define OI(indx, str) {                                                 \
303        if (str != b1)          /* GCC puts strings in text-space. */   \
304                (void)strcpy(b1, str);                                  \
305        a.len = strlen(b1);                                             \
306        if (opts_set(sp, argv, NULL)) {                                 \
307                 optindx = indx;                                        \
308                goto err;                                               \
309        }                                                               \
310}
311        /*
312         * Indirect global options to global space.  Specifically, set up
313         * terminal, lines, columns first, they're used by other options.
314         * Note, don't set the flags until we've set up the indirection.
315         */
316        if (o_set(sp, O_TERM, 0, NULL, GO_TERM))
317                goto err;
318        F_SET(&sp->opts[O_TERM], OPT_GLOBAL);
319        if (o_set(sp, O_LINES, 0, NULL, GO_LINES))
320                goto err;
321        F_SET(&sp->opts[O_LINES], OPT_GLOBAL);
322        if (o_set(sp, O_COLUMNS, 0, NULL, GO_COLUMNS))
323                goto err;
324        F_SET(&sp->opts[O_COLUMNS], OPT_GLOBAL);
325        if (o_set(sp, O_SECURE, 0, NULL, GO_SECURE))
326                goto err;
327        F_SET(&sp->opts[O_SECURE], OPT_GLOBAL);
328
329        /* Initialize string values. */
330        (void)snprintf(b1, sizeof(b1),
331            "cdpath=%s", (s = getenv("CDPATH")) == NULL ? ":" : s);
332        OI(O_CDPATH, b1);
333
334        /*
335         * !!!
336         * Vi historically stored temporary files in /var/tmp.  We store them
337         * in /tmp by default, hoping it's a memory based file system.  There
338         * are two ways to change this -- the user can set either the directory
339         * option or the TMPDIR environmental variable.
340         */
341        (void)snprintf(b1, sizeof(b1),
342            "directory=%s", (s = getenv("TMPDIR")) == NULL ? _PATH_TMP : s);
343        OI(O_DIRECTORY, b1);
344        OI(O_ESCAPETIME, "escapetime=1");
345        OI(O_KEYTIME, "keytime=6");
346        OI(O_MATCHTIME, "matchtime=7");
347        (void)snprintf(b1, sizeof(b1), "msgcat=%s", _PATH_MSGCAT);
348        OI(O_MSGCAT, b1);
349        OI(O_REPORT, "report=5");
350        OI(O_PARAGRAPHS, "paragraphs=IPLPPPQPP LIpplpipbp");
351        (void)snprintf(b1, sizeof(b1), "path=%s", "");
352        OI(O_PATH, b1);
353        (void)snprintf(b1, sizeof(b1), "recdir=%s", _PATH_PRESERVE);
354        OI(O_RECDIR, b1);
355        OI(O_SECTIONS, "sections=NHSHH HUnhsh");
356        (void)snprintf(b1, sizeof(b1),
357            "shell=%s", (s = getenv("SHELL")) == NULL ? _PATH_BSHELL : s);
358        OI(O_SHELL, b1);
359        OI(O_SHELLMETA, "shellmeta=~{[*?$`'\"\\");
360        OI(O_SHIFTWIDTH, "shiftwidth=8");
361        OI(O_SIDESCROLL, "sidescroll=16");
362        OI(O_TABSTOP, "tabstop=8");
363        (void)snprintf(b1, sizeof(b1), "tags=%s", _PATH_TAGS);
364        OI(O_TAGS, b1);
365
366        /*
367         * XXX
368         * Initialize O_SCROLL here, after term; initializing term should
369         * have created a LINES/COLUMNS value.
370         */
371        if ((v = (O_VAL(sp, O_LINES) - 1) / 2) == 0)
372                v = 1;
373        (void)snprintf(b1, sizeof(b1), "scroll=%ld", v);
374        OI(O_SCROLL, b1);
375
376        /*
377         * The default window option values are:
378         *              8 if baud rate <=  600
379         *             16 if baud rate <= 1200
380         *      LINES - 1 if baud rate  > 1200
381         *
382         * Note, the windows option code will correct any too-large value
383         * or when the O_LINES value is 1.
384         */
385        if (sp->gp->scr_baud(sp, &v))
386                return (1);
387        if (v <= 600)
388                v = 8;
389        else if (v <= 1200)
390                v = 16;
391        else
392                v = O_VAL(sp, O_LINES) - 1;
393        (void)snprintf(b1, sizeof(b1), "window=%lu", v);
394        OI(O_WINDOW, b1);
395
396        /*
397         * Set boolean default values, and copy all settings into the default
398         * information.  OS_NOFREE is set, we're copying, not replacing.
399         */
400        for (op = optlist, cnt = 0; op->name != NULL; ++op, ++cnt)
401                switch (op->type) {
402                case OPT_0BOOL:
403                        break;
404                case OPT_1BOOL:
405                        O_SET(sp, cnt);
406                        O_D_SET(sp, cnt);
407                        break;
408                case OPT_NUM:
409                        o_set(sp, cnt, OS_DEF, NULL, O_VAL(sp, cnt));
410                        break;
411                case OPT_STR:
412                        if (O_STR(sp, cnt) != NULL && o_set(sp, cnt,
413                            OS_DEF | OS_NOFREE | OS_STRDUP, O_STR(sp, cnt), 0))
414                                goto err;
415                        break;
416                default:
417                        abort();
418                }
419
420        /*
421         * !!!
422         * Some options can be initialized by the command name or the
423         * command-line arguments.  They don't set the default values,
424         * it's historic practice.
425         */
426        for (; *oargs != -1; ++oargs)
427                OI(*oargs, optlist[*oargs].name);
428        return (0);
429#undef OI
430
431err:    msgq(sp, M_ERR,
432            "031|Unable to set default %s option", optlist[optindx].name);
433        return (1);
434}
435
436/*
437 * opts_set --
438 *      Change the values of one or more options.
439 *
440 * PUBLIC: int opts_set __P((SCR *, ARGS *[], char *));
441 */
442int
443opts_set(sp, argv, usage)
444        SCR *sp;
445        ARGS *argv[];
446        char *usage;
447{
448        enum optdisp disp;
449        enum nresult nret;
450        OPTLIST const *op;
451        OPTION *spo;
452        u_long value, turnoff;
453        int ch, equals, nf, nf2, offset, qmark, rval;
454        char *endp, *name, *p, *sep, *t;
455
456        disp = NO_DISPLAY;
457        for (rval = 0; argv[0]->len != 0; ++argv) {
458                /*
459                 * The historic vi dumped the options for each occurrence of
460                 * "all" in the set list.  Puhleeze.
461                 */
462                if (!strcmp(argv[0]->bp, "all")) {
463                        disp = ALL_DISPLAY;
464                        continue;
465                }
466
467                /* Find equals sign or question mark. */
468                for (sep = NULL, equals = qmark = 0,
469                    p = name = argv[0]->bp; (ch = *p) != '\0'; ++p)
470                        if (ch == '=' || ch == '?') {
471                                if (p == name) {
472                                        if (usage != NULL)
473                                                msgq(sp, M_ERR,
474                                                    "032|Usage: %s", usage);
475                                        return (1);
476                                }
477                                sep = p;
478                                if (ch == '=')
479                                        equals = 1;
480                                else
481                                        qmark = 1;
482                                break;
483                        }
484
485                turnoff = 0;
486                op = NULL;
487                if (sep != NULL)
488                        *sep++ = '\0';
489
490                /* Search for the name, then name without any leading "no". */
491                if ((op = opts_search(name)) == NULL &&
492                    name[0] == 'n' && name[1] == 'o') {
493                        turnoff = 1;
494                        name += 2;
495                        op = opts_search(name);
496                }
497                if (op == NULL) {
498                        opts_nomatch(sp, name);
499                        rval = 1;
500                        continue;
501                }
502
503                /* Find current option values. */
504                offset = op - optlist;
505                spo = sp->opts + offset;
506
507                /*
508                 * !!!
509                 * Historically, the question mark could be a separate
510                 * argument.
511                 */
512                if (!equals && !qmark &&
513                    argv[1]->len == 1 && argv[1]->bp[0] == '?') {
514                        ++argv;
515                        qmark = 1;
516                }
517
518                /* Set name, value. */
519                switch (op->type) {
520                case OPT_0BOOL:
521                case OPT_1BOOL:
522                        /* Some options may not be reset. */
523                        if (F_ISSET(op, OPT_NOUNSET) && turnoff) {
524                                msgq_str(sp, M_ERR, name,
525                            "291|set: the %s option may not be turned off");
526                                rval = 1;
527                                break;
528                        }
529
530                        /* Some options may not be set. */
531                        if (F_ISSET(op, OPT_NOSET) && !turnoff) {
532                                msgq_str(sp, M_ERR, name,
533                            "313|set: the %s option may never be turned on");
534                                rval = 1;
535                                break;
536                        }
537
538                        if (equals) {
539                                msgq_str(sp, M_ERR, name,
540                            "034|set: [no]%s option doesn't take a value");
541                                rval = 1;
542                                break;
543                        }
544                        if (qmark) {
545                                if (!disp)
546                                        disp = SELECT_DISPLAY;
547                                F_SET(spo, OPT_SELECTED);
548                                break;
549                        }
550
551                        /*
552                         * Do nothing if the value is unchanged, the underlying
553                         * functions can be expensive.
554                         */
555                        if (!F_ISSET(op, OPT_ALWAYS))
556                                if (turnoff) {
557                                        if (!O_ISSET(sp, offset))
558                                                break;
559                                } else {
560                                        if (O_ISSET(sp, offset))
561                                                break;
562                                }
563
564                        /* Report to subsystems. */
565                        if (op->func != NULL &&
566                            op->func(sp, spo, NULL, &turnoff) ||
567                            ex_optchange(sp, offset, NULL, &turnoff) ||
568                            v_optchange(sp, offset, NULL, &turnoff) ||
569                            sp->gp->scr_optchange(sp, offset, NULL, &turnoff)) {
570                                rval = 1;
571                                break;
572                        }
573
574                        /* Set the value. */
575                        if (turnoff)
576                                O_CLR(sp, offset);
577                        else
578                                O_SET(sp, offset);
579                        break;
580                case OPT_NUM:
581                        if (turnoff) {
582                                msgq_str(sp, M_ERR, name,
583                                    "035|set: %s option isn't a boolean");
584                                rval = 1;
585                                break;
586                        }
587                        if (qmark || !equals) {
588                                if (!disp)
589                                        disp = SELECT_DISPLAY;
590                                F_SET(spo, OPT_SELECTED);
591                                break;
592                        }
593
594                        if (!isdigit(sep[0]))
595                                goto badnum;
596                        if ((nret =
597                            nget_uslong(&value, sep, &endp, 10)) != NUM_OK) {
598                                p = msg_print(sp, name, &nf);
599                                t = msg_print(sp, sep, &nf2);
600                                switch (nret) {
601                                case NUM_ERR:
602                                        msgq(sp, M_SYSERR,
603                                            "036|set: %s option: %s", p, t);
604                                        break;
605                                case NUM_OVER:
606                                        msgq(sp, M_ERR,
607                            "037|set: %s option: %s: value overflow", p, t);
608                                        break;
609                                case NUM_OK:
610                                case NUM_UNDER:
611                                        abort();
612                                }
613                                if (nf)
614                                        FREE_SPACE(sp, p, 0);
615                                if (nf2)
616                                        FREE_SPACE(sp, t, 0);
617                                rval = 1;
618                                break;
619                        }
620                        if (*endp && !isblank(*endp)) {
621badnum:                         p = msg_print(sp, name, &nf);
622                                t = msg_print(sp, sep, &nf2);
623                                msgq(sp, M_ERR,
624                    "038|set: %s option: %s is an illegal number", p, t);
625                                if (nf)
626                                        FREE_SPACE(sp, p, 0);
627                                if (nf2)
628                                        FREE_SPACE(sp, t, 0);
629                                rval = 1;
630                                break;
631                        }
632
633                        /* Some options may never be set to zero. */
634                        if (F_ISSET(op, OPT_NOZERO) && value == 0) {
635                                msgq_str(sp, M_ERR, name,
636                            "314|set: the %s option may never be set to 0");
637                                rval = 1;
638                                break;
639                        }
640
641                        /*
642                         * Do nothing if the value is unchanged, the underlying
643                         * functions can be expensive.
644                         */
645                        if (!F_ISSET(op, OPT_ALWAYS) &&
646                            O_VAL(sp, offset) == value)
647                                break;
648
649                        /* Report to subsystems. */
650                        if (op->func != NULL &&
651                            op->func(sp, spo, sep, &value) ||
652                            ex_optchange(sp, offset, sep, &value) ||
653                            v_optchange(sp, offset, sep, &value) ||
654                            sp->gp->scr_optchange(sp, offset, sep, &value)) {
655                                rval = 1;
656                                break;
657                        }
658
659                        /* Set the value. */
660                        if (o_set(sp, offset, 0, NULL, value))
661                                rval = 1;
662                        break;
663                case OPT_STR:
664                        if (turnoff) {
665                                msgq_str(sp, M_ERR, name,
666                                    "039|set: %s option isn't a boolean");
667                                rval = 1;
668                                break;
669                        }
670                        if (qmark || !equals) {
671                                if (!disp)
672                                        disp = SELECT_DISPLAY;
673                                F_SET(spo, OPT_SELECTED);
674                                break;
675                        }
676
677                        /*
678                         * Do nothing if the value is unchanged, the underlying
679                         * functions can be expensive.
680                         */
681                        if (!F_ISSET(op, OPT_ALWAYS) &&
682                            O_STR(sp, offset) != NULL &&
683                            !strcmp(O_STR(sp, offset), sep))
684                                break;
685
686                        /* Report to subsystems. */
687                        if (op->func != NULL &&
688                            op->func(sp, spo, sep, NULL) ||
689                            ex_optchange(sp, offset, sep, NULL) ||
690                            v_optchange(sp, offset, sep, NULL) ||
691                            sp->gp->scr_optchange(sp, offset, sep, NULL)) {
692                                rval = 1;
693                                break;
694                        }
695
696                        /* Set the value. */
697                        if (o_set(sp, offset, OS_STRDUP, sep, 0))
698                                rval = 1;
699                        break;
700                default:
701                        abort();
702                }
703        }
704        if (disp != NO_DISPLAY)
705                opts_dump(sp, disp);
706        return (rval);
707}
708
709/*
710 * o_set --
711 *      Set an option's value.
712 *
713 * PUBLIC: int o_set __P((SCR *, int, u_int, char *, u_long));
714 */
715int
716o_set(sp, opt, flags, str, val)
717        SCR *sp;
718        int opt;
719        u_int flags;
720        char *str;
721        u_long val;
722{
723        OPTION *op;
724
725        /* Set a pointer to the options area. */
726        op = F_ISSET(&sp->opts[opt], OPT_GLOBAL) ?
727            &sp->gp->opts[sp->opts[opt].o_cur.val] : &sp->opts[opt];
728
729        /* Copy the string, if requested. */
730        if (LF_ISSET(OS_STRDUP) && (str = strdup(str)) == NULL) {
731                msgq(sp, M_SYSERR, NULL);
732                return (1);
733        }
734
735        /* Free the previous string, if requested, and set the value. */
736        if LF_ISSET(OS_DEF)
737                if (LF_ISSET(OS_STR | OS_STRDUP)) {
738                        if (!LF_ISSET(OS_NOFREE) && op->o_def.str != NULL)
739                                free(op->o_def.str);
740                        op->o_def.str = str;
741                } else
742                        op->o_def.val = val;
743        else
744                if (LF_ISSET(OS_STR | OS_STRDUP)) {
745                        if (!LF_ISSET(OS_NOFREE) && op->o_cur.str != NULL)
746                                free(op->o_cur.str);
747                        op->o_cur.str = str;
748                } else
749                        op->o_cur.val = val;
750        return (0);
751}
752
753/*
754 * opts_empty --
755 *      Return 1 if the string option is invalid, 0 if it's OK.
756 *
757 * PUBLIC: int opts_empty __P((SCR *, int, int));
758 */
759int
760opts_empty(sp, off, silent)
761        SCR *sp;
762        int off, silent;
763{
764        char *p;
765
766        if ((p = O_STR(sp, off)) == NULL || p[0] == '\0') {
767                if (!silent)
768                        msgq_str(sp, M_ERR, optlist[off].name,
769                            "305|No %s edit option specified");
770                return (1);
771        }
772        return (0);
773}
774
775/*
776 * opts_dump --
777 *      List the current values of selected options.
778 *
779 * PUBLIC: void opts_dump __P((SCR *, enum optdisp));
780 */
781void
782opts_dump(sp, type)
783        SCR *sp;
784        enum optdisp type;
785{
786        OPTLIST const *op;
787        int base, b_num, cnt, col, colwidth, curlen, s_num;
788        int numcols, numrows, row;
789        int b_op[O_OPTIONCOUNT], s_op[O_OPTIONCOUNT];
790        char nbuf[20];
791
792        /*
793         * Options are output in two groups -- those that fit in a column and
794         * those that don't.  Output is done on 6 character "tab" boundaries
795         * for no particular reason.  (Since we don't output tab characters,
796         * we can ignore the terminal's tab settings.)  Ignore the user's tab
797         * setting because we have no idea how reasonable it is.
798         *
799         * Find a column width we can live with, testing from 10 columns to 1.
800         */
801        for (numcols = 10; numcols > 1; --numcols) {
802                colwidth = sp->cols / numcols & ~(STANDARD_TAB - 1);
803                if (colwidth >= 10) {
804                        colwidth =
805                            (colwidth + STANDARD_TAB) & ~(STANDARD_TAB - 1);
806                        numcols = sp->cols / colwidth;
807                        break;
808                }
809                colwidth = 0;
810        }
811
812        /*
813         * Get the set of options to list, entering them into
814         * the column list or the overflow list.
815         */
816        for (b_num = s_num = 0, op = optlist; op->name != NULL; ++op) {
817                cnt = op - optlist;
818
819                /* If OPT_NDISP set, it's never displayed. */
820                if (F_ISSET(op, OPT_NDISP))
821                        continue;
822
823                switch (type) {
824                case ALL_DISPLAY:               /* Display all. */
825                        break;
826                case CHANGED_DISPLAY:           /* Display changed. */
827                        /* If OPT_ADISP set, it's always "changed". */
828                        if (F_ISSET(op, OPT_ADISP))
829                                break;
830                        switch (op->type) {
831                        case OPT_0BOOL:
832                        case OPT_1BOOL:
833                        case OPT_NUM:
834                                if (O_VAL(sp, cnt) == O_D_VAL(sp, cnt))
835                                        continue;
836                                break;
837                        case OPT_STR:
838                                if (O_STR(sp, cnt) == O_D_STR(sp, cnt) ||
839                                    O_D_STR(sp, cnt) != NULL &&
840                                    !strcmp(O_STR(sp, cnt), O_D_STR(sp, cnt)))
841                                        continue;
842                                break;
843                        }
844                        break;
845                case SELECT_DISPLAY:            /* Display selected. */
846                        if (!F_ISSET(&sp->opts[cnt], OPT_SELECTED))
847                                continue;
848                        break;
849                default:
850                case NO_DISPLAY:
851                        abort();
852                }
853                F_CLR(&sp->opts[cnt], OPT_SELECTED);
854
855                curlen = strlen(op->name);
856                switch (op->type) {
857                case OPT_0BOOL:
858                case OPT_1BOOL:
859                        if (!O_ISSET(sp, cnt))
860                                curlen += 2;
861                        break;
862                case OPT_NUM:
863                        (void)snprintf(nbuf,
864                            sizeof(nbuf), "%ld", O_VAL(sp, cnt));
865                        curlen += strlen(nbuf);
866                        break;
867                case OPT_STR:
868                        if (O_STR(sp, cnt) != NULL)
869                                curlen += strlen(O_STR(sp, cnt));
870                        curlen += 3;
871                        break;
872                }
873                /* Offset by 2 so there's a gap. */
874                if (curlen <= colwidth - 2)
875                        s_op[s_num++] = cnt;
876                else
877                        b_op[b_num++] = cnt;
878        }
879
880        if (s_num > 0) {
881                /* Figure out the number of rows. */
882                if (s_num > numcols) {
883                        numrows = s_num / numcols;
884                        if (s_num % numcols)
885                                ++numrows;
886                } else
887                        numrows = 1;
888
889                /* Display the options in sorted order. */
890                for (row = 0; row < numrows;) {
891                        for (base = row, col = 0; col < numcols; ++col) {
892                                cnt = opts_print(sp, &optlist[s_op[base]]);
893                                if ((base += numrows) >= s_num)
894                                        break;
895                                (void)ex_printf(sp, "%*s",
896                                    (int)(colwidth - cnt), "");
897                        }
898                        if (++row < numrows || b_num)
899                                (void)ex_puts(sp, "\n");
900                }
901        }
902
903        for (row = 0; row < b_num;) {
904                (void)opts_print(sp, &optlist[b_op[row]]);
905                if (++row < b_num)
906                        (void)ex_puts(sp, "\n");
907        }
908        (void)ex_puts(sp, "\n");
909}
910
911/*
912 * opts_print --
913 *      Print out an option.
914 */
915static int
916opts_print(sp, op)
917        SCR *sp;
918        OPTLIST const *op;
919{
920        int curlen, offset;
921
922        curlen = 0;
923        offset = op - optlist;
924        switch (op->type) {
925        case OPT_0BOOL:
926        case OPT_1BOOL:
927                curlen += ex_printf(sp,
928                    "%s%s", O_ISSET(sp, offset) ? "" : "no", op->name);
929                break;
930        case OPT_NUM:
931                curlen += ex_printf(sp, "%s=%ld", op->name, O_VAL(sp, offset));
932                break;
933        case OPT_STR:
934                curlen += ex_printf(sp, "%s=\"%s\"", op->name,
935                    O_STR(sp, offset) == NULL ? "" : O_STR(sp, offset));
936                break;
937        }
938        return (curlen);
939}
940
941/*
942 * opts_save --
943 *      Write the current configuration to a file.
944 *
945 * PUBLIC: int opts_save __P((SCR *, FILE *));
946 */
947int
948opts_save(sp, fp)
949        SCR *sp;
950        FILE *fp;
951{
952        OPTLIST const *op;
953        int ch, cnt;
954        char *p;
955
956        for (op = optlist; op->name != NULL; ++op) {
957                if (F_ISSET(op, OPT_NOSAVE))
958                        continue;
959                cnt = op - optlist;
960                switch (op->type) {
961                case OPT_0BOOL:
962                case OPT_1BOOL:
963                        if (O_ISSET(sp, cnt))
964                                (void)fprintf(fp, "set %s\n", op->name);
965                        else
966                                (void)fprintf(fp, "set no%s\n", op->name);
967                        break;
968                case OPT_NUM:
969                        (void)fprintf(fp,
970                            "set %s=%-3ld\n", op->name, O_VAL(sp, cnt));
971                        break;
972                case OPT_STR:
973                        if (O_STR(sp, cnt) == NULL)
974                                break;
975                        (void)fprintf(fp, "set ");
976                        for (p = op->name; (ch = *p) != '\0'; ++p) {
977                                if (isblank(ch) || ch == '\\')
978                                        (void)putc('\\', fp);
979                                (void)putc(ch, fp);
980                        }
981                        (void)putc('=', fp);
982                        for (p = O_STR(sp, cnt); (ch = *p) != '\0'; ++p) {
983                                if (isblank(ch) || ch == '\\')
984                                        (void)putc('\\', fp);
985                                (void)putc(ch, fp);
986                        }
987                        (void)putc('\n', fp);
988                        break;
989                }
990                if (ferror(fp)) {
991                        msgq(sp, M_SYSERR, NULL);
992                        return (1);
993                }
994        }
995        return (0);
996}
997
998/*
999 * opts_search --
1000 *      Search for an option.
1001 *
1002 * PUBLIC: OPTLIST const *opts_search __P((char *));
1003 */
1004OPTLIST const *
1005opts_search(name)
1006        char *name;
1007{
1008        OPTLIST const *op, *found;
1009        OABBREV atmp, *ap;
1010        OPTLIST otmp;
1011        size_t len;
1012
1013        /* Check list of abbreviations. */
1014        atmp.name = name;
1015        if ((ap = bsearch(&atmp, abbrev, sizeof(abbrev) / sizeof(OABBREV) - 1,
1016            sizeof(OABBREV), opts_abbcmp)) != NULL)
1017                return (optlist + ap->offset);
1018
1019        /* Check list of options. */
1020        otmp.name = name;
1021        if ((op = bsearch(&otmp, optlist, sizeof(optlist) / sizeof(OPTLIST) - 1,
1022            sizeof(OPTLIST), opts_cmp)) != NULL)
1023                return (op);
1024               
1025        /*
1026         * Check to see if the name is the prefix of one (and only one)
1027         * option.  If so, return the option.
1028         */
1029        len = strlen(name);
1030        for (found = NULL, op = optlist; op->name != NULL; ++op) {
1031                if (op->name[0] < name[0])
1032                        continue;
1033                if (op->name[0] > name[0])
1034                        break;
1035                if (!memcmp(op->name, name, len)) {
1036                        if (found != NULL)
1037                                return (NULL);
1038                        found = op;
1039                }
1040        }
1041        return (found);
1042}
1043
1044/*
1045 * opts_nomatch --
1046 *      Standard nomatch error message for options.
1047 *
1048 * PUBLIC: void opts_nomatch __P((SCR *, char *));
1049 */
1050void
1051opts_nomatch(sp, name)
1052        SCR *sp;
1053        char *name;
1054{
1055        msgq_str(sp, M_ERR, name,
1056            "033|set: no %s option: 'set all' gives all option values");
1057}
1058
1059static int
1060opts_abbcmp(a, b)
1061        const void *a, *b;
1062{
1063        return(strcmp(((OABBREV *)a)->name, ((OABBREV *)b)->name));
1064}
1065
1066static int
1067opts_cmp(a, b)
1068        const void *a, *b;
1069{
1070        return(strcmp(((OPTLIST *)a)->name, ((OPTLIST *)b)->name));
1071}
1072
1073/*
1074 * opts_copy --
1075 *      Copy a screen's OPTION array.
1076 *
1077 * PUBLIC: int opts_copy __P((SCR *, SCR *));
1078 */
1079int
1080opts_copy(orig, sp)
1081        SCR *orig, *sp;
1082{
1083        int cnt, rval;
1084
1085        /* Copy most everything without change. */
1086        memcpy(sp->opts, orig->opts, sizeof(orig->opts));
1087
1088        /* Copy the string edit options. */
1089        for (cnt = rval = 0; cnt < O_OPTIONCOUNT; ++cnt) {
1090                if (optlist[cnt].type != OPT_STR ||
1091                    F_ISSET(&optlist[cnt], OPT_GLOBAL))
1092                        continue;
1093                /*
1094                 * If never set, or already failed, NULL out the entries --
1095                 * have to continue after failure, otherwise would have two
1096                 * screens referencing the same memory.
1097                 */
1098                if (rval || O_STR(sp, cnt) == NULL) {
1099                        o_set(sp, cnt, OS_NOFREE | OS_STR, NULL, 0);
1100                        o_set(sp, cnt, OS_DEF | OS_NOFREE | OS_STR, NULL, 0);
1101                        continue;
1102                }
1103
1104                /* Copy the current string. */
1105                if (o_set(sp, cnt, OS_NOFREE | OS_STRDUP, O_STR(sp, cnt), 0)) {
1106                        o_set(sp, cnt, OS_DEF | OS_NOFREE | OS_STR, NULL, 0);
1107                        goto nomem;
1108                }
1109
1110                /* Copy the default string. */
1111                if (O_D_STR(sp, cnt) != NULL && o_set(sp, cnt,
1112                    OS_DEF | OS_NOFREE | OS_STRDUP, O_D_STR(sp, cnt), 0)) {
1113nomem:                  msgq(orig, M_SYSERR, NULL);
1114                        rval = 1;
1115                }
1116        }
1117        return (rval);
1118}
1119
1120/*
1121 * opts_free --
1122 *      Free all option strings
1123 *
1124 * PUBLIC: void opts_free __P((SCR *));
1125 */
1126void
1127opts_free(sp)
1128        SCR *sp;
1129{
1130        int cnt;
1131
1132        for (cnt = 0; cnt < O_OPTIONCOUNT; ++cnt) {
1133                if (optlist[cnt].type != OPT_STR ||
1134                    F_ISSET(&optlist[cnt], OPT_GLOBAL))
1135                        continue;
1136                if (O_STR(sp, cnt) != NULL)
1137                        free(O_STR(sp, cnt));
1138                if (O_D_STR(sp, cnt) != NULL)
1139                        free(O_D_STR(sp, cnt));
1140        }
1141}
Note: See TracBrowser for help on using the repository browser.