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

Defined functions

accsugg defined in line 350; used 2 times
addsugg defined in line 94; used 4 times
checksugg defined in line 77; used 1 times
delsugg defined in line 152; used 1 times
endsugg defined in line 207; used 1 times
getpattern defined in line 424; used 2 times
initsugg defined in line 42; used 1 times
killsugg defined in line 294; used 3 times
newsugg defined in line 241; used 1 times
nextsugg defined in line 178; used 3 times
readsugg defined in line 382; used 1 times
setsugg defined in line 318; used 1 times
subgetpattern defined in line 449; used 2 times
writesugg defined in line 401; used 2 times

Defined variables

ignorefirstcall defined in line 36; used 4 times
lastsugg defined in line 380; used 6 times
nbuiltin defined in line 34; used 4 times
nsugg defined in line 33; used 10 times
rcsid defined in line 2; never used
suggchanges defined in line 35; used 5 times

Defined macros

MAXNSUGG defined in line 30; used 2 times
SUGGFILE defined in line 27; used 6 times
Last modified: 1985-08-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1746
Valid CSS Valid XHTML 1.0 Strict