📄 b_regexp.c
字号:
/*
* The builtin RegExp object.
* Copyright (c) 1998 New Generation Software (NGS) Oy
*
* Author: Markku Rossi <mtr@ngs.fi>
*/
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA
*/
/*
* $Source: /cygdrive/c/RCVS/CVS/ReactOS/reactos/lib/kjs/ksrc/b_regexp.c,v $
* $Id: b_regexp.c 21681 2006-04-21 15:00:24Z peterw $
*/
#include "jsint.h"
#include "regex.h"
/*
* Types and definitions.
*/
/* These must be in sync with the values, found from `../jsc/asm.js'. */
#define JS_REGEXP_FLAG_G 0x01
#define JS_REGEXP_FLAG_I 0x02
/* Class context. */
struct regexp_ctx_st
{
/* Static properties. */
JSSymbol s_S1;
JSSymbol s_S2;
JSSymbol s_S3;
JSSymbol s_S4;
JSSymbol s_S5;
JSSymbol s_S6;
JSSymbol s_S7;
JSSymbol s_S8;
JSSymbol s_S9;
JSSymbol s_S_;
JSSymbol s_input;
JSSymbol s_lastMatch;
JSSymbol s_lastParen;
JSSymbol s_leftContext;
JSSymbol s_multiline;
JSSymbol s_rightContext;
/* Properties. */
JSSymbol s_global;
JSSymbol s_ignoreCase;
JSSymbol s_lastIndex;
JSSymbol s_source;
/* Methods. */
JSSymbol s_compile;
JSSymbol s_exec;
JSSymbol s_test;
/* Data that is needed for the static properties. */
JSNode input;
struct re_registers regs;
};
typedef struct regexp_ctx_st RegexpCtx;
/* RegExp instance context. */
struct regexp_instance_ctx_st
{
/* The source for this regexp. */
char *source;
unsigned int source_len;
/* Flags. */
unsigned int global : 1;
unsigned int ignore_case : 1;
unsigned int immutable : 1;
/* Compiled pattern. */
struct re_pattern_buffer compiled;
/* The index from which the next match is started. */
unsigned int last_index;
};
typedef struct regexp_instance_ctx_st RegexpInstanceCtx;
/*
* Prorototypes for some static functions.
*/
static void new_proc (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info,
JSNode *args, JSNode *result_return);
/*
* Static functions.
*/
/* A helper for RegExp.exec(). XXX Check the compliancy. */
static void
do_exec (JSVirtualMachine *vm, RegexpCtx *ctx, RegexpInstanceCtx *ictx,
char *input, unsigned int input_len, JSNode *result_return)
{
int result;
int i, j;
result = re_search (&ictx->compiled, input, input_len,
ictx->global ? ictx->last_index : 0,
input_len, &ctx->regs);
if (result < 0)
{
result_return->type = JS_NULL;
return;
}
/* Success. Count how many matches we had. */
for (i = 0; i < ctx->regs.num_regs && ctx->regs.start[i] >= 0; i++)
;
/* Create the result array and enter the sub-matches. */
js_vm_make_array (vm, result_return, i);
for (j = 0; j < i; j++)
js_vm_make_string (vm, &result_return->u.varray->data[j],
input + ctx->regs.start[j],
ctx->regs.end[j] - ctx->regs.start[j]);
ictx->last_index = ctx->regs.end[0];
}
/* Method proc. */
static int
method (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info,
void *instance_context, JSSymbol method, JSNode *result_return,
JSNode *args)
{
RegexpCtx *ctx = builtin_info->obj_context;
RegexpInstanceCtx *ictx = instance_context;
int result;
int i;
/* Set the default return value. */
result_return->type = JS_BOOLEAN;
result_return->u.vboolean = 1;
/* Static methods. */
if (method == vm->syms.s_toString)
{
if (ictx)
js_vm_make_string (vm, result_return, ictx->source, ictx->source_len);
else
js_vm_make_static_string (vm, result_return, "RegExp", 6);
}
/* ********************************************************************** */
else if (ictx)
{
/* Methods */
if (method == ctx->s_compile)
{
int global = 0;
int ignore_case = 0;
const char *error;
JSNode *pattern;
JSNode pattern_cvt;
if (ictx->immutable)
goto immutable;
if (args->u.vinteger != 1 && args->u.vinteger != 2)
goto argument_error;
if (args[1].type == JS_STRING)
pattern = &args[1];
else
{
js_vm_to_string (vm, &args[1], &pattern_cvt);
pattern = &pattern_cvt;
}
if (args->u.vinteger == 2)
{
JSNode *flags;
JSNode cvt;
if (args[2].type == JS_STRING)
flags = &args[2];
else
{
js_vm_to_string (vm, &args[2], &cvt);
flags = &cvt;
}
for (i = 0; i < flags->u.vstring->len; i++)
switch (flags->u.vstring->data[i])
{
case 'g':
global = 1;
break;
case 'i':
ignore_case = 1;
break;
default:
sprintf (vm->error, "new RegExp(): illegal flag `%c'",
flags->u.vstring->data[i]);
js_vm_error (vm);
break;
}
}
if (ictx->source)
js_free (ictx->source);
ictx->source_len = pattern->u.vstring->len;
ictx->source = js_malloc (vm, ictx->source_len);
memcpy (ictx->source, pattern->u.vstring->data, ictx->source_len);
ictx->global = global;
ictx->ignore_case = ignore_case;
if (ictx->compiled.fastmap)
js_free (ictx->compiled.fastmap);
memset (&ictx->compiled, 0, sizeof (ictx->compiled));
if (ictx->ignore_case)
ictx->compiled.translate = js_latin1_tolower;
error = re_compile_pattern (ictx->source, ictx->source_len,
&ictx->compiled);
if (error)
{
sprintf (vm->error,
"RegExp.%s(): compilation of the expression failed: %s",
js_vm_symname (vm, method), error);
js_vm_error (vm);
}
ictx->compiled.fastmap = js_malloc (vm, 256);
re_compile_fastmap (&ictx->compiled);
}
/* ***************************************************************** */
else if (method == ctx->s_exec)
{
char *input;
unsigned int input_len;
JSNode *input_str;
JSNode cvt;
if (args->u.vinteger == 0)
{
if (ctx->input.type == JS_STRING)
input_str = &ctx->input;
else
{
js_vm_to_string (vm, &ctx->input, &cvt);
input_str = &cvt;
}
input = (char*)input_str->u.vstring->data;
input_len = input_str->u.vstring->len;
}
else if (args->u.vinteger == 1)
{
if (args[1].type == JS_STRING)
input_str = &args[1];
else
{
js_vm_to_string (vm, &args[1], &cvt);
input_str = &cvt;
}
input = (char*)input_str->u.vstring->data;
input_len = input_str->u.vstring->len;
/* Set the input property to the class context. */
JS_COPY (&ctx->input, input_str);
}
else
goto argument_error;
do_exec (vm, ctx, ictx, input, input_len, result_return);
}
/* ***************************************************************** */
else if (method == ctx->s_test)
{
char *input;
unsigned int input_len;
JSNode *input_str;
JSNode cvt;
if (args->u.vinteger == 0)
{
if (ctx->input.type == JS_STRING)
input_str = &ctx->input;
else
{
js_vm_to_string (vm, &ctx->input, &cvt);
input_str = &cvt;
}
input = (char*)input_str->u.vstring->data;
input_len = input_str->u.vstring->len;
}
else if (args->u.vinteger == 1)
{
if (args[1].type == JS_STRING)
input_str = &args[1];
else
{
js_vm_to_string (vm, &args[1], &cvt);
input_str = &cvt;
}
input = (char*)input_str->u.vstring->data;
input_len = input_str->u.vstring->len;
/* Set the input property to the class context. */
JS_COPY (&ctx->input, input_str);
}
else
goto argument_error;
result = re_search (&ictx->compiled, input, input_len,
ictx->global ? ictx->last_index : 0,
input_len, &ctx->regs);
result_return->type = JS_BOOLEAN;
result_return->u.vboolean = result >= 0;
if (result >= 0)
/* ctx->regs.num_regs can be 0. Or can it??? */
ictx->last_index = ctx->regs.end[0];
}
/* ***************************************************************** */
else
return JS_PROPERTY_UNKNOWN;
}
/* ********************************************************************** */
else
return JS_PROPERTY_UNKNOWN;
return JS_PROPERTY_FOUND;
/*
* Error handling.
*/
argument_error:
sprintf (vm->error, "RegExp.%s(): illegal amount of arguments",
js_vm_symname (vm, method));
js_vm_error (vm);
/* argument_type_error: */
sprintf (vm->error, "RegExp.%s(): illegal argument",
js_vm_symname (vm, method));
js_vm_error (vm);
immutable:
sprintf (vm->error, "RegExp.%s(): immutable object",
js_vm_symname (vm, method));
js_vm_error (vm);
/* NOTREACHED. */
return 0;
}
/* Global method proc. */
static void
global_method (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info,
void *instance_context, JSNode *result_return,
JSNode *args)
{
RegexpCtx *ctx = builtin_info->obj_context;
RegexpInstanceCtx *ictx = instance_context;
char *input = NULL; /* Initialized to keep the compiler quiet. */
unsigned int input_len = 0; /* Likewise. */
if (ictx)
{
/* A RegExp instance was called as a function. */
if (args->u.vinteger == 0)
{
if (ctx->input.type != JS_STRING)
{
sprintf (vm->error, "RegExp(): RegExp.input is not a string");
js_vm_error (vm);
}
input = (char*)ctx->input.u.vstring->data;
input_len = ctx->input.u.vstring->len;
}
else if (args->u.vinteger == 1)
{
if (args[1].type != JS_STRING)
{
sprintf (vm->error, "RegExp(): illegal argument");
js_vm_error (vm);
}
input = (char*)args[1].u.vstring->data;
input_len = args[1].u.vstring->len;
/* Set the input property to the class context. */
JS_COPY (&ctx->input, &args[1]);
}
else
{
sprintf (vm->error, "RegExp(): illegal amount of arguments");
js_vm_error (vm);
}
do_exec (vm, ctx, ictx, input, input_len, result_return);
}
else
{
/*
* The `RegExp' was called as a function. We do exactly the
* same the `new RegExp()' would do with our arguments.
*/
new_proc (vm, builtin_info, args, result_return);
}
}
/* Property proc. */
static int
property (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info,
void *instance_context, JSSymbol property, int set, JSNode *node)
{
RegexpCtx *ctx = builtin_info->obj_context;
RegexpInstanceCtx *ictx = instance_context;
int index;
/* Static properties. */
if (property == ctx->s_S1)
{
index = 1;
dollar_index:
if (set)
goto immutable;
if (ctx->input.type != JS_STRING
|| ctx->regs.end[0] > ctx->input.u.vstring->len
|| ctx->regs.start[index] < 0)
node->type = JS_UNDEFINED;
else
js_vm_make_string (vm, node,
(char*)ctx->input.u.vstring->data
+ ctx->regs.start[index],
ctx->regs.end[index] - ctx->regs.start[index]);
}
/* ********************************************************************** */
else if (property == ctx->s_S2)
{
index = 2;
goto dollar_index;
}
/* ********************************************************************** */
else if (property == ctx->s_S3)
{
index = 3;
goto dollar_index;
}
/* ********************************************************************** */
else if (property == ctx->s_S4)
{
index = 4;
goto dollar_index;
}
/* ********************************************************************** */
else if (property == ctx->s_S5)
{
index = 5;
goto dollar_index;
}
/* ********************************************************************** */
else if (property == ctx->s_S6)
{
index = 6;
goto dollar_index;
}
/* ********************************************************************** */
else if (property == ctx->s_S7)
{
index = 7;
goto dollar_index;
}
/* ********************************************************************** */
else if (property == ctx->s_S8)
{
index = 8;
goto dollar_index;
}
/* ********************************************************************** */
else if (property == ctx->s_S9)
{
index = 9;
goto dollar_index;
}
/* ********************************************************************** */
else if (property == ctx->s_S_ || property == ctx->s_input)
{
if (set)
{
if (node->type != JS_STRING)
goto argument_type_error;
JS_COPY (&ctx->input, node);
}
else
JS_COPY (node, &ctx->input);
}
/* ********************************************************************** */
else if (property == ctx->s_lastMatch)
{
if (set)
goto immutable;
if (ctx->input.type != JS_STRING
|| ctx->regs.end[0] > ctx->input.u.vstring->len)
node->type = JS_UNDEFINED;
else
js_vm_make_string (vm, node,
(char*)ctx->input.u.vstring->data +
ctx->regs.start[0],
ctx->regs.end[0] - ctx->regs.start[0]);
}
/* ********************************************************************** */
else if (property == ctx->s_lastParen)
{
if (set)
goto immutable;
if (ctx->input.type != JS_STRING
|| ctx->regs.end[0] > ctx->input.u.vstring->len)
node->type = JS_UNDEFINED;
else
{
int i;
for (i = 1; i < ctx->regs.num_regs && ctx->regs.start[i] >= 0; i++)
;
i--;
if (i == 0)
node->type = JS_UNDEFINED;
else
js_vm_make_string (vm, node,
(char*)ctx->input.u.vstring->data
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -