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

unix.superglobalmegacorp.com

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