|
|
1.1 ! root 1: /* String search routines for GNU Emacs. ! 2: Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc. ! 3: ! 4: This file is part of GNU Emacs. ! 5: ! 6: GNU Emacs is distributed in the hope that it will be useful, ! 7: but WITHOUT ANY WARRANTY. No author or distributor ! 8: accepts responsibility to anyone for the consequences of using it ! 9: or for whether it serves any particular purpose or works at all, ! 10: unless he says so in writing. Refer to the GNU Emacs General Public ! 11: License for full details. ! 12: ! 13: Everyone is granted permission to copy, modify and redistribute ! 14: GNU Emacs, but only under the conditions described in the ! 15: GNU Emacs General Public License. A copy of this license is ! 16: supposed to have been given to you along with GNU Emacs so you ! 17: can know your rights and responsibilities. It should be in a ! 18: file named COPYING. Among other things, the copyright notice ! 19: and this notice must be preserved on all copies. */ ! 20: ! 21: ! 22: #include "config.h" ! 23: #include "lisp.h" ! 24: #include "syntax.h" ! 25: #include "buffer.h" ! 26: #include "commands.h" ! 27: #include "regex.h" ! 28: ! 29: #define max(a, b) ((a) > (b) ? (a) : (b)) ! 30: #define min(a, b) ((a) < (b) ? (a) : (b)) ! 31: ! 32: unsigned char downcase_table[01000] = {0}; /* folds upper to lower case */ ! 33: /* A WHEEL WILL FALL OFF IF, IN A trt, CHARACTER A */ ! 34: /* TRANSLATES INTO CHARACTER B AND CHARACTER B DOES NOT */ ! 35: /* ALSO TRANSLATE INTO CHARACTER B. */ ! 36: /* If that constraint is met, compute_trt_inverse will follow a */ ! 37: /* translation table with its inverse. The inverse of a table */ ! 38: /* follows the table at table[0400]. The form of this is that if */ ! 39: /* table[a]=b then the chain starting at table[0400+b], linked by */ ! 40: /* link(x)=table[0400+x] and ended by b must include a. */ ! 41: ! 42: /* At present compute_trt_inverse is blinded and the inverse for this */ ! 43: /* particular table is created by a single-purpose loop. */ ! 44: /* compute_trt_inverse has been tested on the following cases: */ ! 45: /* trt[x]=x, trt[x]=(+ 3 (logand x, 0370)), trt[x]='a', and the */ ! 46: /* downcase table. */ ! 47: ! 48: /* We compile regexps into this buffer and then use it for searching. */ ! 49: ! 50: struct re_pattern_buffer searchbuf; ! 51: ! 52: char search_fastmap[0400]; ! 53: ! 54: /* Last regexp we compiled */ ! 55: ! 56: Lisp_Object last_regexp; ! 57: ! 58: /* Every call to re_match, etc., must pass &search_regs as the regs argument ! 59: unless you can show it is unnecessary (i.e., if re_match is certainly going ! 60: to be called again before region-around-match can be called). */ ! 61: ! 62: static struct re_registers search_regs; ! 63: ! 64: /* error condition signalled when regexp compile_pattern fails */ ! 65: ! 66: Lisp_Object Qinvalid_regexp; ! 67: ! 68: /* Compile a regexp and signal a Lisp error if anything goes wrong. */ ! 69: ! 70: compile_pattern (pattern, bufp, translate) ! 71: Lisp_Object pattern; ! 72: struct re_pattern_buffer *bufp; ! 73: char *translate; ! 74: { ! 75: char *val; ! 76: Lisp_Object dummy; ! 77: ! 78: if (EQ (pattern, last_regexp) ! 79: && translate == bufp->translate) ! 80: return; ! 81: last_regexp = Qnil; ! 82: bufp->translate = translate; ! 83: val = re_compile_pattern (XSTRING (pattern)->data, ! 84: XSTRING (pattern)->size, ! 85: bufp); ! 86: if (val) ! 87: { ! 88: dummy = build_string (val); ! 89: while (1) ! 90: Fsignal (Qinvalid_regexp, Fcons (dummy, Qnil)); ! 91: } ! 92: last_regexp = pattern; ! 93: return; ! 94: } ! 95: ! 96: /* Error condition used for failing searches */ ! 97: Lisp_Object Qsearch_failed; ! 98: ! 99: Lisp_Object ! 100: signal_failure (arg) ! 101: Lisp_Object arg; ! 102: { ! 103: Fsignal (Qsearch_failed, Fcons (arg, Qnil)); ! 104: return Qnil; ! 105: } ! 106: ! 107: DEFUN ("looking-at", Flooking_at, Slooking_at, 1, 1, 0, ! 108: "t if text after point matches regular expression PAT.") ! 109: (string) ! 110: Lisp_Object string; ! 111: { ! 112: Lisp_Object val; ! 113: unsigned char *p1, *p2; ! 114: int s1, s2; ! 115: register int i; ! 116: ! 117: CHECK_STRING (string, 0); ! 118: compile_pattern (string, &searchbuf, ! 119: !NULL (bf_cur->case_fold_search) ? (char *) downcase_table : 0); ! 120: ! 121: immediate_quit = 1; ! 122: QUIT; /* Do a pending quit right away, to avoid paradoxical behavior */ ! 123: ! 124: /* Get pointers and sizes of the two strings ! 125: that make up the visible portion of the buffer. */ ! 126: ! 127: p1 = bf_p1 + bf_head_clip; ! 128: s1 = bf_s1 - (bf_head_clip - 1); ! 129: p2 = bf_p2 + bf_s1 + 1; ! 130: s2 = bf_s2 - bf_tail_clip; ! 131: if (s1 < 0) ! 132: { ! 133: p2 -= s1; ! 134: s2 += s1; ! 135: s1 = 0; ! 136: } ! 137: if (s2 < 0) ! 138: { ! 139: s1 += s2; ! 140: s2 = 0; ! 141: } ! 142: ! 143: val = (0 <= re_match_2 (&searchbuf, p1, s1, p2, s2, ! 144: point - FirstCharacter, &search_regs, ! 145: NumCharacters + 1 - FirstCharacter) ! 146: ? Qt : Qnil); ! 147: for (i = 0; i < RE_NREGS; i++) ! 148: if (search_regs.start[i] >= 0) ! 149: { ! 150: search_regs.start[i] += FirstCharacter; ! 151: search_regs.end[i] += FirstCharacter; ! 152: } ! 153: immediate_quit = 0; ! 154: return val; ! 155: } ! 156: ! 157: DEFUN ("string-match", Fstring_match, Sstring_match, 2, 3, 0, ! 158: "Return index of start of first match for REGEXP in STRING, or nil.\n\ ! 159: If third arg START is non-nil, start search at that index in STRING.\n\ ! 160: For index of first char beyond the match, do (match-end 0).\n\ ! 161: match-end and match-beginning also give indices of substrings\n\ ! 162: matched by parenthesis constructs in the pattern.") ! 163: (regexp, string, start) ! 164: Lisp_Object regexp, string, start; ! 165: { ! 166: int val; ! 167: int s; ! 168: ! 169: CHECK_STRING (regexp, 0); ! 170: CHECK_STRING (string, 1); ! 171: ! 172: if (NULL (start)) ! 173: s = 0; ! 174: else ! 175: { ! 176: int len = XSTRING (string)->size; ! 177: ! 178: CHECK_NUMBER (start, 2); ! 179: s = XINT (start); ! 180: if (s < 0 && -s <= len) ! 181: s = len - s; ! 182: else if (0 > s || s > len) ! 183: args_out_of_range (string, start); ! 184: } ! 185: ! 186: compile_pattern (regexp, &searchbuf, ! 187: !NULL (bf_cur->case_fold_search) ? (char *) downcase_table : 0); ! 188: immediate_quit = 1; ! 189: val = re_search (&searchbuf, XSTRING (string)->data, XSTRING (string)->size, ! 190: s, XSTRING (string)->size - s, &search_regs); ! 191: immediate_quit = 0; ! 192: if (val < 0) return Qnil; ! 193: return make_number (val); ! 194: } ! 195: ! 196: scan_buffer (target, pos, cnt, shortage) ! 197: int *shortage, pos; ! 198: register int cnt, target; ! 199: { ! 200: int lim = ((cnt > 0) ? NumCharacters : FirstCharacter); ! 201: int direction = ((cnt > 0) ? 1 : -1); ! 202: register int lim0; ! 203: unsigned char *base; ! 204: register unsigned char *cursor, *limit; ! 205: ! 206: if (shortage != 0) ! 207: *shortage = 0; ! 208: ! 209: immediate_quit = 1; ! 210: ! 211: if (cnt > 0) ! 212: while (pos != lim + 1) ! 213: { ! 214: lim0 = BufferSafeCeiling (pos); ! 215: lim0 = min (lim, lim0); ! 216: limit = &CharAt (lim0) + 1; ! 217: base = (cursor = &CharAt (pos)); ! 218: while (1) ! 219: { ! 220: while (*cursor != target && ++cursor != limit) ! 221: ; ! 222: if (cursor != limit) ! 223: { ! 224: if (--cnt == 0) ! 225: { ! 226: immediate_quit = 0; ! 227: return (pos + cursor - base + 1); ! 228: } ! 229: else ! 230: if (++cursor == limit) ! 231: break; ! 232: } ! 233: else ! 234: break; ! 235: } ! 236: pos += cursor - base; ! 237: } ! 238: else ! 239: { ! 240: pos--; /* first character we scan */ ! 241: while (pos > lim - 1) ! 242: { /* we WILL scan under pos */ ! 243: lim0 = BufferSafeFloor (pos); ! 244: lim0 = max (lim, lim0); ! 245: limit = &CharAt (lim0) - 1; ! 246: base = (cursor = &CharAt (pos)); ! 247: cursor++; ! 248: while (1) ! 249: { ! 250: while (--cursor != limit && *cursor != target) ! 251: ; ! 252: if (cursor != limit) ! 253: { ! 254: if (++cnt == 0) ! 255: { ! 256: immediate_quit = 0; ! 257: return (pos + cursor - base + 1); ! 258: } ! 259: } ! 260: else ! 261: break; ! 262: } ! 263: pos += cursor - base; ! 264: } ! 265: } ! 266: immediate_quit = 0; ! 267: if (shortage != 0) ! 268: *shortage = cnt * direction; ! 269: return (pos + ((direction == 1 ? 0 : 1))); ! 270: } ! 271: ! 272: int ! 273: find_next_newline (from, cnt) ! 274: register int from, cnt; ! 275: { ! 276: return (scan_buffer ('\n', from, cnt, (int *) 0)); ! 277: } ! 278: ! 279: DEFUN ("skip-chars-forward", Fskip_chars_forward, Sskip_chars_forward, 1, 2, 0, ! 280: "Move point forward, stopping before a char not in CHARS, or at position LIM.\n\ ! 281: CHARS is like the inside of a [...] in a regular expression\n\ ! 282: except that ] is never special and \\ quotes ^, - or \\.\n\ ! 283: Thus, with arg \"a-zA-Z\", this skips letters stopping before first nonletter.\n\ ! 284: With arg \"^a-zA-Z\", skips nonletters stopping before first letter.") ! 285: (string, lim) ! 286: Lisp_Object string, lim; ! 287: { ! 288: skip_chars (1, string, lim); ! 289: return Qnil; ! 290: } ! 291: ! 292: DEFUN ("skip-chars-backward", Fskip_chars_backward, Sskip_chars_backward, 1, 2, 0, ! 293: "Move point backward, stopping after a char not in CHARS, or at position LIM.\n\ ! 294: See skip-chars-forward for details.") ! 295: (string, lim) ! 296: Lisp_Object string, lim; ! 297: { ! 298: skip_chars (0, string, lim); ! 299: return Qnil; ! 300: } ! 301: ! 302: skip_chars (forwardp, string, lim) ! 303: int forwardp; ! 304: Lisp_Object string, lim; ! 305: { ! 306: register unsigned char *p, *pend; ! 307: register unsigned char c; ! 308: unsigned char fastmap[0400]; ! 309: int negate = 0; ! 310: register int i; ! 311: ! 312: CHECK_STRING (string, 0); ! 313: ! 314: if (NULL (lim)) ! 315: XSETINT (lim, forwardp ? NumCharacters + 1 : FirstCharacter); ! 316: else ! 317: CHECK_NUMBER_COERCE_MARKER (lim, 1); ! 318: ! 319: p = XSTRING (string)->data; ! 320: pend = p + XSTRING (string)->size; ! 321: bzero (fastmap, sizeof fastmap); ! 322: ! 323: if (p != pend && *p == '^') ! 324: { ! 325: negate = 1; p++; ! 326: } ! 327: ! 328: /* Find the characters specified and set their elements of fastmap. */ ! 329: ! 330: while (p != pend) ! 331: { ! 332: c = *p++; ! 333: if (c == '\\') ! 334: { ! 335: if (p == pend) break; ! 336: c = *p++; ! 337: } ! 338: if (p != pend && *p == '-') ! 339: { ! 340: p++; ! 341: if (p == pend) break; ! 342: while (c <= *p) ! 343: { ! 344: fastmap[c] = 1; ! 345: c++; ! 346: } ! 347: p++; ! 348: } ! 349: else ! 350: fastmap[c] = 1; ! 351: } ! 352: ! 353: /* If ^ was the first character, complement the fastmap. */ ! 354: ! 355: if (negate) ! 356: for (i = 0; i < sizeof fastmap; i++) ! 357: fastmap[i] ^= 1; ! 358: ! 359: immediate_quit = 1; ! 360: if (forwardp) ! 361: { ! 362: while (point < XINT (lim) && fastmap[CharAt (point)]) ! 363: PointRight (1); ! 364: } ! 365: else ! 366: { ! 367: while (point > XINT (lim) && fastmap[CharAt (point - 1)]) ! 368: PointLeft (1); ! 369: } ! 370: immediate_quit = 0; ! 371: } ! 372: ! 373: /* Subroutines of Lisp buffer search functions. */ ! 374: ! 375: static Lisp_Object ! 376: search_command (string, bound, noerror, count, direction, RE) ! 377: Lisp_Object string, bound, noerror, count; ! 378: int direction; ! 379: int RE; ! 380: { ! 381: register int np; ! 382: int lim; ! 383: int n = direction; ! 384: ! 385: if (!NULL (count)) ! 386: { ! 387: CHECK_NUMBER (count, 3); ! 388: n *= XINT (count); ! 389: } ! 390: ! 391: CHECK_STRING (string, 0); ! 392: if (NULL (bound)) ! 393: lim = n > 0 ? NumCharacters + 1 : FirstCharacter; ! 394: else ! 395: { ! 396: CHECK_NUMBER_COERCE_MARKER (bound, 1); ! 397: lim = XINT (bound); ! 398: if (n > 0 ? lim < point : lim > point) ! 399: error ("Invalid search bound (wrong side of point)"); ! 400: if (lim > NumCharacters + 1) ! 401: lim = NumCharacters + 1; ! 402: if (lim < FirstCharacter) ! 403: lim = FirstCharacter; ! 404: } ! 405: ! 406: np = search_buffer (string, point, lim, n, RE, ! 407: !NULL (bf_cur->case_fold_search) ? downcase_table : 0); ! 408: if (np <= 0) ! 409: { ! 410: if (NULL (noerror)) ! 411: return signal_failure (string); ! 412: if (!EQ (noerror, Qt)) ! 413: { ! 414: if (lim < FirstCharacter || lim > NumCharacters + 1) ! 415: abort (); ! 416: SetPoint (lim); ! 417: } ! 418: return Qnil; ! 419: } ! 420: ! 421: if (np < FirstCharacter || np > NumCharacters + 1) ! 422: abort (); ! 423: ! 424: SetPoint (np); ! 425: ! 426: return Qt; ! 427: } ! 428: ! 429: /* search for the n'th occurrence of `string' in the current buffer, ! 430: starting at position `from' and stopping at position `lim', ! 431: treating `pat' as a literal string if `RE' is false or as ! 432: a regular expression if `RE' is true. ! 433: ! 434: If `n' is positive, searching is forward and `lim' must be greater than `from'. ! 435: If `n' is negative, searching is backward and `lim' must be less than `from'. ! 436: ! 437: Returns -x if only `n'-x occurrences found (x > 0), ! 438: or else the position at the beginning of the `n'th occurrence (if searching backward) ! 439: or the end (if searching forward). */ ! 440: ! 441: /* INTERFACE CHANGE ALERT!!!! search_buffer now returns -x if only */ ! 442: /* n-x occurences are found. */ ! 443: ! 444: search_buffer (string, pos, lim, n, RE, trt) ! 445: Lisp_Object string; ! 446: int pos; ! 447: int lim; ! 448: int n; ! 449: int RE; ! 450: register unsigned char *trt; ! 451: { ! 452: int len = XSTRING (string)->size; ! 453: unsigned char *base_pat = XSTRING (string)->data; ! 454: register int *BM_tab; ! 455: int *BM_tab_base; ! 456: register int direction = ((n > 0) ? 1 : -1); ! 457: register int dirlen; ! 458: int infinity, limit, k, stride_for_teases; ! 459: register unsigned char *pat, *cursor, *p_limit; ! 460: register int i, j; ! 461: unsigned char *p1, *p2; ! 462: int s1, s2; ! 463: ! 464: ! 465: if (!len) ! 466: return (0); ! 467: ! 468: if (RE) ! 469: compile_pattern (string, &searchbuf, (char *) trt); ! 470: ! 471: if (RE /* Here we detect whether the */ ! 472: /* generality of an RE search is */ ! 473: /* really needed. */ ! 474: && *(searchbuf.buffer) == (char) exactn /* first item is "exact match" */ ! 475: && searchbuf.buffer[1] + 2 == searchbuf.used) /*first is ONLY item */ ! 476: { ! 477: RE = 0; /* can do straight (non RE) search */ ! 478: pat = (base_pat = (unsigned char *) searchbuf.buffer + 2); ! 479: /* trt already applied */ ! 480: len = searchbuf.used - 2; ! 481: } ! 482: else if (!RE) ! 483: { ! 484: pat = (unsigned char *) alloca (len); ! 485: ! 486: for (i = len; i--;) /* Copy the pattern; apply trt */ ! 487: *pat++ = (((int) trt) ? trt [*base_pat++] : *base_pat++); ! 488: pat -= len; base_pat = pat; ! 489: } ! 490: ! 491: if (RE) ! 492: { ! 493: immediate_quit = 1; /* Quit immediately if user types ^G, ! 494: because letting this function finish ! 495: can take too long. */ ! 496: QUIT; /* Do a pending quit right away, ! 497: to avoid paradoxical behavior */ ! 498: /* Get pointers and sizes of the two strings ! 499: that make up the visible portion of the buffer. */ ! 500: ! 501: p1 = bf_p1 + bf_head_clip; ! 502: s1 = bf_s1 - (bf_head_clip - 1); ! 503: p2 = bf_p2 + bf_s1 + 1; ! 504: s2 = bf_s2 - bf_tail_clip; ! 505: if (s1 < 0) ! 506: { ! 507: p2 -= s1; ! 508: s2 += s1; ! 509: s1 = 0; ! 510: } ! 511: if (s2 < 0) ! 512: { ! 513: s1 += s2; ! 514: s2 = 0; ! 515: } ! 516: while (n < 0) ! 517: { ! 518: if (re_search_2 (&searchbuf, p1, s1, p2, s2, ! 519: pos - FirstCharacter, lim - pos, &search_regs, ! 520: /* Don't allow match past current point */ ! 521: pos - FirstCharacter) ! 522: >= 0) ! 523: { ! 524: j = FirstCharacter; ! 525: for (i = 0; i < RE_NREGS; i++) ! 526: if (search_regs.start[i] >= 0) ! 527: { ! 528: search_regs.start[i] += j; ! 529: search_regs.end[i] += j; ! 530: } ! 531: /* Set pos to the new position. */ ! 532: pos = search_regs.start[0]; ! 533: } ! 534: else ! 535: { ! 536: immediate_quit = 0; ! 537: return (n); ! 538: } ! 539: n++; ! 540: } ! 541: while (n > 0) ! 542: { ! 543: if (re_search_2 (&searchbuf, p1, s1, p2, s2, ! 544: pos - FirstCharacter, lim - pos, &search_regs, ! 545: lim - FirstCharacter) ! 546: >= 0) ! 547: { ! 548: j = FirstCharacter; ! 549: for (i = 0; i < RE_NREGS; i++) ! 550: if (search_regs.start[i] >= 0) ! 551: { ! 552: search_regs.start[i] += j; ! 553: search_regs.end[i] += j; ! 554: } ! 555: pos = search_regs.end[0]; ! 556: } ! 557: else ! 558: { ! 559: immediate_quit = 0; ! 560: return (0 - n); ! 561: } ! 562: n--; ! 563: } ! 564: immediate_quit = 0; ! 565: return (pos); ! 566: } ! 567: else /* non-RE case */ ! 568: { ! 569: #ifdef C_ALLOCA ! 570: int BM_tab_space[0400]; ! 571: BM_tab = &BM_tab_space[0]; ! 572: #else ! 573: BM_tab = (int *) alloca (0400 * sizeof (int)); ! 574: #endif ! 575: /* The general approach is that we are going to maintain that we know */ ! 576: /* the first (closest to the present position, in whatever direction */ ! 577: /* we're searching) character that could possibly be the last */ ! 578: /* (furthest from present position) character of a valid match. We */ ! 579: /* advance the state of our knowledge by looking at that character */ ! 580: /* and seeing whether it indeed matches the last character of the */ ! 581: /* pattern. If it does, we take a closer look. If it does not, we */ ! 582: /* move our pointer (to putative last characters) as far as is */ ! 583: /* logically possible. This amount of movement, which I call a */ ! 584: /* stride, will be the length of the pattern if the actual character */ ! 585: /* appears nowhere in the pattern, otherwise it will be the distance */ ! 586: /* from the last occurrence of that character to the end of the */ ! 587: /* pattern. */ ! 588: /* As a coding trick, an enormous stride is coded into the table for */ ! 589: /* characters that match the last character. This allows use of only */ ! 590: /* a single test, a test for having gone past the end of the */ ! 591: /* permissible match region, to test for both possible matches (when */ ! 592: /* the stride goes past the end immediately) and failure to */ ! 593: /* match (where you get nudged past the end one stride at a time). */ ! 594: ! 595: /* Here we make a "mickey mouse" BM table. The stride of the search */ ! 596: /* is determined only by the last character of the putative match. */ ! 597: /* If that character does not match, we will stride the proper */ ! 598: /* distance to propose a match that superimposes it on the last */ ! 599: /* instance of a character that matches it (per trt), or misses */ ! 600: /* it entirely if there is none. */ ! 601: ! 602: dirlen = len * direction; ! 603: infinity = dirlen - (lim + pos + len + len) * direction; ! 604: if (direction < 0) ! 605: pat = (base_pat += len - 1); ! 606: BM_tab_base = BM_tab; ! 607: BM_tab += 0400; ! 608: j = dirlen; /* to get it in a register */ ! 609: /* A character that does not appear in the pattern induces a */ ! 610: /* stride equal to the pattern length. */ ! 611: while (BM_tab_base != BM_tab) ! 612: { ! 613: *--BM_tab = j; ! 614: *--BM_tab = j; ! 615: *--BM_tab = j; ! 616: *--BM_tab = j; ! 617: } ! 618: i = 0; ! 619: while (i != infinity) ! 620: { ! 621: j = pat[i]; i += direction; ! 622: if (i == dirlen) i = infinity; ! 623: if ((int) trt) ! 624: { ! 625: k = (j = trt[j]); ! 626: if (i == infinity) ! 627: stride_for_teases = BM_tab[j]; ! 628: BM_tab[j] = dirlen - i; ! 629: /* A translation table is followed by its inverse -- see */ ! 630: /* comment following downcase_table for details */ ! 631: ! 632: while ((j = trt[0400+j]) != k) ! 633: BM_tab[j] = dirlen - i; ! 634: } ! 635: else ! 636: { ! 637: if (i == infinity) ! 638: stride_for_teases = BM_tab[j]; ! 639: BM_tab[j] = dirlen - i; ! 640: } ! 641: /* stride_for_teases tells how much to stride if we get a */ ! 642: /* match on the far character but are subsequently */ ! 643: /* disappointed, by recording what the stride would have been */ ! 644: /* for that character if the last character had been */ ! 645: /* different. */ ! 646: } ! 647: infinity = dirlen - infinity; ! 648: pos += dirlen - ((direction > 0) ? direction : 0); ! 649: /* loop invariant - pos points at where last char (first char if reverse) ! 650: of pattern would align in a possible match. */ ! 651: while (n != 0) ! 652: { ! 653: if ((lim - pos - (direction > 0)) * direction < 0) ! 654: return (n * (0 - direction)); ! 655: /* First we do the part we can by pointers (maybe nothing) */ ! 656: QUIT; ! 657: pat = base_pat; ! 658: limit = pos - dirlen + direction; ! 659: limit = ((direction > 0) ! 660: ? BufferSafeCeiling (limit) ! 661: : BufferSafeFloor (limit)); ! 662: /* LIMIT is now the last (not beyond-last!) value ! 663: POS can take on without hitting edge of buffer or the gap. */ ! 664: limit = ((direction > 0) ! 665: ? min (lim - 1, min (limit, pos + 20000)) ! 666: : max (lim, max (limit, pos - 20000))); ! 667: if ((limit - pos) * direction > 20) ! 668: { ! 669: p_limit = &CharAt (limit); ! 670: p2 = (cursor = &CharAt (pos)); ! 671: /* In this loop, pos + cursor - p2 is the surrogate for pos */ ! 672: while (1) /* use one cursor setting as long as i can */ ! 673: { ! 674: if (direction > 0) /* worth duplicating */ ! 675: { ! 676: /* Use signed comparison if appropriate ! 677: to make cursor+infinity sure to be > p_limit. ! 678: Assuming that the buffer lies in a range of addresses ! 679: that are all "positive" (as ints) or all "negative", ! 680: either kind of comparison will work as long ! 681: as we don't step by infinity. So pick the kind ! 682: that works when we do step by infinity. */ ! 683: if ((int) (p_limit + infinity) > (int) p_limit) ! 684: while ((int) cursor <= (int) p_limit) ! 685: cursor += BM_tab[*cursor]; ! 686: else ! 687: while ((unsigned int) cursor <= (unsigned int) p_limit) ! 688: cursor += BM_tab[*cursor]; ! 689: } ! 690: else ! 691: { ! 692: if ((int) (p_limit + infinity) < (int) p_limit) ! 693: while ((int) cursor >= (int) p_limit) ! 694: cursor += BM_tab[*cursor]; ! 695: else ! 696: while ((unsigned int) cursor >= (unsigned int) p_limit) ! 697: cursor += BM_tab[*cursor]; ! 698: } ! 699: /* If you are here, cursor is beyond the end of the searched region. */ ! 700: /* This can happen if you match on the far character of the pattern, */ ! 701: /* because the "stride" of that character is infinity, a number able */ ! 702: /* to throw you well beyond the end of the search. It can also */ ! 703: /* happen if you fail to match within the permitted region and would */ ! 704: /* otherwise try a character beyond that region */ ! 705: if ((cursor - p_limit) * direction <= len) ! 706: break; /* a small overrun is genuine */ ! 707: cursor -= infinity; /* large overrun = hit */ ! 708: i = dirlen - direction; ! 709: if ((int) trt) ! 710: { ! 711: while ((i -= direction) + direction != 0) ! 712: if (pat[i] != trt[*(cursor -= direction)]) ! 713: break; ! 714: } ! 715: else ! 716: { ! 717: while ((i -= direction) + direction != 0) ! 718: if (pat[i] != *(cursor -= direction)) ! 719: break; ! 720: } ! 721: cursor += dirlen - i - direction; /* fix cursor */ ! 722: if (i + direction == 0) ! 723: { ! 724: cursor -= direction; ! 725: search_regs.start[0] ! 726: = pos + cursor - p2 + ((direction > 0) ! 727: ? 1 - len : 0); ! 728: search_regs.end[0] = len + search_regs.start[0]; ! 729: if ((n -= direction) != 0) ! 730: cursor += dirlen; /* to resume search */ ! 731: else ! 732: return ((direction > 0) ! 733: ? search_regs.end[0] : search_regs.start[0]); ! 734: } ! 735: else ! 736: cursor += stride_for_teases; /* <sigh> we lose - */ ! 737: } ! 738: pos += cursor - p2; ! 739: } ! 740: else ! 741: /* Now we'll pick up a clump that has to be done the hard */ ! 742: /* way because it covers a discontinuity */ ! 743: { ! 744: limit = ((direction > 0) ! 745: ? BufferSafeCeiling (pos - dirlen + 1) ! 746: : BufferSafeFloor (pos - dirlen - 1)); ! 747: limit = ((direction > 0) ! 748: ? min (limit + len, lim - 1) ! 749: : max (limit - len, lim)); ! 750: /* LIMIT is now the last value POS can have ! 751: and still be valid for a possible match. */ ! 752: while (1) ! 753: { ! 754: /* This loop can be coded for space rather than */ ! 755: /* speed because it will usually run only once. */ ! 756: /* (the reach is at most len + 21, and typically */ ! 757: /* does not exceed len) */ ! 758: while ((limit - pos) * direction >= 0) ! 759: pos += BM_tab[CharAt(pos)]; ! 760: /* now run the same tests to distinguish going off the */ ! 761: /* end, a match or a phoney match. */ ! 762: if ((pos - limit) * direction <= len) ! 763: break; /* ran off the end */ ! 764: /* Found what might be a match. ! 765: Set POS back to last (first if reverse) char pos. */ ! 766: pos -= infinity; ! 767: i = dirlen - direction; ! 768: while ((i -= direction) + direction != 0) ! 769: { ! 770: pos -= direction; ! 771: if (pat[i] != (((int) trt) ! 772: ? trt[CharAt(pos)] ! 773: : CharAt (pos))) ! 774: break; ! 775: } ! 776: /* Above loop has moved POS part or all the way ! 777: back to the first char pos (last char pos if reverse). ! 778: Set it once again at the last (first if reverse) char. */ ! 779: pos += dirlen - i- direction; ! 780: if (i + direction == 0) ! 781: { ! 782: pos -= direction; ! 783: search_regs.start[0] ! 784: = pos + ((direction > 0) ? 1 - len : 0); ! 785: search_regs.end[0] = len + search_regs.start[0]; ! 786: if ((n -= direction) != 0) ! 787: pos += dirlen; /* to resume search */ ! 788: else ! 789: return ((direction > 0) ! 790: ? search_regs.end[0] : search_regs.start[0]); ! 791: } ! 792: else ! 793: pos += stride_for_teases; ! 794: } ! 795: } ! 796: /* We have done one clump. Can we continue? */ ! 797: if ((lim - pos) * direction < 0) ! 798: return ((0 - n) * direction); ! 799: } ! 800: } ! 801: } ! 802: ! 803: /* Given a string of words separated by word delimiters, ! 804: compute a regexp that matches those exact words ! 805: separated by arbitrary punctuation. */ ! 806: ! 807: static Lisp_Object ! 808: wordify (string) ! 809: Lisp_Object string; ! 810: { ! 811: register unsigned char *p, *o; ! 812: register int i, len, punct_count = 0, word_count = 0; ! 813: Lisp_Object val; ! 814: ! 815: CHECK_STRING (string, 0); ! 816: p = XSTRING (string)->data; ! 817: len = XSTRING (string)->size; ! 818: ! 819: for (i = 0; i < len; i++) ! 820: if (SYNTAX (p[i]) != Sword) ! 821: { ! 822: punct_count++; ! 823: if (i > 0 && SYNTAX (p[i-1]) == Sword) word_count++; ! 824: } ! 825: if (SYNTAX (p[len-1]) == Sword) word_count++; ! 826: if (!word_count) return build_string (""); ! 827: ! 828: val = make_string (p, len - punct_count + 5 * (word_count - 1) + 4); ! 829: ! 830: o = XSTRING (val)->data; ! 831: *o++ = '\\'; ! 832: *o++ = 'b'; ! 833: ! 834: for (i = 0; i < len; i++) ! 835: if (SYNTAX (p[i]) == Sword) ! 836: *o++ = p[i]; ! 837: else if (i > 0 && SYNTAX (p[i-1]) == Sword && --word_count) ! 838: { ! 839: *o++ = '\\'; ! 840: *o++ = 'W'; ! 841: *o++ = '\\'; ! 842: *o++ = 'W'; ! 843: *o++ = '*'; ! 844: } ! 845: ! 846: *o++ = '\\'; ! 847: *o++ = 'b'; ! 848: ! 849: return val; ! 850: } ! 851: ! 852: DEFUN ("search-backward", Fsearch_backward, Ssearch_backward, 1, 4, ! 853: "sSearch backward: ", ! 854: "Search backward from point for STRING.\n\ ! 855: Set point to the beginning of the occurrence found, and return t.\n\ ! 856: An optional second argument bounds the search; it is a buffer position.\n\ ! 857: The match found must not extend before that position.\n\ ! 858: Optional third argument, if t, means if fail just return nil (no error).\n\ ! 859: If not nil and not t, position at limit of search and return nil.\n\ ! 860: Optional fourth argument is repeat count--search for successive occurrences.") ! 861: (string, bound, noerror, count) ! 862: Lisp_Object string, bound, noerror, count; ! 863: { ! 864: return search_command (string, bound, noerror, count, -1, 0); ! 865: } ! 866: ! 867: DEFUN ("search-forward", Fsearch_forward, Ssearch_forward, 1, 4, "sSearch: ", ! 868: "Search forward from point for STRING.\n\ ! 869: Set point to the end of the occurrence found, and return t.\n\ ! 870: An optional second argument bounds the search; it is a buffer position.\n\ ! 871: The match found must not extend after that position.\n\ ! 872: Optional third argument, if t, means if fail just return nil (no error).\n\ ! 873: If not nil and not t, move to limit of search and return nil.\n\ ! 874: Optional fourth argument is repeat count--search for successive occurrences.") ! 875: (string, bound, noerror, count) ! 876: Lisp_Object string, bound, noerror, count; ! 877: { ! 878: return search_command (string, bound, noerror, count, 1, 0); ! 879: } ! 880: ! 881: DEFUN ("word-search-backward", Fword_search_backward, Sword_search_backward, 1, 4, ! 882: "sWord search backward: ", ! 883: "Search backward from point for STRING, ignoring differences in punctuation.\n\ ! 884: Set point to the beginning of the occurrence found, and return t.\n\ ! 885: An optional second argument bounds the search; it is a buffer position.\n\ ! 886: The match found must not extend before that position.\n\ ! 887: Optional third argument, if t, means if fail just return nil (no error).\n\ ! 888: If not nil and not t, move to limit of search and return nil.\n\ ! 889: Optional fourth argument is repeat count--search for successive occurrences.") ! 890: (string, bound, noerror, count) ! 891: Lisp_Object string, bound, noerror, count; ! 892: { ! 893: return search_command (wordify (string), bound, noerror, count, -1, 1); ! 894: } ! 895: ! 896: DEFUN ("word-search-forward", Fword_search_forward, Sword_search_forward, 1, 4, ! 897: "sWord search: ", ! 898: "Search forward from point for STRING, ignoring differences in punctuation.\n\ ! 899: Set point to the end of the occurrence found, and return t.\n\ ! 900: An optional second argument bounds the search; it is a buffer position.\n\ ! 901: The match found must not extend after that position.\n\ ! 902: Optional third argument, if t, means if fail just return nil (no error).\n\ ! 903: If not nil and not t, move to limit of search and return nil.\n\ ! 904: Optional fourth argument is repeat count--search for successive occurrences.") ! 905: (string, bound, noerror, count) ! 906: Lisp_Object string, bound, noerror, count; ! 907: { ! 908: return search_command (wordify (string), bound, noerror, count, 1, 1); ! 909: } ! 910: ! 911: DEFUN ("re-search-backward", Fre_search_backward, Sre_search_backward, 1, 4, ! 912: "sRE search backward: ", ! 913: "Search backward from point for match for regular expression REGEXP.\n\ ! 914: Set point to the beginning of the match, and return t.\n\ ! 915: The match found is the one starting last in the buffer\n\ ! 916: and yet ending before the place the origin of the search.\n\ ! 917: An optional second argument bounds the search; it is a buffer position.\n\ ! 918: The match found must start at or after that position.\n\ ! 919: Optional third argument, if t, means if fail just return nil (no error).\n\ ! 920: If not nil and not t, move to limit of search and return nil.\n\ ! 921: Optional fourth argument is repeat count--search for successive occurrences.\n\ ! 922: See also the functions match-beginning and match-end and replace-match.") ! 923: (string, bound, noerror, count) ! 924: Lisp_Object string, bound, noerror, count; ! 925: { ! 926: return search_command (string, bound, noerror, count, -1, 1); ! 927: } ! 928: ! 929: DEFUN ("re-search-forward", Fre_search_forward, Sre_search_forward, 1, 4, ! 930: "sRE search: ", ! 931: "Search forward from point for regular expression REGEXP.\n\ ! 932: Set point to the end of the occurrence found, and return t.\n\ ! 933: An optional second argument bounds the search; it is a buffer position.\n\ ! 934: The match found must not extend after that position.\n\ ! 935: Optional third argument, if t, means if fail just return nil (no error).\n\ ! 936: If not nil and not t, move to limit of search and return nil.\n\ ! 937: Optional fourth argument is repeat count--search for successive occurrences.\n\ ! 938: See also the functions match-beginning and match-end and replace-match.") ! 939: (string, bound, noerror, count) ! 940: Lisp_Object string, bound, noerror, count; ! 941: { ! 942: return search_command (string, bound, noerror, count, 1, 1); ! 943: } ! 944: ! 945: DEFUN ("replace-match", Freplace_match, Sreplace_match, 1, 3, 0, ! 946: "Replace text matched by last search with NEWTEXT.\n\ ! 947: If second arg FIXEDCASE is non-nil, do not alter case of replacement text.\n\ ! 948: Otherwise convert to all caps or cap initials, like replaced text.\n\ ! 949: If third arg LITERAL is non-nil, insert NEWTEXT literally.\n\ ! 950: Otherwise treat \\ as special:\n\ ! 951: \\& in NEWTEXT means substitute original matched text,\n\ ! 952: \\N means substitute match for \\(...\\) number N,\n\ ! 953: \\\\ means insert one \\.\n\ ! 954: Leaves point at end of replacement text.") ! 955: (string, fixedcase, literal) ! 956: Lisp_Object string, fixedcase, literal; ! 957: { ! 958: enum { nochange, all_caps, cap_initial } case_action; ! 959: register int pos, last; ! 960: int some_multiletter_word; ! 961: int some_letter = 0; ! 962: register int c, prevc; ! 963: int inslen; ! 964: ! 965: CHECK_STRING (string, 0); ! 966: ! 967: case_action = nochange; /* We tried an initialization */ ! 968: /* but some C compilers blew it */ ! 969: if (search_regs.start[0] < FirstCharacter ! 970: || search_regs.start[0] > search_regs.end[0] ! 971: || search_regs.end[0] > NumCharacters + 1) ! 972: args_out_of_range(make_number (search_regs.start[0]), ! 973: make_number (search_regs.end[0])); ! 974: ! 975: if (NULL (fixedcase)) ! 976: { ! 977: /* Decide how to casify by examining the matched text. */ ! 978: ! 979: last = search_regs.end[0]; ! 980: prevc = '\n'; ! 981: case_action = all_caps; ! 982: ! 983: /* some_multiletter_word is set nonzero if any original word ! 984: is more than one letter long. */ ! 985: some_multiletter_word = 0; ! 986: ! 987: for (pos = search_regs.start[0]; pos < last; pos++) ! 988: { ! 989: c = CharAt (pos); ! 990: if (LOWERCASEP (c)) ! 991: { ! 992: /* Cannot be all caps if any original char is lower case */ ! 993: ! 994: case_action = cap_initial; ! 995: if (SYNTAX (prevc) != Sword) ! 996: { ! 997: /* Cannot even be cap initials ! 998: if some original initial is lower case */ ! 999: case_action = nochange; ! 1000: break; ! 1001: } ! 1002: else ! 1003: some_multiletter_word = 1; ! 1004: } ! 1005: else if (!NOCASEP (c)) ! 1006: { ! 1007: some_letter = 1; ! 1008: if (!some_multiletter_word && SYNTAX (prevc) == Sword) ! 1009: some_multiletter_word = 1; ! 1010: } ! 1011: ! 1012: prevc = c; ! 1013: } ! 1014: ! 1015: /* Do not make new text all caps ! 1016: if the original text contained only single letter words. */ ! 1017: if (case_action == all_caps && !some_multiletter_word) ! 1018: case_action = cap_initial; ! 1019: ! 1020: if (!some_letter) case_action = nochange; ! 1021: } ! 1022: ! 1023: SetPoint (search_regs.end[0]); ! 1024: if (!NULL (literal)) ! 1025: Finsert (1, &string); ! 1026: else ! 1027: { ! 1028: for (pos = 0; pos < XSTRING (string)->size; pos++) ! 1029: { ! 1030: c = XSTRING (string)->data[pos]; ! 1031: if (c == '\\') ! 1032: { ! 1033: c = XSTRING (string)->data[++pos]; ! 1034: if (c == '&') ! 1035: place (search_regs.start[0], ! 1036: search_regs.end[0]); ! 1037: else if (c >= '1' && c <= RE_NREGS + '0') ! 1038: { ! 1039: if (search_regs.start[c - '0'] >= 1) ! 1040: place (search_regs.start[c - '0'], ! 1041: search_regs.end[c - '0']); ! 1042: } ! 1043: else ! 1044: insert_char (c); ! 1045: } ! 1046: else ! 1047: insert_char (c); ! 1048: } ! 1049: } ! 1050: ! 1051: inslen = point - (search_regs.end[0]); ! 1052: del_range (search_regs.start[0], search_regs.end[0]); ! 1053: ! 1054: if (case_action == all_caps) ! 1055: Fupcase_region (make_number (point - inslen), make_number (point)); ! 1056: else if (case_action == cap_initial) ! 1057: upcase_initials_region (make_number (point - inslen), make_number (point)); ! 1058: return Qnil; ! 1059: } ! 1060: ! 1061: static ! 1062: place (l1, l2) ! 1063: int l1, l2; ! 1064: { ! 1065: if (l1 < FirstCharacter) ! 1066: l1 = FirstCharacter; ! 1067: if (l1 >= NumCharacters + 1) ! 1068: l1 = NumCharacters + 1; ! 1069: if (l2 < l1) l2 = l1; ! 1070: if (l2 >= NumCharacters + 1) ! 1071: l2 = NumCharacters + 1; ! 1072: move_gap (point); ! 1073: InsCStr (&CharAt (l1), l2 - l1); ! 1074: } ! 1075: ! 1076: static Lisp_Object ! 1077: match_limit (num, beginningp) ! 1078: Lisp_Object num; ! 1079: int beginningp; ! 1080: { ! 1081: register int n; ! 1082: ! 1083: CHECK_NUMBER (num, 0); ! 1084: n = XINT (num); ! 1085: if (n < 0 || n >= RE_NREGS) ! 1086: args_out_of_range (num, make_number (RE_NREGS)); ! 1087: if (search_regs.start[n] < 0) ! 1088: return Qnil; ! 1089: return (make_number ((beginningp) ? search_regs.start[n] ! 1090: : search_regs.end[n])); ! 1091: } ! 1092: ! 1093: DEFUN ("match-beginning", Fmatch_beginning, Smatch_beginning, 1, 1, 0, ! 1094: "Return the character number of start of text matched by last regexp searched for.\n\ ! 1095: ARG, a number, specifies which parenthesized expression in the last regexp.\n\ ! 1096: Value is nil if ARGth pair didn't match, or there were less than ARG pairs.\n\ ! 1097: Zero means the entire text matched by the whole regexp.") ! 1098: (num) ! 1099: Lisp_Object num; ! 1100: { ! 1101: return match_limit (num, 1); ! 1102: } ! 1103: ! 1104: DEFUN ("match-end", Fmatch_end, Smatch_end, 1, 1, 0, ! 1105: "Return the character number of end of text matched by last regexp searched for.\n\ ! 1106: ARG, a number, specifies which parenthesized expression in the last regexp.\n\ ! 1107: Value is nil if ARGth pair didn't match, or there were less than ARG pairs.\n\ ! 1108: Zero means the entire text matched by the whole regexp.") ! 1109: (num) ! 1110: Lisp_Object num; ! 1111: { ! 1112: return match_limit (num, 0); ! 1113: } ! 1114: ! 1115: DEFUN ("match-data", Fmatch_data, Smatch_data, 0, 0, 0, ! 1116: "Return list containing all info on what the last search matched.\n\ ! 1117: Element 2N is (match-beginning N); element 2N + 1 is (match-end N).\n\ ! 1118: All the elements are markers or nil (nil if the Nth pair didn't match).") ! 1119: () ! 1120: { ! 1121: Lisp_Object data[2 * RE_NREGS]; ! 1122: int i, len; ! 1123: ! 1124: len = -1; ! 1125: for (i = 0; i < RE_NREGS; i++) ! 1126: { ! 1127: int start = search_regs.start[i]; ! 1128: if (start >= 0) ! 1129: { ! 1130: data[2 * i] = Fmake_marker (); ! 1131: Fset_marker (data[2 * i], make_number (start), Qnil); ! 1132: data[2 * i + 1] = Fmake_marker (); ! 1133: Fset_marker (data[2 * i + 1], ! 1134: make_number (search_regs.end[i]), Qnil); ! 1135: len = i; ! 1136: } ! 1137: else ! 1138: data[2 * i] = data [2 * i + 1] = Qnil; ! 1139: } ! 1140: return Flist (2 * len + 2, data); ! 1141: } ! 1142: ! 1143: ! 1144: DEFUN ("store-match-data", Fstore_match_data, Sstore_match_data, 1, 1, 0, ! 1145: "Set internal data on last search match from elements of LIST.\n\ ! 1146: LIST should have been created by calling match-data previously.") ! 1147: (list) ! 1148: register Lisp_Object list; ! 1149: { ! 1150: register int i; ! 1151: register Lisp_Object marker; ! 1152: ! 1153: if (!CONSP (list) && !NULL (list)) ! 1154: list = wrong_type_argument (Qconsp, list, 0); ! 1155: ! 1156: for (i = 0; i < RE_NREGS; i++) ! 1157: { ! 1158: marker = Fcar (list); ! 1159: if (NULL (marker)) ! 1160: { ! 1161: search_regs.start[i] = -1; ! 1162: list = Fcdr (list); ! 1163: } ! 1164: else ! 1165: { ! 1166: CHECK_MARKER (marker, 0); ! 1167: search_regs.start[i] = marker_position (marker); ! 1168: list = Fcdr (list); ! 1169: ! 1170: marker = Fcar (list); ! 1171: CHECK_MARKER (marker, 0); ! 1172: search_regs.end[i] = marker_position (marker); ! 1173: } ! 1174: list = Fcdr (list); ! 1175: } ! 1176: ! 1177: return Qnil; ! 1178: } ! 1179: ! 1180: /* Quote a string to inactivate reg-expr chars */ ! 1181: ! 1182: DEFUN ("regexp-quote", Fregexp_quote, Sregexp_quote, 1, 1, 0, ! 1183: "Return a regexp string which matches exactly STRING and nothing else.") ! 1184: (str) ! 1185: Lisp_Object str; ! 1186: { ! 1187: register unsigned char *p, *cp, *end; ! 1188: register int size; ! 1189: Lisp_Object ostr; ! 1190: ! 1191: CHECK_STRING (str, 0); ! 1192: size = XSTRING (str)->size; ! 1193: ! 1194: /* Increment `size' for the escapes we will need to insert */ ! 1195: ! 1196: for (cp = XSTRING (str)->data, end = cp + size; cp != end; cp++) ! 1197: if (*cp == '[' || *cp == ']' ! 1198: || *cp == '*' || *cp == '.' || *cp == '\\' ! 1199: || *cp == '?' || *cp == '+' ! 1200: || *cp == '^' || *cp == '$') ! 1201: size++; ! 1202: ! 1203: ostr = Fmake_string (make_number (size), make_number (0)); ! 1204: ! 1205: /* Now copy the data into the new string, inserting escapes. */ ! 1206: ! 1207: p = XSTRING (ostr)->data; ! 1208: for (cp = XSTRING (str)->data; cp != end; cp++) ! 1209: { ! 1210: if (*cp == '[' || *cp == ']' ! 1211: || *cp == '*' || *cp == '.' || *cp == '\\' ! 1212: || *cp == '?' || *cp == '+' ! 1213: || *cp == '^' || *cp == '$') ! 1214: *p++ = '\\'; ! 1215: *p++ = *cp; ! 1216: } ! 1217: return ostr; ! 1218: } ! 1219: ! 1220: /* This code should be unzapped when there comes to be multiple */ ! 1221: /* translation tables. It has been certified on various cases. */ ! 1222: /* ! 1223: void ! 1224: compute_trt_inverse (trt) ! 1225: register unsigned char *trt; ! 1226: { ! 1227: register int i = 0400; ! 1228: register unsigned char c, q; ! 1229: ! 1230: while (i--) ! 1231: trt[0400+i] = i; ! 1232: i = 0400; ! 1233: while (i--) ! 1234: { ! 1235: if ((q = trt[i]) != (unsigned char) i) ! 1236: { ! 1237: c = trt[q + 0400]; ! 1238: trt[q + 0400] = i; ! 1239: trt[0400 + i] = c; ! 1240: } ! 1241: } ! 1242: } ! 1243: */ ! 1244: ! 1245: syms_of_search () ! 1246: { ! 1247: register int i; ! 1248: ! 1249: for (i = 0; i < 0400; i++) ! 1250: { ! 1251: downcase_table[i] = (i >= 'A' && i <= 'Z') ? i + 040 : i; ! 1252: /* We do this instead of using compute_trt_inverse to save space. */ ! 1253: /* Does it? */ ! 1254: downcase_table[0400+i] ! 1255: = ((i >= 'A' && i <= 'Z') ! 1256: ? i + ('a' - 'A') ! 1257: : ((i >= 'a' && i <= 'z') ! 1258: ? i + ('A' - 'a') ! 1259: : i)); ! 1260: } ! 1261: /* Use this instead when there come to be multiple translation tables. ! 1262: compute_trt_inverse (downcase_table); */ ! 1263: ! 1264: searchbuf.allocated = 100; ! 1265: searchbuf.buffer = (char *) malloc (searchbuf.allocated); ! 1266: searchbuf.fastmap = search_fastmap; ! 1267: ! 1268: Qsearch_failed = intern ("search-failed"); ! 1269: staticpro (&Qsearch_failed); ! 1270: Qinvalid_regexp = intern ("invalid-regexp"); ! 1271: staticpro (&Qinvalid_regexp); ! 1272: ! 1273: Fput (Qsearch_failed, Qerror_conditions, ! 1274: Fcons (Qsearch_failed, Fcons (Qerror, Qnil))); ! 1275: Fput (Qsearch_failed, Qerror_message, ! 1276: build_string ("Search failed")); ! 1277: ! 1278: Fput (Qinvalid_regexp, Qerror_conditions, ! 1279: Fcons (Qinvalid_regexp, Fcons (Qerror, Qnil))); ! 1280: Fput (Qinvalid_regexp, Qerror_message, ! 1281: build_string ("Invalid regexp")); ! 1282: ! 1283: last_regexp = Qnil; ! 1284: staticpro (&last_regexp); ! 1285: ! 1286: defsubr (&Sstring_match); ! 1287: defsubr (&Slooking_at); ! 1288: defsubr (&Sskip_chars_forward); ! 1289: defsubr (&Sskip_chars_backward); ! 1290: defsubr (&Ssearch_forward); ! 1291: defsubr (&Ssearch_backward); ! 1292: defsubr (&Sword_search_forward); ! 1293: defsubr (&Sword_search_backward); ! 1294: defsubr (&Sre_search_forward); ! 1295: defsubr (&Sre_search_backward); ! 1296: defsubr (&Sreplace_match); ! 1297: defsubr (&Smatch_beginning); ! 1298: defsubr (&Smatch_end); ! 1299: defsubr (&Smatch_data); ! 1300: defsubr (&Sstore_match_data); ! 1301: defsubr (&Sregexp_quote); ! 1302: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.