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 */
39unsigned char	optname[ONMSZ];
40
41void
42set(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) {
246dontset:
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 *)
268gettext("%s: No such option - 'set all' gives all option values"), cp);
269		c = skipwh();
270		if (peekchar() == '?') {
271			ignchar();
272printone:
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) ?
299gettext("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) ?
316gettext("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)
339error(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		}
348next:
349		flush();
350	} while (!skipend());
351	eol();
352}
353
354void
355unterm(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
386int
387setend(void)
388{
389
390	return (iswhite(peekchar()) || endcmd(peekchar()));
391}
392
393void
394prall(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
412void
413propts(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
440void
441propt(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