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