Home | History | Annotate | Line # | Download | only in lisp
      1 /*
      2  * Copyright (c) 2002 by The XFree86 Project, Inc.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice shall be included in
     12  * all copies or substantial portions of the Software.
     13  *
     14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17  * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     18  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
     19  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     20  * SOFTWARE.
     21  *
     22  * Except as contained in this notice, the name of the XFree86 Project shall
     23  * not be used in advertising or otherwise to promote the sale, use or other
     24  * dealings in this Software without prior written authorization from the
     25  * XFree86 Project.
     26  *
     27  * Author: Paulo Csar Pereira de Andrade
     28  */
     29 
     30 /* $XFree86: xc/programs/xedit/lisp/regex.c,v 1.10tsi Exp $ */
     31 
     32 #include "lisp/regex.h"
     33 #include "lisp/private.h"
     34 #include "lisp/helper.h"
     35 
     36 /*
     37  * Prototypes
     38  */
     39 static re_cod *LispRecomp(LispBuiltin*, char*, int);
     40 
     41 /*
     42  * Initialization
     43  */
     44 LispObj *Knomatch;
     45 
     46 /*
     47  * Implementation
     48  */
     49 static re_cod *
     50 LispRecomp(LispBuiltin *builtin, char *pattern, int cflags)
     51 {
     52     int code;
     53     re_cod *regex = LispMalloc(sizeof(re_cod));
     54 
     55     if ((code = recomp(regex, pattern, cflags)) != 0) {
     56 	char buffer[256];
     57 
     58 	reerror(code, regex, buffer, sizeof(buffer));
     59 	refree(regex);
     60 	LispFree(regex);
     61 	LispDestroy("%s: recomp(\"%s\"): %s", STRFUN(builtin), pattern, buffer);
     62     }
     63 
     64     return (regex);
     65 }
     66 
     67 void
     68 LispRegexInit(void)
     69 {
     70     Knomatch = KEYWORD("NOMATCH");
     71 }
     72 
     73 LispObj *
     74 Lisp_Recomp(LispBuiltin *builtin)
     75 /*
     76  re-comp pattern &key nospec icase nosub newline
     77  */
     78 {
     79     re_cod *regex;
     80     int cflags = 0;
     81 
     82     LispObj *result;
     83 
     84     LispObj *pattern, *nospec, *icase, *nosub, *newline;
     85 
     86     newline = ARGUMENT(4);
     87     nosub = ARGUMENT(3);
     88     icase = ARGUMENT(2);
     89     nospec = ARGUMENT(1);
     90     pattern = ARGUMENT(0);
     91 
     92     /* Don't generate an error if it is already a compiled regex. */
     93     if (REGEXP(pattern))
     94 	return (pattern);
     95 
     96     CHECK_STRING(pattern);
     97 
     98     if (nospec != UNSPEC && nospec != NIL)
     99 	cflags |= RE_NOSPEC;
    100     if (icase != UNSPEC && icase != NIL)
    101 	cflags |= RE_ICASE;
    102     if (nosub != UNSPEC && nosub != NIL)
    103 	cflags |= RE_NOSUB;
    104     if (newline != UNSPEC && newline != NIL)
    105 	cflags |= RE_NEWLINE;
    106 
    107     regex = LispRecomp(builtin, THESTR(pattern), cflags);
    108     result = LispNew(pattern, NIL);
    109     result->type = LispRegex_t;
    110     result->data.regex.regex = regex;
    111     result->data.regex.pattern = pattern;
    112     result->data.regex.options = cflags;
    113     LispMused(regex);
    114 
    115     return (result);
    116 }
    117 
    118 LispObj *
    119 Lisp_Reexec(LispBuiltin *builtin)
    120 /*
    121  re-exec regex string &key count start end notbol noteol
    122  */
    123 {
    124     size_t nmatch;
    125     re_mat match[10];
    126     long start, end, length;
    127     int code, cflags, eflags;
    128     char *string;
    129     LispObj *result;
    130     re_cod *regexp;
    131 
    132     LispObj *regex, *ostring, *count, *ostart, *oend, *notbol, *noteol;
    133 
    134     noteol = ARGUMENT(6);
    135     notbol = ARGUMENT(5);
    136     oend = ARGUMENT(4);
    137     ostart = ARGUMENT(3);
    138     count = ARGUMENT(2);
    139     ostring = ARGUMENT(1);
    140     regex = ARGUMENT(0);
    141 
    142     if (STRINGP(regex))
    143 	regexp = LispRecomp(builtin, THESTR(regex), cflags = 0);
    144     else {
    145 	CHECK_REGEX(regex);
    146 	regexp = regex->data.regex.regex;
    147 	cflags = regex->data.regex.options;
    148     }
    149 
    150     CHECK_STRING(ostring);
    151 
    152     if (count == UNSPEC)
    153 	nmatch = 1;
    154     else {
    155 	CHECK_INDEX(count);
    156 	nmatch = FIXNUM_VALUE(count);
    157 	if (nmatch > 10)
    158 	    LispDestroy("%s: COUNT cannot be larger than 10", STRFUN(builtin));
    159     }
    160     if (nmatch && (cflags & RE_NOSUB))
    161 	nmatch = 1;
    162 
    163     eflags = RE_STARTEND;
    164     if (notbol != UNSPEC && notbol != NIL)
    165 	eflags |= RE_NOTBOL;
    166     if (noteol != UNSPEC && noteol != NIL)
    167 	eflags |= RE_NOTEOL;
    168 
    169     string = THESTR(ostring);
    170     LispCheckSequenceStartEnd(builtin, ostring, ostart, oend,
    171 			      &start, &end, &length);
    172 
    173     match[0].rm_so = start;
    174     match[0].rm_eo = end;
    175     code = reexec(regexp, string, nmatch, &match[0], eflags);
    176 
    177     if (code == 0) {
    178 	if (nmatch && match[0].rm_eo >= match[0].rm_so) {
    179 	    result = CONS(CONS(FIXNUM(match[0].rm_so),
    180 			       FIXNUM(match[0].rm_eo)), NIL);
    181 	    if (nmatch > 1 && match[1].rm_eo >= match[1].rm_so) {
    182 		int i;
    183 		GC_ENTER();
    184 		LispObj *cons = result;
    185 
    186 		GC_PROTECT(result);
    187 		for (i = 1;
    188 		     i < nmatch && match[i].rm_eo >= match[i].rm_so;
    189 		     i++) {
    190 		    RPLACD(cons, CONS(CONS(FIXNUM(match[i].rm_so),
    191 					   FIXNUM(match[i].rm_eo)), NIL));
    192 		    cons = CDR(cons);
    193 		}
    194 		GC_LEAVE();
    195 	    }
    196 	}
    197 	else
    198 	    result = NIL;
    199     }
    200     else
    201 	result = Knomatch;
    202 
    203     /* Maybe shoud cache compiled regex, but better the caller do it */
    204     if (!XREGEXP(regex)) {
    205 	refree(regexp);
    206 	LispFree(regexp);
    207     }
    208 
    209     return (result);
    210 }
    211 
    212 LispObj *
    213 Lisp_Rep(LispBuiltin *builtin)
    214 /*
    215  re-p object
    216  */
    217 {
    218     LispObj *object;
    219 
    220     object = ARGUMENT(0);
    221 
    222     return (REGEXP(object) ? T : NIL);
    223 }
    224