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