15dfecf96Smrg/*
25dfecf96Smrg * Copyright (c) 2002 by The XFree86 Project, Inc.
35dfecf96Smrg *
45dfecf96Smrg * Permission is hereby granted, free of charge, to any person obtaining a
55dfecf96Smrg * copy of this software and associated documentation files (the "Software"),
65dfecf96Smrg * to deal in the Software without restriction, including without limitation
75dfecf96Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
85dfecf96Smrg * and/or sell copies of the Software, and to permit persons to whom the
95dfecf96Smrg * Software is furnished to do so, subject to the following conditions:
105dfecf96Smrg *
115dfecf96Smrg * The above copyright notice and this permission notice shall be included in
125dfecf96Smrg * all copies or substantial portions of the Software.
135dfecf96Smrg *
145dfecf96Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
155dfecf96Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
165dfecf96Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
175dfecf96Smrg * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
185dfecf96Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
195dfecf96Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
205dfecf96Smrg * SOFTWARE.
215dfecf96Smrg *
225dfecf96Smrg * Except as contained in this notice, the name of the XFree86 Project shall
235dfecf96Smrg * not be used in advertising or otherwise to promote the sale, use or other
245dfecf96Smrg * dealings in this Software without prior written authorization from the
255dfecf96Smrg * XFree86 Project.
265dfecf96Smrg *
275dfecf96Smrg * Author: Paulo César Pereira de Andrade
285dfecf96Smrg */
295dfecf96Smrg
305dfecf96Smrg/* $XFree86: xc/programs/xedit/lisp/regex.c,v 1.10tsi Exp $ */
315dfecf96Smrg
325dfecf96Smrg#include "lisp/regex.h"
335dfecf96Smrg#include "lisp/private.h"
345dfecf96Smrg#include "lisp/helper.h"
355dfecf96Smrg
365dfecf96Smrg/*
375dfecf96Smrg * Prototypes
385dfecf96Smrg */
395dfecf96Smrgstatic re_cod *LispRecomp(LispBuiltin*, char*, int);
405dfecf96Smrg
415dfecf96Smrg/*
425dfecf96Smrg * Initialization
435dfecf96Smrg */
445dfecf96SmrgLispObj *Knomatch;
455dfecf96Smrg
465dfecf96Smrg/*
475dfecf96Smrg * Implementation
485dfecf96Smrg */
495dfecf96Smrgstatic re_cod *
505dfecf96SmrgLispRecomp(LispBuiltin *builtin, char *pattern, int cflags)
515dfecf96Smrg{
525dfecf96Smrg    int code;
535dfecf96Smrg    re_cod *regex = LispMalloc(sizeof(re_cod));
545dfecf96Smrg
555dfecf96Smrg    if ((code = recomp(regex, pattern, cflags)) != 0) {
565dfecf96Smrg	char buffer[256];
575dfecf96Smrg
585dfecf96Smrg	reerror(code, regex, buffer, sizeof(buffer));
595dfecf96Smrg	refree(regex);
605dfecf96Smrg	LispFree(regex);
615dfecf96Smrg	LispDestroy("%s: recomp(\"%s\"): %s", STRFUN(builtin), pattern, buffer);
625dfecf96Smrg    }
635dfecf96Smrg
645dfecf96Smrg    return (regex);
655dfecf96Smrg}
665dfecf96Smrg
675dfecf96Smrgvoid
685dfecf96SmrgLispRegexInit(void)
695dfecf96Smrg{
705dfecf96Smrg    Knomatch = KEYWORD("NOMATCH");
715dfecf96Smrg}
725dfecf96Smrg
735dfecf96SmrgLispObj *
745dfecf96SmrgLisp_Recomp(LispBuiltin *builtin)
755dfecf96Smrg/*
765dfecf96Smrg re-comp pattern &key nospec icase nosub newline
775dfecf96Smrg */
785dfecf96Smrg{
795dfecf96Smrg    re_cod *regex;
805dfecf96Smrg    int cflags = 0;
815dfecf96Smrg
825dfecf96Smrg    LispObj *result;
835dfecf96Smrg
845dfecf96Smrg    LispObj *pattern, *nospec, *icase, *nosub, *newline;
855dfecf96Smrg
865dfecf96Smrg    newline = ARGUMENT(4);
875dfecf96Smrg    nosub = ARGUMENT(3);
885dfecf96Smrg    icase = ARGUMENT(2);
895dfecf96Smrg    nospec = ARGUMENT(1);
905dfecf96Smrg    pattern = ARGUMENT(0);
915dfecf96Smrg
925dfecf96Smrg    /* Don't generate an error if it is already a compiled regex. */
935dfecf96Smrg    if (REGEXP(pattern))
945dfecf96Smrg	return (pattern);
955dfecf96Smrg
965dfecf96Smrg    CHECK_STRING(pattern);
975dfecf96Smrg
985dfecf96Smrg    if (nospec != UNSPEC && nospec != NIL)
995dfecf96Smrg	cflags |= RE_NOSPEC;
1005dfecf96Smrg    if (icase != UNSPEC && icase != NIL)
1015dfecf96Smrg	cflags |= RE_ICASE;
1025dfecf96Smrg    if (nosub != UNSPEC && nosub != NIL)
1035dfecf96Smrg	cflags |= RE_NOSUB;
1045dfecf96Smrg    if (newline != UNSPEC && newline != NIL)
1055dfecf96Smrg	cflags |= RE_NEWLINE;
1065dfecf96Smrg
1075dfecf96Smrg    regex = LispRecomp(builtin, THESTR(pattern), cflags);
1085dfecf96Smrg    result = LispNew(pattern, NIL);
1095dfecf96Smrg    result->type = LispRegex_t;
1105dfecf96Smrg    result->data.regex.regex = regex;
1115dfecf96Smrg    result->data.regex.pattern = pattern;
1125dfecf96Smrg    result->data.regex.options = cflags;
1135dfecf96Smrg    LispMused(regex);
1145dfecf96Smrg
1155dfecf96Smrg    return (result);
1165dfecf96Smrg}
1175dfecf96Smrg
1185dfecf96SmrgLispObj *
1195dfecf96SmrgLisp_Reexec(LispBuiltin *builtin)
1205dfecf96Smrg/*
1215dfecf96Smrg re-exec regex string &key count start end notbol noteol
1225dfecf96Smrg */
1235dfecf96Smrg{
1245dfecf96Smrg    size_t nmatch;
1255dfecf96Smrg    re_mat match[10];
1265dfecf96Smrg    long start, end, length;
1275dfecf96Smrg    int code, cflags, eflags;
1285dfecf96Smrg    char *string;
1295dfecf96Smrg    LispObj *result;
1305dfecf96Smrg    re_cod *regexp;
1315dfecf96Smrg
1325dfecf96Smrg    LispObj *regex, *ostring, *count, *ostart, *oend, *notbol, *noteol;
1335dfecf96Smrg
1345dfecf96Smrg    noteol = ARGUMENT(6);
1355dfecf96Smrg    notbol = ARGUMENT(5);
1365dfecf96Smrg    oend = ARGUMENT(4);
1375dfecf96Smrg    ostart = ARGUMENT(3);
1385dfecf96Smrg    count = ARGUMENT(2);
1395dfecf96Smrg    ostring = ARGUMENT(1);
1405dfecf96Smrg    regex = ARGUMENT(0);
1415dfecf96Smrg
1425dfecf96Smrg    if (STRINGP(regex))
1435dfecf96Smrg	regexp = LispRecomp(builtin, THESTR(regex), cflags = 0);
1445dfecf96Smrg    else {
1455dfecf96Smrg	CHECK_REGEX(regex);
1465dfecf96Smrg	regexp = regex->data.regex.regex;
1475dfecf96Smrg	cflags = regex->data.regex.options;
1485dfecf96Smrg    }
1495dfecf96Smrg
1505dfecf96Smrg    CHECK_STRING(ostring);
1515dfecf96Smrg
1525dfecf96Smrg    if (count == UNSPEC)
1535dfecf96Smrg	nmatch = 1;
1545dfecf96Smrg    else {
1555dfecf96Smrg	CHECK_INDEX(count);
1565dfecf96Smrg	nmatch = FIXNUM_VALUE(count);
1575dfecf96Smrg	if (nmatch > 10)
1585dfecf96Smrg	    LispDestroy("%s: COUNT cannot be larger than 10", STRFUN(builtin));
1595dfecf96Smrg    }
1605dfecf96Smrg    if (nmatch && (cflags & RE_NOSUB))
1615dfecf96Smrg	nmatch = 1;
1625dfecf96Smrg
1635dfecf96Smrg    eflags = RE_STARTEND;
1645dfecf96Smrg    if (notbol != UNSPEC && notbol != NIL)
1655dfecf96Smrg	eflags |= RE_NOTBOL;
1665dfecf96Smrg    if (noteol != UNSPEC && noteol != NIL)
1675dfecf96Smrg	eflags |= RE_NOTEOL;
1685dfecf96Smrg
1695dfecf96Smrg    string = THESTR(ostring);
1705dfecf96Smrg    LispCheckSequenceStartEnd(builtin, ostring, ostart, oend,
1715dfecf96Smrg			      &start, &end, &length);
1725dfecf96Smrg
1735dfecf96Smrg    match[0].rm_so = start;
1745dfecf96Smrg    match[0].rm_eo = end;
1755dfecf96Smrg    code = reexec(regexp, string, nmatch, &match[0], eflags);
1765dfecf96Smrg
1775dfecf96Smrg    if (code == 0) {
1785dfecf96Smrg	if (nmatch && match[0].rm_eo >= match[0].rm_so) {
1795dfecf96Smrg	    result = CONS(CONS(FIXNUM(match[0].rm_so),
1805dfecf96Smrg			       FIXNUM(match[0].rm_eo)), NIL);
1815dfecf96Smrg	    if (nmatch > 1 && match[1].rm_eo >= match[1].rm_so) {
1825dfecf96Smrg		int i;
1835dfecf96Smrg		GC_ENTER();
1845dfecf96Smrg		LispObj *cons = result;
1855dfecf96Smrg
1865dfecf96Smrg		GC_PROTECT(result);
1875dfecf96Smrg		for (i = 1;
1885dfecf96Smrg		     i < nmatch && match[i].rm_eo >= match[i].rm_so;
1895dfecf96Smrg		     i++) {
1905dfecf96Smrg		    RPLACD(cons, CONS(CONS(FIXNUM(match[i].rm_so),
1915dfecf96Smrg					   FIXNUM(match[i].rm_eo)), NIL));
1925dfecf96Smrg		    cons = CDR(cons);
1935dfecf96Smrg		}
1945dfecf96Smrg		GC_LEAVE();
1955dfecf96Smrg	    }
1965dfecf96Smrg	}
1975dfecf96Smrg	else
1985dfecf96Smrg	    result = NIL;
1995dfecf96Smrg    }
2005dfecf96Smrg    else
2015dfecf96Smrg	result = Knomatch;
2025dfecf96Smrg
2035dfecf96Smrg    /* Maybe shoud cache compiled regex, but better the caller do it */
2045dfecf96Smrg    if (!XREGEXP(regex)) {
2055dfecf96Smrg	refree(regexp);
2065dfecf96Smrg	LispFree(regexp);
2075dfecf96Smrg    }
2085dfecf96Smrg
2095dfecf96Smrg    return (result);
2105dfecf96Smrg}
2115dfecf96Smrg
2125dfecf96SmrgLispObj *
2135dfecf96SmrgLisp_Rep(LispBuiltin *builtin)
2145dfecf96Smrg/*
2155dfecf96Smrg re-p object
2165dfecf96Smrg */
2175dfecf96Smrg{
2185dfecf96Smrg    LispObj *object;
2195dfecf96Smrg
2205dfecf96Smrg    object = ARGUMENT(0);
2215dfecf96Smrg
2225dfecf96Smrg    return (REGEXP(object) ? T : NIL);
2235dfecf96Smrg}
224