Annotation of 43BSDReno/contrib/emacs-18.55/src/search.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.