1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */ 2: static char rcsid[] = "$Header: inse.c,v 2.4 85/02/14 13:27:09 timo Exp $"; 3: 4: /* 5: * Subroutines (refinements) for ins_string() (see que2.c). 6: */ 7: 8: #include "b.h" 9: #include "feat.h" 10: #include "bobj.h" 11: #include "node.h" 12: #include "gram.h" 13: #include "supr.h" 14: #include "tabl.h" 15: 16: #include <ctype.h> 17: 18: 19: /* 20: * Try to insert the character c in the focus *pp. 21: */ 22: 23: Visible bool 24: insguess(pp, c, ep) 25: path *pp; 26: char c; 27: environ *ep; 28: { 29: path pa = parent(*pp); 30: node n; 31: int sympa = pa ? symbol(tree(pa)) : Rootsymbol; 32: int ich = ichild(*pp); 33: struct classinfo *ci = table[sympa].r_class[ich-1]; 34: classptr cp; 35: string *rp; 36: int code = Code(c); 37: int sym; 38: char buf[2]; 39: 40: #ifdef USERSUGG 41: if (isinclass(Suggestion, ci)) { 42: if (setsugg(pp, c, ep)) 43: return Yes; 44: } 45: #endif USERSUGG 46: for (cp = ci->c_insert; *cp; cp += 2) { 47: if (cp[0] == code) 48: break; 49: } 50: if (!*cp) 51: return No; 52: sym = cp[1]; 53: if (sym >= LEXICAL) { 54: buf[0] = c; 55: buf[1] = 0; 56: replace(pp, (node) mk_text(buf)); 57: ep->mode = VHOLE; 58: ep->s1 = 2*ich; 59: ep->s2 = 1; 60: return Yes; 61: } 62: Assert(sym < TABLEN); 63: rp = table[sym].r_repr; 64: n = table[sym].r_node; 65: if (Fw_zero(rp[0])) { 66: buf[0] = c; 67: buf[1] = 0; 68: setchild(&n, 1, (node) mk_text(buf)); 69: replace(pp, n); 70: ep->mode = VHOLE; 71: ep->s1 = 2; 72: ep->s2 = 1; 73: return Yes; 74: } 75: replace(pp, n); 76: if (c == '\n' || c == '\r') { 77: ep->mode = SUBSET; 78: ep->s1 = ep->s2 = 2; 79: } 80: else { 81: ep->mode = FHOLE; 82: ep->s1 = 1; 83: ep->s2 = 1; 84: } 85: return Yes; 86: } 87: 88: 89: /* 90: * Test whether character `c' may be inserted in position `s2' in 91: * child `ich' of node `n'; that child must be a Text. 92: */ 93: 94: Visible bool 95: mayinsert(n, ich, s2, c) 96: node n; 97: int ich; 98: int s2; 99: register char c; 100: { 101: int sympa = symbol(n); 102: struct classinfo *ci; 103: register classptr cp; 104: register value v = (value) child(n, ich); 105: register char c1; 106: bool maycontinue(); 107: bool maystart(); 108: register bool (*fun1)() = s2 > 0 ? maystart : maycontinue; 109: register bool (*fun)() = s2 > 0 ? maycontinue : maystart; 110: 111: Assert(v && v->type == Tex); 112: Assert(sympa > 0 && sympa < TABLEN); 113: ci = table[sympa].r_class[ich-1]; 114: Assert(ci && ci->c_class); 115: c1 = Str(v)[0]; 116: for (cp = ci->c_class; *cp; ++cp) { 117: if (*cp >= LEXICAL && (*fun1)(c1, *cp)) { 118: if ((*fun)(c, *cp)) 119: return Yes; 120: } 121: } 122: return No; 123: } 124: 125: 126: /* 127: * Change a Fixed into a Variable node, given a string pointer variable 128: * which contains the next characters to be inserted. 129: * If the change is not appropriate, No is returned. 130: * Otherwise, as many (though maybe zero) characters from the string 131: * as possible will have been incorporated in the string node. 132: */ 133: 134: Visible bool 135: soften(ep, pstr, alt_c) 136: environ *ep; 137: string *pstr; 138: int alt_c; 139: { 140: path pa = parent(ep->focus); 141: node n; 142: int sympa = pa ? symbol(tree(pa)) : Rootsymbol; 143: struct classinfo *ci; 144: register classptr cp; 145: register int code; 146: string repr; 147: register struct table *tp; 148: char buf[1024]; 149: 150: if (ep->mode == VHOLE && (ep->s1&1)) 151: ep->mode = FHOLE; 152: if (ep->mode != FHOLE || ep->s1 != 1 || ep->s2 <= 0 || !issuggestion(ep)) 153: return No; 154: n = tree(ep->focus); 155: repr = noderepr(n)[0]; 156: if (!repr || !isupper(repr[0])) 157: return No; 158: code = Code(repr[0]); 159: ci = table[sympa].r_class[ichild(ep->focus) - 1]; 160: n = Nnil; 161: for (cp = ci->c_insert; *cp; cp += 2) { 162: if (cp[0] != code) 163: continue; 164: if (cp[1] >= TABLEN) 165: continue; 166: tp = &table[cp[1]]; 167: if (Fw_zero(tp->r_repr[0])) { 168: Assert(tp->r_class[0]->c_class[0] >= LEXICAL); 169: n = tp->r_node; 170: break; 171: } 172: } 173: if (!n) 174: return No; 175: strncpy(buf, repr, ep->s2); 176: buf[ep->s2] = 0; 177: setchild(&n, 1, (node) mk_text(buf)); 178: if (!mayinsert(n, 1, ep->s2, repr[ep->s2])) { 179: if (!**pstr || !mayinsert(n, 1, ep->s2, **pstr) 180: && (!alt_c || !mayinsert(n, 1, ep->s2, alt_c))) { 181: noderelease(n); /* Don't forget! */ 182: return No; 183: } 184: } 185: if (**pstr && mayinsert(n, 1, ep->s2, **pstr)) { 186: do { 187: buf[ep->s2] = **pstr; 188: ++*pstr; 189: ++ep->s2; 190: } while (ep->s2 < sizeof buf - 1 && **pstr 191: && mayinsert(n, 1, ep->s2, **pstr)); 192: buf[ep->s2] = 0; 193: setchild(&n, 1, (node) mk_text(buf)); 194: } 195: replace(&ep->focus, n); 196: ep->mode = VHOLE; 197: ep->s1 = 2; 198: return Yes; 199: } 200: 201: 202: /* 203: * Renew suggestion, or advance in old suggestion. 204: * Return Yes if *pstr has been advanced. 205: */ 206: 207: Visible bool 208: resuggest(ep, pstr, alt_c) 209: environ *ep; 210: string *pstr; 211: int alt_c; 212: { 213: struct table *tp; 214: struct classinfo *ci; 215: classptr cp; 216: path pa; 217: node nn; 218: node n = tree(ep->focus); 219: register string *oldrp = noderepr(n); 220: register int ich = ep->s1/2; 221: register string str = oldrp[ich]; 222: int oldsym = symbol(n); 223: int childsym[MAXCHILD]; 224: string *newrp; 225: int sympa; 226: register int sym; 227: int symfound = -1; 228: register int i; 229: int code; 230: char buf[15]; /* Should be sufficient for all fixed texts */ 231: bool ok; 232: bool anyok = No; 233: 234: if (!str || !**pstr || !issuggestion(ep)) 235: return No; 236: /***** Change this if commands can be prefixes of others! *****/ 237: /***** Well, they can! 238: if (!c) 239: return No; 240: *****/ 241: if (ich > 0 && ifmatch(ep, pstr, str, alt_c)) 242: /* Shortcut: sec. keyword, exact match will do just fine */ 243: return Yes; 244: if (ep->s2 <= 0 || Fw_zero(oldrp[0])) 245: return No; 246: if (**pstr != ' ' && !isupper(**pstr) 247: && !alt_c && **pstr != '"' && **pstr != '\'') 248: /* Shortcut: not a keyword, must match exactly */ 249: return ifmatch(ep, pstr, str, alt_c); 250: for (i = 0; i < ich; ++i) { /* Preset some stuff for main loop */ 251: if (!oldrp[i]) 252: oldrp[i] = ""; 253: childsym[i] = symbol(child(n, i+1)); 254: } 255: Assert(ep->s2 + 1 < sizeof buf); 256: strcpy(buf, oldrp[ich]); 257: buf[ep->s2] = alt_c ? alt_c : **pstr; 258: buf[ep->s2 + 1] = 0; 259: pa = parent(ep->focus); 260: sympa = pa ? symbol(tree(pa)) : Rootsymbol; 261: ci = table[sympa].r_class[ichild(ep->focus) - 1]; 262: code = Code(oldrp[0][0]); 263: 264: for (cp = ci->c_insert; *cp; cp += 2) { 265: if (cp[0] != code) 266: continue; 267: sym = cp[1]; 268: if (sym >= TABLEN) 269: continue; 270: if (sym == oldsym) { 271: anyok = Yes; 272: continue; 273: } 274: tp = &table[sym]; 275: newrp = tp->r_repr; 276: ok = Yes; 277: for (i = 0; i < ich; ++i) { 278: str = newrp[i]; 279: if (!str) 280: str = ""; 281: if (!Strequ(str, oldrp[i]) 282: || childsym[i] != Optional && childsym[i] != Hole 283: && !isinclass(childsym[i], tp->r_class[i])) { 284: ok = No; 285: break; 286: } 287: } 288: if (!ok) 289: continue; 290: str = newrp[i]; 291: if (!str || !Strnequ(str, buf, ep->s2+1)) 292: continue; 293: if (anyok) { 294: if (Strequ(str, oldrp[ich])) 295: continue; /* Same as it was: no new suggestion */ 296: symfound = sym; 297: break; 298: } 299: else if (symfound < 0 && !Strequ(str, oldrp[ich])) 300: symfound = sym; 301: } 302: 303: if (symfound < 0) 304: return ifmatch(ep, pstr, oldrp[ich], alt_c); 305: nn = table[symfound].r_node; 306: for (i = 1; i <= ich; ++i) { /* Copy children to the left of the focus */ 307: sym = symbol(child(n, i)); 308: if (sym == Optional || sym == Hole) 309: continue; 310: setchild(&nn, i, nodecopy(child(n, i))); 311: } 312: replace(&ep->focus, nn); 313: str = newrp[ich]; 314: do { /* Find easy continuation */ 315: ++ep->s2; 316: ++*pstr; 317: } while (**pstr && **pstr == str[ep->s2]); 318: return Yes; 319: } 320: 321: 322: /* 323: * Refinement for resuggest(): see if there is a match, and if so, find 324: * longest match. 325: */ 326: 327: Hidden bool 328: ifmatch(ep, pstr, str, alt_c) 329: register environ *ep; 330: register string *pstr; 331: register string str; 332: register int alt_c; 333: { 334: register int c = str[ep->s2]; 335: 336: if (c != **pstr && (!alt_c || c != alt_c)) 337: return No; 338: do { 339: ++ep->s2; 340: ++*pstr; 341: } while (**pstr && **pstr == str[ep->s2]); 342: return Yes; 343: }