1 /* $Id: random.c,v 1.4.2.3 2001/07/23 18:15:56 amura Exp $ */
2 /*
3  *		Assorted commands.
4  * The file contains the command
5  * processors for a large assortment of unrelated
6  * commands. The only thing they have in common is
7  * that they are all command processors.
8  */
9 
10 /*
11  * $Log: random.c,v $
12  * Revision 1.4.2.3  2001/07/23 18:15:56  amura
13  * now buffers have only one mark (before windows have one mark)
14  *
15  * Revision 1.4.2.2  2001/07/23 18:01:30  amura
16  * fix mark handling when make newline on the mark position
17  *
18  * Revision 1.4.2.1  2001/06/19 18:09:38  amura
19  * add correcting mark position when yank empty line
20  *
21  * Revision 1.4  2000/09/04 20:46:10  amura
22  * fix yank() bug appeared from rev 1.3
23  *
24  * Revision 1.3  2000/09/01 19:44:25  amura
25  * dirty hack for speed optimize of "yank"
26  *
27  * Revision 1.2  2000/06/27 01:49:45  amura
28  * import to CVS
29  *
30  * Revision 1.1  2000/06/01  05:35:32  amura
31  * Initial revision
32  *
33  */
34 /* 90.01.29	Modified for Ng 1.0 by S.Yoshida */
35 /* 91.11.30     Modified by bsh */
36 
37 #include	"config.h"	/* 90.12.20  by S.Yoshida */
38 #include	"def.h"
39 #ifdef	UNDO
40 #include	"undo.h"
41 #endif
42 
43 /*
44  * Display a bunch of useful information about
45  * the current location of dot. The character under the
46  * cursor (in octal), the current line, row, and column, and
47  * approximate position of the cursor in the file (as a percentage)
48  * is displayed. The column position assumes an infinite position
49  * display; it does not truncate just because the screen does.
50  * This is normally bound to "C-X =".
51  */
52 /*ARGSUSED*/
showcpos(f,n)53 showcpos(f, n)
54 {
55 	register LINE	*clp;
56 	register long	nchar;
57 	long		cchar=0;
58 	register int	nline, row;
59 	int		cline=0, cbyte=0;	/* Current line/char/byte */
60 	int		ratio;
61 	int		x, y;
62 
63 	clp = lforw(curbp->b_linep);		/* Collect the data.	*/
64 	nchar = 0;
65 	nline = 0;
66 	for (;;) {
67 		++nline;			/* Count this line	*/
68 		if (clp == curwp->w_dotp) {
69 			cline = nline;		/* Mark line		*/
70 			cchar = nchar + curwp->w_doto;
71 			if (curwp->w_doto == llength(clp))
72 				cbyte = '\n';
73 			else
74 				cbyte = lgetc(clp, curwp->w_doto);
75 		}
76 		nchar += llength(clp);		/* Now count the chars	*/
77 		clp = lforw(clp);
78 		if (clp == curbp->b_linep) break;
79 		nchar++;			/* count the newline	*/
80 	}
81 	row = curwp->w_toprow + 1;		/* Determine row.	*/
82 	clp = curwp->w_linep;
83 	while (clp!=curbp->b_linep && clp!=curwp->w_dotp) {
84 		row += countlines(clp);
85 		clp = lforw(clp);
86 	}
87 	row += colrow(clp, curwp->w_doto, &x, &y);
88 	/*NOSTRICT*/
89 	ratio = nchar ? (100L*cchar) / nchar : 100;
90 	ewprintf(
91 	"Char: %c (0%o)  point=%ld(%d%%)  line=%d  offset=%d  row=%d  col=%d",
92 		cbyte, cbyte, cchar, ratio, cline, getcolpos(), row, x+1);
93 	return TRUE;
94 }
95 
getcolpos()96 getcolpos() {
97 	register int	col, i, c;
98 #ifdef HANKANA  /* 92.11.21  by S.Sasaki */
99 	int kan2nd;
100 #endif  /* HANKANA */
101 #ifdef  VARIABLE_TAB
102 	int	tab = curbp->b_tabwidth;
103 #endif  /* VARIABLE_TAB */
104 #ifdef	BUGFIX	/* 90.04.10  by m.tei (Nikkei MIX) */
105 	col = 0;				/* Determine column.	*/
106 #else	/* NOT BUGFIX */
107 	col = 1;				/* Determine column.	*/
108 #endif	/* BUGFIX */
109 #ifdef HANKANA  /* 92.11.21  by S.Sasaki */
110 	kan2nd = 0;
111 #endif  /* HANKANA */
112 
113 	for (i=0; i<curwp->w_doto; ++i) {
114 		c = lgetc(curwp->w_dotp, i);
115 		if (c == '\t'
116 #ifdef	NOTAB
117 			&& !(curbp->b_flag & BFNOTAB)
118 #endif
119 			) {
120 #ifdef	VARIABLE_TAB
121 		    col = (col/tab + 1)*tab - 1;
122 #else
123 		    col |= 0x07;
124 #endif
125 #ifndef	BUGFIX	/* 90.04.10  by m.tei (Nikkei MIX) */
126 		    ++col;
127 #endif	/* BUGFIX */
128 		} else if (ISCTRL(c) != FALSE)
129 			++col;
130 		++col;
131 #ifdef HANKANA  /* 92.11.21  by S.Sasaki */
132 		if (ISKANJI(c))
133 		    if (kan2nd==0) kan2nd=1;
134 			else kan2nd=1;
135 		if ( (c & 0xff) == SS2 && kan2nd == 1 )
136 		    col--;
137 #endif  /* HANKANA */
138 	}
139 #ifdef	BUGFIX  /* 90.04.10  by m.tei (Nikkei MIX) */
140 	col++;
141 #endif	/* BUGFIX */
142 	return col;
143 }
144 /*
145  * Twiddle the two characters on either side of
146  * dot. If dot is at the end of the line twiddle the
147  * two characters before it. Return with an error if dot
148  * is at the beginning of line; it seems to be a bit
149  * pointless to make this work. This fixes up a very
150  * common typo with a single stroke. Normally bound
151  * to "C-T". This always works within a line, so
152  * "WFEDIT" is good enough.
153  */
154 /*ARGSUSED*/
twiddle(f,n)155 twiddle(f, n)
156 {
157 	register LINE	*dotp;
158 	register int	doto;
159 	register int	cr;
160 #ifdef	KANJI	/* 90.01.29  by S.Yoshida */
161 	register int	cr2;
162 	register int	cr3;
163 	register int	cr4;
164 #endif	/* KANJI */
165 	VOID	 lchange();
166 #ifdef	UNDO
167 	UNDO_DATA	*undo;
168 #endif
169 
170 #ifdef	READONLY	/* 91.01.05  by S.Yoshida */
171 	if (curbp->b_flag & BFRONLY) {	/* If this buffer is read-only, */
172 		warnreadonly();		/* do only displaying warning.	*/
173 		return TRUE;
174 	}
175 #endif	/* READONLY */
176 
177 	dotp = curwp->w_dotp;
178 	doto = curwp->w_doto;
179 	if(doto==llength(dotp)) {
180 		if(--doto<=0) return FALSE;
181 #ifdef	KANJI	/* 90.01.29  by S.Yoshida */
182 		if (ISKANJI(lgetc(dotp, doto))) {
183 			if (--doto <= 0) return FALSE;
184 		}
185 #endif	/* KANJI */
186 	} else {
187 		if(doto==0) return FALSE;
188 		++curwp->w_doto;
189 #ifdef	KANJI	/* 90.01.29  by S.Yoshida */
190 		if (ISKANJI(lgetc(dotp, doto))) {
191 			++curwp->w_doto;
192 		}
193 #endif	/* KANJI */
194 	}
195 #ifdef	UNDO
196 	undo_setup(undo);
197 	if (isundo()) {
198 	    undo_bfree(undo);
199 	    undo->u_dotlno = get_lineno(curbp,dotp);
200 	    undo->u_doto = doto;
201 	    undo->u_type = UDTWIDDLE;
202 	    undo->u_used = 0;
203 	    undo_finish(&(undo->u_next));
204 	}
205 #endif	/* UNDO */
206 #ifdef	KANJI	/* 90.01.29  by S.Yoshida */
207 	cr = lgetc(dotp, doto);
208 	if (ISKANJI(cr)) {			/* It's KANJI 1st byte.	*/
209 		cr2 = lgetc(dotp, doto + 1);	/* Get KANJI 2nd byte.	*/
210 	} else {
211 		cr2 = '\0';			/* cr is ASCII.		*/
212 		/* 91.01.15  NULL -> '\0' */
213 	}
214 	cr3 = lgetc(dotp, --doto);
215 	if (ISKANJI(cr3)) {			/* It's KANJI 2nd byte.	*/
216 		cr4 = cr3;
217 		cr3 = lgetc(dotp, --doto);	/* Get KANJI 1st byte.	*/
218 	} else {
219 		cr4 = '\0';			/* cr3 is ASCII.	*/
220 		/* 91.01.15  NULL -> '\0' */
221 	}
222 	lputc(dotp, doto++, cr);		/* ASCII or KANJI 1st.	*/
223 	if (cr2 != '\0') {			/* This char is KANJI.	*/
224 		/* 91.01.15  NULL -> '\0' */
225 		lputc(dotp, doto++, cr2);	/* Put KANJI 2nd byte.	*/
226 	}
227 	lputc(dotp, doto++, cr3);		/* ASCII or KANJI 1st.	*/
228 	if (cr4 != '\0') {			/* This char is KANJI.	*/
229 		/* 91.01.15  NULL -> '\0' */
230 		lputc(dotp, doto++, cr4);
231 	}
232 #else	/* NOT KANJI */
233 	cr = lgetc(dotp, doto--);
234 	lputc(dotp, doto+1, lgetc(dotp, doto));
235 	lputc(dotp, doto, cr);
236 #endif	/* KANJI */
237 	lchange(WFEDIT);
238 	return TRUE;
239 }
240 
241 /*
242  * Open up some blank space. The basic plan
243  * is to insert a bunch of newlines, and then back
244  * up over them. Everything is done by the subcommand
245  * procerssors. They even handle the looping. Normally
246  * this is bound to "C-O".
247  */
248 /*ARGSUSED*/
openline(f,n)249 openline(f, n)
250 {
251 	register int	i;
252 	register int	s;
253 
254 #ifdef	READONLY	/* 91.01.05  by S.Yoshida */
255 	if (curbp->b_flag & BFRONLY) {	/* If this buffer is read-only, */
256 		warnreadonly();		/* do only displaying warning.	*/
257 		return TRUE;
258 	}
259 #endif	/* READONLY */
260 
261 	if (n < 0)
262 		return FALSE;
263 	if (n == 0)
264 		return TRUE;
265 	i = n;					/* Insert newlines.	*/
266 	do {
267 		s = lnewline();
268 	} while (s==TRUE && --i);
269 	if (s == TRUE)				/* Then back up overtop */
270 		s = backchar(f | FFRAND, n);	/* of them all.		*/
271 	return s;
272 }
273 
274 /*
275  * Insert a newline.
276  * If you are at the end of the line and the
277  * next line is a blank line, just move into the
278  * blank line. This makes "C-O" and "C-X C-O" work
279  * nicely, and reduces the ammount of screen
280  * update that has to be done. This would not be
281  * as critical if screen update were a lot
282  * more efficient.
283  */
284 /*ARGSUSED*/
newline(f,n)285 newline(f, n)
286 {
287 #ifndef	BUGFIX	/* 90.02.14  by S.Yoshida */
288 	register LINE	*lp;
289 #endif	/* BUGFIX */
290 	register int	s;
291 
292 #ifdef	READONLY	/* 91.01.05  by S.Yoshida */
293 	if (curbp->b_flag & BFRONLY) {	/* If this buffer is read-only, */
294 		warnreadonly();		/* do only displaying warning.	*/
295 		return TRUE;
296 	}
297 #endif	/* READONLY */
298 
299 	if (n < 0) return FALSE;
300 	while (n--) {
301 #ifndef	BUGFIX	/* 90.02.14  by S.Yoshida */
302 		lp = curwp->w_dotp;
303 		if (llength(lp) == curwp->w_doto
304 		&& lforw(lp) != curbp->b_linep
305 		&& llength(lforw(lp)) == 0) {
306 			if ((s=forwchar(FFRAND, 1)) != TRUE)
307 				return s;
308 		} else
309 #endif	/* BUGFIX */
310 		if ((s=lnewline()) != TRUE)
311 			return s;
312 	}
313 	return TRUE;
314 }
315 
316 /*
317  * Delete blank lines around dot.
318  * What this command does depends if dot is
319  * sitting on a blank line. If dot is sitting on a
320  * blank line, this command deletes all the blank lines
321  * above and below the current line. If it is sitting
322  * on a non blank line then it deletes all of the
323  * blank lines after the line. Normally this command
324  * is bound to "C-X C-O". Any argument is ignored.
325  */
326 /*ARGSUSED*/
deblank(f,n)327 deblank(f, n)
328 {
329 	register LINE	*lp1;
330 	register LINE	*lp2;
331 	register RSIZE	nld;
332 
333 #ifdef	READONLY	/* 91.01.05  by S.Yoshida */
334 	if (curbp->b_flag & BFRONLY) {	/* If this buffer is read-only, */
335 		warnreadonly();		/* do only displaying warning.	*/
336 		return TRUE;
337 	}
338 #endif	/* READONLY */
339 
340 	lp1 = curwp->w_dotp;
341 	while (llength(lp1)==0 && (lp2=lback(lp1))!=curbp->b_linep)
342 		lp1 = lp2;
343 	lp2 = lp1;
344 	nld = (RSIZE) 0;
345 	while ((lp2=lforw(lp2))!=curbp->b_linep && llength(lp2)==0)
346 		++nld;
347 	if (nld == 0)
348 		return (TRUE);
349 	curwp->w_dotp = lforw(lp1);
350 	curwp->w_doto = 0;
351 	return ldelete((RSIZE)nld, KNONE);
352 }
353 
354 /*
355  * Delete any whitespace around dot, then insert a space.
356  */
justone(f,n)357 justone(f, n) {
358 #ifdef	READONLY	/* 91.01.05  by S.Yoshida */
359 	if (curbp->b_flag & BFRONLY) {	/* If this buffer is read-only, */
360 		warnreadonly();		/* do only displaying warning.	*/
361 		return TRUE;
362 	}
363 #endif	/* READONLY */
364 	(VOID) delwhite(f, n);
365 	return linsert(1, ' ');
366 }
367 /*
368  * Delete any whitespace around dot.
369  */
370 /*ARGSUSED*/
delwhite(f,n)371 delwhite(f, n)
372 {
373 	register int	col, c, s;
374 
375 #ifdef	READONLY	/* 91.01.05  by S.Yoshida */
376 	if (curbp->b_flag & BFRONLY) {	/* If this buffer is read-only, */
377 		warnreadonly();		/* do only displaying warning.	*/
378 		return TRUE;
379 	}
380 #endif	/* READONLY */
381 
382 	col = curwp->w_doto;
383 	while (((c = lgetc(curwp->w_dotp, col)) == ' ' || c == '\t')
384 			&& col < llength(curwp->w_dotp))
385 		++col;
386 	do {
387 		if (curwp->w_doto == 0) {
388 			s = FALSE;
389 			break;
390 		}
391 		if ((s = backchar(FFRAND, 1)) != TRUE) break;
392 	} while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ' || c == '\t');
393 
394 	if (s == TRUE) (VOID) forwchar(FFRAND, 1);
395 	(VOID) ldelete((RSIZE)(col - curwp->w_doto), KNONE);
396 	return TRUE;
397 }
398 /*
399  * Insert a newline, then enough
400  * tabs and spaces to duplicate the indentation
401  * of the previous line. Assumes tabs are every eight
402  * characters. Quite simple. Figure out the indentation
403  * of the current line. Insert a newline by calling
404  * the standard routine. Insert the indentation by
405  * inserting the right number of tabs and spaces.
406  * Return TRUE if all ok. Return FALSE if one
407  * of the subcomands failed. Normally bound
408  * to "C-J".
409  */
410 /*ARGSUSED*/
indent(f,n)411 indent(f, n)
412 {
413 	register int	nicol;
414 	register int	c;
415 	register int	i;
416 #ifdef  VARIABLE_TAB
417 	int	tab = curbp->b_tabwidth;
418 #endif  /* VARIABLE_TAB */
419 
420 #ifdef	READONLY	/* 91.01.05  by S.Yoshida */
421 	if (curbp->b_flag & BFRONLY) {	/* If this buffer is read-only, */
422 		warnreadonly();		/* do only displaying warning.	*/
423 		return TRUE;
424 	}
425 #endif	/* READONLY */
426 
427 	if (n < 0) return (FALSE);
428 	while (n--) {
429 		nicol = 0;
430 		for (i=0; i<llength(curwp->w_dotp); ++i) {
431 			c = lgetc(curwp->w_dotp, i);
432 			if (c!=' ' && c!='\t')
433 				break;
434 			if (c == '\t')
435 #ifdef	VARIABLE_TAB
436 				nicol = (nicol/tab + 1)*tab - 1;
437 #else
438 				nicol |= 0x07;
439 #endif
440 			++nicol;
441 		}
442 		if (lnewline() == FALSE || ((
443 #ifdef	NOTAB
444 		    curbp->b_flag&BFNOTAB) ?
445 			linsert(nicol, ' ') == FALSE : (
446 #endif
447 		    ((i=nicol/8)!=0 && linsert(i, '\t')==FALSE) ||
448 		    ((i=nicol%8)!=0 && linsert(i,  ' ')==FALSE))))
449 			return FALSE;
450 	}
451 	return TRUE;
452 }
453 
454 /*
455  * Delete forward. This is real
456  * easy, because the basic delete routine does
457  * all of the work. Watches for negative arguments,
458  * and does the right thing. If any argument is
459  * present, it kills rather than deletes, to prevent
460  * loss of text if typed with a big argument.
461  * Normally bound to "C-D".
462  */
463 /*ARGSUSED*/
forwdel(f,n)464 forwdel(f, n)
465 {
466 #ifdef	READONLY	/* 91.01.05  by S.Yoshida */
467 	if (curbp->b_flag & BFRONLY) {	/* If this buffer is read-only, */
468 		warnreadonly();		/* do only displaying warning.	*/
469 		return TRUE;
470 	}
471 #endif	/* READONLY */
472 
473 	if (n < 0)
474 		return backdel(f | FFRAND, -n);
475 	if (f & FFARG) {			/* Really a kill.	*/
476 		if ((lastflag&CFKILL) == 0)
477 			kdelete();
478 		thisflag |= CFKILL;
479 	}
480 	return ldelete((RSIZE) n, (f & FFARG) ? KFORW : KNONE);
481 }
482 
483 /*
484  * Delete backwards. This is quite easy too,
485  * because it's all done with other functions. Just
486  * move the cursor back, and delete forwards.
487  * Like delete forward, this actually does a kill
488  * if presented with an argument.
489  */
490 /*ARGSUSED*/
backdel(f,n)491 backdel(f, n)
492 {
493 	register int	s;
494 
495 #ifdef	READONLY	/* 91.01.05  by S.Yoshida */
496 	if (curbp->b_flag & BFRONLY) {	/* If this buffer is read-only, */
497 		warnreadonly();		/* do only displaying warning.	*/
498 		return TRUE;
499 	}
500 #endif	/* READONLY */
501 
502 	if (n < 0)
503 		return forwdel(f | FFRAND, -n);
504 	if (f & FFARG) {			/* Really a kill.	*/
505 		if ((lastflag&CFKILL) == 0)
506 			kdelete();
507 		thisflag |= CFKILL;
508 	}
509 	if ((s=backchar(f | FFRAND, n)) == TRUE)
510 		s = ldelete((RSIZE) n, (f & FFARG) ? KFORW : KNONE);
511 #ifdef	UNDO
512 	if (isundo() && undobefore!=NULL)
513 	    (*undobefore)->u_type = UDBS;
514 #endif
515 	return s;
516 }
517 
518 /*
519  * Kill line. If called without an argument,
520  * it kills from dot to the end of the line, unless it
521  * is at the end of the line, when it kills the newline.
522  * If called with an argument of 0, it kills from the
523  * start of the line to dot. If called with a positive
524  * argument, it kills from dot forward over that number
525  * of newlines. If called with a negative argument it
526  * kills any text before dot on the current line,
527  * then it kills back abs(arg) lines.
528  */
529 /*ARGSUSED*/
killline(f,n)530 killline(f, n) {
531 	register RSIZE	chunk;
532 	register LINE	*nextp;
533 	register int	i, c;
534 	VOID	 kdelete();
535 
536 #ifdef	READONLY	/* 91.01.05  by S.Yoshida */
537 	if (curbp->b_flag & BFRONLY) {	/* If this buffer is read-only, */
538 		warnreadonly();		/* do only displaying warning.	*/
539 		return TRUE;
540 	}
541 #endif	/* READONLY */
542 
543 	if ((lastflag&CFKILL) == 0)		/* Clear kill buffer if */
544 		kdelete();			/* last wasn't a kill.	*/
545 	thisflag |= CFKILL;
546 	if (!(f & FFARG)) {
547 		for (i = curwp->w_doto; i < llength(curwp->w_dotp); ++i)
548 			if ((c = lgetc(curwp->w_dotp, i)) != ' ' && c != '\t')
549 				break;
550 		if (i == llength(curwp->w_dotp))
551 			chunk = llength(curwp->w_dotp)-curwp->w_doto + 1;
552 		else {
553 			chunk = llength(curwp->w_dotp)-curwp->w_doto;
554 			if (chunk == 0)
555 				chunk = 1;
556 		}
557 	} else if (n > 0) {
558 		chunk = llength(curwp->w_dotp)-curwp->w_doto+1;
559 		nextp = lforw(curwp->w_dotp);
560 		i = n;
561 		while (--i) {
562 			if (nextp == curbp->b_linep)
563 				break;
564 			chunk += llength(nextp)+1;
565 			nextp = lforw(nextp);
566 		}
567 	} else {				/* n <= 0		*/
568 		chunk = curwp->w_doto;
569 		curwp->w_doto = 0;
570 		i = n;
571 		while (i++) {
572 			if (lback(curwp->w_dotp) == curbp->b_linep)
573 				break;
574 			curwp->w_dotp = lback(curwp->w_dotp);
575 			curwp->w_flag |= WFMOVE;
576 			chunk += llength(curwp->w_dotp)+1;
577 		}
578 	}
579 	/*
580 	 * KFORW here is a bug. Should be KBACK/KFORW, but we need to
581 	 * rewrite the ldelete code (later)?
582 	 */
583 	return (ldelete(chunk,	KFORW));
584 }
585 
586 /*						*/
587 /*	Kill oneline by S.Sasaki May-05-1992	*/
588 /*						*/
589 
killoneline(f,n)590 killoneline(f, n) {
591 	register RSIZE	chunk;
592 	register LINE	*nextp;
593 	register int	i;
594 	VOID	 kdelete();
595 #ifdef	READONLY	/* 91.01.05  by S.Yoshida */
596 	if (curbp->b_flag & BFRONLY) {	/* If this buffer is read-only, */
597 		warnreadonly();		/* do only displaying warning.	*/
598 		return TRUE;
599 	}
600 #endif	/* READONLY */
601 
602 	if ((lastflag&CFKILL) == 0)		/* Clear kill buffer if */
603 		kdelete();			/* last wasn't a kill.	*/
604 	thisflag |= CFKILL;
605 	if (!(f & FFARG)) {
606 		curwp->w_doto = 0;
607 		chunk = llength(curwp->w_dotp) + 1;
608 	} else if (n > 0) {
609 		curwp->w_doto = 0;
610 		chunk = llength(curwp->w_dotp)+1;
611 		nextp = lforw(curwp->w_dotp);
612 		i = n;
613 		while (--i) {
614 			if (nextp == curbp->b_linep)
615 				break;
616 			chunk += llength(nextp)+1;
617 			nextp = lforw(nextp);
618 		}
619 	} else {				/* n <= 0		*/
620 		chunk = llength(curwp->w_dotp)+1;
621 		curwp->w_doto = 0;
622 		i = n;
623 		while (i++) {
624 			if (lback(curwp->w_dotp) == curbp->b_linep)
625 				break;
626 			curwp->w_dotp = lback(curwp->w_dotp);
627 			curwp->w_flag |= WFMOVE;
628 			chunk += llength(curwp->w_dotp)+1;
629 		}
630 	}
631 	/*
632 	 * KFORW here is a bug. Should be KBACK/KFORW, but we need to
633 	 * rewrite the ldelete code (later)?
634 	 */
635 	return ldelete(chunk,KFORW);
636 }
637 
638 /*
639  * Yank text back from the kill buffer. This
640  * is really easy. All of the work is done by the
641  * standard insert routines. All you do is run the loop,
642  * and check for errors. The blank
643  * lines are inserted with a call to "newline"
644  * instead of a call to "lnewline" so that the magic
645  * stuff that happens when you type a carriage
646  * return also happens when a carriage return is
647  * yanked back from the kill buffer.
648  * An attempt has been made to fix the cosmetic bug
649  * associated with a yank when dot is on the top line of
650  * the window (nothing moves, because all of the new
651  * text landed off screen).
652  */
653 /*ARGSUSED*/
yank(f,n)654 yank(f, n)
655 {
656 	register int	c;
657 	register int	i;
658 	register LINE	*lp;
659 	register int	nline;
660 	VOID	 isetmark();
661 	int mark_adjust = FALSE;
662 #ifdef	UNDO
663 	int run_insert = FALSE;
664 #endif
665 
666 #ifdef	READONLY	/* 91.01.05  by S.Yoshida */
667 	if (curbp->b_flag & BFRONLY) {	/* If this buffer is read-only, */
668 		warnreadonly();		/* do only displaying warning.	*/
669 		return TRUE;
670 	}
671 #endif	/* READONLY */
672 
673 	if (n < 0) return FALSE;
674 #ifdef	CLIPBOARD
675 	if ( !receive_clipboard() ) {
676 		return FALSE ;
677 	}
678 #endif	/* CLIPBOARD */
679 	nline = 0;				/* Newline counting.	*/
680 	while (n--) {
681 		isetmark();			/* mark around last yank */
682 		i = 0;
683 #ifdef	UNDO
684 	    if (isundo()) {
685 		extern int get_lineno pro((BUFFER*,LINE*));
686 		extern int set_lineno;
687 		set_lineno = get_lineno(curbp, curwp->w_dotp);
688 		while ((c=kremove(i)) >= 0) {
689 			if (c == '\n') {
690 				if (i == 0 && curbp->b_marko == 0)
691 					mark_adjust = TRUE;
692 				if (newline(FFRAND, 1) == FALSE) {
693 					set_lineno = -1;
694 					return FALSE;
695 				}
696 				/* Mark position correction.	*/
697 				if (mark_adjust) {
698 					LINE *lp=lback(curwp->w_dotp);
699 					curbp->b_markp  = lp;
700 					curbp->b_marko  = llength(lp);
701 					mark_adjust = FALSE;
702 				}
703 				++nline; ++set_lineno;
704 				run_insert = FALSE;
705 			} else {
706 				if (run_insert)
707 					undoptr = undobefore;
708 				else if (*undoptr != NULL)
709 					(*undoptr)->u_type = UDNONE;
710 				if (linsert(1, c) == FALSE) {
711 					set_lineno = -1;
712 					return FALSE;
713 				}
714 				run_insert = TRUE;
715 			}
716 			++i;
717 		}
718 		set_lineno = -1;
719 	    } else
720 #endif
721 		while ((c=kremove(i)) >= 0) {
722 			if (c == '\n') {
723 				if (i == 0 && curbp->b_marko == 0)
724 					mark_adjust = TRUE;
725 				if (newline(FFRAND, 1) == FALSE)
726 					return FALSE;
727 				/* Mark position correction.	*/
728 				if (mark_adjust) {
729 					LINE *lp=lback(curwp->w_dotp);
730 					curbp->b_markp  = lp;
731 					curbp->b_marko  = llength(lp);
732 					mark_adjust = FALSE;
733 				}
734 
735 				++nline;
736 			} else {
737 				if (linsert(1, c) == FALSE)
738 					return FALSE;
739 			}
740 			++i;
741 		}
742 	}
743 	lp = curwp->w_linep;			/* Cosmetic adjustment	*/
744 	if (curwp->w_dotp == lp) {		/* if offscreen insert. */
745 		while (nline > 0 && lback(lp)!=curbp->b_linep) {
746 			lp = lback(lp);
747 			nline --;
748 		}
749 		curwp->w_linep = lp;		/* Adjust framing.	*/
750 		curwp->w_lines = 0;
751 		curwp->w_flag |= WFHARD;
752 	}
753 	return TRUE;
754 }
755 
756 #ifdef	NOTAB
757 /*ARGSUSED*/
space_to_tabstop(f,n)758 space_to_tabstop(f, n)
759 int f, n;
760 {
761 #ifdef	READONLY	/* 91.01.05  by S.Yoshida */
762     if (curbp->b_flag & BFRONLY) {	/* If this buffer is read-only, */
763 	warnreadonly();			/* do only displaying warning.	*/
764 	return TRUE;
765     }
766 #endif	/* READONLY */
767 
768     if(n<0) return FALSE;
769     if(n==0) return TRUE;
770     return linsert((n<<3) - (curwp->w_doto & 7), ' ');
771 }
772 #endif
773 
774 #ifdef ZAPTOC_A
775 # define ZAPTOCHAR
776 #endif
777 
778 #ifdef ZAPTOCHAR		/* Nov 91, bsh */
779 /*
780  * Zap to ARG'th occurence of char, but not including it.
781  * Goes backward if ARG is negative.
782  * #ifdef ZAPTOC_A
783  *    Goes to end of buffer if char not found.
784  * #else
785  *    do nothing if it can't reach to ARG'th occurence of char.
786  * #endif
787  *
788  * Real work to search CHAR is done by forwsrch, which does real work
789  * of forwsearch() (M-x search-forward). Global buffer `pat' is used
790  * for interface.
791  */
zaptochar(f,n)792 zaptochar(f,n)
793 {
794 	int c;
795 	RSIZE	nbytes;
796 	LINE *sp = curwp->w_dotp;                /* save dot */
797 	int so = curwp->w_doto;
798 	LINE *cp;
799 	int  co;
800 
801 	ewprintf( "Zap to char: " );
802 	c = getkey(FALSE);
803 	if( c == CCHR('G') )			/* you can't zap to ^G */
804 		return FALSE;
805 	pat[0] = c;
806 #ifndef	KANJI
807 	pat[1] = '\0';
808 #else
809 	if( !ISKANJI(c) )
810 		pat[1] = '\0';
811 	else {
812 		c = getkey(FALSE);
813 		if( !ISKANJI(c) )
814 			return FALSE;
815 		pat[1] = c;
816 		pat[2] = '\0';
817 	}
818 #endif	/* KANJI */
819 
820 	if( n == 0 ) n = 1;
821 	if( n < 0 ){
822 		while(n < 0 && backsrch())
823 			++n;
824 		if( n < 0 ){		       /* not found */
825 #ifdef	ZAPTOC_A
826 			curwp->w_dotp  = lforw(curbp->b_linep);
827 			curwp->w_doto  = 0;
828 #else		/* Safer */
829 			goto notfound;
830 #endif
831 		}
832 		else {
833 			/* Not including last occurence of CHR */
834 			forwchar( FFRAND, 1 );
835 		}
836 		cp = curwp->w_dotp;
837 		co = curwp->w_doto;
838 	}
839 	else {
840 		while(n > 0 && forwsrch())
841 			--n;
842 		if( n > 0 ){
843 #ifdef	ZAPTOC_A
844 			curwp->w_dotp  = lback(curbp->b_linep);
845 			curwp->w_doto  = llength(curwp->w_dotp);
846 #else
847 			goto notfound;
848 #endif
849 		}
850 		else {
851 			/* Not including last occurence of CHAR */
852 			backchar( FFRAND, 1 );
853 		}
854 		co = so;
855 		cp = sp;
856 		so = curwp->w_doto;	/* Swap dot and previous point */
857 		sp = curwp->w_dotp;
858 		curwp->w_doto = co;	/* Previous position */
859 		curwp->w_dotp = cp;
860 	}
861 
862 	/* Region to kill is (dot) .. (cp,co).
863 	 * Count up chars and let ldelete() to do real work
864 	 */
865 	if( cp == sp ){			       /* on the same line */
866 		nbytes = so - co;
867 	}
868 	else {
869 		nbytes = llength(cp) - co + 1 + so;
870 		for(cp = lforw(cp); cp != sp; cp = lforw(cp))
871 			nbytes += llength(cp)+1;
872 	}
873 	if ((lastflag&CFKILL) == 0)		/* This is a kill type	*/
874 		kdelete();			/* command, so do magic */
875 	thisflag |= CFKILL;			/* kill buffer stuff.	*/
876 	return (ldelete(nbytes,KFORW));
877 
878 notfound:
879         ewprintf( "Not found" );
880 	curwp->w_dotp = sp;
881 	curwp->w_doto = so;
882 	return FALSE;
883 }
884 #endif
885 
886 #ifdef	ADDFUNC	/* 90.02.15  by S.Yoshida */
887 /*
888  * Count lines in the current page. (Now, page is same as buffer)
889  */
890 /*ARGSUSED*/
pagelines(f,n)891 pagelines(f, n)
892 {
893 	register LINE	*lp;
894 	register int	prelines;
895 	register int	postlines;
896 	register int	totallines;
897 
898 	prelines = 0;
899 	for (lp = lforw(curbp->b_linep); lp != curwp->w_dotp; lp = lforw(lp)) {
900 		prelines++;
901 	}
902 	if (curwp->w_doto > 0) {	/* "dot" is in the line. */
903 		prelines++;
904 	}
905 	postlines = 0;
906 	for (lp = curwp->w_dotp; lp != curbp->b_linep; lp = lforw(lp)) {
907 		postlines++;
908 	}
909 	if (curwp->w_dotp == lback(curbp->b_linep) &&	/* "dot" is at the */
910 	    curwp->w_doto == llength(curwp->w_dotp)) {	/* end of buffer.  */
911 		postlines = 0;
912 	} else if (llength(lback(curbp->b_linep)) == 0) { /* Last line has */
913 		                                          /* no text.      */
914 		postlines--;
915 	}
916 	totallines = prelines + postlines;
917 	if (curwp->w_doto > 0 &&
918 	    !(curwp->w_dotp == lback(curbp->b_linep) &&
919 	      curwp->w_doto == llength(curwp->w_dotp))) {
920 		totallines--;
921 	}
922 	ewprintf("Page has %d lines (%d + %d)",
923 		 totallines, prelines, postlines);
924 	return TRUE;
925 }
926 
927 /*
928  * Count lines in the current region.
929  */
930 /*ARGSUSED*/
regionlines(f,n)931 regionlines(f, n)
932 {
933 	register LINE	*lp;
934 	register int	totallines;
935 	register int	counting;
936 
937 	totallines = 0;
938 	if (curwp->w_dotp == curbp->b_markp) {
939 		if (curwp->w_doto != curbp->b_marko) {
940 			totallines = 1;
941 		}
942 	} else {
943 		counting = FALSE;
944 		for (lp = lforw(curbp->b_linep);
945 		     lp != curbp->b_linep; lp = lforw(lp)) {
946 			if (lp == curwp->w_dotp) {
947 				if (counting) {	/* End of counting. */
948 					if (curwp->w_doto > 0) {
949 						totallines++;
950 					}
951 					break;
952 				} else {	/* Start of counting. */
953 					counting = TRUE;
954 				}
955 			} else if (lp == curbp->b_markp) {
956 				if (counting) {	/* End of counting. */
957 					if (curbp->b_marko > 0) {
958 						totallines++;
959 					}
960 					break;
961 				} else {	/* Start of counting. */
962 					counting = TRUE;
963 				}
964 			}
965 			if (counting) {
966 				totallines++;
967 			}
968 		}
969 	}
970 	ewprintf("Region has %d lines", totallines);
971 	return TRUE;
972 }
973 
974 /*
975    Investigate the dot position to return a ratio value.  The ratio
976    value will be between 0 and 100.  The following values are special
977    case and all of them are negative value.
978 
979    MG_RATIO_ALL   All portion of the buffer is shown in the window.
980    MG_RATIO_TOP   Top portion of the buffer is shown in the window.
981    MG_RATIO_BOT   Bottom portion of the buffer is shown in the window.
982 
983    By Tillanosoft, Mar 21, 1999.
984       patched by amura, 2 Apl 2000
985  */
986 
987 int
windowpos(wp)988 windowpos(wp)
989 register WINDOW *wp;
990 {
991   extern int rowcol2offset pro((LINE *, int, int));
992   LINE *lp, *targetlp;
993   register BUFFER *bp = wp->w_bufp;
994   int top = FALSE, bot = FALSE, off;
995   int res = MG_RATIO_ALL;
996 
997   /* check if the beginning of top line is shown */
998   if (wp->w_linep == lforw(bp->b_linep)) {
999     if (wp->w_lines == 0) {
1000       top = TRUE;
1001     }
1002   }
1003   /* check if the end of the bottom line is shown */
1004   lp = wp->w_linep;
1005   off = rowcol2offset(lp, wp->w_lines + wp->w_ntrows, ncol);
1006   while (off < 0) {
1007     if (lforw(lp) != bp->b_linep) {
1008       lp = lforw(lp);
1009       off = rowcol2offset(lp, -off - 1, ncol);
1010     }
1011     else {
1012       bot = TRUE;
1013       break;
1014     }
1015   }
1016   if (top && bot) {
1017     res = MG_RATIO_ALL;
1018   }
1019   else if (top) {
1020     res = MG_RATIO_TOP;
1021   }
1022   else if (bot) {
1023     res = MG_RATIO_BOT;
1024   }
1025   else {
1026     /* count the bytes of the dot and the end */
1027     long nchar = 0, cchar = 0;
1028 
1029     targetlp = wp->w_linep;
1030     lp = lforw(bp->b_linep);
1031     for (;;) {
1032       if (lp == targetlp) {
1033 	cchar = nchar + skipline(lp, wp->w_lines);
1034       }
1035       nchar += llength(lp); /* Now count the chars */
1036       lp = lforw(lp);
1037       if (lp == bp->b_linep) {
1038 	break;
1039       }
1040       nchar++; /* count the newline */
1041     }
1042     res = (cchar * 100) / nchar;
1043     if (res >= 100) {
1044       res = 99;
1045     }
1046   }
1047   return res;
1048 }
1049 #endif	/* ADDFUNC */
1050