1 /* $Id: buffer.c,v 1.16 2001/05/25 15:36:52 amura Exp $ */
2 /*
3 * Buffer handling.
4 */
5
6 /*
7 * $Log: buffer.c,v $
8 * Revision 1.16 2001/05/25 15:36:52 amura
9 * now buffers have only one mark (before windows have one mark)
10 *
11 * Revision 1.15 2001/05/08 17:52:43 amura
12 * display buffer size in bufferlist
13 *
14 * Revision 1.14 2001/03/02 08:49:04 amura
15 * now AUTOSAVE feature implemented almost all (except for WIN32
16 *
17 * Revision 1.13 2001/02/28 17:06:05 amura
18 * buffer size to use eread() is more secure
19 *
20 * Revision 1.12 2001/02/18 19:26:41 amura
21 * remove malloc() prototype
22 *
23 * Revision 1.11 2001/02/18 17:07:23 amura
24 * append AUTOSAVE feature (but NOW not work)
25 *
26 * Revision 1.10 2001/01/05 14:06:59 amura
27 * first implementation of Hojo Kanji support
28 *
29 * -- snip --
30 *
31 * Revision 1.1 1999/05/19 03:47:59 amura
32 * Initial revision
33 *
34 */
35 /* 90.01.29 Modified for Ng 1.0 by S.Yoshida */
36
37 #include "config.h" /* 90.12.20 by S.Yoshida */
38 #include "def.h"
39 #include "kbd.h" /* needed for modes */
40 #ifdef UNDO
41 #include "undo.h"
42 #endif
43
44 #ifdef VARIABLE_TAB
45 int defb_tab = 8;
46 int cmode_tab = 0;
47 #endif /* VARIABLE_TAB */
48 #define GETNUMLEN 6
49 static BUFFER *makelist pro((void));
50 static long buffersize pro((BUFFER*));
51
52 #ifdef MOVE_BUFFER /* 95.08.29 by M.Suzuki */
53 /* Move to the next buffer */
nextbuffer(f,n)54 nextbuffer(f,n)
55 {
56 register BUFFER *bp;
57
58 /* Get buffer to use from user */
59 if ((curbp->b_altb == NULL)
60 && ((curbp->b_altb = bfind("*scratch*", TRUE)) == NULL))
61 return FALSE;
62
63 bp = bheadp;
64 while (bp != NULL) {
65 if (fncmp(curbp->b_bname, bp->b_bname) == 0){
66 bp = bp->b_bufp;
67 break;
68 }
69 bp = bp->b_bufp;
70 }
71 if ( bp == NULL){
72 bp = bheadp;
73 }
74
75 /* and put it in current window */
76 curbp = bp;
77 return showbuffer(bp, curwp, WFFORCE|WFHARD);
78 }
79
80 /* Move to the previous buffer */
prevbuffer(f,n)81 prevbuffer(f,n)
82 {
83 register BUFFER *bp,*bp1;
84
85 if ((curbp->b_altb == NULL)
86 && ((curbp->b_altb = bfind("*scratch*", TRUE)) == NULL))
87 return FALSE;
88
89 bp1 = bp = bheadp;
90 while (bp != NULL) {
91 if (fncmp(curbp->b_bname, bp->b_bname) == 0){
92 if( bp == bp1 ){ /* abnomal found */
93 while( bp != NULL ){ /* last search */
94 bp1 = bp;
95 bp = bp->b_bufp;
96 }
97 }
98 break;
99 }
100 bp1 = bp;
101 bp = bp->b_bufp;
102 }
103
104 /* and put it in current window */
105 curbp = bp1;
106 return showbuffer(bp1, curwp, WFFORCE|WFHARD);
107 }
108 #endif /* MOVE_BUFFER */
109
110 /*
111 * Attach a buffer to a window. The values of dot and mark come
112 * from the buffer if the use count is 0. Otherwise, they come
113 * from some other window. *scratch* is the default alternate
114 * buffer.
115 */
116 /*ARGSUSED*/
usebuffer(f,n)117 usebuffer(f, n)
118 {
119 register BUFFER *bp;
120 register int s;
121 char bufn[NBUFN];
122
123 /* Get buffer to use from user */
124 if ((curbp->b_altb == NULL)
125 && ((curbp->b_altb = bfind("*scratch*", TRUE)) == NULL))
126 s=eread("Switch to buffer: ", bufn, sizeof(bufn), EFNEW|EFBUF);
127 else
128 s=eread("Switch to buffer: (default %s) ", bufn, sizeof(bufn),
129 EFNEW|EFBUF, curbp->b_altb->b_bname);
130
131 if (s == ABORT) return s;
132 if (s == FALSE && curbp->b_altb != NULL) bp = curbp->b_altb ;
133 else if ((bp=bfind(bufn, TRUE)) == NULL) return FALSE;
134
135 /* and put it in current window */
136 curbp = bp;
137 return showbuffer(bp, curwp, WFFORCE|WFHARD);
138 }
139
140 /*
141 * pop to buffer asked for by the user.
142 */
143 /*ARGSUSED*/
poptobuffer(f,n)144 poptobuffer(f, n)
145 {
146 register BUFFER *bp;
147 register WINDOW *wp;
148 register int s;
149 char bufn[NBUFN];
150 WINDOW *popbuf();
151
152 /* Get buffer to use from user */
153 if ((curbp->b_altb == NULL)
154 && ((curbp->b_altb = bfind("*scratch*", TRUE)) == NULL))
155 s=eread("Switch to buffer in other window: ",
156 bufn, sizeof(bufn), EFNEW|EFBUF);
157 else
158 s=eread("Switch to buffer in other window: (default %s) ",
159 bufn, sizeof(bufn), EFNEW|EFBUF, curbp->b_altb->b_bname);
160 if (s == ABORT) return s;
161 if (s == FALSE && curbp->b_altb != NULL) bp = curbp->b_altb ;
162 else if ((bp=bfind(bufn, TRUE)) == NULL) return FALSE;
163
164 /* and put it in a new window */
165 if ((wp = popbuf(bp)) == NULL) return FALSE;
166 curbp = bp;
167 curwp = wp;
168 return TRUE;
169 }
170
171 /*
172 * Dispose of a buffer, by name.
173 * Ask for the name. Look it up (don't get too
174 * upset if it isn't there at all!). Clear the buffer (ask
175 * if the buffer has been changed). Then free the header
176 * line and the buffer header. Bound to "C-X K".
177 */
178 /*ARGSUSED*/
killbuffer(f,n)179 killbuffer(f, n)
180 {
181 register BUFFER *bp;
182 register BUFFER *bp1;
183 register BUFFER *bp2;
184 WINDOW *wp;
185 register int s;
186 char bufn[NBUFN];
187
188 if ((s=eread("Kill buffer: (default %s) ", bufn, sizeof(bufn),
189 EFNEW|EFBUF, curbp->b_bname)) == ABORT) return (s);
190 else if (s == FALSE) bp = curbp;
191 else if ((bp=bfind(bufn, FALSE)) == NULL) return FALSE;
192
193 /* find some other buffer to display. try the alternate buffer,
194 * then the first different buffer in the buffer list. if
195 * there's only one buffer, create buffer *scratch* and make
196 * it the alternate buffer. return if *scratch* is only buffer
197 */
198 #ifdef BUGFIX /* 90.02.22 by S.Yoshida */
199 if ((bp1 = bp->b_altb) == NULL || bp1 == bp) {
200 #else /* ORIGINAL */
201 if ((bp1 = bp->b_altb) == NULL) {
202 #endif /* BUGFIX */
203 bp1 = (bp == bheadp) ? bp->b_bufp : bheadp;
204 if (bp1 == NULL) {
205 /* only one buffer. see if it's *scratch* */
206 if (bp == bfind("*scratch*",FALSE))
207 return FALSE;
208 /* create *scratch* for alternate buffer */
209 if ((bp1 = bfind("*scratch*",TRUE)) == NULL)
210 return FALSE;
211 }
212 }
213 if (bp->b_fname == NULL) {
214 /* Do not ask for saving
215 if the buffer is not associated with a file.
216 by Tillanosoft */
217 bp->b_flag &= ~BFCHG;
218 }
219 if (bclear(bp) != TRUE) return FALSE;
220 for (wp = wheadp; bp->b_nwnd > 0; wp = wp->w_wndp) {
221 if (wp->w_bufp == bp) {
222 bp2 = bp1->b_altb; /* save alternate buffer */
223 if(showbuffer(bp1, wp, WFMODE|WFFORCE|WFHARD) != FALSE)
224 bp1->b_altb = bp2;
225 else bp1 = bp2;
226 }
227 }
228 if (bp == curbp) curbp = bp1;
229 free((char *) bp->b_linep); /* Release header line. */
230 bp2 = NULL; /* Find the header. */
231 bp1 = bheadp;
232 while (bp1 != bp) {
233 if (bp1->b_altb == bp)
234 bp1->b_altb = (bp->b_altb == bp1) ? NULL : bp->b_altb;
235 bp2 = bp1;
236 bp1 = bp1->b_bufp;
237 }
238 bp1 = bp1->b_bufp; /* Next one in chain. */
239 if (bp2 == NULL) /* Unlink it. */
240 bheadp = bp1;
241 else
242 bp2->b_bufp = bp1;
243 while (bp1 != NULL) { /* Finish with altb's */
244 if (bp1->b_altb == bp)
245 bp1->b_altb = (bp->b_altb == bp1) ? NULL : bp->b_altb;
246 bp1 = bp1->b_bufp;
247 }
248 if (bp->b_fname != NULL) /* Release filename block */
249 free(bp->b_fname);
250 #ifdef EXTD_DIR
251 if (bp->b_cwd != NULL) /* Release pathname block */
252 free(bp->b_cwd);
253 #endif
254 free(bp->b_bname); /* Release name block */
255 #ifdef UNDO
256 undo_clean(bp); /* Release undo data */
257 #endif
258 free((char *) bp); /* Release buffer block */
259 return TRUE;
260 }
261
262 /*
263 * Save some buffers - just call anycb with the arg flag.
264 */
265 /*ARGSUSED*/
266 savebuffers(f, n)
267 {
268 if (anycb(f) == ABORT) return ABORT;
269 return TRUE;
270 }
271
272 /*
273 * Display the buffer list. This is done
274 * in two parts. The "makelist" routine figures out
275 * the text, and puts it in a buffer. "popbuf"
276 * then pops the data onto the screen. Bound to
277 * "C-X C-B".
278 */
279 /*ARGSUSED*/
280 listbuffers(f, n)
281 {
282 register BUFFER *bp;
283 register WINDOW *wp;
284 BUFFER *makelist();
285 WINDOW *popbuf();
286
287 if ((bp=makelist()) == NULL || (wp=popbuf(bp)) == NULL)
288 return FALSE;
289 wp->w_dotp = bp->b_dotp; /* fix up if window already on screen */
290 wp->w_doto = bp->b_doto;
291 #ifdef BUFFER_MODE
292 bp->b_modes[0] = name_mode("Buffer Menu");
293 if (bp->b_modes[0] == NULL) {
294 bp->b_modes[0] = &map_table[0];
295 ewprintf("Could not find \"Buffer Menu\" mode");
296 }
297 else {
298 bp->b_nmodes = 0;
299 }
300 #endif
301 return TRUE;
302 }
303
304 /*
305 * This routine rebuilds the text for the
306 * list buffers command. Return TRUE if
307 * everything works. Return FALSE if there
308 * is an error (if there is no memory).
309 */
310 BUFFER *
311 makelist() {
312 register char *cp1;
313 register char *cp2;
314 register int c;
315 register BUFFER *bp;
316 LINE *lp;
317 BUFFER *blp;
318 char b[6+1];
319 char line[4+NBUFN+7+NFILEN+4];
320 #ifdef HANKANA
321 int nhankana;
322 #endif
323
324 if ((blp = bfind("*Buffer List*", TRUE)) == NULL) return NULL;
325 if (bclear(blp) != TRUE) return NULL;
326 #ifdef AUTOSAVE /* 96.12.24 by M.Suzuki */
327 blp->b_flag &= ~(BFCHG|BFACHG); /* Blow away old. */
328 #else
329 blp->b_flag &= ~BFCHG; /* Blow away old. */
330 #endif /* AUTOSAVE */
331
332 (VOID) strcpy(line, " MR Buffer");
333 cp1 = line + 10;
334 while(cp1 < line + 4 + NBUFN + 1) *cp1++ = ' ';
335 (VOID) strcpy(cp1, "Size File");
336 if (addline(blp, line) == FALSE) return NULL;
337 (VOID) strcpy(line, " -- ------");
338 cp1 = line + 10;
339 while(cp1 < line + 4 + NBUFN + 1) *cp1++ = ' ';
340 (VOID) strcpy(cp1, "---- ----");
341 if (addline(blp, line) == FALSE) return NULL;
342 bp = bheadp; /* For all buffers */
343 while (bp != NULL) {
344 sprintf(line,"%c%c%c %-30.30s %7ld %s",
345 (bp == curbp) ? '.' : ' ',
346 (bp->b_flag & BFCHG) ? '*' : ' ',
347 #ifdef READONLY /* 91.01.05 by S.Yoshida */
348 (bp->b_flag & BFRONLY) ? '%' : ' ',
349 #else
350 ' ',
351 #endif
352 bp->b_bname, buffersize(bp),
353 (bp->b_fname != NULL) ? bp->b_fname : "" );
354 if (addline(blp, line) == FALSE)
355 return NULL;
356 bp = bp->b_bufp;
357 }
358 blp->b_dotp = lforw(blp->b_linep); /* put dot at beginning of buffer */
359 blp->b_doto = 0;
360 #ifdef READONLY /* 91.02.06 by N.Kamei */
361 blp->b_flag |= BFRONLY;
362 #endif /* READONLY */
363 return blp; /* All done */
364 }
365
366 /*
367 * Calculate buffer size
368 */
369 static long
370 buffersize(bp)
371 BUFFER *bp;
372 {
373 long size = 0;
374 LINE *line;
375 line = bp->b_linep;
376 line = lforw(line);
377 while (line != bp->b_linep) {
378 size += llength(line);
379 size++;
380 line = lforw(line);
381 }
382 return size;
383 }
384
385 /*
386 * The argument "text" points to
387 * a string. Append this line to the
388 * buffer. Handcraft the EOL
389 * on the end. Return TRUE if it worked and
390 * FALSE if you ran out of room.
391 */
392 addline(bp, text) register BUFFER *bp; char *text; {
393 register LINE *lp;
394 register int i;
395 register int ntext;
396
397 ntext = strlen(text);
398 if ((lp=lalloc(ntext)) == NULL)
399 return FALSE;
400 for (i=0; i<ntext; ++i)
401 lputc(lp, i, text[i]);
402 bp->b_linep->l_bp->l_fp = lp; /* Hook onto the end */
403 lp->l_bp = bp->b_linep->l_bp;
404 bp->b_linep->l_bp = lp;
405 lp->l_fp = bp->b_linep;
406 #ifdef CANTHAPPEN
407 if (bp->b_dotp == bp->b_linep) /* If "." is at the end */
408 bp->b_dotp = lp; /* move it to new line */
409 if (bp->b_markp == bp->b_linep) /* ditto for mark */
410 bp->b_markp = lp;
411 #endif
412 return TRUE;
413 }
414
415 /*
416 * Look through the list of buffers, giving the user
417 * a chance to save them. Return TRUE if there are
418 * any changed buffers afterwards. Buffers that don't
419 * have an associated file don't count. Return FALSE
420 * if there are no changed buffers.
421 */
422 anycb(f) {
423 register BUFFER *bp;
424 register int s = FALSE, save = FALSE;
425 char *prompt;
426 VOID upmodes();
427
428 for (bp = bheadp; bp != NULL; bp = bp->b_bufp) {
429 if (bp->b_fname != NULL
430 && (bp->b_flag&BFCHG) != 0) {
431 prompt = alloca(10 + strlen(bp->b_fname) + 1);
432 if (prompt != NULL) {
433 (VOID) strcpy(prompt, "Save file ");
434 (VOID) strcpy(prompt + 10, bp->b_fname);
435 }
436 else {
437 prompt = "Save file <Somethings>";
438 }
439 if ((f == TRUE || (save = eyorn(prompt)) == TRUE)
440 && buffsave(bp) == TRUE) {
441 #ifdef AUTOSAVE /* 96.12.24 by M.Suzuki */
442 bp->b_flag &= ~(BFCHG|BFACHG);
443 #else
444 bp->b_flag &= ~BFCHG;
445 #endif /* AUTOSAVE */
446 upmodes(bp);
447 } else s = TRUE;
448 if (save == ABORT) return (save);
449 save = TRUE;
450 }
451 }
452 if (save == FALSE /* && kbdmop == NULL */ ) /* experimental */
453 ewprintf("(No files need saving)");
454 return s;
455 }
456
457 /*
458 * Search for a buffer, by name.
459 * If not found, and the "cflag" is TRUE,
460 * create a buffer and put it in the list of
461 * all buffers. Return pointer to the BUFFER
462 * block for the buffer.
463 */
464 BUFFER *
465 bfind(bname, cflag) register char *bname; {
466 register BUFFER *bp;
467 register LINE *lp;
468 int i;
469 extern int defb_nmodes;
470 extern MAPS *defb_modes[PBMODES];
471 extern int defb_flag;
472 extern int defb_tab;
473
474 bp = bheadp;
475 while (bp != NULL) {
476 if (fncmp(bname, bp->b_bname) == 0)
477 return bp;
478 bp = bp->b_bufp;
479 }
480 if (cflag!=TRUE) return NULL;
481 /*NOSTRICT*/
482 if ((bp=(BUFFER *)malloc(sizeof(BUFFER))) == NULL) {
483 ewprintf("Can't get %d bytes", sizeof(BUFFER));
484 return NULL;
485 }
486 if ((bp->b_bname=malloc((unsigned)(strlen(bname)+1))) == NULL) {
487 ewprintf("Can't get %d bytes", strlen(bname)+1);
488 free((char *) bp);
489 return NULL;
490 }
491 if ((lp = lalloc(0)) == NULL) {
492 free(bp->b_bname);
493 free((char *) bp);
494 return NULL;
495 }
496 #ifdef UNDO
497 bzero(bp->b_ustack, sizeof(UNDO_DATA *)*(UNDOSIZE+1));
498 undo_reset(bp);
499 #endif
500 bp->b_altb = bp->b_bufp = NULL;
501 bp->b_dotp = lp;
502 bp->b_doto = 0;
503 bp->b_markp = NULL;
504 bp->b_marko = 0;
505 bp->b_flag = defb_flag;
506 bp->b_nwnd = 0;
507 bp->b_linep = lp;
508 bp->b_nmodes = defb_nmodes;
509 #ifdef KANJI /* 90.01.29 by S.Yoshida */
510 bp->b_kfio = NIL; /* changed by amura */
511 /* set in fileio.c */
512 #endif /* KANJI */
513 #ifdef VARIABLE_TAB
514 bp->b_tabwidth = defb_tab;
515 #endif /* VARIABLE_TAB */
516 i = 0;
517 do {
518 bp->b_modes[i] = defb_modes[i];
519 } while(i++ < defb_nmodes);
520 bp->b_fname = NULL;
521 #ifdef EXTD_DIR
522 bp->b_cwd = NULL;
523 if (curbp) {
524 if (curbp->b_cwd == NULL) {
525 extern void storecwd pro((BUFFER *bp));
526 storecwd(curbp);
527 }
528 if (curbp->b_cwd != NULL &&
529 (bp->b_cwd=malloc(strlen(curbp->b_cwd)+1)) != NULL)
530 strcpy(bp->b_cwd, curbp->b_cwd);
531 }
532 #endif
533 (VOID) strcpy(bp->b_bname, bname);
534 lp->l_fp = lp;
535 lp->l_bp = lp;
536 bp->b_bufp = bheadp;
537 bheadp = bp;
538 return bp;
539 }
540
541 /*
542 * This routine blows away all of the text
543 * in a buffer. If the buffer is marked as changed
544 * then we ask if it is ok to blow it away; this is
545 * to save the user the grief of losing text. The
546 * window chain is nearly always wrong if this gets
547 * called; the caller must arrange for the updates
548 * that are required. Return TRUE if everything
549 * looks good.
550 */
551 bclear(bp) register BUFFER *bp; {
552 register LINE *lp;
553 register int s;
554 VOID lfree();
555
556 if ((bp->b_flag&BFCHG) != 0 /* Changed. */
557 && (s=eyesno("Buffer modified; kill anyway")) != TRUE)
558 return (s);
559 #ifdef AUTOSAVE /* 96.12.25 by M.Suzuki */
560 if (bp->b_bname && bp->b_bname[0] != '*' ){/* file buffer only */
561 del_autosave_file(bp->b_fname);
562 }
563 bp->b_flag &= ~(BFCHG|BFACHG); /* Not changed */
564 #else
565 bp->b_flag &= ~BFCHG; /* Not changed */
566 #endif /* AUTOSAVE */
567 while ((lp=lforw(bp->b_linep)) != bp->b_linep)
568 lfree(lp);
569 bp->b_dotp = bp->b_linep; /* Fix "." */
570 bp->b_doto = 0;
571 bp->b_markp = NULL; /* Invalidate "mark" */
572 bp->b_marko = 0;
573 return TRUE;
574 }
575
576 /*
577 * Display the given buffer in the given window. Flags indicated
578 * action on redisplay.
579 */
580 showbuffer(bp, wp, flags) register BUFFER *bp; register WINDOW *wp; {
581 register BUFFER *obp;
582 WINDOW *owp;
583
584 if (wp->w_bufp == bp) { /* Easy case! */
585 wp->w_flag |= flags;
586 return TRUE;
587 }
588
589 /* First, dettach the old buffer from the window */
590 if ((bp->b_altb = obp = wp->w_bufp) != NULL) {
591 if (--obp->b_nwnd == 0) {
592 obp->b_dotp = wp->w_dotp;
593 obp->b_doto = wp->w_doto;
594 }
595 }
596
597 /* Now, attach the new buffer to the window */
598 wp->w_bufp = bp;
599
600 if (bp->b_nwnd++ == 0) { /* First use. */
601 wp->w_dotp = bp->b_dotp;
602 wp->w_doto = bp->b_doto;
603 } else
604 /* already on screen, steal values from other window */
605 #ifdef BUGFIX /* ? 90.12.08 Sawayanagi Yosirou */
606 for (owp = wheadp; owp != NULL; owp = owp->w_wndp)
607 if (owp->w_bufp == bp && owp != wp) {
608 #else /* ORIGINAL */
609 for (owp = wheadp; owp != NULL; owp = wp->w_wndp)
610 if (wp->w_bufp == bp && owp != wp) {
611 #endif /* BUGFIX */
612 wp->w_dotp = owp->w_dotp;
613 wp->w_doto = owp->w_doto;
614 break;
615 }
616 wp->w_flag |= WFMODE|flags;
617 return TRUE;
618 }
619
620 /*
621 * Pop the buffer we got passed onto the screen.
622 * Returns a status.
623 */
624 WINDOW *
625 popbuf(bp) register BUFFER *bp; {
626 register WINDOW *wp;
627
628 if (bp->b_nwnd == 0) { /* Not on screen yet. */
629 if ((wp=wpopup()) == NULL) return NULL;
630 } else
631 for (wp = wheadp; wp != NULL; wp = wp->w_wndp)
632 if (wp->w_bufp == bp) {
633 wp->w_flag |= WFHARD|WFFORCE;
634 return wp ;
635 }
636 if (showbuffer(bp, wp, WFHARD) != TRUE) return NULL;
637 return wp;
638 }
639
640 /*
641 * Insert another buffer at dot. Very useful.
642 */
643 /*ARGSUSED*/
644 bufferinsert(f, n)
645 {
646 register BUFFER *bp;
647 register LINE *clp;
648 register int clo;
649 register int nline;
650 int s;
651 char bufn[NBUFN];
652
653 #ifdef READONLY /* 91.01.05 by S.Yoshida */
654 if (curbp->b_flag & BFRONLY) { /* If this buffer is read-only, */
655 warnreadonly(); /* do only displaying warning. */
656 return TRUE;
657 }
658 #endif /* READONLY */
659
660 /* Get buffer to use from user */
661 if (curbp->b_altb != NULL)
662 s=eread("Insert buffer: (default %s) ", bufn, sizeof(bufn),
663 #ifdef BUGFIX /* 91.01.04 by S.Yoshida */
664 EFNEW|EFBUF, curbp->b_altb->b_bname);
665 else
666 s=eread("Insert buffer: ", bufn, sizeof(bufn), EFNEW|EFBUF);
667 #else /* ORIGINAL */
668 EFNEW|EFBUF, &(curbp->b_altb->b_bname),
669 (char *) NULL) ;
670 else
671 s=eread("Insert buffer: ", bufn, sizeof(bufn), EFNEW|EFBUF,
672 (char *) NULL) ;
673 #endif /* BUGFIX */
674 if (s == ABORT) return (s);
675 if (s == FALSE && curbp->b_altb != NULL) bp = curbp->b_altb;
676 else if ((bp=bfind(bufn, FALSE)) == NULL) return FALSE;
677
678 if (bp==curbp) {
679 ewprintf("Cannot insert buffer into self");
680 return FALSE;
681 }
682
683 /* insert the buffer */
684 nline = 0;
685 clp = lforw(bp->b_linep);
686 for(;;) {
687 for (clo = 0; clo < llength(clp); clo++)
688 if (linsert(1, lgetc(clp, clo)) == FALSE)
689 return FALSE;
690 if((clp = lforw(clp)) == bp->b_linep) break;
691 if (newline(FFRAND, 1) == FALSE) /* fake newline */
692 return FALSE;
693 nline++;
694 }
695 if (nline == 1) ewprintf("[Inserted 1 line]");
696 else ewprintf("[Inserted %d lines]", nline);
697
698 clp = curwp->w_linep; /* cosmetic adjustment */
699 if (curwp->w_dotp == clp) { /* for offscreen insert */
700 while (nline > 0 && lback(clp)!=curbp->b_linep) {
701 clp = lback(clp);
702 nline --;
703 }
704 curwp->w_linep = clp; /* adjust framing. */
705 curwp->w_lines = 0;
706 curwp->w_flag |= WFHARD;
707 }
708 return (TRUE);
709 }
710
711 /*
712 * Turn off the dirty bit on this buffer.
713 */
714 /*ARGSUSED*/
715 notmodified(f, n)
716 {
717 register WINDOW *wp;
718
719 #ifdef AUTOSAVE /* 96.12.24 by M.Suzuki */
720 curbp->b_flag &= ~(BFCHG|BFACHG);
721 #else
722 curbp->b_flag &= ~BFCHG;
723 #endif /* AUTOSAVE */
724 wp = wheadp; /* Update mode lines. */
725 while (wp != NULL) {
726 if (wp->w_bufp == curbp)
727 wp->w_flag |= WFMODE;
728 wp = wp->w_wndp;
729 }
730 ewprintf("Modification-flag cleared");
731 return TRUE;
732 }
733
734 #ifdef READONLY /* 91.01.05 by S.Yoshida */
735 /*
736 * Toggle the read-only bit on this buffer.
737 */
738 /*ARGSUSED*/
739 togglereadonly(f, n)
740 {
741 register WINDOW *wp;
742
743 curbp->b_flag ^= BFRONLY; /* Toggle read-only bit. */
744 wp = wheadp; /* Update mode lines. */
745 while (wp != NULL) {
746 if (wp->w_bufp == curbp)
747 wp->w_flag |= WFMODE;
748 wp = wp->w_wndp;
749 }
750 return TRUE;
751 }
752
753 /*
754 * Display warning message.
755 */
756 VOID
757 warnreadonly()
758 {
759 ewprintf("Buffer is read-only: #<buffer %s>", curbp->b_bname);
760 ttbeep(); /* 91.02.06 Add beep. by S.Yoshida */
761 }
762 #endif /* READONLY */
763
764 #ifndef NO_HELP
765 /*
766 * Popbuf and set all windows to top of buffer. Currently only used by
767 * help functions.
768 */
769
770 popbuftop(bp)
771 register BUFFER *bp;
772 {
773 register WINDOW *wp;
774
775 bp->b_dotp = lforw(bp->b_linep);
776 bp->b_doto = 0;
777 if(bp->b_nwnd != 0) {
778 for(wp = wheadp; wp!=NULL; wp = wp->w_wndp)
779 if(wp->w_bufp == bp) {
780 wp->w_dotp = bp->b_dotp;
781 wp->w_doto = 0;
782 wp->w_flag |= WFHARD;
783 }
784 }
785 return popbuf(bp) != NULL;
786 }
787 #endif
788
789 #if defined(CMODE)||defined(VARIABLE_TAB)||defined(AUTOSAVE)
790 #define USING_GETNUM 1
791 #endif
792
793 #ifdef USING_GETNUM
794 getnum(prompt, num)
795 char *prompt;
796 int *num;
797 {
798 char numstr[GETNUMLEN];
799
800 if (ereply("%s : ", numstr, GETNUMLEN, prompt) == FALSE)
801 return (FALSE);
802 *num = atoi(numstr);
803 return (TRUE);
804 }
805 #undef USING_GETNUM
806 #endif /* USING_GETNUM */
807
808 #ifdef VARIABLE_TAB
809 set_default_tabwidth(f, n)
810 int f, n;
811 {
812 if ((f & FFARG) == 0)
813 {
814 if (getnum("default-tab-width", &n) == FALSE)
815 return (FALSE);
816 }
817 if (n>64 || n<=2)
818 return (FALSE);
819 defb_tab = n;
820 return (TRUE);
821 }
822
823 set_tabwidth(f, n)
824 int f, n;
825 {
826 extern int refresh();
827 if ((f & FFARG) == 0)
828 {
829 if (getnum("tab-width", &n) == FALSE)
830 return (FALSE);
831 }
832 if (n == 0)
833 n = defb_tab;
834 else if (n>64 || n<=2)
835 return (FALSE);
836 curbp->b_tabwidth = n;
837 if (f >= 0)
838 refresh(0, 0);
839 return (TRUE);
840 }
841
842 set_cmode_tabwidth(f, n)
843 int f, n;
844 {
845 if ((f & FFARG) == 0)
846 {
847 if (getnum("c-tab-width", &n) == FALSE)
848 return (FALSE);
849 }
850 if (n>64 || n<=2)
851 return (FALSE);
852 cmode_tab = n;
853 return (TRUE);
854 }
855 #endif /* VARIABLE_TAB */
856
857 #ifdef BUFFER_MODE
858
859 #define BUFNAME_START_COL 4
860
861 static int
862 b_makename(lp, buf, len)
863 LINE *lp;
864 char *buf;
865 int len;
866 {
867 if (BUFNAME_START_COL < llength(lp)) {
868 char *p = lp->l_text + BUFNAME_START_COL, *q = buf, *ep = p + NBUFN;
869
870 while (*ep == ' ') {
871 ep--;
872 }
873 ep++;
874 while (p < ep) {
875 *q++ = *p++;
876 }
877 *q = '\0';
878 return TRUE;
879 }
880 return FALSE;
881 }
882
883 /*ARGSUSED*/
884 b_thiswin(f, n)
885 int f, n;
886 {
887 char bufname[NBUFN];
888 register BUFFER *bp;
889 LINE *lp = curwp->w_dotp;
890 int s;
891
892 s = b_makename(lp, bufname, NBUFN);
893 if (s) {
894 bp = bfind(bufname, FALSE);
895 if (bp != NULL) {
896 /* put it in current window */
897 curbp = bp;
898 return showbuffer(bp, curwp, WFFORCE|WFHARD);
899 }
900 else {
901 ewprintf("No buffer named \"%s\"", bufname);
902 }
903 }
904 return FALSE;
905 }
906
907 /*ARGSUSED*/
908 static
909 b_delundel(ch)
910 int ch;
911 {
912 LINE *lp = curwp->w_dotp;
913
914 if (lback(lp) != curbp->b_linep &&
915 lback(lback(lp)) != curbp->b_linep) {
916 if (llength(lp) > 0) {
917 lputc(lp, 0, ch);
918 }
919 if (lforw(lp) != curbp->b_linep) {
920 curwp->w_dotp = lforw(lp);
921 }
922 curwp->w_flag |= WFEDIT | WFMOVE;
923 curwp->w_doto = 0;
924 return TRUE;
925 }
926 return FALSE;
927 }
928
929 /*ARGSUSED*/
930 b_del(f, n)
931 int f, n;
932 {
933 return b_delundel((int)'D');
934 }
935
936 /*ARGSUSED*/
937 b_undel(f, n)
938 int f, n;
939 {
940 return b_delundel((int)' ');
941 }
942
943 /*ARGSUSED*/
944 b_expunge(f, n)
945 int f, n;
946 {
947 char bufname[NBUFN];
948 register LINE *lp, *nlp;
949 VOID lfree();
950
951 for (lp = lforw(curbp->b_linep) ; lp != curbp->b_linep ; lp = nlp) {
952 nlp = lforw(lp);
953 if (0 < llength(lp) && lgetc(lp, 0) == 'D') {
954 switch (b_makename(lp, bufname, NBUFN)) {
955 case FALSE:
956 break;
957
958 case TRUE:
959 eargset(bufname);
960 if (killbuffer(f, n)) {
961 lfree(lp);
962 curwp->w_flag |= WFHARD;
963 }
964 break;
965 }
966 }
967 }
968 return TRUE;
969 }
970 #endif /* BUFFER_MODE */
971