|
|
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.