xref: /illumos-gate/usr/src/cmd/vi/port/ex_set.c (revision 55fea89d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27 /*	  All Rights Reserved  	*/
28 
29 
30 /* Copyright (c) 1981 Regents of the University of California */
31 
32 #include "ex.h"
33 #include "ex_temp.h"
34 #include "ex_tty.h"
35 
36 /*
37  * Set command.
38  */
39 unsigned char	optname[ONMSZ];
40 
41 void
set(void)42 set(void)
43 {
44 	unsigned char *cp;
45 	struct option *op;
46 	int c;
47 	bool no;
48 	extern short ospeed;
49 #ifdef TRACE
50 	int k, label;
51 	line *tmpadr;
52 #endif
53 
54 	setnoaddr();
55 	if (skipend()) {
56 		if (peekchar() != EOF)
57 			ignchar();
58 		propts();
59 		return;
60 	}
61 	do {
62 		cp = optname;
63 		do {
64 			if (cp < &optname[ONMSZ - 2])
65 				*cp++ = getchar();
66 		} while (isalnum(peekchar()));
67 		*cp = 0;
68 		cp = optname;
69 		if (eq("all", cp)) {
70 			if (inopen)
71 				pofix();
72 			prall();
73 			goto next;
74 		}
75 		no = 0;
76 #ifdef TRACE
77  		/*
78  		 * General purpose test code for looking at address of those
79  		 * invisible marks (as well as the visible ones).
80  		 */
81  		if (eq("marks", cp)) {
82 			viprintf("Marks   Address\n\r");
83 			viprintf("					\n");
84 			viprintf("\n");
85 			for (k = 0; k <= 25; k++)
86 				viprintf("Mark:%c\t%d\n", k+'a', names[k]);
87  		goto next;
88  		}
89 
90 		/*
91 		 * General purpose test code for looking at
92 		 * named registers.
93 		 */
94 
95 		if (eq("named",cp)) {
96 			if (inopen)
97 				pofix();
98 			shownam();
99 			goto next;
100 		}
101 
102 		/*
103 	   	 * General purpose test code for looking at
104 		 * numbered registers.
105 		 */
106 
107 		if (eq("nbrreg",cp)) {
108 			if (inopen)
109 				pofix();
110 			shownbr();
111 			goto next;
112 		}
113 
114 		/*
115  		 * General purpose test code for looking at addresses
116 		 * in the edit and save areas of VI.
117  		 */
118 
119  		if (eq("buffers",cp)) {
120  			if (inopen)
121 				pofix();
122 			viprintf("\nLabels   Address	Contents\n");
123  			viprintf("======   =======	========");
124 			for (tmpadr = zero; tmpadr <= dol; tmpadr++) {
125  				label =0;
126 				if (tmpadr == zero) {
127 					viprintf("ZERO:\t");
128  					label = 2;
129  				}
130  				if (tmpadr == one) {
131 					if (label > 0)
132 						viprintf("\nONE:\t");
133 					else
134 						viprintf("ONE:\t");
135  					label = 1;
136  				}
137  				if (tmpadr == dot) {
138 					if (label > 0)
139 						viprintf("\nDOT:\t");
140 					else
141 						viprintf("DOT:\t");
142  					label = 1;
143  				}
144  				if (tmpadr == undap1) {
145  					if (label > 0)
146 						viprintf("\nUNDAP1:\t");
147  					else
148 						viprintf("UNDAP1:\t");
149  					label = 1;
150  				}
151  				if (tmpadr == undap2) {
152  					if (label > 0)
153 						viprintf("\nUNDAP2:\t");
154  					else
155 						viprintf("UNDAP2:\t");
156  					label = 1;
157  				}
158  				if (tmpadr == unddel) {
159  					if (label > 0)
160 						viprintf("\nUNDDEL:\t");
161  					else
162 						viprintf("UNDDEL:\t");
163  					label = 1;
164  				}
165  				if (tmpadr == dol) {
166  					if (label > 0)
167 						viprintf("\nDOL:\t");
168  					else
169 						viprintf("DOL:\t");
170  					label = 1;
171  				}
172  				for (k=0; k<=25; k++)
173  					if (names[k] == (*tmpadr &~ 01)) {
174  						if (label > 0)
175 							viprintf(
176 "\nMark:%c\t%d\t", k+'a', names[k]);
177  						else
178 							viprintf(
179 "Mark:%c\t%d\t", k+'a', names[k]);
180  						label=1;
181  					}
182  				if (label == 0)
183  					continue;
184 
185  				if (label == 2)
186 					viprintf("%d\n", tmpadr);
187  				else  {
188 					viprintf("%d\t", tmpadr);
189  					getaline(*tmpadr);
190  					pline(lineno(tmpadr));
191  					putchar('\n');
192  				}
193  			}
194 
195  			for (tmpadr = dol+1; tmpadr <= unddol; tmpadr++) {
196  				label =0;
197  				if (tmpadr == dol+1) {
198 					viprintf("DOL+1:\t");
199  					label = 1;
200  				}
201  				if (tmpadr == unddel) {
202  					if (label > 0)
203 						viprintf("\nUNDDEL:\t");
204  					else
205 						viprintf("UNDDEL:\t");
206  					label = 1;
207  				}
208  				if (tmpadr == unddol) {
209  					if (label > 0)
210 						viprintf("\nUNDDOL:\t");
211  					else
212 						viprintf("UNDDOL:\t");
213  					label = 1;
214  				}
215  				for (k=0; k<=25; k++)
216  					if (names[k] == (*tmpadr &~ 01)) {
217  						if (label > 0)
218 							viprintf(
219 "\nMark:%c\t%d\t", k+'a', names[k]);
220  						else
221 							viprintf(
222 "Mark:%c\t%d\t", k+'a', names[k]);
223  						label=1;
224  					}
225  				if (label == 0)
226  					continue;
227  				if (label == 2)
228 					viprintf("%d\n", tmpadr);
229  				else  {
230 					viprintf("%d\t", tmpadr);
231  					getaline(*tmpadr);
232  					pline(lineno(tmpadr));
233  					putchar('\n');
234  				}
235  			}
236  			goto next;
237  		}
238 #endif
239 		if (cp[0] == 'n' && cp[1] == 'o' && cp[2] != 'v') {
240 			cp += 2;
241 			no++;
242 		}
243 		/* Implement w300, w1200, and w9600 specially */
244 		if (eq(cp, "w300")) {
245 			if (ospeed >= B1200) {
246 dontset:
247 				(void)getchar();	/* = */
248 				(void)getnum();	/* value */
249 				continue;
250 			}
251 			cp = (unsigned char *)"window";
252 		} else if (eq(cp, "w1200")) {
253 			if (ospeed < B1200 || ospeed >= B2400)
254 				goto dontset;
255 			cp = (unsigned char *)"window";
256 		} else if (eq(cp, "w9600")) {
257 			if (ospeed < B2400)
258 				goto dontset;
259 			cp = (unsigned char *)"window";
260 		}
261 		for (op = options; op < &options[vi_NOPTS]; op++)
262 			if (eq(op->oname, cp) || op->oabbrev && eq(op->oabbrev, cp))
263 				break;
264 		if (op->oname == 0)
265 			serror(value(vi_TERSE) ? (unsigned char *)
266 			    gettext("%s: No such option") :
267 			    (unsigned char *)
268 gettext("%s: No such option - 'set all' gives all option values"), cp);
269 		c = skipwh();
270 		if (peekchar() == '?') {
271 			ignchar();
272 printone:
273 			propt(op);
274 			noonl();
275 			goto next;
276 		}
277 		if (op->otype == ONOFF) {
278 			op->ovalue = 1 - no;
279 			if (op == &options[vi_PROMPT])
280 				oprompt = 1 - no;
281 			goto next;
282 		}
283 		if (no)
284 			serror((unsigned char *)
285 			    gettext("Option %s is not a toggle"), op->oname);
286 		if (c != 0 || setend())
287 			goto printone;
288 		if (getchar() != '=')
289 			serror(value(vi_TERSE) ? (unsigned char *)
290 			    gettext("Missing =") :
291 			    (unsigned char *)
292 			    gettext("Missing = in assignment to option %s"),
293 			    op->oname);
294 		switch (op->otype) {
295 
296 		case NUMERIC:
297 			if (!isdigit(peekchar()))
298 				error(value(vi_TERSE) ?
299 gettext("Digits required") : gettext("Digits required after ="));
300 			op->ovalue = getnum();
301 			if (value(vi_TABSTOP) <= 0)
302 				value(vi_TABSTOP) = TABS;
303 			if (op == &options[vi_WINDOW]) {
304 				if (value(vi_WINDOW) >= lines)
305 					value(vi_WINDOW) = lines-1;
306 				vsetsiz(value(vi_WINDOW));
307 			}
308 			break;
309 
310 		case STRING:
311 		case OTERM:
312 			cp = optname;
313 			while (!setend()) {
314 				if (cp >= &optname[ONMSZ])
315 					error(value(vi_TERSE) ?
316 gettext("String too long") : gettext("String too long in option assignment"));
317 				/* adb change:  allow whitepace in strings */
318 				if( (*cp = getchar()) == '\\')
319 					if( peekchar() != EOF)
320 						*cp = getchar();
321 				cp++;
322 			}
323 			*cp = 0;
324 			if (op->otype == OTERM) {
325 /*
326  * At first glance it seems like we shouldn't care if the terminal type
327  * is changed inside visual mode, as long as we assume the screen is
328  * a mess and redraw it. However, it's a much harder problem than that.
329  * If you happen to change from 1 crt to another that both have the same
330  * size screen, it's OK. But if the screen size if different, the stuff
331  * that gets initialized in vop() will be wrong. This could be overcome
332  * by redoing the initialization, e.g. making the first 90% of vop into
333  * a subroutine. However, the most useful case is where you forgot to do
334  * a setenv before you went into the editor and it thinks you're on a dumb
335  * terminal. Ex treats this like hardcopy and goes into HARDOPEN mode.
336  * This loses because the first part of vop calls oop in this case.
337  */
338 				if (inopen)
339 error(gettext("Can't change type of terminal from within open/visual"));
340 				unterm();
341 				setterm(optname);
342 			} else {
343 				CP(op->osvalue, optname);
344 				op->odefault = 1;
345 			}
346 			break;
347 		}
348 next:
349 		flush();
350 	} while (!skipend());
351 	eol();
352 }
353 
354 void
unterm(void)355 unterm(void)
356 {
357 	/*
358 	 *  All terminal mapped statements must be deleted.
359 	 *  All user-defined mapped statements, cap=descr,
360 	 *  are left unchanged.
361 	 */
362 
363 	int i;
364 
365 	for (i=0; i < MAXNOMACS; i++) {
366 
367 		/*
368 		 * Unmap any terminal-defined arrow keys
369 		 */
370 
371 		if (arrows[i].cap && arrows[i].descr &&
372 		    strcmp(arrows[i].cap, arrows[i].descr))
373 			addmac(arrows[i].cap, NOSTR, NOSTR, arrows);
374 
375 		/*
376 		 * Unmap any terminal-defined function keys
377 		 */
378 
379 		if (immacs[i].cap && immacs[i].descr && strcmp(immacs[i].cap, immacs[i].descr))
380 			addmac(immacs[i].cap, NOSTR, NOSTR, immacs);
381 
382 	}
383 }
384 
385 
386 int
setend(void)387 setend(void)
388 {
389 
390 	return (iswhite(peekchar()) || endcmd(peekchar()));
391 }
392 
393 void
prall(void)394 prall(void)
395 {
396 	int incr = (vi_NOPTS + 2) / 3;
397 	int rows = incr;
398 	struct option *op = options;
399 
400 	for (; rows; rows--, op++) {
401 		propt(op);
402 		gotab(24);
403 		propt(&op[incr]);
404 		if (&op[2*incr] < &options[vi_NOPTS]) {
405 			gotab(56);
406 			propt(&op[2 * incr]);
407 		}
408 		putNFL();
409 	}
410 }
411 
412 void
propts(void)413 propts(void)
414 {
415 	struct option *op;
416 
417 	for (op = options; op < &options[vi_NOPTS]; op++) {
418 		if (op == &options[vi_TTYTYPE])
419 			continue;
420 		switch (op->otype) {
421 
422 		case ONOFF:
423 		case NUMERIC:
424 			if (op->ovalue == op->odefault)
425 				continue;
426 			break;
427 
428 		case STRING:
429 			if (op->odefault == 0)
430 				continue;
431 			break;
432 		}
433 		propt(op);
434 		putchar(' ');
435 	}
436 	noonl();
437 	flush();
438 }
439 
440 void
propt(struct option * op)441 propt(struct option *op)
442 {
443 	unsigned char *name;
444 
445 	name = (unsigned char *)op->oname;
446 
447 	switch (op->otype) {
448 
449 	case ONOFF:
450 		viprintf("%s%s", op->ovalue ? "" : "no", name);
451 		break;
452 
453 	case NUMERIC:
454 		viprintf("%s=%d", name, op->ovalue);
455 		break;
456 
457 	case STRING:
458 	case OTERM:
459 		viprintf("%s=%s", name, op->osvalue);
460 		break;
461 	}
462 }
463