Rev 42397 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/** R : A Computer Language for Statistical Data Analysis* Copyright (C) 2003-7 The R Development Core Team.** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, a copy is available at* http://www.r-project.org/Licenses/*//* <UTF8> OK, provided the delimiters are ASCIImatch length is in now in chars.*/#include <R.h>#include "tools.h"#ifdef SUPPORT_MBCS#include <stdlib.h> /* for MB_CUR_MAX */#include <wchar.h>LibExtern Rboolean mbcslocale;size_t Rf_mbrtowc(wchar_t *wc, const char *s, size_t n, mbstate_t *ps);#endifSEXPdelim_match(SEXP x, SEXP delims){/*Match delimited substrings in a character vector x.Returns an integer vector with the same length of x giving thestarting position of the match (including the start delimiter), or-1 if there is none, with attribute "match.length" giving thelength of the matched text (including the end delimiter), or -1for no match.This is still very experimental.Currently, the start and end delimiters must be single characters;it would be nice to allow for arbitrary regexps.Currently, the only syntax supported is Rd ('\' is the escapecharacter, '%' starts a comment extending to the next newline, noquote characters. It would be nice to generalize this, too.Nevertheless, this is already useful for parsing Rd.*/char c;const char *s, *s0, *delim_start, *delim_end;Sint n, i, pos, start, end, delim_depth;int lstart, lend;Rboolean is_escaped, equal_start_and_end_delims;SEXP ans, matchlen;#ifdef SUPPORT_MBCSmbstate_t mb_st; int used;#endifif(!isString(x) || !isString(delims) || (length(delims) != 2))error(_("invalid argument type"));delim_start = translateChar(STRING_ELT(delims, 0));delim_end = translateChar(STRING_ELT(delims, 1));lstart = strlen(delim_start); lend = strlen(delim_end);equal_start_and_end_delims = strcmp(delim_start, delim_end) == 0;n = length(x);PROTECT(ans = allocVector(INTSXP, n));PROTECT(matchlen = allocVector(INTSXP, n));for(i = 0; i < n; i++) {#ifdef SUPPORT_MBCSmemset(&mb_st, 0, sizeof(mbstate_t));#endifstart = end = -1;s0 = s = translateChar(STRING_ELT(x, i));pos = is_escaped = delim_depth = 0;while((c = *s) != '\0') {if(c == '\n') {is_escaped = FALSE;}else if(c == '\\') {is_escaped = is_escaped ? FALSE : TRUE;}else if(is_escaped) {is_escaped = FALSE;}else if(c == '%') {while((c != '\0') && (c != '\n')) {#ifdef SUPPORT_MBCSif(mbcslocale) {used = Rf_mbrtowc(NULL, s, MB_CUR_MAX, &mb_st);if(used == 0) break;s += used; c = *s;} else#endifc = *++s;pos++;}}else if(strncmp(s, delim_end, lend) == 0) {if(delim_depth > 1) delim_depth--;else if(delim_depth == 1) {end = pos;break;}else if(equal_start_and_end_delims) {start = pos;delim_depth++;}}else if(strncmp(s, delim_start, lstart) == 0) {if(delim_depth == 0) start = pos;delim_depth++;}#ifdef SUPPORT_MBCSif(mbcslocale) {used = Rf_mbrtowc(NULL, s, MB_CUR_MAX, &mb_st);if(used == 0) break;s += used;} else#endifs++;pos++;}if(end > -1) {INTEGER(ans)[i] = start + 1; /* index from one */INTEGER(matchlen)[i] = end - start + 1;}else {INTEGER(ans)[i] = INTEGER(matchlen)[i] = -1;}}setAttrib(ans, install("match.length"), matchlen);UNPROTECT(2);return(ans);}SEXPcheck_nonASCII(SEXP text, SEXP ignore_quotes){/* Check if all the lines in 'text' are ASCII, after removingcomments and ignoring the contents of quotes (unless ignore_quotes)(which might span more than one line and might be escaped).This cannot be entirely correct, as quotes and \ might occur aspart of another character in a MBCS: but this does not happenin UTF-8.*/int i, nbslash = 0; /* number of preceding backslashes */const char *p;char quote= '\0';Rboolean ign, inquote = FALSE;if(TYPEOF(text) != STRSXP) error("invalid input");ign = asLogical(ignore_quotes);if(ign == NA_LOGICAL) error("'ignore_quotes' must be TRUE or FALSE");for (i = 0; i < LENGTH(text); i++) {p = CHAR(STRING_ELT(text, i)); /* ASCII or not not affected by charset */inquote =FALSE; /* avoid runaway quotes */for(; *p; p++) {if(!inquote && *p == '#') break;if(!inquote || ign) {if((unsigned int) *p > 127) {/* Rprintf("%s\n", CHAR(STRING_ELT(text, i)));Rprintf("found %x\n", (unsigned int) *p); */return ScalarLogical(TRUE);}}if(nbslash % 2 && (*p == '"' || *p == '\'')) {if(inquote && *p == quote) {inquote = FALSE;} else if(!inquote) {quote = *p;inquote = TRUE;}}if(*p == '\\') nbslash++; else nbslash = 0;}}return ScalarLogical(FALSE);}