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 |
---|
13 | static 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 | |
---|
34 | static int opts_abbcmp __P((const void *, const void *)); |
---|
35 | static int opts_cmp __P((const void *, const void *)); |
---|
36 | static 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 | */ |
---|
46 | OPTLIST 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 | |
---|
232 | typedef struct abbrev { |
---|
233 | char *name; |
---|
234 | int offset; |
---|
235 | } OABBREV; |
---|
236 | |
---|
237 | static 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 | */ |
---|
284 | int |
---|
285 | opts_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 | |
---|
431 | err: 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 | */ |
---|
442 | int |
---|
443 | opts_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)) { |
---|
621 | badnum: 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 | */ |
---|
715 | int |
---|
716 | o_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 | */ |
---|
759 | int |
---|
760 | opts_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 | */ |
---|
781 | void |
---|
782 | opts_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 | */ |
---|
915 | static int |
---|
916 | opts_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 | */ |
---|
947 | int |
---|
948 | opts_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 | */ |
---|
1004 | OPTLIST const * |
---|
1005 | opts_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 | */ |
---|
1050 | void |
---|
1051 | opts_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 | |
---|
1059 | static int |
---|
1060 | opts_abbcmp(a, b) |
---|
1061 | const void *a, *b; |
---|
1062 | { |
---|
1063 | return(strcmp(((OABBREV *)a)->name, ((OABBREV *)b)->name)); |
---|
1064 | } |
---|
1065 | |
---|
1066 | static int |
---|
1067 | opts_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 | */ |
---|
1079 | int |
---|
1080 | opts_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)) { |
---|
1113 | nomem: 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 | */ |
---|
1126 | void |
---|
1127 | opts_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 | } |
---|