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