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_vput.c	1.49 (gritter) 2/15/05";
77
#endif
78
#endif
79
 
80
/* from ex_vput.c	7.4.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
 * Deal with the screen, clearing, cursor positioning, putting characters
88
 * into the screen image, and deleting characters.
89
 * Really hard stuff here is utilizing insert character operations
90
 * on intelligent terminals which differs widely from terminal to terminal.
91
 */
92
void 
93
vclear(void)
94
{
95
 
96
#ifdef ADEBUG
97
	if (trace)
98
		tfixnl(), fprintf(trace, "------\nvclear\n");
99
#endif
100
	tputs(CL, TLINES, putch);
101
	destcol = 0;
102
	outcol = 0;
103
	destline = 0;
104
	outline = 0;
105
	if (inopen)
106
		vclrcell(vtube0, WCOLS * (WECHO - ZERO + 1));
107
}
108
 
109
/*
110
 * Clear memory.
111
 */
112
void 
113
vclrcell(register cell *cp, register int i)
114
{
115
	if (i > 0)
116
		do
117
			*cp++ = 0;
118
		while (--i != 0);
119
}
120
 
121
/*
122
 * Clear a physical display line, high level.
123
 */
124
void 
125
vclrlin(int l, line *tp)
126
{
127
 
128
	vigoto(l, 0);
129
	if ((hold & HOLDAT) == 0)
130
#ifndef	UCVISUAL
131
		putchar(tp > dol ? '~' : '@');
132
#else
133
		putchar(tp > dol ? ((UPPERCASE || xHZ) ? '^' : '~') : '@');
134
#endif
135
	if (state == HARDOPEN)
136
		sethard();
137
	vclreol();
138
}
139
 
140
/*
141
 * Clear to the end of the current physical line
142
 */
143
void
144
vclreol(void)
145
{
146
	register int i, j;
147
	register cell *tp;
148
 
149
	if (destcol == WCOLS)
150
		return;
151
	destline += destcol / WCOLS;
152
	destcol %= WCOLS;
153
	if (destline < 0 || destline > WECHO)
154
		error(catgets(catd, 1, 237, "Internal error: vclreol"));
155
	i = WCOLS - destcol;
156
	tp = vtube[destline] + destcol;
157
	if (CE) {
158
		if (IN && *tp || !ateopr()) {
159
			vcsync();
160
			vputp(CE, 1);
161
		}
162
		vclrcell(tp, i);
163
		return;
164
	}
165
	if (*tp == 0)
166
		return;
167
	while (i > 0 && (j = *tp & (QUOTE|TRIM|MULTICOL))) {
168
		if ((j != ' ' && (j & QUOTE) == 0)) {
169
			destcol = WCOLS - i;
170
			vputchar(' ');
171
		}
172
		--i, *tp++ = 0;
173
	}
174
}
175
 
176
/*
177
 * Clear the echo line.
178
 * If didphys then its been cleared physically (as
179
 * a side effect of a clear to end of display, e.g.)
180
 * so just do it logically.
181
 * If work here is being held off, just remember, in
182
 * heldech, if work needs to be done, don't do anything.
183
 */
184
void
185
vclrech(bool didphys)
186
{
187
 
188
	if (Peekkey == ATTN)
189
		return;
190
	if (hold & HOLDECH) {
191
		heldech = !didphys;
192
		return;
193
	}
194
	if (!didphys && (CD || CE)) {
195
		splitw++;
196
		/*
197
		 * If display is retained below, then MUST use CD or CE
198
		 * since we don't really know whats out there.
199
		 * Vigoto might decide (incorrectly) to do nothing.
200
		 */
201
		if (DB) {
202
			vgoto(WECHO, 0);
203
			vputp(CD ? CD : CE, 1);
204
		} else {
205
			if (XT) {
206
				/*
207
				 * This code basically handles the t1061
208
				 * where positioning at (0, 0) won't work
209
				 * because the terminal won't let you put
210
				 * the cursor on it's magic cookie.
211
				 *
212
				 * Should probably be XS above, or even a
213
				 * new X? glitch, but right now t1061 is the
214
				 * only terminal with XT.
215
				 */
216
				vgoto(WECHO, 0);
217
				vputp(DL, 1);
218
			} else {
219
				vigoto(WECHO, 0);
220
				vclreol();
221
			}
222
		}
223
		splitw = 0;
224
		didphys = 1;
225
	}
226
	if (didphys)
227
		vclrcell(vtube[WECHO], WCOLS);
228
	heldech = 0;
229
}
230
 
231
/*
232
 * Fix the echo area for use, setting
233
 * the state variable splitw so we wont rollup
234
 * when we move the cursor there.
235
 */
236
void
237
fixech(void)
238
{
239
 
240
	splitw++;
241
	if (state != VISUAL && state != CRTOPEN) {
242
		vclean();
243
		vcnt = 0;
244
	}
245
	vgoto(WECHO, 0); flusho();
246
}
247
 
248
/*
249
 * Put the cursor ``before'' cp.
250
 */
251
void
252
vcursbef(register char *cp)
253
{
254
 
255
	if (cp <= linebuf)
256
		vgotoCL(value(NUMBER) << 3);
257
	else
258
		vgotoCL(column(cp - 1) - 1);
259
}
260
 
261
/*
262
 * Put the cursor ``at'' cp.
263
 */
264
void
265
vcursat(register char *cp)
266
{
267
 
268
	if (cp <= linebuf && linebuf[0] == 0)
269
		vgotoCL(value(NUMBER) << 3);
270
	else
271
		vgotoCL(column(cp + skipleft(linebuf, cp)));
272
}
273
 
274
/*
275
 * Put the cursor ``after'' cp.
276
 */
277
void
278
vcursaft(register char *cp)
279
{
280
 
281
	vgotoCL(column(cp));
282
}
283
 
284
/*
285
 * Fix the cursor to be positioned in the correct place
286
 * to accept a command.
287
 */
288
void
289
vfixcurs(void)
290
{
291
 
292
	vsetcurs(cursor);
293
}
294
 
295
/*
296
 * Compute the column position implied by the cursor at ``nc'',
297
 * and move the cursor there.
298
 */
299
void
300
vsetcurs(register char *nc)
301
{
302
	register int col;
303
 
304
	col = column(nc);
305
	if (linebuf[0])
306
		col--;
307
	vgotoCL(col);
308
	cursor = vcolbp;
309
}
310
 
311
/*
312
 * Move the cursor invisibly, i.e. only remember to do it.
313
 */
314
void
315
vigoto(int y, int x)
316
{
317
 
318
	destline = y;
319
	destcol = x;
320
}
321
 
322
/*
323
 * Move the cursor to the position implied by any previous
324
 * vigoto (or low level hacking with destcol/destline as in readecho).
325
 */
326
void
327
vcsync(void)
328
{
329
 
330
	vgoto(destline, destcol);
331
}
332
 
333
/*
334
 * Goto column x of the current line.
335
 */
336
void
337
vgotoCL(register int x)
338
{
339
 
340
	if (splitw)
341
		vgoto(WECHO, x);
342
	else
343
		vgoto(LINE(vcline), x);
344
}
345
 
346
/*
347
 * Invisible goto column x of current line.
348
 */
349
void
350
vigotoCL(register int x)
351
{
352
 
353
	if (splitw)
354
		vigoto(WECHO, x);
355
	else
356
		vigoto(LINE(vcline), x);
357
}
358
 
359
/*
360
 * Move cursor to line y, column x, handling wraparound and scrolling.
361
 */
362
void
363
vgoto(register int y, register int x)
364
{
365
	register cell *tp;
366
	register int c;
367
 
368
	/*
369
	 * Fold the possibly too large value of x.
370
	 */
371
	if (x >= WCOLS) {
372
		y += x / WCOLS;
373
		x %= WCOLS;
374
	}
375
#ifdef	MB
376
	if (y >= 0 && y <= WLINES && mb_cur_max > 1 && !insmode) {
377
		while (x > 0 && (vtube[y][x]&(MULTICOL|TRIM)) == MULTICOL &&
378
				vtube[y][x-1] & MULTICOL &&
379
				(vtube[y][x-1]&(MULTICOL|TRIM)) != MULTICOL)
380
			x--;
381
	}
382
#endif	/* MB */
383
	if (y < 0)
384
		error(catgets(catd, 1, 238, "Internal error: vgoto"));
385
	if (outcol >= WCOLS) {
386
		if (AM) {
387
			outline += outcol / WCOLS;
388
			outcol %= WCOLS;
389
		} else
390
			outcol = WCOLS - 1;
391
	}
392
 
393
	/*
394
	 * In a hardcopy or glass crt open, print the stuff
395
	 * implied by a motion, or backspace.
396
	 */
397
	if (state == HARDOPEN || state == ONEOPEN) {
398
		if (y != outline)
399
			error(catgets(catd, 1, 239, "Line too long for open"));
400
		if (x + 1 < outcol - x || (outcol > x && !BS))
401
			destcol = 0, fgoto();
402
		tp = vtube[WBOT] + outcol;
403
		while (outcol != x)
404
			if (outcol < x) {
405
				if (*tp == 0)
406
					*tp = ' ';
407
				c = *tp++ & TRIM;
408
				vputc(c && (!OS || EO) ? c : ' ');
409
				outcol++;
410
			} else {
411
				if (BC)
412
					vputp(BC, 0);
413
				else
414
					vputc('\b');
415
				outcol--;
416
			}
417
		destcol = outcol = x;
418
		destline = outline;
419
		return;
420
	}
421
 
422
	/*
423
	 * If the destination position implies a scroll, do it.
424
	 */
425
	destline = y;
426
	if (destline > WBOT && (!splitw || destline > WECHO)) {
427
		endim();
428
		vrollup(destline);
429
	}
430
 
431
	/*
432
	 * If there really is a motion involved, do it.
433
	 * The check here is an optimization based on profiling.
434
	 */
435
	destcol = x;
436
	if ((destline - outline) * WCOLS != destcol - outcol) {
437
		if (!MI)
438
			endim();
439
		fgoto();
440
	}
441
}
442
 
443
/*
444
 * This is the hardest code in the editor, and deals with insert modes
445
 * on different kinds of intelligent terminals.  The complexity is due
446
 * to the cross product of three factors:
447
 *
448
 *	1. Lines may display as more than one segment on the screen.
449
 *	2. There are 2 kinds of intelligent terminal insert modes.
450
 *	3. Tabs squash when you insert characters in front of them,
451
 *	   in a way in which current intelligent terminals don't handle.
452
 *
453
 * The two kinds of terminals are typified by the DM2500 or HP2645 for
454
 * one and the CONCEPT-100 or the FOX for the other.
455
 *
456
 * The first (HP2645) kind has an insert mode where the characters
457
 * fall off the end of the line and the screen is shifted rigidly
458
 * no matter how the display came about.
459
 *
460
 * The second (CONCEPT-100) kind comes from terminals which are designed
461
 * for forms editing and which distinguish between blanks and ``spaces''
462
 * on the screen, spaces being like blank, but never having had
463
 * and data typed into that screen position (since, e.g. a clear operation
464
 * like clear screen).  On these terminals, when you insert a character,
465
 * the characters from where you are to the end of the screen shift
466
 * over till a ``space'' is found, and the null character there gets
467
 * eaten up.
468
 *
469
 *
470
 * The code here considers the line as consisting of several parts
471
 * the first part is the ``doomed'' part, i.e. a part of the line
472
 * which is being typed over.  Next comes some text up to the first
473
 * following tab.  The tab is the next segment of the line, and finally
474
 * text after the tab.
475
 *
476
 * We have to consider each of these segments and the effect of the
477
 * insertion of a character on them.  On terminals like HP2645's we
478
 * must simulate a multi-line insert mode using the primitive one
479
 * line insert mode.  If we are inserting in front of a tab, we have
480
 * to either delete characters from the tab or insert white space
481
 * (when the tab reaches a new spot where it gets larger) before we
482
 * insert the new character.
483
 *
484
 * On a terminal like a CONCEPT our strategy is to make all
485
 * blanks be displayed, while trying to keep the screen having ``spaces''
486
 * for portions of tabs.  In this way the terminal hardward does some
487
 * of the hacking for compression of tabs, although this tends to
488
 * disappear as you work on the line and spaces change into blanks.
489
 *
490
 * There are a number of boundary conditions (like typing just before
491
 * the first following tab) where we can avoid a lot of work.  Most
492
 * of them have to be dealt with explicitly because performance is
493
 * much, much worse if we don't.
494
 *
495
 * A final thing which is hacked here is two flavors of insert mode.
496
 * Datamedia's do this by an insert mode which you enter and leave
497
 * and by having normal motion character operate differently in this
498
 * mode, notably by having a newline insert a line on the screen in
499
 * this mode.  This generally means it is unsafe to move around
500
 * the screen ignoring the fact that we are in this mode.
501
 * This is possible on some terminals, and wins big (e.g. HP), so
502
 * we encode this as a ``can move in insert capability'' mi,
503
 * and terminals which have it can do insert mode with much less
504
 * work when tabs are present following the cursor on the current line.
505
 */
506
 
507
/*
508
 * Routine to expand a tab, calling the normal Outchar routine
509
 * to put out each implied character.  Note that we call outchar
510
 * with a QUOTE.  We use QUOTE internally to represent a position
511
 * which is part of the expansion of a tab.
512
 */
513
void
514
vgotab(void)
515
{
516
	register int i = tabcol(destcol, value(TABSTOP)) - destcol;
517
 
518
	do
519
		(*Outchar)(QUOTE);
520
	while (--i);
521
}
522
 
523
/*
524
 * Variables for insert mode.
525
 */
526
int	linend;			/* The column position of end of line */
527
int	tabstart;		/* Column of start of first following tab */
528
int	tabend;			/* Column of end of following tabs */
529
int	tabsize;		/* Size of the following tabs */
530
int	tabslack;		/* Number of ``spaces'' in following tabs */
531
int	inssiz;			/* Number of characters to be inserted */
532
int	inscol;			/* Column where insertion is taking place */
533
int	insmc0;			/* Multi-column character before insertion */
534
int	insmc1;			/* Multi-column character at insertion */
535
int	shft;			/* Amount tab expansion shifted rest of line */
536
int	slakused;		/* This much of tabslack will be used up */
537
 
538
/*
539
 * This routine MUST be called before insert mode is run,
540
 * and brings all segments of the current line to the top
541
 * of the screen image buffer so it is easier for us to
542
 * maniuplate them.
543
 */
544
void
545
vprepins(void)
546
{
547
	register int i;
548
	register cell *cp = vtube0;
549
 
550
	for (i = 0; i < DEPTH(vcline); i++) {
551
		vmaktop(LINE(vcline) + i, cp);
552
		cp += WCOLS;
553
	}
554
}
555
 
556
void
557
vmaktop(register int p, cell *cp)
558
{
559
	register int i;
560
	cell temp[TUBECOLS];
561
 
562
	if (p < 0 || vtube[p] == cp)
563
		return;
564
	for (i = ZERO; i <= WECHO; i++)
565
		if (vtube[i] == cp) {
566
			copy(temp, vtube[i], WCOLS * sizeof *temp);
567
			copy(vtube[i], vtube[p], WCOLS * sizeof *temp);
568
			copy(vtube[p], temp, WCOLS * sizeof *temp);
569
			vtube[i] = vtube[p];
570
			vtube[p] = cp;
571
			return;
572
		}
573
	error(catgets(catd, 1, 240, "Line too long"));
574
}
575
 
576
/*
577
 * Insert character c at current cursor position.
578
 * Multi-character inserts occur only as a result
579
 * of expansion of tabs (i.e. inssize == 1 except
580
 * for tabs) and code assumes this in several place
581
 * to make life simpler.
582
 */
583
int
584
vinschar(int c)
585
/*	int c;		/\* mjm: char --> int */
586
{
587
	register int i;
588
	register cell *tp;
589
	char	*OIM;
590
	bool	OXN;
591
	int	noim, filler = 0;
592
 
593
	insmc1 = colsc(c) - 1;
594
	if ((!IM || !EI) && ((hold & HOLDQIK) || !value(REDRAW) || value(SLOWOPEN))) {
595
		/*
596
		 * Don't want to try to use terminal
597
		 * insert mode, or to try to fake it.
598
		 * Just put the character out; the screen
599
		 * will probably be wrong but we will fix it later.
600
		 */
601
		if (c == '\t') {
602
			vgotab();
603
			return c;
604
		}
605
		vputchar(c);
606
#ifdef	MB
607
		if (insmc1 == 0 && (vtube0[destcol]&(TRIM|MULTICOL))==MULTICOL)
608
			vtube0[destcol] = INVBIT;
609
#endif	/* MB */
610
		if (DEPTH(vcline) * WCOLS + !value(REDRAW) >
611
		    (destline - LINE(vcline)) * WCOLS + destcol)
612
			return c;
613
		/*
614
		 * The next line is about to be clobbered
615
		 * make space for another segment of this line
616
		 * (on an intelligent terminal) or just remember
617
		 * that next line was clobbered (on a dumb one
618
		 * if we don't care to redraw the tail.
619
		 */
620
		if (AL) {
621
			vnpins(0);
622
		} else {
623
			c = LINE(vcline) + DEPTH(vcline);
624
			if (c < LINE(vcline + 1) || c > WBOT)
625
				return c;
626
			i = destcol;
627
			vinslin(c, 1, vcline);
628
			DEPTH(vcline)++;
629
			vigoto(c, i);
630
			vprepins();
631
		}
632
		return c;
633
	}
634
	/*
635
	 * Compute the number of positions in the line image of the
636
	 * current line.  This is done from the physical image
637
	 * since that is faster.  Note that we have no memory
638
	 * from insertion to insertion so that routines which use
639
	 * us don't have to worry about moving the cursor around.
640
	 */
641
	if (*vtube0 == 0)
642
		linend = 0;
643
	else {
644
		/*
645
		 * Search backwards for a non-null character
646
		 * from the end of the displayed line.
647
		 */
648
		i = WCOLS * DEPTH(vcline);
649
		if (i == 0)
650
			i = WCOLS;
651
		tp = vtube0 + i;
652
		while (*--tp == 0)
653
			if (--i == 0)
654
				break;
655
		linend = i + insmc1;
656
	}
657
 
658
	/*
659
	 * We insert at a position based on the physical location
660
	 * of the output cursor.
661
	 */
662
	inscol = destcol + (destline - LINE(vcline)) * WCOLS;
663
	insmc0 = 0;
664
#ifdef	MB
665
	i = 0;
666
	while (inscol+i < LBSIZE && vtube0[inscol+i]&MULTICOL &&
667
			(vtube0[inscol+insmc0+i]&(MULTICOL|TRIM)) != MULTICOL)
668
		i++;
669
	while (inscol+insmc0+i < LBSIZE &&
670
			(vtube0[inscol+insmc0+i]&(MULTICOL|TRIM)) == MULTICOL)
671
		insmc0++;
672
#endif	/* MB */
673
	if (c == '\t') {
674
		/*
675
		 * Characters inserted from a tab must be
676
		 * remembered as being part of a tab, but we can't
677
		 * use QUOTE here since we really need to print blanks.
678
		 * QUOTE|' ' is the representation of this.
679
		 */
680
		inssiz = tabcol(inscol+insmc0, value(TABSTOP)) - inscol - insmc0;
681
		c = ' ' | QUOTE;
682
	} else
683
		inssiz = 1;
684
 
685
	/*
686
	 * If the text to be inserted is less than the number
687
	 * of doomed positions, then we don't need insert mode,
688
	 * rather we can just typeover.
689
	 */
690
	if (inssiz + insmc1 <= doomed) {
691
		endim();
692
		if (inscol + insmc0 != linend)
693
			doomed -= inssiz + insmc1;
694
#ifdef	MB
695
		if (insmc1 == 0 && c != '\t' &&
696
				vtube0[inscol+insmc0] & MULTICOL)
697
			vtube0[inscol+insmc0] = INVBIT;
698
#endif	/* MB */
699
		do
700
			vputchar(c);
701
		while (--inssiz);
702
		return c;
703
	}
704
 
705
	/*
706
	 * Have to really do some insertion, thus
707
	 * stake out the bounds of the first following
708
	 * group of tabs, computing starting position,
709
	 * ending position, and the number of ``spaces'' therein
710
	 * so we can tell how much it will squish.
711
	 */
712
	tp = vtube0 + inscol + insmc0;
713
	for (i = inscol + insmc0; i < linend; i++) {
714
		if (*tp++ & QUOTE) {
715
			--tp;
716
			break;
717
		}
718
	}
719
	tabstart = tabend = i;
720
	tabslack = 0;
721
	while (tabend < linend) {
722
		i = *tp++;
723
		if ((i & QUOTE) == 0)
724
			break;
725
		if ((i & (TRIM|MULTICOL)) == 0)
726
			tabslack++;
727
		tabsize++;
728
		tabend++;
729
	}
730
	tabsize = tabend - tabstart;
731
 
732
	/*
733
	 * For HP's and DM's, e.g. tabslack has no meaning.
734
	 */
735
	if (!IN)
736
		tabslack = 0;
737
#ifdef IDEBUG
738
	if (trace) {
739
		fprintf(trace, "inscol %d, inssiz %d, tabstart %d, ",
740
			inscol, inssiz, tabstart);
741
		fprintf(trace, "tabend %d, tabslack %d, linend %d\n",
742
			tabend, tabslack, linend);
743
	}
744
#endif
745
	OIM = IM;
746
	OXN = XN;
747
	noim = 0;
748
#ifdef	MB
749
	if (mb_cur_max > 1) {
750
		if (destcol + 1 + insmc1 == WCOLS + 1) {
751
			noim = 1;
752
			if (insmc1 == 1 && insmc0 == 0)
753
				filler = 1;
754
		}
755
		for (i = inscol; vtube0[i]; i++)
756
			if (i + 1 >= WCOLS && vtube0[i] & MULTICOL) {
757
				noim = 1;
758
				break;
759
			}
760
	}
761
#endif	/* MB */
762
	if (noim) {
763
		endim();
764
		IM = 0;
765
		XN = 0;
766
	}
767
 
768
	/*
769
	 * The real work begins.
770
	 */
771
	slakused = 0;
772
	shft = 0;
773
	if (tabsize) {
774
		/*
775
		 * There are tabs on this line.
776
		 * If they need to expand, then the rest of the line
777
		 * will have to be shifted over.  In this case,
778
		 * we will need to make sure there are no ``spaces''
779
		 * in the rest of the line (on e.g. CONCEPT-100)
780
		 * and then grab another segment on the screen if this
781
		 * line is now deeper.  We then do the shift
782
		 * implied by the insertion.
783
		 */
784
		if (inssiz >= doomed + tabcol(tabstart, value(TABSTOP)) - tabstart) {
785
			if (IN)
786
				vrigid();
787
			vneedpos(value(TABSTOP));
788
			vishft();
789
		}
790
	} else if (inssiz + insmc1 > doomed)
791
		/*
792
		 * No tabs, but line may still get deeper.
793
		 */
794
		vneedpos(inssiz + insmc1 - doomed);
795
	/*
796
	 * Now put in the inserted characters.
797
	 */
798
	viin(c);
799
 
800
	/*
801
	 * Now put the cursor in its final resting place.
802
	 */
803
	destline = LINE(vcline);
804
	destcol = inscol + inssiz + insmc1 + filler;
805
	vcsync();
806
	if (IM != OIM) {
807
		IM = OIM;
808
		XN = OXN;
809
	}
810
	return c;
811
}
812
 
813
/*
814
 * Rigidify the rest of the line after the first
815
 * group of following tabs, typing blanks over ``spaces''.
816
 */
817
void
818
vrigid(void)
819
{
820
	register int col;
821
	register cell *tp = vtube0 + tabend;
822
 
823
	for (col = tabend; col < linend; col++) {
824
		if ((*tp++ & TRIM) == 0) {
825
			endim();
826
			vgotoCL(col);
827
			vputchar(' ' | QUOTE);
828
		}
829
	}
830
}
831
 
832
/*
833
 * We need cnt more positions on this line.
834
 * Open up new space on the screen (this may in fact be a
835
 * screen rollup).
836
 *
837
 * On a dumb terminal we may infact redisplay the rest of the
838
 * screen here brute force to keep it pretty.
839
 */
840
void
841
vneedpos(int npcnt)
842
{
843
	register int d = DEPTH(vcline);
844
	register int rmdr = d * WCOLS - linend;
845
 
846
	/*
847
	 * Delete the showmode string on wraparound to last line. Cannot use
848
	 * vclrech() since the mode string is printed on the echo area, but
849
	 * not actually a part of it.
850
	 */
851
	if (value(SHOWMODE) && (value(REDRAW) || (IM && EI)) &&
852
			npcnt == rmdr - IN && LINE(vcline) + d == WECHO) {
853
		int sdc, sdl;
854
		char *ocurs;
855
 
856
		endim();
857
		sdc = destcol, sdl = destline, ocurs = cursor;
858
		splitw++;
859
		vgoto(WECHO, 0);
860
		if (CD) {
861
			vputp(CD, 1);
862
		} else if (CE) {
863
			vputp(CE, 1);
864
		} else {
865
			int i;
866
 
867
			for (i = 1; i < WCOLS; i++)
868
				vputchar(' ');
869
		}
870
		destcol = sdc, destline = sdl; cursor = ocurs;
871
		splitw = 0;
872
	}
873
	if (npcnt <= rmdr - IN)
874
		return;
875
	endim();
876
	vnpins(1);
877
}
878
 
879
void
880
vnpins(int dosync)
881
{
882
	register int d = DEPTH(vcline);
883
	register int e;
884
 
885
	e = LINE(vcline) + DEPTH(vcline);
886
	if (e < LINE(vcline + 1)) {
887
		vigoto(e, 0);
888
		vclreol();
889
		return;
890
	}
891
	DEPTH(vcline)++;
892
	if (e < WECHO) {
893
		e = vglitchup(vcline, d);
894
		vigoto(e, 0); vclreol();
895
		if (dosync) {
896
			int (*Ooutchar)() = Outchar;
897
			Outchar = vputchar;
898
			vsync(e + 1);
899
			Outchar = Ooutchar;
900
		}
901
	} else {
902
		vup1();
903
		vigoto(WBOT, 0);
904
		vclreol();
905
	}
906
	vprepins();
907
}
908
 
909
/*
910
 * Do the shift of the next tabstop implied by
911
 * insertion so it expands.
912
 */
913
void
914
vishft(void)
915
{
916
	int tshft = 0;
917
	int j;
918
	register int i;
919
	register cell *tp = vtube0;
920
	register cell *up;
921
	short oldhold = hold;
922
 
923
	shft = value(TABSTOP);
924
	hold |= HOLDPUPD;
925
	if (!IM && !EI) {
926
		/*
927
		 * Dumb terminals are easy, we just have
928
		 * to retype the text.
929
		 */
930
		vigotoCL(tabend + shft);
931
		up = tp + tabend;
932
		for (i = tabend; i < linend; i++)
933
			vputchar(*up++);
934
	} else if (IN) {
935
		/*
936
		 * CONCEPT-like terminals do most of the work for us,
937
		 * we don't have to muck with simulation of multi-line
938
		 * insert mode.  Some of the shifting may come for free
939
		 * also if the tabs don't have enough slack to take up
940
		 * all the inserted characters.
941
		 */
942
		i = shft;
943
		slakused = inssiz - doomed;
944
		if (slakused > tabslack) {
945
			i -= slakused - tabslack;
946
			slakused -= tabslack;
947
		}
948
		if (i > 0 && tabend != linend) {
949
			tshft = i;
950
			vgotoCL(tabend);
951
			goim();
952
			do
953
				vputchar(' ' | QUOTE);
954
			while (--i);
955
		}
956
	} else {
957
		/*
958
		 * HP and Datamedia type terminals have to have multi-line
959
		 * insert faked.  Hack each segment after where we are
960
		 * (going backwards to where we are.)  We then can
961
		 * hack the segment where the end of the first following
962
		 * tab group is.
963
		 */
964
		for (j = DEPTH(vcline) - 1; j > (tabend + shft) / WCOLS; j--) {
965
			vgotoCL(j * WCOLS);
966
			goim();
967
			up = tp + j * WCOLS - shft;
968
			i = shft;
969
			do {
970
				if (*up)
971
					vputchar(*up++);
972
				else
973
					break;
974
			} while (--i);
975
		}
976
		vigotoCL(tabstart);
977
		i = shft - (inssiz - doomed);
978
		if (i > 0) {
979
			tabslack = inssiz - doomed;
980
			vcsync();
981
			goim();
982
			do
983
				vputchar(' ');
984
			while (--i);
985
		}
986
	}
987
	/*
988
	 * Now do the data moving in the internal screen
989
	 * image which is common to all three cases.
990
	 */
991
	tp += linend;
992
	up = tp + shft;
993
	i = linend - tabend;
994
	if (i > 0)
995
		do
996
			*--up = *--tp;
997
		while (--i);
998
	if (IN && tshft) {
999
		i = tshft;
1000
		do
1001
			*--up = ' ' | QUOTE;
1002
		while (--i);
1003
	}
1004
	hold = oldhold;
1005
}
1006
 
1007
/*
1008
 * Now do the insert of the characters (finally).
1009
 */
1010
void
1011
viin(int c)
1012
/*	int c;		/\* mjm: char --> int */
1013
{
1014
	register cell *tp, *up;
1015
	register int i, j;
1016
	register bool noim = 0;
1017
	int remdoom;
1018
	short oldhold = hold;
1019
 
1020
	hold |= HOLDPUPD;
1021
	if (tabsize && (IM && EI) && inssiz - doomed > tabslack)
1022
		/*
1023
		 * There is a tab out there which will be affected
1024
		 * by the insertion since there aren't enough doomed
1025
		 * characters to take up all the insertion and we do
1026
		 * have insert mode capability.
1027
		 */
1028
		if (inscol + insmc0 + doomed == tabstart) {
1029
			/*
1030
			 * The end of the doomed characters sits right at the
1031
			 * start of the tabs, then we don't need to use insert
1032
			 * mode; unless the tab has already been expanded
1033
			 * in which case we MUST use insert mode.
1034
			 */
1035
			slakused = 0;
1036
			noim = !shft;
1037
		} else {
1038
			/*
1039
			 * The last really special case to handle is case
1040
			 * where the tab is just sitting there and doesn't
1041
			 * have enough slack to let the insertion take
1042
			 * place without shifting the rest of the line
1043
			 * over.  In this case we have to go out and
1044
			 * delete some characters of the tab before we start
1045
			 * or the answer will be wrong, as the rest of the
1046
			 * line will have been shifted.  This code means
1047
			 * that terminals with only insert chracter (no
1048
			 * delete character) won't work correctly.
1049
			 */
1050
			i = inssiz - doomed - tabslack - slakused;
1051
			i %= value(TABSTOP);
1052
			if (i > 0) {
1053
				vgotoCL(tabstart);
1054
				godm();
1055
				for (i = inssiz - doomed - tabslack; i > 0; i--)
1056
					vputp(DC, DEPTH(vcline));
1057
				enddm();
1058
			}
1059
		}
1060
 
1061
	/* 
1062
	 * Now put out the characters of the actual insertion.
1063
	 */
1064
	vigotoCL(inscol);
1065
	remdoom = doomed;
1066
	for (i = inssiz; i > 0; i--) {
1067
		if (remdoom > insmc1) {
1068
			remdoom--;
1069
			endim();
1070
		} else if (noim || insmc1 && remdoom == insmc1)
1071
			endim();
1072
		else if (IM && EI) {
1073
			vcsync();
1074
			goim();
1075
		}
1076
		vputchar(c);
1077
	}
1078
 
1079
	if (!IM || !EI || remdoom && remdoom == insmc1) {
1080
		/*
1081
		 * We are a dumb terminal; brute force update
1082
		 * the rest of the line; this is very much an n^^2 process,
1083
		 * and totally unreasonable at low speed.
1084
		 *
1085
		 * You asked for it, you get it.
1086
		 */
1087
		tp = vtube0 + inscol + doomed;
1088
		for (i = inscol + doomed; i < tabstart; i++)
1089
			vputchar(*tp++);
1090
		hold = oldhold;
1091
		vigotoCL(tabstart + inssiz + insmc0 - doomed);
1092
		for (i = tabsize - (inssiz - insmc0 - doomed) + shft;
1093
				i > 0; i--)
1094
			vputchar(' ' | QUOTE);
1095
	} else {
1096
		if (!IN) {
1097
			/*
1098
			 * On terminals without multi-line
1099
			 * insert in the hardware, we must go fix the segments
1100
			 * between the inserted text and the following
1101
			 * tabs, if they are on different lines.
1102
			 *
1103
			 * Aaargh.
1104
			 */
1105
			tp = vtube0;
1106
			for (j = (inscol + insmc0 + inssiz - 1) / WCOLS + 1;
1107
			    j <= (tabstart + inssiz - doomed - 1) / WCOLS; j++) {
1108
				vgotoCL(j * WCOLS);
1109
				i = inssiz - doomed + insmc1;
1110
				up = tp + j * WCOLS - i;
1111
				goim();
1112
				do
1113
					vputchar(*up++);
1114
				while (--i && *up);
1115
			}
1116
		} else {
1117
			/*
1118
			 * On terminals with multi line inserts,
1119
			 * life is simpler, just reflect eating of
1120
			 * the slack.
1121
			 */
1122
			tp = vtube0 + tabend;
1123
			for (i = tabsize - (inssiz + insmc1 - doomed); i >= 0; i--) {
1124
				if ((*--tp & (QUOTE|TRIM)) == QUOTE) {
1125
					--tabslack;
1126
					if (tabslack >= slakused)
1127
						continue;
1128
				}
1129
				*tp = ' ' | QUOTE;
1130
			}
1131
		}
1132
		/*
1133
		 * Blank out the shifted positions to be tab positions.
1134
		 */
1135
		if (shft) {
1136
			tp = vtube0 + tabend + shft;
1137
			for (i = tabsize - (inssiz - doomed) + shft; i > 0; i--)
1138
				if ((*--tp & QUOTE) == 0)
1139
					*tp = ' ' | QUOTE;
1140
		}
1141
	}
1142
 
1143
	/*
1144
	 * Finally, complete the screen image update
1145
	 * to reflect the insertion.
1146
	 */
1147
	hold = oldhold;
1148
	tp = vtube0 + tabstart;
1149
	up = tp + insmc1 + inssiz - doomed;
1150
	for (i = tabstart; i > inscol + doomed; i--)
1151
		*--up = *--tp;
1152
#ifdef	MB
1153
	for (i = insmc1; i > 0; i--)
1154
		*--up = MULTICOL;
1155
#endif
1156
	for (i = inssiz; i > 0; i--)
1157
		*--up = c | (insmc1 ? MULTICOL : 0);
1158
	doomed = 0;
1159
}
1160
 
1161
/*
1162
 * Go into ``delete mode''.  If the
1163
 * sequence which goes into delete mode
1164
 * is the same as that which goes into insert
1165
 * mode, then we are in delete mode already.
1166
 */
1167
void
1168
godm(void)
1169
{
1170
 
1171
	if (insmode) {
1172
		if (eq(DM, IM))
1173
			return;
1174
		endim();
1175
	}
1176
	vputp(DM, 0);
1177
}
1178
 
1179
/*
1180
 * If we are coming out of delete mode, but
1181
 * delete and insert mode end with the same sequence,
1182
 * it wins to pretend we are now in insert mode,
1183
 * since we will likely want to be there again soon
1184
 * if we just moved over to delete space from part of
1185
 * a tab (above).
1186
 */
1187
void
1188
enddm(void)
1189
{
1190
 
1191
	if (eq(DM, IM)) {
1192
		insmode = 1;
1193
		return;
1194
	}
1195
	vputp(ED, 0);
1196
}
1197
 
1198
/*
1199
 * In and out of insert mode.
1200
 * Note that the code here demands that there be
1201
 * a string for insert mode (the null string) even
1202
 * if the terminal does all insertions a single character
1203
 * at a time, since it branches based on whether IM is null.
1204
 */
1205
void
1206
goim(void)
1207
{
1208
 
1209
	if (!insmode)
1210
		vputp(IM, 0);
1211
	insmode = 1;
1212
}
1213
 
1214
void
1215
endim(void)
1216
{
1217
 
1218
	if (insmode) {
1219
		vputp(EI, 0);
1220
		insmode = 0;
1221
	}
1222
}
1223
 
1224
/*
1225
 * Put the character c on the screen at the current cursor position.
1226
 * This routine handles wraparound and scrolling and understands not
1227
 * to roll when splitw is set, i.e. we are working in the echo area.
1228
 * There is a bunch of hacking here dealing with the difference between
1229
 * QUOTE, QUOTE|' ', and ' ' for CONCEPT-100 like terminals, and also
1230
 * code to deal with terminals which overstrike, including CRT's where
1231
 * you can erase overstrikes with some work.  CRT's which do underlining
1232
 * implicitly which has to be erased (like CONCEPTS) are also handled.
1233
 */
1234
int
1235
vputchar(register int c)
1236
{
1237
	register cell *tp;
1238
	register int d, m, n;
1239
 
1240
#ifndef	BIT8
1241
	c &= (QUOTE|TRIM);
1242
#endif
1243
#ifdef TRACE
1244
	if (trace)
1245
		tracec(c);
1246
#endif
1247
	/* Fix problem of >79 chars on echo line. */
1248
	if (destcol >= WCOLS-1 && splitw && destline == WECHO)
1249
		pofix();
1250
#ifdef	MB
1251
	if (mb_cur_max > 1) {
1252
		if (c == MULTICOL)
1253
			return c;
1254
		/*
1255
		 * If a multicolumn character extends beyond the screen
1256
		 * width, it must be put on the next line. A tilde is
1257
		 * printed as an indicator but must disappear when the
1258
		 * text is moved at a later time.
1259
		 */
1260
		if (c == ('~'|INVBIT|QUOTE))
1261
			c = '~'|INVBIT;
1262
		else if (c == ('~'|INVBIT))
1263
			return c;
1264
		else if (destcol < WCOLS && destcol +
1265
				colsc(c==QUOTE ? ' ' : c&TRIM&~MULTICOL) - 1
1266
				>= WCOLS)
1267
			vputchar('~'|INVBIT|QUOTE);
1268
	}
1269
#endif	/* MB */
1270
	if (destcol >= WCOLS) {
1271
		destline += destcol / WCOLS;
1272
		destcol %= WCOLS;
1273
	}
1274
	if (destline > WBOT && (!splitw || destline > WECHO))
1275
		vrollup(destline);
1276
	tp = vtube[destline] + destcol;
1277
	if (c == QUOTE) {
1278
		if (insmode) {
1279
			/*
1280
			 * When in insert mode, tabs have to expand
1281
			 * to real, printed blanks.
1282
			 */
1283
			c = ' ' | QUOTE;
1284
			goto def;
1285
		}
1286
		if (*tp == 0) {
1287
			/*
1288
			 * A ``space''.
1289
			 */
1290
			if ((hold & HOLDPUPD) == 0)
1291
				*tp = QUOTE;
1292
			destcol++;
1293
			return c;
1294
		}
1295
		/*
1296
		 * A ``space'' ontop of a part of a tab.
1297
		 */
1298
		if (*tp & QUOTE) {
1299
			destcol++;
1300
			return c;
1301
		}
1302
		c = ' ' | QUOTE;
1303
		goto def;
1304
	}
1305
 
1306
#ifdef	notdef
1307
#ifdef	BIT8
1308
	if (c == ' ' | QUOTE) {
1309
		c = ' ';
1310
		goto def;
1311
	}
1312
#endif
1313
#endif
1314
	switch (c) {
1315
 
1316
	case '\t':
1317
		vgotab();
1318
		return c;
1319
 
1320
	case ' ':
1321
		/*
1322
		 * We can get away without printing a space in a number
1323
		 * of cases, but not always.  We get away with doing nothing
1324
		 * if we are not in insert mode, and not on a CONCEPT-100
1325
		 * like terminal, and either not in hardcopy open or in hardcopy
1326
		 * open on a terminal with no overstriking, provided,
1327
		 * in all cases, that nothing has ever been displayed
1328
		 * at this position.  Ugh.
1329
		 */
1330
		if (!insmode && !IN && (state != HARDOPEN || OS)
1331
		&& (*tp&QUOTE)) {
1332
			*tp = ' ';
1333
			destcol++;
1334
			return c;
1335
		}
1336
		goto def;
1337
 
1338
def:
1339
	default:
1340
		d = *tp & TRIM;
1341
		/*
1342
		 * Now get away with doing nothing if the characters
1343
		 * are the same, provided we are not in insert mode
1344
		 * and if we are in hardopen, that the terminal has overstrike.
1345
		 */
1346
		if ((d & ~MULTICOL) == (c & TRIM & ~MULTICOL) && !insmode &&
1347
				(state != HARDOPEN || OS) && c != MULTICOL) {
1348
			n = colsc(d);
1349
			for (m = 1; m < n; m++)
1350
				if ((tp[m] & (MULTICOL|TRIM)) != MULTICOL)
1351
					break;
1352
			if (m == n) {
1353
				if ((hold & HOLDPUPD) == 0)
1354
					*tp = c | (n > 1 ? MULTICOL : 0);
1355
				destcol += n;
1356
				return c;
1357
			}
1358
		}
1359
		/*
1360
		 * Backwards looking optimization.
1361
		 * The low level cursor motion routines will use
1362
		 * a cursor motion right sequence to step 1 character
1363
		 * right.  On, e.g., a DM3025A this is 2 characters
1364
		 * and printing is noticeably slower at 300 baud.
1365
		 * Since the low level routines are not allowed to use
1366
		 * spaces for positioning, we discover the common
1367
		 * case of a single space here and force a space
1368
		 * to be printed.
1369
		 */
1370
		if (destcol == outcol + 1 && tp[-1] == ' ' && outline == destline) {
1371
			vputc(' ');
1372
			outcol++;
1373
		}
1374
 
1375
		/*
1376
		 * This is an inline expansion a call to vcsync() dictated
1377
		 * by high frequency in a profile.
1378
		 */
1379
		if (outcol != destcol || outline != destline)
1380
			vgoto(destline, destcol);
1381
 
1382
		/*
1383
		 * Deal with terminals which have overstrike.
1384
		 * We handle erasing general overstrikes, erasing
1385
		 * underlines on terminals (such as CONCEPTS) which
1386
		 * do underlining correctly automatically (e.g. on nroff
1387
		 * output), and remembering, in hardcopy mode,
1388
		 * that we have overstruct something.
1389
		 */
1390
		if (!insmode && d && d != ' ' && d != (c & TRIM)) {
1391
			if (EO && (OS || UL && (c == '_' || d == '_'))) {
1392
				vputc(' ');
1393
				outcol++, destcol++;
1394
				back1();
1395
			} else
1396
				rubble = 1;
1397
		}
1398
 
1399
		/*
1400
		 * Unless we are just bashing characters around for
1401
		 * inner working of insert mode, update the display.
1402
		 */
1403
		if ((hold & HOLDPUPD) == 0)
1404
			*tp = c;
1405
 
1406
		/*
1407
		 * In insert mode, put out the IC sequence, padded
1408
		 * based on the depth of the current line.
1409
		 * A terminal which had no real insert mode, rather
1410
		 * opening a character position at a time could do this.
1411
		 * Actually should use depth to end of current line
1412
		 * but this rarely matters.
1413
		 */
1414
#ifdef	notdef
1415
		if (insmode)
1416
#else
1417
		/*
1418
		 * It seems today's termcap writers consider this
1419
		 * an either-or situation; if both im and ic
1420
		 * are used vi puts out additional spaces.
1421
		 *
1422
		 * SVR4 ex does not include this change. If it hits
1423
		 * your terminal, change back to the old way and
1424
		 * mail me a description.
1425
		 *
1426
		 * GR July 2000
1427
		 */
1428
		if (insmode && (!IM || !*IM))
1429
#endif	/* !notdef */
1430
		{
1431
			n = colsc(c&TRIM);
1432
			for (m = 0; m < n; m++)
1433
				vputp(IC, DEPTH(vcline));
1434
		}
1435
		vputc(c & TRIM);
1436
 
1437
		/*
1438
		 * In insert mode, IP is a post insert pad.
1439
		 */
1440
		if (insmode)
1441
			vputp(IP, DEPTH(vcline));
1442
		destcol++, outcol++;
1443
 
1444
		/*
1445
		 * CONCEPT braindamage in early models:  after a wraparound
1446
		 * the next newline is eaten.  It's hungry so we just
1447
		 * feed it now rather than worrying about it.
1448
		 * Fixed to use	return linefeed to work right
1449
		 * on vt100/tab132 as well as concept.
1450
		 */
1451
		if (XN && outcol % WCOLS == 0) {
1452
			vputc('\r');
1453
			vputc('\n');
1454
		}
1455
	}
1456
#ifdef	MB
1457
	if (mb_cur_max > 1 && (d = colsc(c&TRIM&~MULTICOL)) > 1) {
1458
		if ((hold & HOLDPUPD) == 0)
1459
			*tp |= MULTICOL;
1460
		while (--d) {
1461
			if ((hold & HOLDPUPD) == 0)
1462
				*++tp = MULTICOL;
1463
			destcol++;
1464
			outcol++;
1465
		}
1466
	}
1467
#endif	/* MB */
1468
	return c;
1469
}
1470
 
1471
/*
1472
 * Delete display positions stcol through endcol.
1473
 * Amount of use of special terminal features here is limited.
1474
 */
1475
void
1476
physdc(int stcol, int endcol)
1477
{
1478
	register cell *tp, *up;
1479
	cell *tpe = NULL;
1480
	register int i;
1481
	register int nc = endcol - stcol;
1482
 
1483
#ifdef IDEBUG
1484
	if (trace)
1485
		tfixnl(), fprintf(trace, "physdc(%d, %d)\n", stcol, endcol);
1486
#endif
1487
	if (!DC || nc <= 0)
1488
		return;
1489
	if (IN) {
1490
		/*
1491
		 * CONCEPT-100 like terminal.
1492
		 * If there are any ``spaces'' in the material to be
1493
		 * deleted, then this is too hard, just retype.
1494
		 */
1495
		vprepins();
1496
		up = vtube0 + stcol;
1497
		i = nc;
1498
		do {
1499
			if ((*up++ & (QUOTE|TRIM)) == QUOTE)
1500
				return;
1501
		} while (--i);
1502
		i = 2 * nc;
1503
		do {
1504
			if (*up == 0 || (*up++ & QUOTE) == QUOTE)
1505
				return;
1506
		} while (--i);
1507
		vgotoCL(stcol);
1508
	} else {
1509
		/*
1510
		 * HP like delete mode.
1511
		 * Compute how much text we are moving over by deleting.
1512
		 * If it appears to be faster to just retype
1513
		 * the line, do nothing and that will be done later.
1514
		 * We are assuming 2 output characters per deleted
1515
		 * characters and that clear to end of line is available.
1516
		 */
1517
		i = stcol / WCOLS;
1518
		if (i != endcol / WCOLS)
1519
			return;
1520
		i += LINE(vcline);
1521
		stcol %= WCOLS;
1522
		endcol %= WCOLS;
1523
		up = vtube[i]; tp = up + endcol; tpe = up + WCOLS;
1524
		while (tp < tpe && *tp)
1525
			tp++;
1526
		if (tp - (up + stcol) < 2 * nc)
1527
			return;
1528
		vgoto(i, stcol);
1529
	}
1530
 
1531
	/*
1532
	 * Go into delete mode and do the actual delete.
1533
	 * Padding is on DC itself.
1534
	 */
1535
	godm();
1536
	for (i = nc; i > 0; i--)
1537
		vputp(DC, DEPTH(vcline));
1538
	vputp(ED, 0);
1539
 
1540
	/*
1541
	 * Straighten up.
1542
	 * With CONCEPT like terminals, characters are pulled left
1543
	 * from first following null.  HP like terminals shift rest of
1544
	 * this (single physical) line rigidly.
1545
	 */
1546
	if (IN) {
1547
		up = vtube0 + stcol;
1548
		tp = vtube0 + endcol;
1549
		while (i = *tp++) {
1550
			if ((i & (QUOTE|TRIM)) == QUOTE)
1551
				break;
1552
			*up++ = i;
1553
		}
1554
		do
1555
			*up++ = i;
1556
		while (--nc);
1557
	} else {
1558
		copy(up + stcol, up + endcol,
1559
				(WCOLS - endcol) * sizeof *up);
1560
		vclrcell(tpe - nc, nc);
1561
	}
1562
}
1563
 
1564
#ifdef TRACE
1565
void
1566
tfixnl(void)
1567
{
1568
 
1569
	if (trubble || techoin)
1570
		fprintf(trace, "\n");
1571
	trubble = 0, techoin = 0;
1572
}
1573
 
1574
void
1575
tvliny(void)
1576
{
1577
	register int i;
1578
 
1579
	if (!trace)
1580
		return;
1581
	tfixnl();
1582
	fprintf(trace, "vcnt = %d, vcline = %d, vliny = ", vcnt, vcline);
1583
	for (i = 0; i <= vcnt; i++) {
1584
		fprintf(trace, "%d", LINE(i));
1585
		if (FLAGS(i) & VDIRT)
1586
			fprintf(trace, "*");
1587
		if (DEPTH(i) != 1)
1588
			fprintf(trace, "<%d>", DEPTH(i));
1589
		if (i < vcnt)
1590
			fprintf(trace, " ");
1591
	}
1592
	fprintf(trace, "\n");
1593
}
1594
 
1595
void
1596
tracec(int c)
1597
/*	int c;		/\* mjm: char --> int */
1598
{
1599
 
1600
	if (!techoin)
1601
		trubble = 1;
1602
	if (c == ESCAPE)
1603
		fprintf(trace, "$");
1604
	else if (c & QUOTE)	/* mjm: for 3B (no sign extension) */
1605
		fprintf(trace, "~%c", ctlof(c&TRIM));
1606
	else if (c < ' ' || c == DELETE)
1607
		fprintf(trace, "^%c", ctlof(c));
1608
	else
1609
		fprintf(trace, "%c", c);
1610
}
1611
#endif
1612
 
1613
/*
1614
 * Put a character with possible tracing.
1615
 */
1616
int
1617
vputch(int c)
1618
{
1619
 
1620
#ifdef TRACE
1621
	if (trace)
1622
		tracec(c);
1623
#endif
1624
	return vputc(c);
1625
}