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