home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
- static char rcsid[] = "$Header: sugg.c,v 2.4 84/10/26 12:10:51 guido Exp $";
-
- /*
- * B editor -- New suggestion handling module.
- */
-
- #include "feat.h"
-
- #ifdef USERSUGG
-
- #include "b.h"
- #include "bobj.h"
- #include "node.h"
- #include "supr.h"
- #include "gram.h"
- #include "queu.h"
-
- #include <ctype.h>
-
- extern bool dflag;
- extern bool edontop;
-
- extern bool lefttorite;
-
- #ifndef SUGGFILE
- #define SUGGFILE ".Bed_sugg"
- #endif
-
- #define MAXNSUGG 1000
-
- Hidden value sugg[MAXNSUGG];
- Hidden int nsugg;
- Hidden int nbuiltin;
- Hidden bool suggchanges;
- Hidden bool ignorefirstcall; /* Communication between killsugg and setsugg */
-
- /*
- * Read the suggestion table from file.
- */
-
- Visible Procedure
- initsugg()
- {
- char buffer[1000];
- register FILE *fp;
- register c;
-
- fp = fopen(SUGGFILE, "r");
- if (!fp) {
- if (dflag) {
- fprintf(stderr, "*** No suggestion file: ");
- perror(SUGGFILE);
- }
- return;
- }
- while (fgets(buffer, sizeof buffer, fp)) {
- if (!index(buffer, '\n')) { /* Skip long line */
- fprintf(stderr,
- "*** Excessively long suggestion ignored\n");
- while ((c = getc(fp)) != '\n' && c != EOF)
- ;
- }
- else
- addsugg(buffer, -1);
- }
- fclose(fp);
- }
-
-
- /*
- * Make sure a line looks like a suggestion, return No if not.
- * Replace the trailing newline or comment-sign by a zero byte.
- * ***** Should check more thoroughly. *****
- */
-
- Hidden bool
- checksugg(bp)
- string bp;
- {
- if (!isascii(*bp) || !isupper(*bp))
- return No;
- while (*bp && *bp != '\n' && *bp != '\\')
- ++bp;
- *bp = 0;
- return Yes;
- }
-
-
- /*
- * Procedure to add a suggestion to the suggestion table.
- */
-
- Visible Procedure
- addsugg(str, builtin)
- string str;
- int builtin;
- {
- int i;
- int j;
- int len;
- int cmp;
- string suggi;
- int where = (builtin == -1) ? nsugg : nbuiltin;
-
- if (!checksugg(str))
- return;
- for (len = 0; str[len] && str[len] != ' '; ++len)
- ;
- for (i = nsugg-1; i >= 0; --i) {
- suggi = Str(sugg[i]);
- cmp = strncmp(str, suggi, len);
- if (cmp < 0)
- continue;
- if (cmp > 0) {
- if (i >= where)
- where = i+1;
- continue;
- }
- if (suggi[len] && suggi[len] != ' ')
- continue; /* No match, just prefix */
- if (Strequ(str+len, suggi+len))
- return; /* Ignore exact duplicates */
- if (i < nbuiltin)
- return; /* Cannot replace built-in */
- /* Replacement */
- sugg[i] = mk_text(str); /* No use to release the old one... */
- /* ...its refcount is infinite */
- fix(sugg[i]);
- suggchanges = Yes;
- return;
- }
- /* Insertion */
- if (nsugg >= MAXNSUGG)
- return; /* Table overflow */
- if (builtin == Yes)
- ++nbuiltin;
- for (j = nsugg; j > where; --j)
- sugg[j] = sugg[j-1];
- ++nsugg;
- sugg[where] = mk_text(str);
- fix(sugg[where]);
- suggchanges = Yes;
- }
-
-
- /*
- * Procedure to delete a suggestion from the suggestion table.
- * Must supply the whole string as argument.
- */
-
- Hidden Procedure
- delsugg(str)
- string str;
- {
- int i;
-
- for (i = 0; i < nsugg; ++i) {
- if (Strequ(str, Str(sugg[i]))) {
- --nsugg;
- for (; i < nsugg; ++i)
- sugg[i] = sugg[i+1];
- suggchanges = Yes;
- return;
- }
- }
- }
-
-
- /*
- * Return a suitable suggestion which matches str for len characters.
- * If len > 1, and all of str (even beyond len) equals some table
- * entry, the first matching entry after that is preferred; otherwise,
- * the first matching entry at all is returned.
- * Vnil is returned if no entry matches.
- */
-
- Hidden node
- nextsugg(str, len)
- string str;
- int len;
- {
- bool found = !str[len];
- int first = -1;
- int i;
-
- for (i = 0; i < nsugg; ++i) {
- if (!Strnequ(str, Str(sugg[i]), len))
- continue;
- if (found)
- return (node) sugg[i];
- if (Strequ(str+len, Str(sugg[i])+len))
- found = Yes;
- if (first < 0)
- first = i;
- }
- if (first >= 0)
- return (node) sugg[first];
- return Nnil;
- }
-
-
- /*
- * Procedure to save the suggestion file if it has been changed.
- */
-
- Visible Procedure
- endsugg()
- {
- FILE *fp;
- int i;
-
- if (!suggchanges)
- return;
- suggchanges = No;
- fp = fopen(SUGGFILE, "w");
- if (!fp) {
- if (dflag) {
- fprintf(stderr, "*** Can't rewrite ");
- perror(SUGGFILE);
- }
- return;
- }
- if (dflag)
- fprintf(stderr, "*** [Rewriting suggestion file]\n");
- for (i = nbuiltin; i < nsugg; ++i)
- fprintf(fp, "%s\n", Str(sugg[i]));
- if (fclose(fp) == EOF) {
- fprintf(stderr, "*** Can't finish writing ");
- perror(SUGGFILE);
- return;
- }
- }
-
-
- /*
- * Find a new suggestion or advance in the current one.
- * Interface styled like resuggest: string pointer is advanced here.
- */
-
- Visible bool
- newsugg(ep, pstr, alt_c)
- environ *ep;
- string *pstr;
- int alt_c;
- {
- char buffer[1000];
- node n = tree(ep->focus);
- node nn;
- int sym = symbol(n);
- string str;
- string bp;
- bool end;
-
- Assert(pstr && *pstr);
- if (sym != Suggestion || ep->mode != VHOLE || ep->s1 != 2)
- return No;
- strncpy(buffer, Str((value)firstchild(n)), sizeof buffer);
- for (str = *pstr, bp = buffer+ep->s2, end = No;
- *str && bp < buffer + sizeof buffer; ++str, ++bp) {
- if (!*bp)
- end = Yes;
- *bp = *str;
- }
- if (end)
- *bp = 0;
- nn = (node)nextsugg(buffer, ep->s2 + 1);
- if (!nn) {
- if (!alt_c)
- return No;
- buffer[ep->s2] = alt_c;
- nn = (node)nextsugg(buffer, ep->s2 + 1);
- if (!nn)
- return No;
- }
- if (nn != firstchild(n)) {
- s_down(ep);
- replace(&ep->focus, nn);
- s_up(ep);
- }
- /* No need to release because its refcount is infinite anyway */
- ++ep->s2;
- if (**pstr == ' ')
- accsugg(ep);
- ++*pstr;
- return Yes;
- }
-
-
- /*
- * Kill suggestion -- only the part to the left of the focus is kept.
- */
-
- Visible Procedure
- killsugg(ep)
- environ *ep;
- {
- queue q = Qnil;
- char buffer[1000];
- node n = tree(ep->focus);
-
- Assert(ep->mode == VHOLE && ep->s1 == 2 && symbol(n) == Suggestion);
- strncpy(buffer, Str((value)firstchild(n)), ep->s2);
- buffer[ep->s2] = 0;
- delfocus(&ep->focus);
- ep->mode = WHOLE;
- ignorefirstcall = Yes;
- ins_string(ep, buffer, &q, 0);
- qrelease(q);
- ignorefirstcall = No;
- }
-
-
- /*
- * Place an initial suggestion in a node.
- */
-
- Visible bool
- setsugg(pp, c, ep)
- path *pp;
- char c;
- environ *ep;
- {
- char buf[2];
- node n;
-
- if (lefttorite)
- return No;
- if (ignorefirstcall) {
- ignorefirstcall = No;
- return No;
- }
- buf[0] = c;
- buf[1] = 0;
- n = (node)nextsugg(buf, 1);
- if (!n)
- return No;
- replace(pp, newnode(1, Suggestion, &n));
- ep->mode = VHOLE;
- ep->s1 = 2;
- ep->s2 = 1;
- return Yes;
- }
-
-
- /*
- * Accept a suggestion -- turn it into real nodes.
- */
-
- Visible Procedure
- accsugg(ep)
- environ *ep;
- {
- node n = tree(ep->focus);
- int s2 = ep->s2;
- queue q = Qnil;
- environ env;
-
- Assert(symbol(n) == Suggestion && ep->mode == VHOLE && ep->s1 == 2);
- stringtoqueue(Str((value)firstchild(n)) + s2, &q);
- killsugg(ep);
- Ecopy(*ep, env);
- if (app_queue(ep, &q))
- Erelease(env);
- else {
- Erelease(*ep);
- Emove(env, *ep);
- qrelease(q);
- }
- }
-
-
- /*
- * Procedure called when a unit is read in.
- * It tries to update the suggestion database.
- * It also remembers the suggestion so that it can be removed by writesugg
- * if that finds the unit was deleted.
- */
-
- Hidden char lastsugg[1000];
-
- Visible Procedure
- readsugg(p)
- path p;
- {
- p = pathcopy(p);
- top(&p);
- getpattern(lastsugg, tree(p));
- pathrelease(p);
- addsugg(lastsugg, No);
- }
-
-
- /*
- * Procedure called when a unit is saved.
- * It tries to update the suggestion database.
- * If the unit appears empty, the last suggestion passed to readsugg
- * will be deleted.
- */
-
- Visible Procedure
- writesugg(p)
- path p;
- {
- p = pathcopy(p);
- top(&p);
- if (width(tree(p)) == 0)
- delsugg(lastsugg);
- else {
- getpattern(lastsugg, tree(p));
- if (lastsugg[0])
- addsugg(lastsugg, No);
- }
- pathrelease(p);
- }
-
-
- /*
- * Procedure to find out the suggestion that fits the current unit.
- * Makes the buffer empty if not a HOW'TO unit.
- * ***** Won't work if B-grammar is severely changed! *****
- */
-
- Hidden Procedure
- getpattern(buffer, n)
- string buffer;
- node n;
- {
- string *rp = noderepr(n);
-
- buffer[0] = 0;
- while (Fw_zero(rp[0])) {
- if (nchildren(n) == 0)
- return;
- n = firstchild(n);
- rp = noderepr(n);
- }
- if (!Strequ(rp[0], "HOW'TO ") || nchildren(n) < 1)
- return;
- subgetpattern(&buffer, firstchild(n));
- *buffer = 0;
- }
-
-
- /*
- * Refinement for getpattern to do the work.
- */
-
- Hidden Procedure
- subgetpattern(pbuf, n)
- string *pbuf;
- node n;
- {
- string *rp;
- int i;
- int nch;
-
- rp = noderepr(n);
- nch = (Type(n) == Tex) ? 0 : nchildren(n);
- for (i = 0; i <= nch; ++i) {
- if (i > 0)
- subgetpattern(pbuf, child(n, i));
- if (Fw_positive(rp[i])) {
- if (islower(rp[i][0]))
- *(*pbuf)++ = '?';
- else {
- strcpy(*pbuf, rp[i]);
- *pbuf += strlen(*pbuf);
- }
- }
- }
- }
-
- #endif USERSUGG
-