Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
99 7u83 1
/*
2
 * This code contains changes by
3
 *      Gunnar Ritter, Freiburg i. Br., Germany, 2002. All rights reserved.
4
 *
5
 * Conditions 1, 2, and 4 and the no-warranty notice below apply
6
 * to these changes.
7
 *
8
 *
9
 * Copyright (c) 1980, 1993
10
 * 	The Regents of the University of California.  All rights reserved.
11
 *
12
 * Redistribution and use in source and binary forms, with or without
13
 * modification, are permitted provided that the following conditions
14
 * are met:
15
 * 1. Redistributions of source code must retain the above copyright
16
 *    notice, this list of conditions and the following disclaimer.
17
 * 2. Redistributions in binary form must reproduce the above copyright
18
 *    notice, this list of conditions and the following disclaimer in the
19
 *    documentation and/or other materials provided with the distribution.
20
 * 3. All advertising materials mentioning features or use of this software
21
 *    must display the following acknowledgement:
22
 * 	This product includes software developed by the University of
23
 * 	California, Berkeley and its contributors.
24
 * 4. Neither the name of the University nor the names of its contributors
25
 *    may be used to endorse or promote products derived from this software
26
 *    without specific prior written permission.
27
 *
28
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38
 * SUCH DAMAGE.
39
 *
40
 *
41
 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
42
 *
43
 * Redistribution and use in source and binary forms, with or without
44
 * modification, are permitted provided that the following conditions
45
 * are met:
46
 *   Redistributions of source code and documentation must retain the
47
 *    above copyright notice, this list of conditions and the following
48
 *    disclaimer.
49
 *   Redistributions in binary form must reproduce the above copyright
50
 *    notice, this list of conditions and the following disclaimer in the
51
 *    documentation and/or other materials provided with the distribution.
52
 *   All advertising materials mentioning features or use of this software
53
 *    must display the following acknowledgement:
54
 *      This product includes software developed or owned by Caldera
55
 *      International, Inc.
56
 *   Neither the name of Caldera International, Inc. nor the names of
57
 *    other contributors may be used to endorse or promote products
58
 *    derived from this software without specific prior written permission.
59
 *
60
 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
61
 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
62
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
63
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
64
 * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
65
 * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
66
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
67
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
68
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
69
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
70
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
71
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
72
 */
73
 
74
#ifndef	lint
75
#ifdef	DOSCCS
76
static char sccsid[] = "@(#)ex_put.c	1.32 (gritter) 2/17/05";
77
#endif
78
#endif
79
 
80
/* from ex_put.c	7.9.1 (2.11BSD GTE) 12/9/94 */
81
 
82
#include "ex.h"
83
#include "ex_tty.h"
84
#include "ex_vis.h"
85
 
86
/*
87
 * Terminal driving and line formatting routines.
88
 * Basic motion optimizations are done here as well
89
 * as formatting of lines (printing of control characters,
90
 * line numbering and the like).
91
 */
92
 
93
/*
94
 * The routines outchar, putchar and pline are actually
95
 * variables, and these variables point at the current definitions
96
 * of the routines.  See the routine setflav.
97
 * We sometimes make outchar be routines which catch the characters
98
 * to be printed, e.g. if we want to see how long a line is.
99
 * During open/visual, outchar and putchar will be set to
100
 * routines in the file ex_vput.c (vputchar, vinschar, etc.).
101
 */
102
int	(*Outchar)(int) = termchar;
103
int	(*Putchar)(int) = normchar;
104
void	(*Pline)(int) = normline;
105
 
106
int (*
107
setlist(int t))(int)
108
{
109
	register int (*P)(int);
110
 
111
	listf = t;
112
	P = Putchar;
113
	Putchar = t ? listchar : normchar;
114
	return (P);
115
}
116
 
117
void (*
118
setnumb(int t))(int)
119
{
120
	register void (*P)(int);
121
 
122
	numberf = t;
123
	P = Pline;
124
	Pline = t ? numbline : normline;
125
	return (P);
126
}
127
 
128
/*
129
 * Format c for list mode; leave things in common
130
 * with normal print mode to be done by normchar.
131
 */
132
int 
133
listchar(int c)
134
{
135
 
136
	if (c & MULTICOL) {
137
		c &= ~MULTICOL;
138
		if (c == 0)
139
			return MULTICOL;
140
	}
141
	c &= (TRIM|QUOTE);
142
	switch (c) {
143
	case '\t':
144
	case '\b':
145
		c = ctlof(c);
146
		outchar('^');
147
		break;
148
 
149
	case '\n':
150
		break;
151
 
152
	default:
153
		if (c == ('\n' | QUOTE))
154
			outchar('$');
155
		if (c & QUOTE)
156
			break;
157
#ifndef	BIT8
158
		if (c < ' ' && c != '\n')
159
			outchar('^'), c = ctlof(c);
160
#else	/* !BIT8 */
161
		if (!printable(c) && c != '\n' || c == DELETE)
162
			c = printof(c);
163
#endif
164
		break;
165
	}
166
	return normchar(c);
167
}
168
 
169
/*
170
 * Format c for printing. Handle funnies of upper case terminals
171
 * and crocky hazeltines which don't have ~.
172
 */
173
int
174
normchar(register int c)
175
{
176
	int	u;
177
 
178
#ifdef	UCVISUAL
179
	register char *colp;
180
 
181
	if (c == '~' && xHZ) {
182
		normchar('\\');
183
		c = '^';
184
	}
185
#endif
186
 
187
	if (c & MULTICOL) {
188
		c &= ~MULTICOL;
189
		if (c == 0)
190
			return MULTICOL;
191
	}
192
	c &= (TRIM|QUOTE);
193
	u = c & TRIM;
194
	if (c & QUOTE) {
195
		if (c == (' ' | QUOTE) || c == ('\b' | QUOTE))
196
			/*EMPTY*/;
197
		else if (c == QUOTE)
198
			return c;
199
		else
200
			c &= TRIM;
201
	}
202
#ifdef	BIT8
203
	else {
204
		if (!printable(c) && (u != '\b' || !OS) &&
205
				u != '\n' && u != '\t')
206
			c = printof(u);
207
		else {
208
			c = u;
209
			if (0)
210
				/*EMPTY*/;
211
#else	/* !BIT8 */
212
	else if (c < ' ' && (c != '\b' || !OS) && c != '\n' && c != '\t')
213
		putchar('^'), c = ctlof(c);
214
#endif	/* !BIT8 */
215
#ifdef	UCVISUAL
216
	else if (UPPERCASE)
217
		if (xisupper(c)) {
218
			outchar('\\');
219
			c = tolower(c);
220
		} else {
221
			colp = "({)}!|^~'`";
222
			while (*colp++)
223
				if (c == *colp++) {
224
					outchar('\\');
225
					c = colp[-2];
226
					break;
227
				}
228
		}
229
#endif	/* UCVISUAL */
230
#ifdef	BIT8
231
		}
232
	}
233
#endif
234
	outchar(c);
235
	return c;
236
}
237
 
238
/*
239
 * Given c at the beginning of a line, determine whether
240
 * the printing of the line will erase or otherwise obliterate
241
 * the prompt which was printed before.  If it won't, do it now.
242
 */
243
void
244
slobber(int c)
245
{
246
 
247
	shudclob = 0;
248
	switch (c) {
249
 
250
	case '\t':
251
		if (Putchar == listchar)
252
			return;
253
		break;
254
 
255
	default:
256
		return;
257
 
258
	case ' ':
259
	case 0:
260
		break;
261
	}
262
	if (OS)
263
		return;
264
	flush();
265
	putch(' ');
266
	if (BC)
267
		tputs(BC, 0, putch);
268
	else
269
		putch('\b');
270
}
271
 
272
/*
273
 * Print a line with a number.
274
 */
275
void
276
numbline(int i)
277
{
278
 
279
	if (shudclob)
280
		slobber(' ');
281
	printf("%6d  ", i);
282
	normline(0);
283
}
284
 
285
/*
286
 * Normal line output, no numbering.
287
 */
288
/*ARGSUSED*/
289
void
290
normline(int unused)
291
{
292
	register char *cp;
293
	int	c, n;
294
 
295
	if (shudclob)
296
		slobber(linebuf[0]);
297
	/* pdp-11 doprnt is not reentrant so can't use "printf" here
298
	   in case we are tracing */
299
	cp = linebuf;
300
	vcolbp = cp;
301
	while (*cp) {
302
		vcolbp = cp;
303
		nextc(c, cp, n);
304
		cp += n;
305
		putchar(c);
306
	}
307
	if (!inopen) {
308
		putchar('\n' | QUOTE);
309
	}
310
}
311
 
312
/*
313
 * The output buffer is initialized with a useful error
314
 * message so we don't have to keep it in data space.
315
 */
316
static	char linb[66+MB_LEN_MAX];
317
char *linp = linb;
318
 
319
/*
320
 * Phadnl records when we have already had a complete line ending with \n.
321
 * If another line starts without a flush, and the terminal suggests it,
322
 * we switch into -nl mode so that we can send lineffeeds to avoid
323
 * a lot of spacing.
324
 */
325
static	bool phadnl;
326
 
327
/*
328
 * Indirect to current definition of putchar.
329
 */
330
int
331
putchar(int c)
332
{
333
	if (c & MULTICOL) {
334
		c &= ~MULTICOL;
335
		if (c == 0)
336
			return MULTICOL;
337
	}
338
	(*Putchar)(c);
339
	return c;
340
}
341
 
342
/*
343
 * Termchar routine for command mode.
344
 * Watch for possible switching to -nl mode.
345
 * Otherwise flush into next level of buffering when
346
 * small buffer fills or at a newline.
347
 */
348
int
349
termchar(int c)
350
{
351
 
352
	if (pfast == 0 && phadnl)
353
		pstart();
354
	if (c == '\n')
355
		phadnl = 1;
356
	else if (linp >= &linb[63])
357
		flush1();
358
#ifdef	MB
359
	if (mb_cur_max > 1 && c & ~(wchar_t)0177) {
360
		char	mb[MB_LEN_MAX];
361
		int	i, n;
362
		n = wctomb(mb, c&TRIM);
363
		for (i = 0; i < n; i++)
364
			*linp++ = mb[i];
365
	} else
366
#endif	/* MB */
367
		*linp++ = c;
368
	if (linp >= &linb[63]) {
369
		fgoto();
370
		flush1();
371
	}
372
	return c;
373
}
374
 
375
void
376
flush2(void)
377
{
378
 
379
	fgoto();
380
	flusho();
381
	pstop();
382
}
383
 
384
void
385
flush(void)
386
{
387
 
388
	flush1();
389
	flush2();
390
}
391
 
392
/*
393
 * Flush from small line buffer into output buffer.
394
 * Work here is destroying motion into positions, and then
395
 * letting fgoto do the optimized motion.
396
 */
397
void
398
flush1(void)
399
{
400
	register char *lp;
401
	int c, n;
402
 
403
	*linp = 0;
404
	lp = linb;
405
	while (*lp) {
406
		nextc(c, lp, n);
407
		lp += n;
408
		switch (c) {
409
 
410
		case '\r':
411
			destline += destcol / TCOLUMNS;
412
			destcol = 0;
413
			continue;
414
 
415
		case '\b':
416
			if (destcol)
417
				destcol--;
418
			continue;
419
 
420
		case ' ':
421
			destcol++;
422
			continue;
423
 
424
		case '\t':
425
			destcol += value(TABSTOP) - destcol % value(TABSTOP);
426
			continue;
427
 
428
		case '\n':
429
			destline += destcol / TCOLUMNS + 1;
430
			if (destcol != 0 && destcol % TCOLUMNS == 0)
431
				destline--;
432
			destcol = 0;
433
			continue;
434
 
435
		default:
436
			fgoto();
437
			for (;;) {
438
				if (AM == 0 && outcol == TCOLUMNS)
439
					fgoto();
440
				c &= TRIM;
441
				putch(c);
442
				if (c == '\b') {
443
					outcol--;
444
					destcol--;
445
#ifndef	BIT8
446
				} else if ( c >= ' ' && c != DELETE) {
447
#else
448
				} else if (printable(c)) {
449
#endif
450
#ifdef	MB
451
					n = colsc(c);
452
					outcol += n;
453
					destcol += n;
454
#else	/* !MB */
455
					outcol++;
456
					destcol++;
457
#endif	/* !MB */
458
					if (XN && outcol % TCOLUMNS == 0)
459
						putch('\r'), putch('\n');
460
				}
461
				nextc(c, lp, n);
462
				lp += n;
463
#ifndef BIT8
464
				if (c <= ' ')
465
#else
466
				if (c == ' ' || !printable(c))
467
#endif
468
					break;
469
			}
470
			--lp;
471
			continue;
472
		}
473
	}
474
	linp = linb;
475
}
476
 
477
static int plodcnt, plodflg;
478
 
479
/*
480
 * Move (slowly) to destination.
481
 * Hard thing here is using home cursor on really deficient terminals.
482
 * Otherwise just use cursor motions, hacking use of tabs and overtabbing
483
 * and backspace.
484
 */
485
 
486
int
487
plodput(int c)
488
{
489
 
490
	if (plodflg)
491
		plodcnt--;
492
	else
493
		putch(c);
494
	return c;
495
}
496
 
497
int
498
plod(int cnt)
499
{
500
	register int i, j, k = 0;
501
	register int soutcol, soutline;
502
 
503
	plodcnt = plodflg = cnt;
504
	soutcol = outcol;
505
	soutline = outline;
506
	/*
507
	 * Consider homing and moving down/right from there, vs moving
508
	 * directly with local motions to the right spot.
509
	 */
510
	if (HO) {
511
		/*
512
		 * i is the cost to home and tab/space to the right to
513
		 * get to the proper column.  This assumes ND space costs
514
		 * 1 char.  So i+destcol is cost of motion with home.
515
		 */
516
		if (GT)
517
			i = (destcol / value(HARDTABS)) + (destcol % value(HARDTABS));
518
		else
519
			i = destcol;
520
		/*
521
		 * j is cost to move locally without homing
522
		 */
523
		if (destcol >= outcol) {	/* if motion is to the right */
524
			j = destcol / value(HARDTABS) - outcol / value(HARDTABS);
525
			if (GT && j)
526
				j += destcol % value(HARDTABS);
527
			else
528
				j = destcol - outcol;
529
		} else
530
			/* leftward motion only works if we can backspace. */
531
			if (outcol - destcol <= i && (BS || BC))
532
				i = j = outcol - destcol; /* cheaper to backspace */
533
			else
534
				j = i + 1; /* impossibly expensive */
535
 
536
		/* k is the absolute value of vertical distance */
537
		k = outline - destline;
538
		if (k < 0)
539
			k = -k;
540
		j += k;
541
 
542
		/*
543
		 * Decision.  We may not have a choice if no UP.
544
		 */
545
		if (i + destline < j || (!UP && destline < outline)) {
546
			/*
547
			 * Cheaper to home.  Do it now and pretend it's a
548
			 * regular local motion.
549
			 */
550
			tputs(HO, 0, plodput);
551
			outcol = outline = 0;
552
		} else if (LL) {
553
			/*
554
			 * Quickly consider homing down and moving from there.
555
			 * Assume cost of LL is 2.
556
			 */
557
			k = (TLINES - 1) - destline;
558
			if (i + k + 2 < j && (k<=0 || UP)) {
559
				tputs(LL, 0, plodput);
560
				outcol = 0;
561
				outline = TLINES - 1;
562
			}
563
		}
564
	} else
565
	/*
566
	 * No home and no up means it's impossible, so we return an
567
	 * incredibly big number to make cursor motion win out.
568
	 */
569
		if (!UP && destline < outline)
570
			return (500);
571
	if (GT)
572
		i = destcol % value(HARDTABS)
573
		    + destcol / value(HARDTABS);
574
	else
575
		i = destcol;
576
/*
577
	if (BT && outcol > destcol && (j = (((outcol+7) & ~7) - destcol - 1) >> 3)) {
578
		j *= (k = strlen(BT));
579
		if ((k += (destcol&7)) > 4)
580
			j += 8 - (destcol&7);
581
		else
582
			j += k;
583
	} else
584
*/
585
		j = outcol - destcol;
586
	/*
587
	 * If we will later need a \n which will turn into a \r\n by
588
	 * the system or the terminal, then don't bother to try to \r.
589
	 */
590
	if ((NONL || !pfast) && outline < destline)
591
		goto dontcr;
592
	/*
593
	 * If the terminal will do a \r\n and there isn't room for it,
594
	 * then we can't afford a \r.
595
	 */
596
	if (NC && outline >= destline)
597
		goto dontcr;
598
	/*
599
	 * If it will be cheaper, or if we can't back up, then send
600
	 * a return preliminarily.
601
	 */
602
	if (j > i + 1 || outcol > destcol && !BS && !BC) {
603
		/*
604
		 * BUG: this doesn't take the (possibly long) length
605
		 * of xCR into account.
606
		 */
607
		if (ospeed != B0) {
608
			if (xCR)
609
				tputs(xCR, 0, plodput);
610
			else
611
				plodput('\r');
612
		}
613
		if (NC) {
614
			if (xNL)
615
				tputs(xNL, 0, plodput);
616
			else
617
				plodput('\n');
618
			outline++;
619
		}
620
		outcol = 0;
621
	}
622
dontcr:
623
	/* Move down, if necessary, until we are at the desired line */
624
	while (outline < destline) {
625
		j = destline - outline;
626
		if (j > costDP && DOWN_PARM) {
627
			/* Win big on Tek 4025 */
628
			tputs(tgoto(DOWN_PARM, 0, j), j, plodput);
629
			outline += j;
630
		}
631
		else {
632
			outline++;
633
			if (xNL && pfast)
634
				tputs(xNL, 0, plodput);
635
			else
636
				plodput('\n');
637
		}
638
		if (plodcnt < 0)
639
			goto out;
640
		if (NONL || pfast == 0)
641
			outcol = 0;
642
	}
643
	if (BT)
644
		k = strlen(BT);	/* should probably be cost(BT) and moved out */
645
	/* Move left, if necessary, to desired column */
646
	while (outcol > destcol) {
647
		if (plodcnt < 0)
648
			goto out;
649
		if (BT && !insmode && outcol - destcol > 4+k) {
650
			tputs(BT, 0, plodput);
651
			outcol--;
652
			outcol -= outcol % value(HARDTABS); /* outcol &= ~7; */
653
			continue;
654
		}
655
		j = outcol - destcol;
656
		if (j > costLP && LEFT_PARM) {
657
			tputs(tgoto(LEFT_PARM, 0, j), j, plodput);
658
			outcol -= j;
659
		}
660
		else {
661
			outcol--;
662
			if (BC)
663
				tputs(BC, 0, plodput);
664
			else
665
				plodput('\b');
666
		}
667
	}
668
	/* Move up, if necessary, to desired row */
669
	while (outline > destline) {
670
		j = outline - destline;
671
		if (UP_PARM && j > 1) {
672
			/* Win big on Tek 4025 */
673
			tputs(tgoto(UP_PARM, 0, j), j, plodput);
674
			outline -= j;
675
		}
676
		else {
677
			outline--;
678
			tputs(UP, 0, plodput);
679
		}
680
		if (plodcnt < 0)
681
			goto out;
682
	}
683
	/*
684
	 * Now move to the right, if necessary.  We first tab to
685
	 * as close as we can get.
686
	 */
687
	if (GT && !insmode && destcol - outcol > 1) {
688
		/* tab to right as far as possible without passing col */
689
		for (;;) {
690
			i = tabcol(outcol, value(HARDTABS));
691
			if (i > destcol)
692
				break;
693
			if (TA)
694
				tputs(TA, 0, plodput);
695
			else
696
				plodput('\t');
697
			outcol = i;
698
		}
699
		/* consider another tab and then some backspaces */
700
		if (destcol - outcol > 4 && i < TCOLUMNS && (BC || BS)) {
701
			if (TA)
702
				tputs(TA, 0, plodput);
703
			else
704
				plodput('\t');
705
			outcol = i;
706
			/*
707
			 * Back up.  Don't worry about LEFT_PARM because
708
			 * it's never more than 4 spaces anyway.
709
			 */
710
			while (outcol > destcol) {
711
				outcol--;
712
				if (BC)
713
					tputs(BC, 0, plodput);
714
				else
715
					plodput('\b');
716
			}
717
		}
718
	}
719
	/*
720
	 * We've tabbed as much as possible.  If we still need to go
721
	 * further (not exact or can't tab) space over.  This is a
722
	 * very common case when moving to the right with space.
723
	 */
724
	while (outcol < destcol) {
725
		j = destcol - outcol;
726
		if (j > costRP && RIGHT_PARM) {
727
			/*
728
			 * This probably happens rarely, if at all.
729
			 * It seems mainly useful for ANSI terminals
730
			 * with no hardware tabs, and I don't know
731
			 * of any such terminal at the moment.
732
			 */
733
			tputs(tgoto(RIGHT_PARM, 0, j), j, plodput);
734
			outcol += j;
735
		}
736
		else {
737
			/*
738
			 * move one char to the right.  We don't use ND space
739
			 * because it's better to just print the char we are
740
			 * moving over.  There are various exceptions, however.
741
			 * If !inopen, vtube contains garbage.  If the char is
742
			 * a null or a tab we want to print a space.  Other
743
			 * random chars we use space for instead, too.
744
			 */
745
			if (!inopen || vtube[outline]==NULL ||
746
#ifndef	BIT8
747
				((i=vtube[outline][outcol]) < ' ')
748
#else
749
				((i=vtube[outline][outcol]) == 0)
750
					|| (i!=MULTICOL && !printable(i&~INVBIT&~MULTICOL))
751
#endif
752
				)
753
				i = ' ';
754
			if((i & (QUOTE|INVBIT)) == QUOTE) /* mjm: no sign
755
							     extension on 3B */
756
				i = ' ';
757
			if ((insmode || i == MULTICOL) && ND)
758
				tputs(ND, 0, plodput);
759
			else if (i == MULTICOL) {
760
				if (BS && BC)
761
					tputs(BC, 0, plodput);
762
				else
763
					plodput('\b');
764
				plodput(vtube[outline][outcol-1]);
765
			} else
766
				plodput(i);
767
			outcol += i == MULTICOL ? 1 : colsc(i & ~MULTICOL);
768
		}
769
		if (plodcnt < 0)
770
			goto out;
771
	}
772
out:
773
	if (plodflg) {
774
		outcol = soutcol;
775
		outline = soutline;
776
	}
777
	return(plodcnt);
778
}
779
 
780
/*
781
 * Sync the position of the output cursor.
782
 * Most work here is rounding for terminal boundaries getting the
783
 * column position implied by wraparound or the lack thereof and
784
 * rolling up the screen to get destline on the screen.
785
 */
786
void
787
fgoto(void)
788
{
789
	register int l, c;
790
 
791
	if (destcol > TCOLUMNS - 1) {
792
		destline += destcol / TCOLUMNS;
793
		destcol %= TCOLUMNS;
794
	}
795
	if (outcol > TCOLUMNS - 1) {
796
		l = (outcol + 1) / TCOLUMNS;
797
		outline += l;
798
		outcol %= TCOLUMNS;
799
		if (AM == 0) {
800
			while (l > 0) {
801
				if (pfast && ospeed != B0)
802
					if (xCR)
803
						tputs(xCR, 0, putch);
804
					else
805
						putch('\r');
806
				if (xNL)
807
					tputs(xNL, 0, putch);
808
				else
809
					putch('\n');
810
				l--;
811
			}
812
			outcol = 0;
813
		}
814
		if (outline > TLINES - 1) {
815
			destline -= outline - (TLINES - 1);
816
			outline = TLINES - 1;
817
		}
818
	}
819
	if (destline > TLINES - 1) {
820
		l = destline;
821
		destline = TLINES - 1;
822
		if (outline < TLINES - 1) {
823
			c = destcol;
824
			if (pfast == 0 && (!CA || holdcm))
825
				destcol = 0;
826
			fgoto();
827
			destcol = c;
828
		}
829
		while (l > TLINES - 1) {
830
			/*
831
			 * The following linefeed (or simulation thereof)
832
			 * is supposed to scroll up the screen, since we
833
			 * are on the bottom line.  We make the assumption
834
			 * that linefeed will scroll.  If ns is in the
835
			 * capability list this won't work.  We should
836
			 * probably have an sc capability but sf will
837
			 * generally take the place if it works.
838
			 *
839
			 * Superbee glitch:  in the middle of the screen we
840
			 * have to use esc B (down) because linefeed screws up
841
			 * in "Efficient Paging" (what a joke) mode (which is
842
			 * essential in some SB's because CRLF mode puts garbage
843
			 * in at end of memory), but you must use linefeed to
844
			 * scroll since down arrow won't go past memory end.
845
			 * I turned this off after recieving Paul Eggert's
846
			 * Superbee description which wins better.
847
			 */
848
			if (xNL /* && !XB */ && pfast)
849
				tputs(xNL, 0, putch);
850
			else
851
				putch('\n');
852
			l--;
853
			if (pfast == 0)
854
				outcol = 0;
855
		}
856
	}
857
	if (destline < outline && !(CA && !holdcm || UP != NOSTR))
858
		destline = outline;
859
	if (CA && !holdcm)
860
		if (plod(costCM) > 0)
861
			plod(0);
862
		else
863
			tputs(tgoto(CM, destcol, destline), 0, putch);
864
	else
865
		plod(0);
866
	outline = destline;
867
	outcol = destcol;
868
}
869
 
870
/*
871
 * Tab to column col by flushing and then setting destcol.
872
 * Used by "set all".
873
 */
874
void
875
tab(int col)
876
{
877
 
878
	flush1();
879
	destcol = col;
880
}
881
 
882
/*
883
 * An input line arrived.
884
 * Calculate new (approximate) screen line position.
885
 * Approximate because kill character echoes newline with
886
 * no feedback and also because of long input lines.
887
 */
888
void
889
noteinp(void)
890
{
891
 
892
	outline++;
893
	if (outline > TLINES - 1)
894
		outline = TLINES - 1;
895
	destline = outline;
896
	destcol = outcol = 0;
897
}
898
 
899
/*
900
 * Something weird just happened and we
901
 * lost track of whats happening out there.
902
 * Since we cant, in general, read where we are
903
 * we just reset to some known state.
904
 * On cursor addressible terminals setting to unknown
905
 * will force a cursor address soon.
906
 */
907
void
908
termreset(void)
909
{
910
 
911
	endim();
912
	if (TI)	/* otherwise it flushes anyway, and 'set tty=dumb' vomits */
913
		putpad(TI);	 /*adb change -- emit terminal initial sequence */
914
	destcol = 0;
915
	destline = TLINES - 1;
916
	if (CA) {
917
		outcol = UKCOL;
918
		outline = UKCOL;
919
	} else {
920
		outcol = destcol;
921
		outline = destline;
922
	}
923
}
924
 
925
/*
926
 * Low level buffering, with the ability to drain
927
 * buffered output without printing it.
928
 */
929
char	*obp = obuf;
930
 
931
void
932
draino(void)
933
{
934
 
935
	obp = obuf;
936
}
937
 
938
void
939
flusho(void)
940
{
941
 
942
	if (obp != obuf) {
943
		write(1, obuf, obp - obuf);
944
		obp = obuf;
945
	}
946
}
947
 
948
void
949
putnl(void)
950
{
951
 
952
	putchar('\n');
953
}
954
 
955
void
956
putS(char *cp)
957
{
958
 
959
	if (cp == NULL)
960
		return;
961
	while (*cp)
962
		putch(*cp++);
963
}
964
 
965
 
966
int
967
putch(int c)
968
{
969
 
970
#ifdef OLD3BTTY		/* mjm */
971
	if(c == '\n')	/* mjm: Fake "\n\r" for '\n' til fix in 3B firmware */
972
		putch('\r');	/* mjm: vi does "stty -icanon" => -onlcr !! */
973
#endif
974
	if (c & MULTICOL) {
975
		c &= ~MULTICOL;
976
		if (c == 0)
977
			return MULTICOL;
978
	}
979
	c &= ~INVBIT;	/* strip '~' | INVBIT multicolumn filler */
980
#ifdef	MB
981
	if (mb_cur_max > 1 && c & ~(wchar_t)0177) {
982
		char	mb[MB_LEN_MAX];
983
		int	i, n;
984
		n = wctomb(mb, c&TRIM);
985
		for (i = 0; i < n; i++) {
986
			*obp++ = mb[i];
987
			if (obp >= &obuf[sizeof obuf])
988
				flusho();
989
		}
990
	} else
991
#endif	/* MB */
992
		*obp++ = c & TRIM;
993
	if (obp >= &obuf[sizeof obuf])
994
		flusho();
995
	return c;
996
}
997
 
998
/*
999
 * Miscellaneous routines related to output.
1000
 */
1001
 
1002
/*
1003
 * Put with padding
1004
 */
1005
void
1006
putpad(char *cp)
1007
{
1008
 
1009
	flush();
1010
	tputs(cp, 0, putch);
1011
}
1012
 
1013
/*
1014
 * Set output through normal command mode routine.
1015
 */
1016
void
1017
setoutt(void)
1018
{
1019
 
1020
	Outchar = termchar;
1021
}
1022
 
1023
/*
1024
 * Printf (temporarily) in list mode.
1025
 */
1026
/*VARARGS2*/
1027
void
1028
vlprintf(char *cp, va_list ap)
1029
{
1030
	register int (*P)();
1031
 
1032
	P = setlist(1);
1033
	vprintf(cp, ap);
1034
	Putchar = P;
1035
}
1036
 
1037
void
1038
lprintf(char *cp, ...)
1039
{
1040
	va_list ap;
1041
 
1042
	va_start(ap, cp);
1043
	vlprintf(cp, ap);
1044
	va_end(ap);
1045
}
1046
 
1047
/*
1048
 * Newline + flush.
1049
 */
1050
void
1051
putNFL(void)
1052
{
1053
 
1054
	putnl();
1055
	flush();
1056
}
1057
 
1058
/*
1059
 * sTTY: set the tty modes on file descriptor i to be what's
1060
 * currently in global "tty".  (Also use nttyc if needed.)
1061
 */
1062
void
1063
sTTY(int i)
1064
{
1065
 
1066
	tcsetattr(i, TCSADRAIN, &tty);
1067
}
1068
 
1069
/*
1070
 * Try to start -nl mode.
1071
 */
1072
void
1073
pstart(void)
1074
{
1075
 
1076
	if (NONL)
1077
		return;
1078
 	if (!value(OPTIMIZE))
1079
		return;
1080
	if (ruptible == 0 || pfast)
1081
		return;
1082
	fgoto();
1083
	flusho();
1084
	pfast = 1;
1085
	normtty++;
1086
	tty = normf;
1087
	tty.c_oflag &= ~(ONLCR
1088
#if defined (TAB3)
1089
			| TAB3
1090
#elif defined (XTABS)
1091
			| XTABS
1092
#endif
1093
			);
1094
	tty.c_lflag &= ~ECHO;
1095
	sTTY(1);
1096
}
1097
 
1098
/*
1099
 * Stop -nl mode.
1100
 */
1101
void
1102
pstop(void)
1103
{
1104
 
1105
	if (inopen)
1106
		return;
1107
	phadnl = 0;
1108
	linp = linb;
1109
	draino();
1110
	normal(normf);
1111
	pfast &= ~1;
1112
}
1113
 
1114
/*
1115
 * Turn off start/stop chars if they aren't the default ^S/^Q.
1116
 * This is so idiots who make esc their start/stop don't lose.
1117
 * We always turn off quit since datamedias send ^\ for their
1118
 * right arrow key.
1119
 */
1120
void
1121
ttcharoff(void)
1122
{
1123
#ifdef	_PC_VDISABLE
1124
	long vdis;
1125
 
1126
	errno = 0;
1127
#ifndef	__dietlibc__
1128
	vdis = fpathconf(1, _PC_VDISABLE);
1129
	if (errno)
1130
		/*
1131
		 * Use the old value of 0377, hope it is not
1132
		 * the user's favourite character.
1133
		 */
1134
#endif	/* !__dietlibc__ */
1135
		vdis = '\377';
1136
#else	/* !_PC_VDISABLE */
1137
#define	vdis	'\377';
1138
#endif	/* !_PC_VDISABLE */
1139
	tty.c_cc[VQUIT] = vdis;
1140
#ifdef	VSUSP
1141
	tty.c_cc[VSUSP] = vdis;
1142
#endif
1143
#ifdef	VDSUSP
1144
	tty.c_cc[VDSUSP] = vdis;
1145
#endif
1146
#ifdef	VREPRINT
1147
	tty.c_cc[VREPRINT] = vdis;
1148
#endif
1149
#ifdef	VDISCRD
1150
	tty.c_cc[VDISCRD] = vdis;
1151
#endif
1152
#ifdef	VWERASE
1153
	tty.c_cc[VWERASE] = vdis;
1154
#endif
1155
#ifdef	VLNEXT
1156
	tty.c_cc[VLNEXT] = vdis;
1157
#endif
1158
#ifdef	VSTATUS
1159
	tty.c_cc[VSTATUS] = vdis;
1160
#endif
1161
# ifdef VSTART
1162
	/*
1163
	 * The following is sample code if USG ever lets people change
1164
	 * their start/stop chars.  As long as they can't we can't get
1165
	 * into trouble so we just leave them alone.
1166
	 */
1167
	if (tty.c_cc[VSTART] != CTRL('q'))
1168
		tty.c_cc[VSTART] = vdis;
1169
	if (tty.c_cc[VSTOP] != CTRL('s'))
1170
		tty.c_cc[VSTOP] = vdis;
1171
# endif
1172
}
1173
 
1174
/*
1175
 * Prep tty for open mode.
1176
 */
1177
struct termios
1178
ostart(void)
1179
{
1180
	struct termios f;
1181
 
1182
	if (!intty)
1183
		error(catgets(catd, 1, 120,
1184
				"Open and visual must be used interactively"));
1185
	gTTY(1);
1186
	normtty++;
1187
	f = tty;
1188
	tty = normf;
1189
	tty.c_iflag &= ~ICRNL;
1190
	tty.c_lflag &= ~(ECHO|ICANON);
1191
	tty.c_oflag &= ~(ONLCR
1192
#if defined (TAB3)
1193
			| TAB3
1194
#elif defined (XTABS)
1195
			| XTABS
1196
#endif
1197
			);
1198
	tty.c_cc[VMIN] = 1;
1199
	tty.c_cc[VTIME] = 1;
1200
	ttcharoff();
1201
	sTTY(1);
1202
	tostart();
1203
	pfast |= 2;
1204
	return (f);
1205
}
1206
 
1207
/* actions associated with putting the terminal in open mode */
1208
void
1209
tostart(void)
1210
{
1211
	putpad(VS);
1212
	putpad(KS);
1213
	if (!value(MESG)) {
1214
		if (ttynbuf[0] == 0) {
1215
			register char *tn;
1216
			if ((tn=ttyname(2)) == NULL &&
1217
			    (tn=ttyname(1)) == NULL &&
1218
			    (tn=ttyname(0)) == NULL)
1219
				ttynbuf[0] = 1;
1220
			else
1221
				safecp(ttynbuf, tn, sizeof ttynbuf,
1222
						"%s too long", tn);
1223
		}
1224
		if (ttynbuf[0] != 1) {
1225
			struct stat sbuf;
1226
			stat(ttynbuf, &sbuf);
1227
			ttymesg = sbuf.st_mode & 0777;
1228
			chmod(ttynbuf,
1229
#ifdef UCBV7
1230
	/*
1231
	 * This applies to the UCB V7 Pdp-11 system with the
1232
	 * -u write option only.
1233
	 */
1234
					0611	/* 11 = urgent only allowed */
1235
#else
1236
					0600
1237
#endif
1238
						);
1239
		}
1240
	}
1241
}
1242
 
1243
/*
1244
 * Stop open, restoring tty modes.
1245
 */
1246
void
1247
ostop(struct termios f)
1248
{
1249
 
1250
	pfast = (f.c_oflag & ONLCR) == 0;
1251
	termreset(), fgoto(), flusho();
1252
	normal(f);
1253
	tostop();
1254
}
1255
 
1256
/* Actions associated with putting the terminal in the right mode. */
1257
void
1258
tostop(void)
1259
{
1260
	putpad(VE);
1261
	putpad(KE);
1262
	if (!value(MESG) && ttynbuf[0]>1)
1263
		chmod(ttynbuf, ttymesg);
1264
}
1265
 
1266
/*
1267
 * Restore flags to normal state f.
1268
 */
1269
void
1270
normal(struct termios f)
1271
{
1272
 
1273
	if (normtty > 0) {
1274
		setty(f);
1275
		normtty--;
1276
	}
1277
}
1278
 
1279
/*
1280
 * Straight set of flags to state f.
1281
 */
1282
struct termios
1283
setty(struct termios f)
1284
{
1285
	struct termios ot;
1286
	ot = tty;
1287
 
1288
	if (tty.c_lflag & ICANON)
1289
		ttcharoff();
1290
	tty = f;
1291
	sTTY(1);
1292
	return (ot);
1293
}
1294
 
1295
void
1296
gTTY(int i)
1297
{
1298
 
1299
	tcgetattr(i, &tty);
1300
}
1301
 
1302
/*
1303
 * Print newline, or blank if in open/visual
1304
 */
1305
void
1306
noonl(void)
1307
{
1308
 
1309
	putchar(Outchar != termchar ? ' ' : '\n');
1310
}