scsh-0.6/scsh/rx/re1.c

194 lines
6.1 KiB
C
Raw Normal View History

1999-09-23 10:27:41 -04:00
/* Scheme48 interface to Henry Spencer's Posix regular expression package.
** Copyright (c) 1993, 1994, 1998 by Olin Shivers.
*/
/* Todo:
** not_eol not_bol support on searchers
** error code -> err msg
** regex freeing
** regexp-string -> regex_t caching
** make filter_stringvec return an error code.
2001-01-01 12:19:55 -05:00
** TODO: filter_stringvec is used nowhere, why?
1999-09-23 10:27:41 -04:00
*/
#include <stdlib.h>
#include <sys/types.h>
#include "../regexp/regex.h"
#include "../cstuff.h"
/* Make sure our exports match up w/the implementation: */
#include "re1.h"
/*
** Compile regexp into a malloc'd struct.
** The flag sm_p is true if we want to compile for submatches.
** On success, store pointer to struct into cr and return 0.
** On failure, free the struct, store NULL into cr,
** and return a non-zero error code.
*/
2001-01-01 12:19:55 -05:00
s48_value compile_re(s48_value re_str, s48_value sm_p)
1999-09-23 10:27:41 -04:00
{
1999-09-23 13:46:46 -04:00
char *s = s48_extract_string(re_str);
2001-01-01 12:19:55 -05:00
int len = S48_STRING_LENGTH(re_str);
int err;
regex_t *re = Alloc(regex_t);
if( !re ) s48_raise_out_of_memory_error();
re->re_endp = s + len;
err = regcomp(re, s, REG_EXTENDED | REG_PEND
| ((sm_p != S48_FALSE) ? 0 : REG_NOSUB));
if( err ) {
Free(re);
return s48_cons(s48_enter_fixnum (err), s48_enter_fixnum (0));
}
else return s48_enter_integer((unsigned long) re);
}
1999-09-23 10:27:41 -04:00
/* Do a regex search of RE through string STR, beginning at STR[START].
** - STR is passed as a Scheme value as it is allowed to contain nul bytes.
**
** - trans_vec contains the translation from the user's "virtual" submatches to
** the actual submatches the engine will report:
** - trans_vec[i] = #F means user submatch #i is a dead submatch.
** - trans_vec[i] = j means user submatch #i corresponds to paren #j in re.
**
** Indexing fence-posts are a little complicated due to the fact that you
** get an extra match elt back from the matcher -- match 0 is not a
** paren-based *sub*match, but rather the match info for the whole thing.
**
** So, here is how it works:
** length(start_vec) = length(end_vec) = length(trans_vec) + 1
** because trans_vec doesn't have a translation for submatch 0, which
** is SRE submatch #0 => Posix submatch #0. For SRE submatch #i (1, 2, ...),
** we want the submatch associated with Posix paren # trans_vec[i-1].
**
** - MAX_PSM is the maximum paren in which we have submatch interest -- the
** max element in TRANS_VEC. Any parens after paren #MAX_PSM are just for
** grouping, not for marking submatches. We only have to allocate MAX_PSM+1
** elements in the submatch vector we pass into the search engine. If
** MAX_PSM = -1, then we don't even want the whole-match match bounds, which
** is really good -- the search engine can really fly in this case.
**
** If we match, map re's submatches over to the exported start_vec and
** end_vec match vectors using trans_vec.
**
** Return 0 on success; #f if no match; non-zero integer error code otherwise.
*/
2001-01-01 12:19:55 -05:00
s48_value re_search(s48_value _re, s48_value str, s48_value _start,
s48_value trans_vec, s48_value _max_psm,
1999-09-23 13:46:46 -04:00
s48_value start_vec, s48_value end_vec)
1999-09-23 10:27:41 -04:00
{
2001-01-01 12:19:55 -05:00
const regex_t *re = (const regex_t *) s48_extract_integer (_re);
1999-09-23 13:46:46 -04:00
char *s = s48_extract_string(str);
2001-01-01 12:19:55 -05:00
int len = S48_STRING_LENGTH(str); /* it might contain nul bytes. */
int start = s48_extract_fixnum (_start);
int max_psm = s48_extract_fixnum (_max_psm);
1999-09-23 13:46:46 -04:00
int vlen = S48_VECTOR_LENGTH(start_vec);
1999-09-23 10:27:41 -04:00
int retval;
regmatch_t static_pmatch[10], *pm;
/* If max_psm+1 > 10, we can't use static_pmatch. */
if( max_psm < 10 ) pm = static_pmatch;
else {
pm = Malloc(regmatch_t, max_psm+1);/* Add 1 for the whole-match info. */
2001-01-01 12:19:55 -05:00
if( !pm ) s48_raise_out_of_memory_error();
1999-09-23 10:27:41 -04:00
}
pm[0].rm_so = start;
pm[0].rm_eo = len;
retval = regexec(re, s, max_psm+1, pm, REG_STARTEND); /* Do it. */
/* We matched and have match-bound info, so translate it over. */
if( !retval && max_psm >= 0 ) {
int i;
1999-09-23 13:46:46 -04:00
S48_VECTOR_SET(start_vec,0, s48_enter_fixnum(pm[0].rm_so));
S48_VECTOR_SET(end_vec,0, s48_enter_fixnum(pm[0].rm_eo));
1999-09-23 10:27:41 -04:00
for( i=vlen-1; --i >= 0; ) { /* submatches */
1999-09-23 13:46:46 -04:00
s48_value j_scm = S48_VECTOR_REF(trans_vec,i);
if( j_scm != S48_FALSE ) {
int j = s48_extract_fixnum(j_scm);
1999-09-23 10:27:41 -04:00
int k = pm[j].rm_so,
l = pm[j].rm_eo;
1999-09-23 13:46:46 -04:00
S48_VECTOR_SET(start_vec,i+1, (k != -1) ? s48_enter_fixnum(k) : S48_FALSE);
S48_VECTOR_SET(end_vec, i+1, (l != -1) ? s48_enter_fixnum(l) : S48_FALSE);
1999-09-23 10:27:41 -04:00
}
}
1999-09-23 13:46:46 -04:00
}
1999-09-23 10:27:41 -04:00
if( max_psm >= 10 ) Free(pm);
1999-09-23 13:46:46 -04:00
if( retval==REG_NOMATCH ) return S48_FALSE;
if( ! retval ) return S48_TRUE;
return s48_enter_fixnum(retval);
2001-01-01 12:19:55 -05:00
}
1999-09-23 10:27:41 -04:00
/* Filter a vector of strings by regexp RE_STR.
** Stringvec is a NULL-terminated vector of strings;
** filter it in-place, copying the survivors back to compact them.
** Put the number of survivors in nummatch.
*/
1999-09-23 13:46:46 -04:00
int filter_stringvec(s48_value re_str, char const **stringvec)
1999-09-23 10:27:41 -04:00
{
1999-09-23 13:46:46 -04:00
int re_len = S48_STRING_LENGTH(re_str);/* Passed as a s48_value because */
//JMG: char *re_chars = &STRING_REF(re_str,0);/* it might contain nul bytes. */
char *re_chars = s48_extract_string (re_str);/* it might contain nul bytes. */
regex_t re;
1999-09-23 10:27:41 -04:00
char const **p, **q;
/* REG_NOSUB -- We just want to know if it matches or not. */
re.re_endp = re_chars + re_len;
if( regcomp(&re, re_chars, REG_EXTENDED | REG_PEND | REG_NOSUB) ) {
return 0;
}
for(p=q=stringvec; *p; p++) {
char const *s = *p;
if( ! regexec(&re, s, 0, 0, 0) ) *q++ = s;
}
regfree(&re);
return q-stringvec;
2001-01-01 12:19:55 -05:00
}
1999-09-23 10:27:41 -04:00
2001-01-01 12:19:55 -05:00
s48_value re_errint2str(s48_value _errcode, s48_value _re)
1999-09-23 10:27:41 -04:00
{
2001-01-01 12:19:55 -05:00
const regex_t *re = (const regex_t *) s48_extract_integer (_re);
int errcode = s48_extract_fixnum (_errcode);
1999-09-23 10:27:41 -04:00
int size = regerror(errcode, re, 0, 0);
char *s = Malloc(char,size);
if(s) regerror(errcode, re, s, size);
2001-01-01 12:19:55 -05:00
return s48_enter_string(s);
}
1999-09-23 10:27:41 -04:00
2001-01-01 12:19:55 -05:00
s48_value free_re(s48_value _re)
1999-09-23 10:27:41 -04:00
{
2001-01-01 12:19:55 -05:00
regex_t *re = (regex_t *) s48_extract_integer(_re);
1999-09-23 10:27:41 -04:00
regfree(re);
Free(re);
2001-01-01 12:19:55 -05:00
return S48_UNSPECIFIC;
}
s48_value s48_init_re_low(void)
{
S48_EXPORT_FUNCTION(compile_re);
S48_EXPORT_FUNCTION(re_search);
S48_EXPORT_FUNCTION(re_errint2str);
S48_EXPORT_FUNCTION(free_re);
return S48_UNSPECIFIC;
}