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