|
|
1.1 root 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: #include "jove.h"
11:
12: #include "ctype.h"
13:
14: /* Make a newline after AFTER in buffer BUF, UNLESS after is 0,
15: in which case we insert the newline before after. */
16:
17: Line *
18: listput(buf, after)
19: register Buffer *buf;
20: register Line *after;
21: {
22: register Line *newline = nbufline();
23:
24: if (after == 0) { /* Before the first line */
25: newline->l_next = buf->b_first;
26: newline->l_prev = 0;
27: buf->b_first = newline;
28: } else {
29: newline->l_prev = after;
30: newline->l_next = after->l_next;
31: after->l_next = newline;
32: }
33: if (newline->l_next)
34: newline->l_next->l_prev = newline;
35: else
36: if (buf)
37: buf->b_last = newline;
38: if (buf && buf->b_dot == 0)
39: buf->b_dot = newline;
40: return newline;
41: }
42:
43: /* Divide the current line and move the current line to the next one */
44:
45: LineInsert()
46: {
47: register int num = exp;
48: char newline[LBSIZE];
49: register Line *newdot,
50: *olddot;
51: int oldchar;
52:
53: exp = 1;
54: olddot = curline;
55: oldchar = curchar;
56:
57: newdot = curline;
58: while (--num >= 0) {
59: newdot = listput(curbuf, newdot);
60: SavLine(newdot, NullStr);
61: }
62:
63: modify();
64: if (curchar != 0) {
65: strcpy(newline, &linebuf[curchar]);
66: linebuf[curchar] = '\0'; /* Shorten this line */
67: SavLine(curline, linebuf);
68: strcpy(linebuf, newline);
69: } else { /* Redisplay optimization */
70: newdot->l_dline = curline->l_dline;
71: SavLine(curline, NullStr);
72: }
73:
74: makedirty(curline);
75: curline = newdot;
76: curchar = 0;
77: makedirty(curline);
78: IFixMarks(olddot, oldchar, curline, curchar);
79: }
80:
81: n_indent(goal)
82: register int goal;
83: {
84: if (goal < 0)
85: return;
86: DoTimes(Insert('\t'), (goal / tabstop));
87: if (goal % tabstop)
88: DoTimes(Insert(' '), (goal % tabstop));
89: exp_p = 0;
90: exp = 1;
91: }
92:
93: SelfInsert()
94: {
95: #ifdef ABBREV
96: if (MinorMode(Abbrev) && !ismword(LastKeyStruck) &&
97: !bolp() && ismword(linebuf[curchar - 1]))
98: AbbrevExpand();
99: #endif
100: if (MinorMode(OverWrite)) {
101: register int num,
102: i;
103:
104: for (i = 0, num = exp, exp = 1; i < num; i++) {
105: int pos = calc_pos(linebuf, curchar);
106:
107: if (!eolp()) {
108: if (linebuf[curchar] == '\t') {
109: if ((pos + 1) == ((pos + tabstop) - (pos % tabstop)))
110: DelNChar();
111: } else
112: DelNChar();
113: }
114: Insert(LastKeyStruck);
115: }
116: } else
117: Insert(LastKeyStruck);
118:
119: if (MinorMode(Fill) && (curchar >= RMargin ||
120: (calc_pos(linebuf, curchar) >= RMargin)))
121: DoJustify(curline, 0, curline,
122: curchar + strlen(&linebuf[curchar]), 1, LMargin);
123: }
124:
125: Insert(c)
126: {
127: if (exp <= 0)
128: return;
129: modify();
130: makedirty(curline);
131: ins_c(c, linebuf, curchar, exp, LBSIZE);
132: IFixMarks(curline, curchar, curline, curchar + exp);
133: curchar += exp;
134: }
135:
136: /* Tab in to the right place for C mode */
137:
138: Tab()
139: {
140: #ifdef LISP
141: if (MajorMode(LISPMODE)) {
142: Mark *m = bolp() ? 0 : MakeMark(curline, curchar, FLOATER);
143:
144: Bol();
145: DelWtSpace();
146: (void) lisp_indent();
147: if (m) {
148: ToMark(m);
149: DelMark(m);
150: }
151: if (bolp())
152: ToIndent();
153: return;
154: }
155: #endif
156: if (MajorMode(CMODE) && strlen(linebuf) == 0)
157: (void) c_indent(CIndIncrmt);
158: else
159: SelfInsert();
160: }
161:
162: QuotChar()
163: {
164: int c;
165: extern int alarmed; /* If waitfor had to wait. */
166:
167: c = waitchar();
168: if (alarmed)
169: message(key_strokes);
170: if (c == CTL(J))
171: LineInsert();
172: else if (c != CTL(@))
173: Insert(c);
174: }
175:
176: /* Insert the paren. If in C mode and c is a '}' then insert the
177: '}' in the "right" place for C indentation; that is indented
178: the same amount as the matching '{' is indented. */
179:
180: int PDelay = 5, /* 1/2 a second */
181: CIndIncrmt = 8;
182:
183: DoParen()
184: {
185: Bufpos *bp = (Bufpos *) -1;
186: int nx,
187: c = LastKeyStruck;
188:
189: if (!isclosep(c)) {
190: SelfInsert();
191: return;
192: }
193:
194: if (MajorMode(CMODE) && c == '}' && blnkp(linebuf)) {
195: DelWtSpace();
196: bp = c_indent(0);
197: }
198: #ifdef LISP
199: if (MajorMode(LISPMODE) && c == ')' && blnkp(linebuf)) {
200: DelWtSpace();
201: bp = lisp_indent();
202: }
203: #endif
204: SelfInsert();
205: if (MinorMode(ShowMatch) && !charp() && !in_macro()) {
206: BackChar(); /* Back onto the ')' */
207: if ((int) bp == -1)
208: bp = m_paren(c, BACKWARD, NO, YES);
209: ForChar();
210: if (bp != 0) {
211: nx = in_window(curwind, bp->p_line);
212: if (nx != -1) { /* is visible */
213: Bufpos b;
214:
215: DOTsave(&b);
216: SetDot(bp);
217: (void) SitFor(PDelay);
218: SetDot(&b);
219: } else
220: s_mess("%s", lcontents(bp->p_line));
221: }
222: mp_error(); /* display error message */
223: }
224: }
225:
226: LineAI()
227: {
228: DoNewline(TRUE);
229: }
230:
231: Newline()
232: {
233: DoNewline(MinorMode(Indent));
234: }
235:
236: DoNewline(indentp)
237: {
238: Bufpos save;
239: int indent;
240:
241: /* first we calculate the indent of the current line */
242: DOTsave(&save);
243: ToIndent();
244: indent = calc_pos(linebuf, curchar);
245: SetDot(&save);
246:
247: /* If there is more than 2 blank lines in a row then don't make
248: a newline, just move down one. */
249:
250: #ifdef ABBREV
251: if (MinorMode(Abbrev) && !ismword(LastKeyStruck) &&
252: !bolp() && ismword(linebuf[curchar - 1]))
253: AbbrevExpand();
254: #endif
255: #ifdef LISP
256: if (MajorMode(LISPMODE))
257: DelWtSpace();
258: #endif
259: else if (blnkp(linebuf))
260: DelWtSpace();
261:
262: if (exp == 1 && eolp() && TwoBlank())
263: SetLine(curline->l_next);
264: else
265: LineInsert();
266:
267: if (indentp)
268: #ifdef LISP
269: if (MajorMode(LISPMODE))
270: (void) lisp_indent();
271: else
272: #endif
273: n_indent((LMargin == 0) ? indent : LMargin);
274: }
275:
276: ins_str(str, ok_nl)
277: register char *str;
278: {
279: register char c;
280: Bufpos save;
281: int llen;
282:
283: DOTsave(&save);
284: llen = strlen(linebuf);
285: while (c = *str++) {
286: if (c == '\n' || (ok_nl && llen >= LBSIZE - 2)) {
287: IFixMarks(save.p_line, save.p_char, curline, curchar);
288: modify();
289: makedirty(curline);
290: LineInsert();
291: DOTsave(&save);
292: llen = strlen(linebuf);
293: }
294: if (c != '\n') {
295: ins_c(c, linebuf, curchar++, 1, LBSIZE);
296: llen++;
297: }
298: }
299: IFixMarks(save.p_line, save.p_char, curline, curchar);
300: modify();
301: makedirty(curline);
302: }
303:
304: OpenLine()
305: {
306: Bufpos dot;
307:
308: DOTsave(&dot);
309: LineInsert(); /* Open the lines... */
310: SetDot(&dot);
311: }
312:
313: /* Take the region FLINE/FCHAR to TLINE/TCHAR and insert it at
314: ATLINE/ATCHAR in WHATBUF. */
315:
316: Bufpos *
317: DoYank(fline, fchar, tline, tchar, atline, atchar, whatbuf)
318: Line *fline,
319: *tline,
320: *atline;
321: Buffer *whatbuf;
322: {
323: register Line *newline;
324: static Bufpos bp;
325: char save[LBSIZE],
326: buf[LBSIZE];
327: Line *startline = atline;
328: int startchar = atchar;
329:
330: lsave();
331: if (whatbuf)
332: modify();
333: (void) ltobuf(atline, genbuf);
334: strcpy(save, &genbuf[atchar]);
335:
336: (void) ltobuf(fline, buf);
337: if (fline == tline)
338: buf[tchar] = '\0';
339:
340: linecopy(genbuf, atchar, &buf[fchar]);
341: atline->l_dline = putline(genbuf);
342: makedirty(atline);
343:
344: fline = fline->l_next;
345: while (fline != tline->l_next) {
346: newline = listput(whatbuf, atline);
347: newline->l_dline = fline->l_dline;
348: makedirty(newline);
349: fline = fline->l_next;
350: atline = newline;
351: atchar = 0;
352: }
353:
354: (void) getline(atline->l_dline, genbuf);
355: atchar += tchar;
356: linecopy(genbuf, atchar, save);
357: atline->l_dline = putline(genbuf);
358: makedirty(atline);
359: IFixMarks(startline, startchar, atline, atchar);
360: bp.p_line = atline;
361: bp.p_char = atchar;
362: this_cmd = YANKCMD;
363: getDOT(); /* Whatever used to be in linebuf */
364: return &bp;
365: }
366:
367: YankPop()
368: {
369: Line *line,
370: *last;
371: Mark *mp = CurMark();
372: Bufpos *dot;
373: int dir = -1; /* Direction to rotate the ring */
374:
375: if (last_cmd != YANKCMD)
376: complain("Yank something first!");
377:
378: lfreelist(reg_delete(mp->m_line, mp->m_char, curline, curchar));
379:
380: /* Now must find a recently killed region. */
381:
382: if (exp < 0)
383: dir = 1;
384:
385: killptr += dir;
386: for (;;) {
387: if (killptr < 0)
388: killptr = NUMKILLS - 1;
389: else if (killptr >= NUMKILLS)
390: killptr = 0;
391: if (killbuf[killptr])
392: break;
393: killptr += dir;
394: }
395:
396: this_cmd = YANKCMD;
397:
398: line = killbuf[killptr];
399: last = lastline(line);
400: dot = DoYank(line, 0, last, length(last), curline, curchar, curbuf);
401: MarkSet(CurMark(), curline, curchar);
402: SetDot(dot);
403: }
404:
405: /* This is an attempt to reduce the amount of memory taken up by each line.
406: Without this each malloc of a line uses sizeof (line) + sizeof(HEADER)
407: where line is 3 words and HEADER is 1 word.
408: This is going to allocate memory in chucks of CHUNKSIZE * sizeof (line)
409: and divide each chuck into lineS. A line is free in a chunk when its
410: line->l_dline == 0, so freeline sets dline to 0. */
411:
412: #define CHUNKSIZE 300
413:
414: struct chunk {
415: int c_nlines; /* Number of lines in this chunk (so they
416: don't all have to be CHUNKSIZE long). */
417: Line *c_block; /* Chunk of memory */
418: struct chunk *c_nextfree; /* Next chunk of lines */
419: };
420:
421: static struct chunk *fchunk = 0;
422: static Line *ffline = 0; /* First free line */
423:
424: freeline(line)
425: register Line *line;
426: {
427: line->l_dline = 0;
428: line->l_next = ffline;
429: if (ffline)
430: ffline->l_prev = line;
431: line->l_prev = 0;
432: ffline = line;
433: }
434:
435: lfreelist(first)
436: register Line *first;
437: {
438: if (first)
439: lfreereg(first, lastline(first));
440: }
441:
442: /* Append region from line1 to line2 onto the free list of lines */
443:
444: lfreereg(line1, line2)
445: register Line *line1,
446: *line2;
447: {
448: register Line *next,
449: *last = line2->l_next;
450:
451: while (line1 != last) {
452: next = line1->l_next;
453: freeline(line1);
454: line1 = next;
455: }
456: }
457:
458: static
459: newchunk()
460: {
461: register Line *newline;
462: register int i;
463: struct chunk *f;
464: int nlines = CHUNKSIZE;
465:
466: f = (struct chunk *) emalloc(sizeof (struct chunk));
467: if (f == 0)
468: return 0;
469:
470: if ((f->c_block = (Line *) malloc((unsigned) (sizeof (Line) * nlines))) == 0) {
471: while (nlines > 0) {
472: f->c_block = (Line *) malloc((unsigned) (sizeof (Line) * nlines));
473: if (f->c_block != 0)
474: break;
475: nlines /= 2;
476: }
477: }
478:
479: if (nlines <= 0)
480: return 0;
481:
482: f->c_nlines = nlines;
483: for (i = 0, newline = f->c_block; i < nlines; newline++, i++)
484: freeline(newline);
485: f->c_nextfree = fchunk;
486: fchunk = f;
487: return 1;
488: }
489:
490: /* New BUFfer LINE */
491:
492: Line *
493: nbufline()
494: {
495: register Line *newline;
496:
497: if (ffline == 0) /* No free list */
498: if (newchunk() == 0)
499: complain("[Out of lines] ");
500: newline = ffline;
501: ffline = ffline->l_next;
502: if (ffline)
503: ffline->l_prev = 0;
504: return newline;
505: }
506:
507: /* Remove the free lines, in chunk c, from the free list because they are
508: no longer free. */
509:
510: static
511: remfreelines(c)
512: register struct chunk *c;
513: {
514: register Line *lp;
515: register int i;
516:
517: for (lp = c->c_block, i = 0; i < c->c_nlines; i++, lp++) {
518: if (lp->l_prev)
519: lp->l_prev->l_next = lp->l_next;
520: else
521: ffline = lp->l_next;
522: if (lp->l_next)
523: lp->l_next->l_prev = lp->l_prev;
524: }
525: }
526:
527: /* This is used to garbage collect the chunks of lines when malloc fails
528: and we are NOT looking for a new buffer line. This goes through each
529: chunk, and if every line in a given chunk is not allocated, the entire
530: chunk is `free'd by "free()". */
531:
532: GCchunks()
533: {
534: register struct chunk *cp;
535: struct chunk *prev = 0,
536: *next = 0;
537: register int i;
538: register Line *newline;
539:
540: for (cp = fchunk; cp != 0; cp = next) {
541: for (i = 0, newline = cp->c_block; i < cp->c_nlines; newline++, i++)
542: if (newline->l_dline != 0)
543: break;
544:
545: next = cp->c_nextfree;
546:
547: if (i == cp->c_nlines) { /* Unlink it!!! */
548: if (prev)
549: prev->c_nextfree = cp->c_nextfree;
550: else
551: fchunk = cp->c_nextfree;
552: remfreelines(cp);
553: free((char *) cp->c_block);
554: free((char *) cp);
555: } else
556: prev = cp;
557: }
558: }
559:
560: #ifdef LISP
561:
562: /* Grind S-Expr */
563:
564: GSexpr()
565: {
566: Bufpos dot,
567: end;
568:
569: if (linebuf[curchar] != '(')
570: complain((char *) 0);
571: DOTsave(&dot);
572: FSexpr();
573: DOTsave(&end);
574: exp = 1;
575: SetDot(&dot);
576: for (;;) {
577: if (curline == end.p_line)
578: break;
579: line_move(FORWARD, NO);
580: if (!blnkp(linebuf)) {
581: DelWtSpace();
582: (void) lisp_indent();
583: }
584: }
585: SetDot(&dot);
586: }
587:
588: /* lisp_indent() indents a new line in Lisp Mode, according to where
589: the matching close-paren would go if we typed that (sort of). */
590:
591: Bufpos *
592: lisp_indent()
593: {
594: Bufpos *bp,
595: savedot;
596: int goal;
597:
598: bp = m_paren(')', BACKWARD, NO, YES);
599:
600: if (bp == 0)
601: return 0;
602:
603: /*
604: * Otherwise, we indent to the first argument of
605: * the current s-expression. This is done by
606: * starting at the matching paren, skipping
607: * to a word (atom), skipping over it, and
608: * skipping to the next one.
609: *
610: * We want to end up
611: *
612: * (atom atom atom ...
613: * ^ here.
614: */
615:
616: DOTsave(&savedot);
617: SetDot(bp);
618: DoTimes(ForChar(), 1);
619: if (linebuf[curchar] != '(') {
620: static char *specials[] = {
621: "def",
622: "let",
623: "lambda",
624: "fluid-let",
625: "macro",
626: "lexpr",
627: "nlambda",
628: "dolist",
629: "caseq",
630: "selectq",
631: "while",
632: "prog",
633: 0
634: };
635: int i = 0;
636:
637: while (specials[i]) {
638: char *cp1 = specials[i],
639: *cp2 = &linebuf[curchar];
640: int n = strlen(cp1);
641:
642: while (--n >= 0)
643: if (Upper(*cp1++) != Upper(*cp2++))
644: break;
645: if (n < 0)
646: break; /* Matched. */
647: i++;
648: }
649: if (specials[i] == 0) {
650: if (index(&linebuf[curchar], ' ') != 0) {
651: WITH_TABLE(curbuf->b_major)
652: ForWord();
653: END_TABLE();
654: while (linebuf[curchar] == ' ')
655: curchar++;
656: }
657: } else
658: curchar++;
659: }
660: goal = calc_pos(linebuf, curchar);
661: SetDot(&savedot);
662: n_indent(goal);
663:
664: return bp;
665: }
666: #endif LISP
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.