1 /* opts.c */
2 
3 /* Author:
4  *	Steve Kirkendall
5  *	16820 SW Tallac Way
6  *	Beaverton, OR 97006
7  *	kirkenda@jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
8  */
9 
10 
11 /* This file contains the code that manages the run-time options -- The
12  * values that can be modified via the "set" command.
13  */
14 
15 #include "config.h"
16 #include "vi.h"
17 #ifndef NULL
18 #define NULL (char *)0
19 #endif
20 extern char	*getenv();
21 
22 /* These are the default values of all options */
23 char	o_autoindent[1] =	{FALSE};
24 char	o_autowrite[1] = 	{FALSE};
25 #ifndef NO_CHARATTR
26 char	o_charattr[1] =		{FALSE};
27 #endif
28 char	o_columns[3] =		{80, 32, 255};
29 char	o_directory[30] =	TMPDIR;
30 char	o_errorbells[1] =	{TRUE};
31 char	o_exrefresh[1] =	{TRUE};
32 #ifndef NO_SENTENCE
33 char	o_hideformat[1] =	{FALSE};
34 #endif
35 char	o_ignorecase[1] =	{FALSE};
36 #ifndef NO_EXTENSIONS
37 char	o_inputmode[1] =	{FALSE};
38 #endif
39 char	o_keytime[3] =		{2, 0, 5};
40 char	o_keywordprg[80] =	KEYWORDPRG;
41 char	o_lines[3] =		{25, 2, 50};	/* More lines? Enlarge kbuf */
42 char	o_list[1] =		{FALSE};
43 #ifndef NO_MAGIC
44 char	o_magic[1] =		{TRUE};
45 #endif
46 #ifndef NO_SENTENCE
47 char	o_paragraphs[30] =	"PPppPApa";
48 #endif
49 #if MSDOS
50 char	o_pcbios[1] =		{TRUE};
51 #endif
52 char	o_readonly[1] =		{FALSE};
53 char	o_redraw[1] =		{TRUE};
54 char	o_report[3] =		{5, 1, 127};
55 char	o_scroll[3] =		{12, 1, 127};
56 #ifndef NO_SENTENCE
57 char	o_sections[30] =	"SEseSHsh";
58 #endif
59 char	o_shell[60] =		"/bin/sh";
60 char	o_shiftwidth[3] =	{8, 1, 255};
61 #ifndef	NO_SHOWMODE
62 char	o_showmode[1] =		{FALSE};
63 #endif
64 char	o_sidescroll[3] =	{8, 1, 40};
65 char	o_sync[1] =		{FALSE};
66 char	o_tabstop[3] =		{8, 1, 40};
67 char	o_term[30] =		"?";
68 char	o_vbell[1] =		{TRUE};
69 char	o_warn[1] =		{TRUE};
70 char	o_wrapmargin[3] =	{0, 0, 255};
71 char	o_wrapscan[1] =		{TRUE};
72 
73 
74 /* The following describes the names & types of all options */
75 #define BOOL	0
76 #define	NUM	1
77 #define	STR	2
78 #define SET	0x01	/* this option has had its value altered */
79 #define CANSET	0x02	/* this option can be set at any time */
80 #define RCSET	0x06	/* this option can be set in a .exrc file only */
81 #define MR	0x40	/* does this option affect the way text is displayed? */
82 struct
83 {
84 	char	*name;	/* name of an option */
85 	char	*nm;	/* short name of an option */
86 	char	type;	/* type of an option */
87 	char	flags;	/* boolean: has this option been set? */
88 	char	*value;	/* value */
89 }
90 	opts[] =
91 {
92 	/* name			type	flags	redraw	value */
93 	{ "autoindent",	"ai",	BOOL,	CANSET	,	o_autoindent	},
94 	{ "autowrite",	"aw",	BOOL,	CANSET	,	o_autowrite	},
95 #ifndef NO_CHARATTR
96 	{ "charattr",	"ca",	BOOL,	CANSET	| MR,	o_charattr	},
97 #endif
98 	{ "columns",	"co",	NUM,	SET	,	o_columns	},
99 	{ "directory",	"dir",	STR,	RCSET	,	o_directory	},
100 	{ "errorbells",	"eb",	BOOL,	CANSET	,	o_errorbells	},
101 	{ "exrefresh",	"er",	BOOL,	CANSET	,	o_exrefresh	},
102 #ifndef NO_SENTENCE
103 	{ "hideformat",	"hf",	BOOL,	CANSET	| MR,	o_hideformat	},
104 #endif
105 	{ "ignorecase",	"ic",	BOOL,	CANSET	,	o_ignorecase	},
106 #ifndef NO_EXTENSIONS
107 	{ "inputmode",	"im",	BOOL,	CANSET	,	o_inputmode	},
108 #endif
109 	{ "keytime",	"kt",	NUM,	CANSET	,	o_keytime	},
110 	{ "keywordprg",	"kp",	STR,	CANSET	,	o_keywordprg	},
111 	{ "lines",	"ls",	NUM,	SET	,	o_lines		},
112 	{ "list",	"li",	BOOL,	CANSET	| MR,	o_list		},
113 #ifndef NO_MAGIC
114 	{ "magic",	"ma",	BOOL,	CANSET	,	o_magic		},
115 #endif
116 #ifndef NO_SENTENCE
117 	{ "paragraphs",	"pa",	STR,	CANSET	,	o_paragraphs	},
118 #endif
119 #if	MSDOS
120 	{ "pcbios",	"pc",	BOOL,	SET	,	o_pcbios	},
121 #endif
122 	{ "readonly",	"ro",	BOOL,	CANSET	,	o_readonly	},
123 	{ "redraw",	"rd",	BOOL,	CANSET	,	o_redraw	},
124 	{ "report",	"re",	NUM,	CANSET	,	o_report	},
125 	{ "scroll",	"sc",	NUM,	CANSET	,	o_scroll	},
126 #ifndef NO_SENTENCE
127 	{ "sections",	"se",	STR,	CANSET	,	o_sections	},
128 #endif
129 	{ "shell",	"sh",	STR,	CANSET	,	o_shell		},
130 #ifndef	NO_SHOWMODE
131 	{ "showmode",	"sho",	BOOL,	CANSET	,	o_showmode	},
132 #endif
133 	{ "shiftwidth",	"sw",	NUM,	CANSET	,	o_shiftwidth	},
134 	{ "sidescroll",	"ss",	NUM,	CANSET	,	o_sidescroll	},
135 	{ "sync",	"sy",	BOOL,	CANSET	,	o_sync		},
136 	{ "tabstop",	"ts",	NUM,	CANSET	| MR,	o_tabstop	},
137 	{ "term",	"te",	STR,	SET	,	o_term		},
138 	{ "vbell",	"vb",	BOOL,	CANSET	,	o_vbell		},
139 	{ "warn",	"wa",	BOOL,	CANSET	,	o_warn		},
140 	{ "wrapmargin",	"wm",	NUM,	CANSET	,	o_wrapmargin	},
141 	{ "wrapscan",	"ws",	BOOL,	CANSET	,	o_wrapscan	},
142 	{ NULL, NULL, 0, CANSET, NULL }
143 };
144 
145 
146 /* This function initializes certain options from environment variables, etc. */
initopts()147 initopts()
148 {
149 	char	*val;
150 	int	i;
151 
152 	/* set some stuff from environment variables */
153 #if	ANY_UNIX || TOS
154 	if (val = getenv("SHELL")) /* yes, ASSIGNMENT! */
155 	{
156 		strcpy(o_shell, val);
157 	}
158 	if (val = getenv("TERM")) /* yes, ASSIGNMENT! */
159 	{
160 		strcpy(o_term, val);
161 	}
162 #endif
163 #if	MSDOS
164 	if (val = getenv("COMSPEC")) /* yes, ASSIGNMENT! */
165 	{
166 		strcpy(o_shell, val);
167 	}
168 	if ((val = getenv("TERM")) /* yes, ASSIGNMENT! */
169 		&& strcmp(val, "pcbios"))
170 	{
171 		strcpy(o_term, val);
172 		o_pcbios[0] = 0;
173 	}
174 	else
175 	{
176 		strcpy(o_term, "pcbios");
177 		o_pcbios[0] = 1;
178 	}
179 #endif
180 #if	MSDOS || TOS
181 	if ((val = getenv("TMP")) /* yes, ASSIGNMENT! */
182 	||  (val = getenv("TEMP")))
183 		strcpy(o_directory, val);
184 #endif
185 
186 	*o_scroll = LINES / 2 - 1;
187 
188 	/* disable the vbell option if we don't know how to do a vbell */
189 	if (!has_VB)
190 	{
191 		for (i = 0; opts[i].value != o_vbell; i++)
192 		{
193 		}
194 		opts[i].flags &= ~CANSET;
195 		*o_vbell = FALSE;
196 	}
197 }
198 
199 /* This function lists the current values of all options */
dumpopts(all)200 dumpopts(all)
201 	int	all;	/* boolean: dump all options, or just set ones? */
202 {
203 	int	i;
204 	int	col;
205 	char	nbuf[4];
206 
207 	for (i = col = 0; opts[i].name; i++)
208 	{
209 		/* if not set and not all, ignore this option */
210 		if (!all && !(opts[i].flags & SET))
211 		{
212 			continue;
213 		}
214 
215 		/* align this option in one of the columns */
216 		if (col > 52)
217 		{
218 			addch('\n');
219 			col = 0;
220 		}
221 		else if (col > 26)
222 		{
223 			while (col < 52)
224 			{
225 				qaddch(' ');
226 				col++;
227 			}
228 		}
229 		else if (col > 0)
230 		{
231 			while (col < 26)
232 			{
233 				qaddch(' ');
234 				col++;
235 			}
236 		}
237 
238 		switch (opts[i].type)
239 		{
240 		  case BOOL:
241 			if (!*opts[i].value)
242 			{
243 				qaddch('n');
244 				qaddch('o');
245 				col += 2;
246 			}
247 			qaddstr(opts[i].name);
248 			col += strlen(opts[i].name);
249 			break;
250 
251 		  case NUM:
252 			sprintf(nbuf, "%-3d", UCHAR(*opts[i].value));
253 			qaddstr(opts[i].name);
254 			qaddch('=');
255 			qaddstr(nbuf);
256 			col += 4 + strlen(opts[i].name);
257 			break;
258 
259 		  case STR:
260 			qaddstr(opts[i].name);
261 			qaddch('=');
262 			qaddch('"');
263 			qaddstr(opts[i].value);
264 			qaddch('"');
265 			col += 3 + strlen(opts[i].name) + strlen(opts[i].value);
266 			break;
267 		}
268 		exrefresh();
269 	}
270 	if (col > 0)
271 	{
272 		addch('\n');
273 		exrefresh();
274 	}
275 }
276 
277 /* This function saves the current configuarion of options to a file */
saveopts(fd)278 saveopts(fd)
279 	int	fd;	/* file descriptor to write to */
280 {
281 	int	i;
282 	char	buf[256], *pos;
283 
284 	/* write each set options */
285 	for (i = 0; opts[i].name; i++)
286 	{
287 		/* if unset or unsettable, ignore this option */
288 		if (!(opts[i].flags & SET) || !(opts[i].flags & CANSET))
289 		{
290 			continue;
291 		}
292 
293 		strcpy(buf, "set ");
294 		pos = &buf[4];
295 		switch (opts[i].type)
296 		{
297 		  case BOOL:
298 			if (!*opts[i].value)
299 			{
300 				*pos++='n';
301 				*pos++='o';
302 			}
303 			strcpy(pos, opts[i].name);
304 			strcat(pos, "\n");
305 			break;
306 
307 		  case NUM:
308 			sprintf(pos, "%s=%-3d\n", opts[i].name, *opts[i].value & 0xff);
309 			break;
310 
311 		  case STR:
312 			sprintf(pos, "%s=\"%s\"\n", opts[i].name, opts[i].value);
313 			break;
314 		}
315 		twrite(fd, buf, strlen(buf));
316 	}
317 }
318 
319 
320 /* This function changes the values of one or more options. */
setopts(assignments)321 setopts(assignments)
322 	char	*assignments;	/* a string containing option assignments */
323 {
324 	char	*name;		/* name of variable in assignments */
325 	char	*value;		/* value of the variable */
326 	char	*scan;		/* used for moving through strings */
327 	int	i, j;
328 
329 	/* for each assignment... */
330 	for (name = assignments; *name; )
331 	{
332 		/* skip whitespace */
333 		if (*name == ' ' || *name == '\t')
334 		{
335 			name++;
336 			continue;
337 		}
338 
339 		/* find the value, if any */
340 		for (scan = name; *scan >= 'a' && *scan <= 'z'; scan++)
341 		{
342 		}
343 		if (*scan == '=')
344 		{
345 			*scan++ = '\0';
346 			if (*scan == '"')
347 			{
348 				value = ++scan;
349 				while (*scan && *scan != '"')
350 				{
351 					scan++;
352 				}
353 				if (*scan)
354 				{
355 					*scan++ = '\0';
356 				}
357 			}
358 			else
359 			{
360 				value = scan;
361 				while (*scan && *scan != ' ' && *scan != '\t')
362 				{
363 					scan++;
364 				}
365 				if (*scan)
366 				{
367 					*scan++ = '\0';
368 				}
369 			}
370 		}
371 		else
372 		{
373 			if (*scan)
374 			{
375 				*scan++ = '\0';
376 			}
377 			value = NULL;
378 			if (name[0] == 'n' && name[1] == 'o')
379 			{
380 				name += 2;
381 			}
382 		}
383 
384 		/* find the variable */
385 		for (i = 0;
386 		     opts[i].name && strcmp(opts[i].name, name) && strcmp(opts[i].nm, name);
387 		     i++)
388 		{
389 		}
390 
391 		/* change the variable */
392 		if (!opts[i].name)
393 		{
394 			msg("invalid option name \"%s\"", name);
395 		}
396 		else if ((opts[i].flags & CANSET) != CANSET)
397 		{
398 			msg("option \"%s\" can't be altered", name);
399 		}
400 		else if ((opts[i].flags & RCSET) != CANSET && nlines >= 1L)
401 		{
402 			msg("option \"%s\" can only be set in a %s file", name, EXRC);
403 		}
404 		else if (value)
405 		{
406 			switch (opts[i].type)
407 			{
408 			  case BOOL:
409 				msg("option \"[no]%s\" is boolean", name);
410 				break;
411 
412 			  case NUM:
413 				j = atoi(value);
414 				if (j == 0 && *value != '0')
415 				{
416 					msg("option \"%s\" must have a numeric value", name);
417 				}
418 				else if (j < opts[i].value[1] || j > (opts[i].value[2] & 0xff))
419 				{
420 					msg("option \"%s\" must have a value between %d and %d",
421 						name, opts[i].value[1], opts[i].value[2] & 0xff);
422 				}
423 				else
424 				{
425 					*opts[i].value = atoi(value);
426 					opts[i].flags |= SET;
427 				}
428 				break;
429 
430 			  case STR:
431 				strcpy(opts[i].value, value);
432 				opts[i].flags |= SET;
433 				break;
434 			}
435 			if (opts[i].flags & MR)
436 			{
437 				mustredraw = TRUE;
438 			}
439 		}
440 		else /* valid option, no value */
441 		{
442 			if (opts[i].type == BOOL)
443 			{
444 				*opts[i].value = (name[-1] != 'o');
445 				opts[i].flags |= SET;
446 				if (opts[i].flags & MR)
447 				{
448 					mustredraw = TRUE;
449 				}
450 			}
451 			else
452 			{
453 				msg("option \"%s\" must be given a value", name);
454 			}
455 		}
456 
457 		/* move on to the next option */
458 		name = scan;
459 	}
460 }
461