Annotation of 43BSD/contrib/emacs/src/search.c, revision 1.1

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

unix.superglobalmegacorp.com

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