|
|
1.1 root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
2: static char rcsid[] = "$Header: sugg.c,v 2.4 84/10/26 12:10:51 guido Exp $";
3:
4: /*
5: * B editor -- New suggestion handling module.
6: */
7:
8: #include "feat.h"
9:
10: #ifdef USERSUGG
11:
12: #include "b.h"
13: #include "bobj.h"
14: #include "node.h"
15: #include "supr.h"
16: #include "gram.h"
17: #include "queu.h"
18:
19: #include <ctype.h>
20:
21: extern bool dflag;
22: extern bool edontop;
23:
24: extern bool lefttorite;
25:
26: #ifndef SUGGFILE
27: #define SUGGFILE ".Bed_sugg"
28: #endif
29:
30: #define MAXNSUGG 1000
31:
32: Hidden value sugg[MAXNSUGG];
33: Hidden int nsugg;
34: Hidden int nbuiltin;
35: Hidden bool suggchanges;
36: Hidden bool ignorefirstcall; /* Communication between killsugg and setsugg */
37:
38: /*
39: * Read the suggestion table from file.
40: */
41:
42: Visible Procedure
43: initsugg()
44: {
45: char buffer[1000];
46: register FILE *fp;
47: register c;
48:
49: fp = fopen(SUGGFILE, "r");
50: if (!fp) {
51: if (dflag) {
52: fprintf(stderr, "*** No suggestion file: ");
53: perror(SUGGFILE);
54: }
55: return;
56: }
57: while (fgets(buffer, sizeof buffer, fp)) {
58: if (!index(buffer, '\n')) { /* Skip long line */
59: fprintf(stderr,
60: "*** Excessively long suggestion ignored\n");
61: while ((c = getc(fp)) != '\n' && c != EOF)
62: ;
63: }
64: else
65: addsugg(buffer, -1);
66: }
67: fclose(fp);
68: }
69:
70:
71: /*
72: * Make sure a line looks like a suggestion, return No if not.
73: * Replace the trailing newline or comment-sign by a zero byte.
74: * ***** Should check more thoroughly. *****
75: */
76:
77: Hidden bool
78: checksugg(bp)
79: string bp;
80: {
81: if (!isascii(*bp) || !isupper(*bp))
82: return No;
83: while (*bp && *bp != '\n' && *bp != '\\')
84: ++bp;
85: *bp = 0;
86: return Yes;
87: }
88:
89:
90: /*
91: * Procedure to add a suggestion to the suggestion table.
92: */
93:
94: Visible Procedure
95: addsugg(str, builtin)
96: string str;
97: int builtin;
98: {
99: int i;
100: int j;
101: int len;
102: int cmp;
103: string suggi;
104: int where = (builtin == -1) ? nsugg : nbuiltin;
105:
106: if (!checksugg(str))
107: return;
108: for (len = 0; str[len] && str[len] != ' '; ++len)
109: ;
110: for (i = nsugg-1; i >= 0; --i) {
111: suggi = Str(sugg[i]);
112: cmp = strncmp(str, suggi, len);
113: if (cmp < 0)
114: continue;
115: if (cmp > 0) {
116: if (i >= where)
117: where = i+1;
118: continue;
119: }
120: if (suggi[len] && suggi[len] != ' ')
121: continue; /* No match, just prefix */
122: if (Strequ(str+len, suggi+len))
123: return; /* Ignore exact duplicates */
124: if (i < nbuiltin)
125: return; /* Cannot replace built-in */
126: /* Replacement */
127: sugg[i] = mk_text(str); /* No use to release the old one... */
128: /* ...its refcount is infinite */
129: fix(sugg[i]);
130: suggchanges = Yes;
131: return;
132: }
133: /* Insertion */
134: if (nsugg >= MAXNSUGG)
135: return; /* Table overflow */
136: if (builtin == Yes)
137: ++nbuiltin;
138: for (j = nsugg; j > where; --j)
139: sugg[j] = sugg[j-1];
140: ++nsugg;
141: sugg[where] = mk_text(str);
142: fix(sugg[where]);
143: suggchanges = Yes;
144: }
145:
146:
147: /*
148: * Procedure to delete a suggestion from the suggestion table.
149: * Must supply the whole string as argument.
150: */
151:
152: Hidden Procedure
153: delsugg(str)
154: string str;
155: {
156: int i;
157:
158: for (i = 0; i < nsugg; ++i) {
159: if (Strequ(str, Str(sugg[i]))) {
160: --nsugg;
161: for (; i < nsugg; ++i)
162: sugg[i] = sugg[i+1];
163: suggchanges = Yes;
164: return;
165: }
166: }
167: }
168:
169:
170: /*
171: * Return a suitable suggestion which matches str for len characters.
172: * If len > 1, and all of str (even beyond len) equals some table
173: * entry, the first matching entry after that is preferred; otherwise,
174: * the first matching entry at all is returned.
175: * Vnil is returned if no entry matches.
176: */
177:
178: Hidden node
179: nextsugg(str, len)
180: string str;
181: int len;
182: {
183: bool found = !str[len];
184: int first = -1;
185: int i;
186:
187: for (i = 0; i < nsugg; ++i) {
188: if (!Strnequ(str, Str(sugg[i]), len))
189: continue;
190: if (found)
191: return (node) sugg[i];
192: if (Strequ(str+len, Str(sugg[i])+len))
193: found = Yes;
194: if (first < 0)
195: first = i;
196: }
197: if (first >= 0)
198: return (node) sugg[first];
199: return Nnil;
200: }
201:
202:
203: /*
204: * Procedure to save the suggestion file if it has been changed.
205: */
206:
207: Visible Procedure
208: endsugg()
209: {
210: FILE *fp;
211: int i;
212:
213: if (!suggchanges)
214: return;
215: suggchanges = No;
216: fp = fopen(SUGGFILE, "w");
217: if (!fp) {
218: if (dflag) {
219: fprintf(stderr, "*** Can't rewrite ");
220: perror(SUGGFILE);
221: }
222: return;
223: }
224: if (dflag)
225: fprintf(stderr, "*** [Rewriting suggestion file]\n");
226: for (i = nbuiltin; i < nsugg; ++i)
227: fprintf(fp, "%s\n", Str(sugg[i]));
228: if (fclose(fp) == EOF) {
229: fprintf(stderr, "*** Can't finish writing ");
230: perror(SUGGFILE);
231: return;
232: }
233: }
234:
235:
236: /*
237: * Find a new suggestion or advance in the current one.
238: * Interface styled like resuggest: string pointer is advanced here.
239: */
240:
241: Visible bool
242: newsugg(ep, pstr, alt_c)
243: environ *ep;
244: string *pstr;
245: int alt_c;
246: {
247: char buffer[1000];
248: node n = tree(ep->focus);
249: node nn;
250: int sym = symbol(n);
251: string str;
252: string bp;
253: bool end;
254:
255: Assert(pstr && *pstr);
256: if (sym != Suggestion || ep->mode != VHOLE || ep->s1 != 2)
257: return No;
258: strncpy(buffer, Str((value)firstchild(n)), sizeof buffer);
259: for (str = *pstr, bp = buffer+ep->s2, end = No;
260: *str && bp < buffer + sizeof buffer; ++str, ++bp) {
261: if (!*bp)
262: end = Yes;
263: *bp = *str;
264: }
265: if (end)
266: *bp = 0;
267: nn = (node)nextsugg(buffer, ep->s2 + 1);
268: if (!nn) {
269: if (!alt_c)
270: return No;
271: buffer[ep->s2] = alt_c;
272: nn = (node)nextsugg(buffer, ep->s2 + 1);
273: if (!nn)
274: return No;
275: }
276: if (nn != firstchild(n)) {
277: s_down(ep);
278: replace(&ep->focus, nn);
279: s_up(ep);
280: }
281: /* No need to release because its refcount is infinite anyway */
282: ++ep->s2;
283: if (**pstr == ' ')
284: accsugg(ep);
285: ++*pstr;
286: return Yes;
287: }
288:
289:
290: /*
291: * Kill suggestion -- only the part to the left of the focus is kept.
292: */
293:
294: Visible Procedure
295: killsugg(ep)
296: environ *ep;
297: {
298: queue q = Qnil;
299: char buffer[1000];
300: node n = tree(ep->focus);
301:
302: Assert(ep->mode == VHOLE && ep->s1 == 2 && symbol(n) == Suggestion);
303: strncpy(buffer, Str((value)firstchild(n)), ep->s2);
304: buffer[ep->s2] = 0;
305: delfocus(&ep->focus);
306: ep->mode = WHOLE;
307: ignorefirstcall = Yes;
308: ins_string(ep, buffer, &q, 0);
309: qrelease(q);
310: ignorefirstcall = No;
311: }
312:
313:
314: /*
315: * Place an initial suggestion in a node.
316: */
317:
318: Visible bool
319: setsugg(pp, c, ep)
320: path *pp;
321: char c;
322: environ *ep;
323: {
324: char buf[2];
325: node n;
326:
327: if (lefttorite)
328: return No;
329: if (ignorefirstcall) {
330: ignorefirstcall = No;
331: return No;
332: }
333: buf[0] = c;
334: buf[1] = 0;
335: n = (node)nextsugg(buf, 1);
336: if (!n)
337: return No;
338: replace(pp, newnode(1, Suggestion, &n));
339: ep->mode = VHOLE;
340: ep->s1 = 2;
341: ep->s2 = 1;
342: return Yes;
343: }
344:
345:
346: /*
347: * Accept a suggestion -- turn it into real nodes.
348: */
349:
350: Visible Procedure
351: accsugg(ep)
352: environ *ep;
353: {
354: node n = tree(ep->focus);
355: int s2 = ep->s2;
356: queue q = Qnil;
357: environ env;
358:
359: Assert(symbol(n) == Suggestion && ep->mode == VHOLE && ep->s1 == 2);
360: stringtoqueue(Str((value)firstchild(n)) + s2, &q);
361: killsugg(ep);
362: Ecopy(*ep, env);
363: if (app_queue(ep, &q))
364: Erelease(env);
365: else {
366: Erelease(*ep);
367: Emove(env, *ep);
368: qrelease(q);
369: }
370: }
371:
372:
373: /*
374: * Procedure called when a unit is read in.
375: * It tries to update the suggestion database.
376: * It also remembers the suggestion so that it can be removed by writesugg
377: * if that finds the unit was deleted.
378: */
379:
380: Hidden char lastsugg[1000];
381:
382: Visible Procedure
383: readsugg(p)
384: path p;
385: {
386: p = pathcopy(p);
387: top(&p);
388: getpattern(lastsugg, tree(p));
389: pathrelease(p);
390: addsugg(lastsugg, No);
391: }
392:
393:
394: /*
395: * Procedure called when a unit is saved.
396: * It tries to update the suggestion database.
397: * If the unit appears empty, the last suggestion passed to readsugg
398: * will be deleted.
399: */
400:
401: Visible Procedure
402: writesugg(p)
403: path p;
404: {
405: p = pathcopy(p);
406: top(&p);
407: if (width(tree(p)) == 0)
408: delsugg(lastsugg);
409: else {
410: getpattern(lastsugg, tree(p));
411: if (lastsugg[0])
412: addsugg(lastsugg, No);
413: }
414: pathrelease(p);
415: }
416:
417:
418: /*
419: * Procedure to find out the suggestion that fits the current unit.
420: * Makes the buffer empty if not a HOW'TO unit.
421: * ***** Won't work if B-grammar is severely changed! *****
422: */
423:
424: Hidden Procedure
425: getpattern(buffer, n)
426: string buffer;
427: node n;
428: {
429: string *rp = noderepr(n);
430:
431: buffer[0] = 0;
432: while (Fw_zero(rp[0])) {
433: if (nchildren(n) == 0)
434: return;
435: n = firstchild(n);
436: rp = noderepr(n);
437: }
438: if (!Strequ(rp[0], "HOW'TO ") || nchildren(n) < 1)
439: return;
440: subgetpattern(&buffer, firstchild(n));
441: *buffer = 0;
442: }
443:
444:
445: /*
446: * Refinement for getpattern to do the work.
447: */
448:
449: Hidden Procedure
450: subgetpattern(pbuf, n)
451: string *pbuf;
452: node n;
453: {
454: string *rp;
455: int i;
456: int nch;
457:
458: rp = noderepr(n);
459: nch = (Type(n) == Tex) ? 0 : nchildren(n);
460: for (i = 0; i <= nch; ++i) {
461: if (i > 0)
462: subgetpattern(pbuf, child(n, i));
463: if (Fw_positive(rp[i])) {
464: if (islower(rp[i][0]))
465: *(*pbuf)++ = '?';
466: else {
467: strcpy(*pbuf, rp[i]);
468: *pbuf += strlen(*pbuf);
469: }
470: }
471: }
472: }
473:
474: #endif USERSUGG
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.