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