1: /* String search routines for GNU Emacs.
   2:    Copyright (C) 1985 Richard M. Stallman.
   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 <ctype.h>
  23: #include "config.h"
  24: #include "lisp.h"
  25: #include "syntax.h"
  26: #include "buffer.h"
  27: #include "commands.h"
  28: #include "regex.h"
  29: 
  30: unsigned char downcase_table[0400] = {0};   /* folds upper to lower case */
  31: 
  32: /* We compile regexps into this buffer and then use it for searching. */
  33: 
  34: static struct re_pattern_buffer searchbuf;
  35: 
  36: char search_fastmap[0400];
  37: 
  38: /* Last regexp we compiled */
  39: 
  40: Lisp_Object last_regexp;
  41: 
  42: /* Every call to re_match, etc., must pass &search_regs as the regs argument
  43:  unless you can show it is unnecessary (i.e., if re_match is certainly going
  44:  to be called again before region-around-match can be called).  */
  45: 
  46: static struct re_registers search_regs;
  47: 
  48: /* error condition signalled when regexp compile_pattern fails */
  49: 
  50: Lisp_Object Qinvalid_regexp;
  51: 
  52: /* Compile a regexp and signal a Lisp error if anything goes wrong.  */
  53: 
  54: compile_pattern (pattern, bufp, translate)
  55:      Lisp_Object pattern;
  56:      struct re_pattern_buffer *bufp;
  57:      char *translate;
  58: {
  59:   char *val;
  60:   Lisp_Object dummy;
  61: 
  62:   if (EQ (pattern, last_regexp)
  63:       && translate == bufp->translate)
  64:     return;
  65:   last_regexp = Qnil;
  66:   bufp->translate = translate;
  67:   val = re_compile_pattern (XSTRING (pattern)->data,
  68:                 XSTRING (pattern)->size,
  69:                 bufp);
  70:   if (val)
  71:     {
  72:       dummy = build_string (val);
  73:       while (1)
  74:     Fsignal (Qinvalid_regexp, Fcons (dummy, Qnil));
  75:     }
  76:   last_regexp = pattern;
  77:   return;
  78: }
  79: 
  80: /* Error condition used for failing searches */
  81: Lisp_Object Qsearch_failed;
  82: 
  83: Lisp_Object
  84: signal_failure (arg)
  85:      Lisp_Object arg;
  86: {
  87:   Fsignal (Qsearch_failed, Fcons (arg, Qnil));
  88:   return Qnil;
  89: }
  90: 
  91: DEFUN ("looking-at", Flooking_at, Slooking_at, 1, 1, 0,
  92:   "t if text after point matches regular expression PAT.")
  93:   (string)
  94:      Lisp_Object string;
  95: {
  96:   Lisp_Object val;
  97:   unsigned char *p1, *p2;
  98:   int s1, s2;
  99:   register int i;
 100: 
 101:   CHECK_STRING (string, 0);
 102:   compile_pattern (string, &searchbuf,
 103:            !NULL (bf_cur->case_fold_search) ? (char *) downcase_table : 0);
 104: 
 105:   immediate_quit = 1;
 106:   QUIT;         /* Do a pending quit right away, to avoid paradoxical behavior */
 107: 
 108:   /* Get pointers and sizes of the two strings
 109:      that make up the visible portion of the buffer. */
 110: 
 111:   p1 = bf_p1 + bf_head_clip;
 112:   s1 = bf_s1 - (bf_head_clip - 1);
 113:   p2 = bf_p2 + bf_s1 + 1;
 114:   s2 = bf_s2 - bf_tail_clip;
 115:   if (s1 < 0)
 116:     {
 117:       p2 -= s1;
 118:       s2 += s1;
 119:       s1 = 0;
 120:     }
 121:   if (s2 < 0)
 122:     {
 123:       s1 += s2;
 124:       s2 = 0;
 125:     }
 126: 
 127:   val = (0 <= re_match_2 (&searchbuf, p1, s1, p2, s2,
 128:               point - FirstCharacter, &search_regs,
 129:               NumCharacters + 1 - FirstCharacter)
 130:      ? Qt : Qnil);
 131:   for (i = 0; i < RE_NREGS; i++)
 132:     {
 133:       search_regs.start[i] += FirstCharacter - 1;
 134:       search_regs.end[i] += FirstCharacter - 1;
 135:     }
 136:   immediate_quit = 0;
 137:   return val;
 138: }
 139: 
 140: DEFUN ("string-match", Fstring_match, Sstring_match, 2, 3, 0,
 141:   "Return index of start of first match for REGEXP in STRING, or nil.\n\
 142: If third arg START is non-nil, start search at that index in STRING.\n\
 143: For index of first char beyond the match, do (match-end 0).\n\
 144: match-end and match-beginning also give indices of substrings\n\
 145: matched by parenthesis constructs in the pattern.")
 146:   (regexp, string, start)
 147:      Lisp_Object regexp, string, start;
 148: {
 149:   int val;
 150:   int s;
 151: 
 152:   CHECK_STRING (regexp, 0);
 153:   CHECK_STRING (string, 1);
 154: 
 155:   if (NULL (start))
 156:     s = 0;
 157:   else
 158:     {
 159:       CHECK_NUMBER (start, 2);
 160:       s = XINT (start);
 161:     }
 162: 
 163:   compile_pattern (regexp, &searchbuf,
 164:            !NULL (bf_cur->case_fold_search) ? (char *) downcase_table : 0);
 165:   val = re_search (&searchbuf, XSTRING (string)->data, XSTRING (string)->size,
 166:                    s, XSTRING (string)->size - s, &search_regs);
 167:   /* Correct for propensity of match-beginning and match-end
 168:      to add 1 to each of these (which is correct for buffer positions
 169:      since they are origin-1, but not for indices in strings).  */
 170:   for (s = 0; s < RE_NREGS; s++)
 171:     {
 172:       search_regs.start[s]--;
 173:       search_regs.end[s]--;
 174:     }
 175:   if (val < 0) return Qnil;
 176:   return make_number (val);
 177: }
 178: 
 179: DEFUN ("scan-buffer", Fscan_buffer, Sscan_buffer, 3, 3, 0,
 180:   "Scan from character number FROM for COUNT occurrences of character C.\n\
 181: Returns the character number of the position after the character found.\n\
 182: If not found, returns char number of beginning or end of buffer.\n\
 183: Note that this does -not- take take  case-fold-search  into consideration.")
 184:   (from, count, c)
 185:      Lisp_Object from, count, c;
 186: {
 187:   CHECK_NUMBER_COERCE_MARKER (from, 0);
 188:   CHECK_NUMBER (count, 1);
 189:   CHECK_NUMBER (c, 2);
 190: 
 191:   return make_number (ScanBf (XINT (c), XINT (from), XINT (count)));
 192: }
 193: 
 194: ScanBf (target, pos, cnt)
 195:      register int target, pos, cnt;
 196: {
 197:   register int end;
 198:   if (cnt > 0)
 199:     {
 200:       end = NumCharacters + 1;
 201:       while (pos < end)
 202:     {
 203:       if (CharAt (pos) == target && !--cnt)
 204:         return pos + 1;
 205:       pos++;
 206:     }
 207:       return pos;
 208:     }
 209:   if (cnt < 0)
 210:     {
 211:       end = FirstCharacter;
 212:       do pos--;
 213:       while (pos >= end &&
 214:          (CharAt (pos) != target || ++cnt));
 215:     }
 216:   return pos + 1;
 217: }
 218: 
 219: DEFUN ("skip-chars-forward", Fskip_chars_forward, Sskip_chars_forward, 1, 2, 0,
 220:   "Move point forward, stopping before a char not in CHARS, or at position LIM.\n\
 221: CHARS is like the inside of a [...] in a regular expression\n\
 222: except that ] is never special and \\ quotes ^, - or \\.\n\
 223: Thus, with arg \"a-zA-Z\", this skips letters stopping before first nonletter.\n\
 224: With arg \"^a-zA-Z\", skips nonletters stopping before first letter.")
 225:   (string, lim)
 226:      Lisp_Object string, lim;
 227: {
 228:   skip_chars (1, string, lim);
 229:   return Qnil;
 230: }
 231: 
 232: DEFUN ("skip-chars-backward", Fskip_chars_backward, Sskip_chars_backward, 1, 2, 0,
 233:   "Move point backward, stopping after a char not in CHARS, or at position LIM.\n\
 234: See skip-chars-forward for details.")
 235:   (string, lim)
 236:      Lisp_Object string, lim;
 237: {
 238:   skip_chars (0, string, lim);
 239:   return Qnil;
 240: }
 241: 
 242: skip_chars (forwardp, string, lim)
 243:      int forwardp;
 244:      Lisp_Object string, lim;
 245: {
 246:   register unsigned char *p, *pend;
 247:   register unsigned char c;
 248:   unsigned char fastmap[0400];
 249:   int negate = 0;
 250:   register int i;
 251: 
 252:   CHECK_STRING (string, 0);
 253: 
 254:   if (NULL (lim))
 255:     XSETINT (lim, forwardp ? NumCharacters + 1 : FirstCharacter);
 256:   else
 257:     CHECK_NUMBER_COERCE_MARKER (lim, 1);
 258: 
 259:   p = XSTRING (string)->data;
 260:   pend = p + XSTRING (string)->size;
 261:   bzero (fastmap, sizeof fastmap);
 262: 
 263:   if (p != pend && *p == '^')
 264:     {
 265:       negate = 1; p++;
 266:     }
 267: 
 268:   /* Find the characters specified and set their elements of fastmap.  */
 269: 
 270:   while (p != pend)
 271:     {
 272:       c = *p++;
 273:       if (*p == '\\')
 274:         {
 275:       if (p == pend) break;
 276:       c = *p++;
 277:     }
 278:       if (p != pend && *p == '-')
 279:     {
 280:       p++;
 281:       if (p == pend) break;
 282:       while (c <= *p)
 283:         {
 284:           fastmap[c] = 1;
 285:           c++;
 286:         }
 287:       p++;
 288:     }
 289:       else
 290:     fastmap[c] = 1;
 291:     }
 292: 
 293:   /* If ^ was the first character, complement the fastmap. */
 294: 
 295:   if (negate)
 296:     for (i = 0; i < sizeof fastmap; i++)
 297:       fastmap[i] ^= 1;
 298: 
 299:   if (forwardp)
 300:     {
 301:       while (point < XINT (lim) && fastmap[CharAt (point)])
 302:     PointRight (1);
 303:     }
 304:   else
 305:     {
 306:       while (point > XINT (lim) && fastmap[CharAt (point - 1)])
 307:     PointLeft (1);
 308:     }
 309: }
 310: 
 311: /* Subroutines of Lisp buffer search functions. */
 312: 
 313: static Lisp_Object
 314: search_command (string, bound, noerror, count, direction, RE)
 315:      Lisp_Object string, bound, noerror, count;
 316:      int direction;
 317:      int RE;
 318: {
 319:   register int np;
 320:   int lim;
 321:   int n = direction;
 322: 
 323:   if (!NULL (count))
 324:     {
 325:       CHECK_NUMBER (count, 3);
 326:       n *= XINT (count);
 327:     }
 328: 
 329:   CHECK_STRING (string, 0);
 330:   if (NULL (bound))
 331:     lim = n > 0 ? NumCharacters + 1 : FirstCharacter;
 332:   else
 333:     {
 334:       CHECK_NUMBER_COERCE_MARKER (bound, 1);
 335:       lim = XINT (bound);
 336:       if (n > 0 ? lim < point : lim > point)
 337:     error ("Invalid search bound (wrong side of point)");
 338:       if (lim > NumCharacters + 1)
 339:     lim = NumCharacters + 1;
 340:       if (lim < FirstCharacter)
 341:     lim = FirstCharacter;
 342:     }
 343: 
 344:   np = search_buffer (string, point, lim, n, RE,
 345:               !NULL (bf_cur->case_fold_search) ? downcase_table : 0);
 346:   if (np == 0)
 347:     {
 348:       if (NULL (noerror))
 349:     return signal_failure (string);
 350:       if (!EQ (noerror, Qt))
 351:     SetPoint (lim);
 352:       return Qnil;
 353:     }
 354:   else
 355:     SetPoint (np);
 356: 
 357:   return Qt;
 358: }
 359: 
 360: /* search for the n'th occurrence of `string' in the current buffer,
 361:    starting at position `from' and stopping at position `lim',
 362:    treating `pat' as a literal string if `RE' is false or as
 363:    a regular expression if `RE' is true.
 364: 
 365:    If `n' is positive, searching is forward and `lim' must be greater than `from'.
 366:    If `n' is negative, searching is backward and `lim' must be less than `from'.
 367: 
 368:    Returns 0 if `n' occurrences are not found,
 369:    or else the position at the beginning of the `n'th occurrence (if searching backward)
 370:    or the end (if searching forward).  */
 371: 
 372: search_buffer (string, from, lim, n, RE, trt)
 373:      Lisp_Object string;
 374:      int from;
 375:      register int lim;
 376:      int n;
 377:      int RE;
 378:      unsigned char *trt;
 379: {
 380:   register int pos = from;
 381:   unsigned char *pat = XSTRING (string)->data;
 382:   register int len = XSTRING (string)->size;
 383:   register int i, j;
 384:   unsigned char *p1, *p2;
 385:   int s1, s2;
 386: 
 387:   immediate_quit = 1;   /* Quit immediately if user types ^G,
 388: 			   because letting this function finish can take too long. */
 389:   QUIT;         /* Do a pending quit right away, to avoid paradoxical behavior */
 390: 
 391:   if (RE)
 392:     {
 393:       compile_pattern (string, &searchbuf, (char *) trt);
 394: 
 395:       /* Get pointers and sizes of the two strings
 396: 	 that make up the visible portion of the buffer. */
 397: 
 398:       p1 = bf_p1 + bf_head_clip;
 399:       s1 = bf_s1 - (bf_head_clip - 1);
 400:       p2 = bf_p2 + bf_s1 + 1;
 401:       s2 = bf_s2 - bf_tail_clip;
 402:       if (s1 < 0)
 403:     {
 404:       p2 -= s1;
 405:       s2 += s1;
 406:       s1 = 0;
 407:     }
 408:       if (s2 < 0)
 409:     {
 410:       s1 += s2;
 411:       s2 = 0;
 412:     }
 413:     }
 414: 
 415:   while (n < 0)
 416:     {
 417:       if (!RE)
 418:     {
 419:           pos -= len;
 420:       if (trt && !(trt == downcase_table && !isalpha (pat[0])))
 421:         {
 422:           j = trt[pat[0]];
 423:           while (pos >= lim
 424:              && (j != trt[CharAt (pos)]
 425:              || bcmp_buffer_translated (pat, len, pos, trt)))
 426:         pos--;
 427:         }
 428:       else
 429:         {
 430:           j = pat[0];
 431:           while (pos >= lim
 432:              && (j != CharAt (pos)
 433:              || bcmp_buffer_translated (pat, len, pos, trt)))
 434:         pos--;
 435:         }
 436: 
 437:       if (pos < lim)
 438:         {
 439:           immediate_quit = 0;
 440:           return 0;
 441:         }
 442:       search_regs.start[0] = pos - 1;
 443:       search_regs.end[0] = pos - 1 + len;
 444:     }
 445:       else
 446:     {
 447:       if (re_search_2 (&searchbuf, p1, s1, p2, s2,
 448:                pos - FirstCharacter, lim - pos, &search_regs,
 449:                /* Don't allow match past current point */
 450:                pos - FirstCharacter)
 451:           >= 0)
 452:         {
 453:           j = FirstCharacter - 1;
 454:           for (i = 0; i < RE_NREGS; i++)
 455:         {
 456:           search_regs.start[i] += j;
 457:           search_regs.end[i] += j;
 458:         }
 459:           /* Set pos to the new position. */
 460:           pos = search_regs.start[0] + 1;
 461:         }
 462:       else
 463:         {
 464:           immediate_quit = 0;
 465:           return 0;
 466:         }
 467:     }
 468:       n++;
 469:     }
 470: 
 471:   while (n > 0)
 472:     {
 473:       if (!RE)
 474:     {
 475:       lim -= len;
 476:       if (trt && !(trt == downcase_table && !isalpha (pat[0])))
 477:         {
 478:           j = trt[pat[0]];
 479:           while (pos <= lim
 480:              && (j != trt[CharAt (pos)]
 481:              || bcmp_buffer_translated (pat, len, pos, trt)))
 482:         pos++;
 483:         }
 484:       else
 485:         {
 486:           j = pat[0];
 487:           while (pos <= lim
 488:              && (j != CharAt (pos)
 489:              || bcmp_buffer_translated (pat, len, pos, trt)))
 490:         pos++;
 491:         }
 492: 
 493:       if (pos > lim)
 494:         {
 495:           immediate_quit = 0;
 496:           return 0;
 497:         }
 498: 
 499:       lim += len;
 500: 
 501:       search_regs.start[0] = pos - 1;
 502:       pos += len;
 503:       search_regs.end[0] = pos - 1;
 504:     }
 505:       else
 506:     {
 507:       if (re_search_2 (&searchbuf, p1, s1, p2, s2,
 508:                pos - FirstCharacter, lim - pos, &search_regs,
 509:                lim - FirstCharacter)
 510:           >= 0)
 511:         {
 512:           j = FirstCharacter - 1;
 513:           for (i = 0; i < RE_NREGS; i++)
 514:         {
 515:           search_regs.start[i] += j;
 516:           search_regs.end[i] += j;
 517:         }
 518:           pos = 1 + search_regs.end[0];
 519:         }
 520:       else
 521:         {
 522:           immediate_quit = 0;
 523:           return 0;
 524:         }
 525:     }
 526:       n--;
 527:     }
 528:   immediate_quit = 0;
 529:   return pos;
 530: }
 531: 
 532: /* Return nonzero unless the `len' characters in the buffer starting at position `pos'
 533:   match the `len' characters at `pat', with all characters going through the
 534:   translate table `trt' if `trt' is nonzero.  */
 535: 
 536: static int
 537: bcmp_buffer_translated (pat, len, pos, trt)
 538:      unsigned char *pat;
 539:      int len;
 540:      int pos;
 541:      register char *trt;
 542: {
 543:   int dist1 = 0;
 544:   register int i;
 545:   register unsigned char *p1, *p2;
 546: 
 547:   if (pos - 1 < bf_s1)
 548:     {
 549:       p1 = pat, p2 = &CharAt (pos);
 550:       dist1 = bf_s1 - (pos - 1);
 551:       if (dist1 > len) dist1 = len;
 552:       i = dist1;
 553: 
 554:       if (trt)
 555:     {
 556:       for (; i; i--)
 557:         if (trt[*p1++] != trt [*p2++]) return 1;
 558:     }
 559:       else
 560:     {
 561:       for (; i; i--)
 562:         if (*p1++ != *p2++) return 1;
 563:     }
 564:     }
 565: 
 566:   if (dist1 < len)
 567:     {
 568:       p1 = pat + dist1, p2 = &CharAt (pos + dist1);
 569:       i = len - dist1;
 570: 
 571:       if (trt)
 572:     {
 573:       for (; i; i--)
 574:         if (trt[*p1++] != trt [*p2++]) return 1;
 575:     }
 576:       else
 577:     {
 578:       for (; i; i--)
 579:         if (*p1++ != *p2++) return 1;
 580:     }
 581:     }
 582:   return 0;
 583: }
 584: 
 585: /* Given a string of words separated by word delimiters,
 586:   compute a regexp that matches those exact words
 587:   separated by arbitrary punctuation.  */
 588: 
 589: static Lisp_Object
 590: wordify (string)
 591:      Lisp_Object string;
 592: {
 593:   register unsigned char *p, *o;
 594:   register int i, len, punct_count = 0, word_count = 0;
 595:   Lisp_Object val;
 596: 
 597:   CHECK_STRING (string, 0);
 598:   p = XSTRING (string)->data;
 599:   len = XSTRING (string)->size;
 600: 
 601:   for (i = 0; i < len; i++)
 602:     if (SYNTAX (p[i]) != Sword)
 603:       {
 604:     punct_count++;
 605:     if (i > 0 && SYNTAX (p[i-1]) == Sword) word_count++;
 606:       }
 607:   if (SYNTAX (p[len-1]) == Sword) word_count++;
 608:   if (!word_count) return build_string ("");
 609: 
 610:   val = make_string (p, len - punct_count + 5 * (word_count - 1) + 4);
 611: 
 612:   o = XSTRING (val)->data;
 613:   *o++ = '\\';
 614:   *o++ = 'b';
 615: 
 616:   for (i = 0; i < len; i++)
 617:     if (SYNTAX (p[i]) == Sword)
 618:       *o++ = p[i];
 619:     else if (i > 0 && SYNTAX (p[i-1]) == Sword && --word_count)
 620:       {
 621:     *o++ = '\\';
 622:     *o++ = 'W';
 623:     *o++ = '\\';
 624:     *o++ = 'W';
 625:     *o++ = '*';
 626:       }
 627: 
 628:   *o++ = '\\';
 629:   *o++ = 'b';
 630: 
 631:   return val;
 632: }
 633: 
 634: DEFUN ("search-backward", Fsearch_backward, Ssearch_backward, 1, 4,
 635:   "sSearch backward: ",
 636:   "Search backward from point for STRING.\n\
 637: Set point to the beginning of the occurrence found, and return t.\n\
 638: An optional second argument bounds the search; it is a buffer position.\n\
 639: The match found must not extend before that position.\n\
 640: Optional third argument, if t, means if fail just return nil (no error).\n\
 641:  If not nil and not t, position at limit of search and return nil.\n\
 642: Optional fourth argument is repeat count--search for successive occurrences.")
 643:   (string, bound, noerror, count)
 644:      Lisp_Object string, bound, noerror, count;
 645: {
 646:   return search_command (string, bound, noerror, count, -1, 0);
 647: }
 648: 
 649: DEFUN ("search-forward", Fsearch_forward, Ssearch_forward, 1, 4, "sSearch: ",
 650:   "Search forward from point for STRING.\n\
 651: Set point to the end of the occurrence found, and return t.\n\
 652: An optional second argument bounds the search; it is a buffer position.\n\
 653: The match found must not extend after that position.\n\
 654: Optional third argument, if t, means if fail just return nil (no error).\n\
 655:   If not nil and not t, move to limit of search and return nil.\n\
 656: Optional fourth argument is repeat count--search for successive occurrences.")
 657:   (string, bound, noerror, count)
 658:      Lisp_Object string, bound, noerror, count;
 659: {
 660:   return search_command (string, bound, noerror, count, 1, 0);
 661: }
 662: 
 663: DEFUN ("word-search-backward", Fword_search_backward, Sword_search_backward, 1, 4,
 664:   "sWord search backward: ",
 665:   "Search backward from point for STRING, ignoring differences in punctuation.\n\
 666: Set point to the beginning of the occurrence found, and return t.\n\
 667: An optional second argument bounds the search; it is a buffer position.\n\
 668: The match found must not extend before that position.\n\
 669: Optional third argument, if t, means if fail just return nil (no error).\n\
 670:   If not nil and not t, move to limit of search and return nil.\n\
 671: Optional fourth argument is repeat count--search for successive occurrences.")
 672:   (string, bound, noerror, count)
 673:      Lisp_Object string, bound, noerror, count;
 674: {
 675:   return search_command (wordify (string), bound, noerror, count, -1, 1);
 676: }
 677: 
 678: DEFUN ("word-search-forward", Fword_search_forward, Sword_search_forward, 1, 4,
 679:   "sWord search: ",
 680:   "Search forward from point for STRING, ignoring differences in punctuation.\n\
 681: Set point to the end of the occurrence found, and return t.\n\
 682: An optional second argument bounds the search; it is a buffer position.\n\
 683: The match found must not extend after that position.\n\
 684: Optional third argument, if t, means if fail just return nil (no error).\n\
 685:   If not nil and not t, move to limit of search and return nil.\n\
 686: Optional fourth argument is repeat count--search for successive occurrences.")
 687:   (string, bound, noerror, count)
 688:      Lisp_Object string, bound, noerror, count;
 689: {
 690:   return search_command (wordify (string), bound, noerror, count, 1, 1);
 691: }
 692: 
 693: DEFUN ("re-search-backward", Fre_search_backward, Sre_search_backward, 1, 4,
 694:   "sRE search backward: ",
 695:   "Search backward from point for regular expression REGEXP.\n\
 696: Set point to the beginning of the occurrence found, and return t.\n\
 697: An optional second argument bounds the search; it is a buffer position.\n\
 698: The match found must not extend before that position.\n\
 699: Optional third argument, if t, means if fail just return nil (no error).\n\
 700:   If not nil and not t, move to limit of search and return nil.\n\
 701: Optional fourth argument is repeat count--search for successive occurrences.\n\
 702: See also the functions match-beginning and match-end and replace-match.")
 703:   (string, bound, noerror, count)
 704:      Lisp_Object string, bound, noerror, count;
 705: {
 706:   return search_command (string, bound, noerror, count, -1, 1);
 707: }
 708: 
 709: DEFUN ("re-search-forward", Fre_search_forward, Sre_search_forward, 1, 4,
 710:   "sRE search: ",
 711:   "Search forward from point for regular expression REGEXP.\n\
 712: Set point to the end of the occurrence found, and return t.\n\
 713: An optional second argument bounds the search; it is a buffer position.\n\
 714: The match found must not extend after that position.\n\
 715: Optional third argument, if t, means if fail just return nil (no error).\n\
 716:   If not nil and not t, move to limit of search and return nil.\n\
 717: Optional fourth argument is repeat count--search for successive occurrences.\n\
 718: See also the functions match-beginning and match-end and replace-match.")
 719:   (string, bound, noerror, count)
 720:      Lisp_Object string, bound, noerror, count;
 721: {
 722:   return search_command (string, bound, noerror, count, 1, 1);
 723: }
 724: 
 725: DEFUN ("replace-match", Freplace_match, Sreplace_match, 1, 3, 0,
 726:   "Replace text matched by last search with NEWTEXT.\n\
 727: If second arg FIXEDCASE is non-nil, do not alter case of replacement text.\n\
 728: Otherwise convert to all caps or cap initials, like replaced text.\n\
 729: If third arg LITERAL is non-nil, insert NEWTEXT literally.\n\
 730: Otherwise treat \\ as special:\n\
 731:   \\& in NEWTEXT means substitute original matched text,\n\
 732:   \\<n> means substitute match for \\(...\\) number <n>,\n\
 733:   \\\\ means insert one \\.\n\
 734: Leaves point at end of replacement text.")
 735:   (string, fixedcase, literal)
 736:      Lisp_Object string, fixedcase, literal;
 737: {
 738:   enum { nochange, all_caps, cap_initial } case_action = nochange;
 739:   register int pos, last;
 740:   int some_multiletter_word = 0;
 741:   int some_letter = 0;
 742:   register char c, prevc;
 743:   int inslen;
 744: 
 745:   if (search_regs.start[0] + 1 < FirstCharacter
 746:       || search_regs.start[0] > search_regs.end[0]
 747:       || search_regs.end[0] > NumCharacters)
 748:     args_out_of_range(make_number (search_regs.start[0]),
 749:               make_number (search_regs.end[0]));
 750: 
 751:   if (NULL (fixedcase))
 752:     {
 753:       /* Decide how to casify by examining the matched text. */
 754: 
 755:       last = search_regs.end[0];
 756:       prevc = '\n';
 757:       case_action = all_caps;
 758: 
 759:       /* some_multiletter_word is set nonzero if any original word
 760: 	 is more than one letter long. */
 761:       some_multiletter_word = 0;
 762: 
 763:       for (pos = search_regs.start[0] + 1; pos <= last; pos++)
 764:     {
 765:       c = CharAt (pos);
 766:       if (c >= 'a' && c <= 'z')
 767:         {
 768:           /* Cannot be all caps if any original char is lower case */
 769: 
 770:           case_action = cap_initial;
 771:           if (SYNTAX (prevc) != Sword)
 772:         {
 773:           /* Cannot even be cap initials
 774: 		     if some original initial is lower case */
 775:           case_action = nochange;
 776:           break;
 777:         }
 778:           else
 779:         some_multiletter_word = 1;
 780:         }
 781:       else if (c >= 'A' && c <= 'Z')
 782:         {
 783:           some_letter = 1;
 784:           if (!some_multiletter_word && SYNTAX (prevc) == Sword)
 785:         some_multiletter_word = 1;
 786:         }
 787: 
 788:       prevc = c;
 789:     }
 790: 
 791:       /* Do not make new text all caps
 792: 	 if the original text contained only single letter words. */
 793:       if (case_action == all_caps && !some_multiletter_word)
 794:     case_action = cap_initial;
 795: 
 796:       if (!some_letter) case_action = nochange;
 797:     }
 798: 
 799:   SetPoint (search_regs.end[0] + 1);
 800:   if (!NULL (literal))
 801:     Finsert (1, &string);
 802:   else
 803:     {
 804:       for (pos = 0; pos < XSTRING (string)->size; pos++)
 805:     {
 806:       c = XSTRING (string)->data[pos];
 807:       if (c == '\\')
 808:         {
 809:           c = XSTRING (string)->data[++pos];
 810:           if (c == '&')
 811:         place (search_regs.start[0] + 1,
 812:                search_regs.end[0] + 1);
 813:           else if (c >= '1' && c <= RE_NREGS + '0')
 814:         place (search_regs.start[c - '0'] + 1,
 815:                search_regs.end[c - '0'] + 1);
 816:           else
 817:         insert_char (c);
 818:         }
 819:       else
 820:         insert_char (c);
 821:     }
 822:     }
 823: 
 824:   inslen = point - (search_regs.end[0] + 1);
 825:   del_range (search_regs.start[0] + 1, search_regs.end[0] + 1);
 826: 
 827:   if (case_action == all_caps)
 828:     Fupcase_region (make_number (point - inslen), make_number (point));
 829:   else if (case_action == cap_initial)
 830:     {  /* Fcapitalize_region won't do; must not downcase anything.  */
 831:       last = 0;
 832:       for (pos = point - inslen; pos < point; pos++)
 833:     {
 834:       c = CharAt (pos);
 835:       if (!last && (c >= 'a' && c <= 'z'))
 836:         CharAt (pos) = c ^ ('a' - 'A');
 837:       last = SYNTAX (c) == Sword;
 838:     }
 839:     }
 840:   return Qnil;
 841: }
 842: 
 843: static
 844: place (l1, l2)
 845:      int l1, l2;
 846: {
 847:   if (l1 < FirstCharacter)
 848:     l1 = FirstCharacter;
 849:   if (l1 >= NumCharacters)
 850:     l1 = NumCharacters;
 851:   if (l2 < l1) l2 = l1;
 852:   if (l2 >= NumCharacters)
 853:     l2 = NumCharacters;
 854:   GapTo (point);
 855:   InsCStr (&CharAt (l1), l2 - l1);
 856: }
 857: 
 858: DEFUN ("match-beginning", Fmatch_beginning, Smatch_beginning, 1, 1, 0,
 859:   "Return the character number of start of text matched by last regexp searched for.\n\
 860: ARG, a number, specifies which parenthesized expression in the last regexp.\n\
 861: Zero means the entire text matched by the whole regexp.")
 862:   (num)
 863:      Lisp_Object num;
 864: {
 865:   register    n;
 866:   CHECK_NUMBER (num, 0);
 867:   n = XINT (num);
 868:   if (n < 0 || n >= RE_NREGS)
 869:     error ("Out-of-bounds argument");
 870:   return make_number (search_regs.start[n] + 1);
 871: }
 872: 
 873: DEFUN ("match-end", Fmatch_end, Smatch_end, 1, 1, 0,
 874:   "Return the character number of end of text matched by last regexp searched for.\n\
 875: ARG, a number, specifies which parenthesized expression in the last regexp.\n\
 876: Zero means the entire text matched by the whole regexp.")
 877:   (num)
 878:      Lisp_Object num;
 879: {
 880:   register    n;
 881:   CHECK_NUMBER (num, 0);
 882:   n = XINT (num);
 883:   if (n < 0 || n >= RE_NREGS)
 884:     error ("Out-of-bounds argument");
 885:   return make_number (search_regs.end[n] + 1);
 886: }
 887: 
 888: DEFUN ("match-data", Fmatch_data, Smatch_data, 0, 0, 0,
 889:   "Return list containing all info on what the last search matched.\n\
 890: Element 2N is (match-beginning N); element 2N + 1 is (match-end N).\n\
 891: All are represented as markers.")
 892:   ()
 893: {
 894:   Lisp_Object data[2 * RE_NREGS];
 895:   int i;
 896: 
 897:   for (i = 0; i < RE_NREGS; i++)
 898:     {
 899:       data[2 * i] = Fmake_marker ();
 900:       Fset_marker (data[2*i], make_number (search_regs.start[i] + 1), Qnil);
 901:       data[2 * i + 1] = Fmake_marker ();
 902:       Fset_marker (data[2*i + 1], make_number (search_regs.end[i] + 1), Qnil);
 903:     }
 904: 
 905:   return Flist (2 * RE_NREGS, data);
 906: }
 907: 
 908: 
 909: DEFUN ("store-match-data", Fstore_match_data, Sstore_match_data, 1, 1, 0,
 910:   "Set internal data on last search match from elements of LIST.\n\
 911: LIST should have been created by calling match-data previously.")
 912:   (list)
 913:      register Lisp_Object list;
 914: {
 915:   register int i;
 916:   register Lisp_Object marker;
 917: 
 918:   if (!LISTP (list))
 919:     list = wrong_type_argument (Qlistp, list, 0);
 920: 
 921:   for (i = 0; i < RE_NREGS; i++)
 922:     {
 923:       marker = Fcar (list);
 924:       CHECK_MARKER (marker, 0);
 925:       search_regs.start[i] = marker_position (marker) - 1;
 926:       list = Fcdr (list);
 927: 
 928:       marker = Fcar (list);
 929:       CHECK_MARKER (marker, 0);
 930:       search_regs.end[i] = marker_position (marker) - 1;
 931:       list = Fcdr (list);
 932:     }
 933: 
 934:   return Qnil;
 935: }
 936: 
 937: /* Quote a string to inactivate reg-expr chars */
 938: 
 939: DEFUN ("regexp-quote", Fregexp_quote, Sregexp_quote, 1, 1, 0,
 940:   "Return a regexp string which matches exactly STRING and nothing else.")
 941:   (str)
 942:      Lisp_Object str;
 943: {
 944:   register unsigned char *p, *cp, *end;
 945:   register int size;
 946:   Lisp_Object ostr;
 947: 
 948:   CHECK_STRING (str, 0);
 949:   size = XSTRING (str)->size;
 950: 
 951:   /* Increment `size' for the escapes we will need to insert */
 952: 
 953:   for (cp = XSTRING (str)->data, end = cp + size; cp != end; cp++)
 954:     if (*cp == '[' || *cp == ']'
 955:     || *cp == '*' || *cp == '.' || *cp == '\\'
 956:     || *cp == '?' || *cp == '+'
 957:     || *cp == '^' || *cp == '$')
 958:       size++;
 959: 
 960:   ostr = Fmake_string (make_number (size), make_number (0));
 961: 
 962:   /* Now copy the data into the new string, inserting escapes. */
 963: 
 964:   p = XSTRING (ostr)->data;
 965:   for (cp = XSTRING (str)->data; cp != end; cp++)
 966:     {
 967:       if (*cp == '[' || *cp == ']'
 968:       || *cp == '*' || *cp == '.' || *cp == '\\'
 969:       || *cp == '?' || *cp == '+'
 970:       || *cp == '^' || *cp == '$')
 971:     *p++ = '\\';
 972:       *p++ = *cp;
 973:     }
 974:   return ostr;
 975: }
 976: 
 977: syms_of_search ()
 978: {
 979:   register int i;
 980: 
 981:   for (i = 0; i < 0400; i++)
 982:     downcase_table[i] = (i >= 'A' && i <= 'Z') ? i + 040 : i;
 983: 
 984:   searchbuf.allocated = 100;
 985:   searchbuf.buffer = (char *) malloc (searchbuf.allocated);
 986:   searchbuf.fastmap = search_fastmap;
 987: 
 988:   Qsearch_failed = intern ("search-failed");
 989:   staticpro (&Qsearch_failed);
 990:   Qinvalid_regexp = intern ("invalid-regexp");
 991:   staticpro (&Qinvalid_regexp);
 992: 
 993:   Fput (Qsearch_failed, Qerror_conditions,
 994:     Fcons (Qsearch_failed, Fcons (Qerror, Qnil)));
 995:   Fput (Qsearch_failed, Qerror_message,
 996:     build_string ("Search failed"));
 997: 
 998:   Fput (Qinvalid_regexp, Qerror_conditions,
 999:     Fcons (Qinvalid_regexp, Fcons (Qerror, Qnil)));
1000:   Fput (Qinvalid_regexp, Qerror_message,
1001:     build_string ("Invalid regexp"));
1002: 
1003:   last_regexp = Qnil;
1004:   staticpro (&last_regexp);
1005: 
1006:   defsubr (&Sstring_match);
1007:   defsubr (&Slooking_at);
1008:   defsubr (&Sscan_buffer);
1009:   defsubr (&Sskip_chars_forward);
1010:   defsubr (&Sskip_chars_backward);
1011:   defsubr (&Ssearch_forward);
1012:   defsubr (&Ssearch_backward);
1013:   defsubr (&Sword_search_forward);
1014:   defsubr (&Sword_search_backward);
1015:   defsubr (&Sre_search_forward);
1016:   defsubr (&Sre_search_backward);
1017:   defsubr (&Sreplace_match);
1018:   defsubr (&Smatch_beginning);
1019:   defsubr (&Smatch_end);
1020:   defsubr (&Smatch_data);
1021:   defsubr (&Sstore_match_data);
1022:   defsubr (&Sregexp_quote);
1023: }

Defined functions

DEFUN defined in line 939; never used
ScanBf defined in line 194; used 10 times
bcmp_buffer_translated defined in line 536; used 4 times
compile_pattern defined in line 54; used 3 times
place defined in line 843; used 2 times
search_buffer defined in line 372; used 1 times
search_command defined in line 313; used 6 times
signal_failure defined in line 83; used 1 times
skip_chars defined in line 242; used 2 times
syms_of_search defined in line 977; used 1 times
wordify defined in line 589; used 2 times

Defined variables

Qinvalid_regexp defined in line 50; used 6 times
Qsearch_failed defined in line 81; used 6 times
downcase_table defined in line 30; used 6 times
last_regexp defined in line 40; used 5 times
search_fastmap defined in line 36; used 1 times
search_regs defined in line 46; used 40 times
searchbuf defined in line 34; used 11 times
Last modified: 1985-12-08
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2315
Valid CSS Valid XHTML 1.0 Strict