BSD 4_3 development
[unix-history] / usr / contrib / jove / buf.c
CommitLineData
394a1d25
C
1/*************************************************************************
2 * This program is copyright (C) 1985, 1986 by Jonathan Payne. It is *
3 * provided to you without charge for use only on a licensed Unix *
4 * system. You may copy JOVE provided that this notice is included with *
5 * the copy. You may not sell copies of this program or versions *
6 * modified for use on microcomputer systems, unless the copies are *
7 * included with a Unix system distribution and the source is provided. *
8 *************************************************************************/
9
10/* Contains commands that deal with creating, selecting, killing and
11 listing buffers, and buffer modes, and find-file, etc. */
12
13#include "jove.h"
14
15#include <sys/stat.h>
16
17char *Mainbuf = "Main",
18 *NoName = "Sans un nom!";
19
20Buffer *world = 0, /* First in the list */
21 *curbuf = 0,
22 *lastbuf = 0; /* Last buffer we were in so we have a default
23 buffer during a select buffer. */
24
25/* Toggle BIT in the current buffer's minor mode flags. If argument is
26 supplied, a positive one always turns on the mode and zero argument
27 always turns it off. */
28
29TogMinor(bit)
30{
31 if (exp_p) {
32 if (exp == 0)
33 curbuf->b_minor &= ~bit;
34 else
35 curbuf->b_minor |= bit;
36 } else
37 curbuf->b_minor ^= bit;
38 UpdModLine++;
39}
40
41/* Creates a new buffer, links it at the end of the buffer chain, and
42 returns it. */
43
44static Buffer *
45buf_alloc()
46{
47 register Buffer *b,
48 *lastbp;
49
50 lastbp = 0;
51 for (b = world; b != 0; lastbp = b, b = b->b_next)
52 ;
53
54 b = (Buffer *) emalloc(sizeof (Buffer));
55 if (lastbp)
56 lastbp->b_next = b;
57 else
58 world = b;
59 b->b_first = 0;
60 b->b_next = 0;
61
62 return b;
63}
64
65/* Makes a buffer and initializes it. Obsolete. Used to take two
66 arguments, a buffer name and a file name. */
67
68static Buffer *
69mak_buf()
70{
71 register Buffer *newb;
72 register int i;
73
74 newb = buf_alloc();
75 newb->b_fname = 0;
76 newb->b_name = NoName;
77 set_ino(newb);
78 newb->b_marks = 0;
79 newb->b_themark = 0; /* Index into markring */
80 /* No marks yet */
81 for (i = 0; i < NMARKS; i++)
82 newb->b_markring[i] = 0;
83 newb->b_modified = 0;
84 newb->b_type = B_FILE; /* File until proven SCRATCH */
85 newb->b_ntbf = 0;
86 newb->b_minor = 0;
87 newb->b_major = TEXT;
88 newb->b_first = 0;
89 initlist(newb);
90 return newb;
91}
92
93ReNamBuf()
94{
95 register char *new = 0,
96 *prompt = ProcFmt,
97 *second = "%s already exists; new name? ";
98
99 for (;;) {
100 new = ask((char *) 0, prompt, new);
101 if (!buf_exists(new))
102 break;
103 prompt = second;
104 }
105 setbname(curbuf, new);
106}
107
108FindFile()
109{
110 register char *name;
111 char fnamebuf[FILESIZE];
112
113 name = ask_file(curbuf->b_fname, fnamebuf);
114 SetABuf(curbuf);
115 SetBuf(do_find(curwind, name, 0));
116}
117
118static
119mkbuflist(bnamp)
120register char **bnamp;
121{
122 register Buffer *b;
123
124 for (b = world; b != 0; b = b->b_next)
125 if (b->b_name != 0)
126 *bnamp++ = b->b_name;
127 *bnamp = 0;
128}
129
130char *
131ask_buf(def)
132Buffer *def;
133{
134 char *bnames[100];
135 register char *bname;
136 register int offset;
137 char prompt[100];
138
139 if (def != 0 && def->b_name != 0)
140 sprintf(prompt, ": %f (default %s) ", def->b_name);
141 else
142 sprintf(prompt, ProcFmt);
143 mkbuflist(bnames);
144 offset = complete(bnames, prompt, RET_STATE);
145 if (offset == EOF)
146 complain((char *) 0);
147 if (offset == ORIGINAL)
148 bname = Minibuf;
149 else if (offset == NULLSTRING) {
150 if (def)
151 bname = def->b_name;
152 else
153 complain((char *) 0);
154 } else if (offset < 0)
155 complain((char *) 0);
156 else
157 bname = bnames[offset];
158
159 return bname;
160}
161
162BufSelect()
163{
164 register char *bname;
165
166 bname = ask_buf(lastbuf);
167 SetABuf(curbuf);
168 SetBuf(do_select(curwind, bname));
169}
170
171static
172defb_wind(b)
173register Buffer *b;
174{
175 register Window *w = fwind;
176 char *alt;
177
178 if (lastbuf == b || lastbuf == 0) {
179 lastbuf = 0;
180 alt = (b->b_next != 0) ? b->b_next->b_name : Mainbuf;
181 } else
182 alt = lastbuf->b_name;
183
184 do {
185 if (w->w_bufp == b) {
186 if (one_windp())
187 (void) do_select(w, alt);
188 else {
189 register Window *save = w->w_next;
190
191 del_wind(w);
192 w = save->w_prev;
193 }
194 }
195 w = w->w_next;
196 } while (w != fwind);
197}
198
199Buffer *
200getNMbuf()
201{
202 register Buffer *delbuf;
203 register char *bname;
204
205 bname = ask_buf(curbuf);
206 if ((delbuf = buf_exists(bname)) == 0)
207 complain("[No such buffer]");
208 if (delbuf->b_modified)
209 confirm("%s modified, are you sure? ", bname);
210 return delbuf;
211}
212
213BufErase()
214{
215 register Buffer *delbuf;
216
217 if (delbuf = getNMbuf()) {
218 initlist(delbuf);
219 delbuf->b_modified = 0;
220 }
221}
222
223static
224kill_buf(delbuf)
225register Buffer *delbuf;
226{
227 register Buffer *b,
228 *lastb = 0;
229 extern Buffer *perr_buf;
230
231#ifdef IPROCS
232 pbuftiedp(delbuf); /* Make sure buffer is not tied to a process */
233#endif
234 for (b = world; b != 0; lastb = b, b = b->b_next)
235 if (b == delbuf)
236 break;
237 if (lastb)
238 lastb->b_next = delbuf->b_next;
239 else
240 world = delbuf->b_next;
241
242#define okay_free(ptr) if (ptr) free(ptr)
243
244 lfreelist(delbuf->b_first);
245 okay_free(delbuf->b_name);
246 okay_free(delbuf->b_fname);
247 free((char *) delbuf);
248
249 if (delbuf == lastbuf)
250 SetABuf(curbuf);
251 if (perr_buf == delbuf) {
252 ErrFree();
253 perr_buf = 0;
254 }
255 defb_wind(delbuf);
256 if (curbuf == delbuf)
257 SetBuf(curwind->w_bufp);
258}
259
260/* offer to kill some buffers */
261
262KillSome()
263{
264 register Buffer *b,
265 *next;
266 Buffer *oldb;
267 register char *y_or_n;
268
269 for (b = world; b != 0; b = next) {
270 next = b->b_next;
271 y_or_n = ask("No", "Kill %s? ", b->b_name);
272 if (Upper(*y_or_n) != 'Y')
273 continue;
274 if (IsModified(b)) {
275 y_or_n = ask("No", "%s modified; should I save it? ", b->b_name);
276 if (Upper(*y_or_n) == 'Y') {
277 oldb = curbuf;
278 SetBuf(b);
279 SaveFile();
280 SetBuf(oldb);
281 }
282 }
283 kill_buf(b);
284 }
285}
286
287BufKill()
288{
289 Buffer *b;
290
291 if ((b = getNMbuf()) == 0)
292 return;
293 kill_buf(b);
294}
295
296static char *
297line_cnt(b, buf)
298register Buffer *b;
299char *buf;
300{
301 register int nlines = 0;
302 register Line *lp;
303
304 for (lp = b->b_first; lp != 0; lp = lp->l_next, nlines++)
305 ;
306 sprintf(buf, "%d", nlines);
307 return buf;
308}
309
310static char *TypeNames[] = {
311 0,
312 "Scratch",
313 "File",
314 "Process",
315 "I-process"
316};
317
318BufList()
319{
320 register char *format = "%-2s %-5s %-11s %-1s %-*s %-s";
321 register Buffer *b;
322 int bcount = 1, /* To give each buffer a number */
323 buf_width = 11;
324 char nbuf[10];
325 extern int ModCount;
326
327 for (b = world; b != 0; b = b->b_next)
328 buf_width = max(buf_width, strlen(b->b_name));
329
330 TOstart("Buffer list", TRUE); /* true means auto-newline */
331
332 Typeout("(* means buffer needs saving)");
333 Typeout("(+ means file hasn't been read yet)");
334 Typeout(NullStr);
335 Typeout(format, "NO", "Lines", "Type", NullStr, buf_width, "Name", "File");
336 Typeout(format, "--", "-----", "----", NullStr, buf_width, "----", "----");
337 for (b = world; b != 0; b = b->b_next) {
338 Typeout(format, itoa(bcount++),
339 line_cnt(b, nbuf),
340 TypeNames[b->b_type],
341 IsModified(b) ? "*" :
342 b->b_ntbf ? "+" : NullStr,
343 buf_width,
344 /* For the * (variable length field) */
345 b->b_name,
346 filename(b));
347
348 if (TOabort)
349 break;
350 }
351 TOstop();
352}
353
354bufname(b)
355register Buffer *b;
356{
357 char tmp[100],
358 *cp;
359 int try = 1;
360
361 if (b->b_fname == 0)
362 complain("[No file name]");
363 cp = basename(b->b_fname);
364 strcpy(tmp, cp);
365 while (buf_exists(tmp)) {
366 sprintf(tmp, "%s.%d", cp, try);
367 try++;
368 }
369 setbname(b, tmp);
370}
371
372initlist(b)
373register Buffer *b;
374{
375 lfreelist(b->b_first);
376 b->b_first = b->b_dot = b->b_last = 0;
377 (void) listput(b, b->b_first);
378
379 SavLine(b->b_dot, NullStr);
380 b->b_char = 0;
381 AllMarkSet(b, b->b_dot, 0);
382 if (b == curbuf)
383 getDOT();
384}
385
386/* Returns pointer to buffer with name NAME, or if NAME is a string of digits
387 returns the buffer whose number equals those digits. Otherwise, returns
388 0. */
389
390Buffer *
391buf_exists(name)
392register char *name;
393{
394 register Buffer *bp;
395 register int n;
396
397 if (name == 0)
398 return 0;
399
400 for (bp = world; bp != 0; bp = bp->b_next)
401 if (strcmp(bp->b_name, name) == 0)
402 return bp;
403
404 /* Doesn't match any names. Try for a buffer number... */
405
406 if ((n = chr_to_int(name, 10, 1)) > 0) {
407 for (bp = world; n > 1; bp = bp->b_next) {
408 if (bp == 0)
409 break;
410 --n;
411 }
412 return bp;
413 }
414
415 return 0;
416}
417
418/* Returns buffer pointer with a file name NAME, if one exists. Stat's the
419 file and compares inodes, in case NAME is a link, as well as the actual
420 characters that make up the file name. */
421
422Buffer *
423file_exists(name)
424register char *name;
425{
426 struct stat stbuf;
427 register struct stat *s = &stbuf;
428 register Buffer *b = 0;
429 char fnamebuf[FILESIZE];
430
431 if (name) {
432 PathParse(name, fnamebuf);
433 if (stat(fnamebuf, s) == -1)
434 s->st_ino = 0;
435 for (b = world; b != 0; b = b->b_next) {
436 if ((b->b_ino != 0 && b->b_ino == s->st_ino) ||
437 (strcmp(b->b_fname, fnamebuf) == 0))
438 break;
439 }
440 }
441 return b;
442}
443
444char *
445ralloc(obj, size)
446register char *obj;
447{
448 register char *new;
449
450 if (obj)
451 new = realloc(obj, (unsigned) size);
452 if (new == 0 || !obj)
453 new = emalloc(size);
454 return new;
455}
456
457setbname(b, name)
458register Buffer *b;
459register char *name;
460{
461 UpdModLine++; /* Kludge ... but speeds things up considerably */
462 if (name) {
463 if (b->b_name == NoName)
464 b->b_name = 0;
465 b->b_name = ralloc(b->b_name, strlen(name) + 1);
466 strcpy(b->b_name, name);
467 } else
468 b->b_name = 0;
469}
470
471setfname(b, name)
472register Buffer *b;
473register char *name;
474{
475 char wholename[FILESIZE],
476 oldname[FILESIZE],
477 *oldptr = oldname;
478 Buffer *save = curbuf;
479
480 SetBuf(b);
481 UpdModLine++; /* Kludge ... but speeds things up considerably */
482 if (b->b_fname == 0)
483 oldptr = 0;
484 else
485 strcpy(oldname, b->b_fname);
486 if (name) {
487 PathParse(name, wholename);
488 curbuf->b_fname = ralloc(curbuf->b_fname, strlen(wholename) + 1);
489 strcpy(curbuf->b_fname, wholename);
490 } else
491 b->b_fname = 0;
492 DoAutoExec(curbuf->b_fname, oldptr);
493 curbuf->b_mtime = curbuf->b_ino = 0; /* until they're known. */
494 SetBuf(save);
495}
496
497set_ino(b)
498register Buffer *b;
499{
500 struct stat stbuf;
501
502 if (b->b_fname == 0 || stat(b->b_fname, &stbuf) == -1) {
503 b->b_ino = 0;
504 b->b_mtime = 0;
505 } else {
506 b->b_ino = stbuf.st_ino;
507 b->b_mtime = stbuf.st_mtime;
508 }
509}
510
511/* Find the file `fname' into buf and put in in window `w' */
512
513Buffer *
514do_find(w, fname, force)
515register Window *w;
516register char *fname;
517{
518 register Buffer *b;
519
520 b = file_exists(fname);
521 if (b == 0) {
522 b = mak_buf();
523 setfname(b, fname);
524 bufname(b);
525 set_ino(b);
526 b->b_ntbf = 1;
527 if (force) {
528 Buffer *oldb = curbuf;
529
530 SetBuf(b); /* this'll read the file */
531 SetBuf(oldb);
532 }
533 }
534 if (w)
535 tiewind(w, b);
536 return b;
537}
538
539/* Set alternate buffer */
540
541SetABuf(b)
542Buffer *b;
543{
544 if (b != 0)
545 lastbuf = b;
546}
547
548SetBuf(newbuf)
549register Buffer *newbuf;
550{
551 register Buffer *oldb = curbuf;
552
553 if (newbuf == curbuf || newbuf == 0)
554 return;
555
556 lsave();
557 curbuf = newbuf;
558 getDOT();
559 /* Do the read now ... */
560 if (curbuf->b_ntbf)
561 read_file(curbuf->b_fname, 0);
562
563#ifdef IPROCS
564 if (oldb != 0 && oldb->b_type != curbuf->b_type) {
565 if (curbuf->b_type == B_IPROCESS)
566 PushPBs(); /* Push process bindings */
567 else if (oldb->b_type == B_IPROCESS)
568 PopPBs();
569 }
570 assign_p(); /* Set cur_proc */
571#endif
572}
573
574Buffer *
575do_select(w, name)
576register Window *w;
577register char *name;
578{
579 register Buffer *new;
580
581 if ((new = buf_exists(name)) == 0) {
582 new = mak_buf();
583 setfname(new, (char *) 0);
584 setbname(new, name);
585 }
586 if (w)
587 tiewind(w, new);
588 return new;
589}