1 /*
2 * Copyright (c) 2002 by Michael J. Roberts. All Rights Reserved.
3 *
4 * Please see the accompanying license file, LICENSE.TXT, for information
5 * on using and copying this software.
6 */
7 /*
8 Name
9 vmpat.cpp - regular-expression compiled pattern object
10 Function
11
12 Notes
13
14 Modified
15 08/27/02 MJRoberts - Creation
16 */
17
18 #include <stdlib.h>
19 #include <os.h>
20 #include "vmtype.h"
21 #include "vmobj.h"
22 #include "vmmeta.h"
23 #include "vmglob.h"
24 #include "vmregex.h"
25 #include "vmpat.h"
26 #include "vmstack.h"
27 #include "vmbif.h"
28 #include "vmbiftad.h"
29 #include "vmfile.h"
30
31
32 /* ------------------------------------------------------------------------ */
33 /*
34 * Statics
35 */
36 static CVmMetaclassPattern metaclass_reg_obj;
37 CVmMetaclass *CVmObjPattern::metaclass_reg_ = &metaclass_reg_obj;
38
39 /* function table */
40 int (CVmObjPattern::
41 *CVmObjPattern::func_table_[])(VMG_ vm_obj_id_t self,
42 vm_val_t *retval, uint *argc) =
43 {
44 &CVmObjPattern::getp_undef,
45 &CVmObjPattern::getp_get_str
46 };
47
48 /* ------------------------------------------------------------------------ */
49 /*
50 * create
51 */
CVmObjPattern(VMG_ re_compiled_pattern * pat,const vm_val_t * src_str)52 CVmObjPattern::CVmObjPattern(VMG_ re_compiled_pattern *pat,
53 const vm_val_t *src_str)
54 {
55 /* allocate my extension data */
56 ext_ = (char *)G_mem->get_var_heap()
57 ->alloc_mem(sizeof(vmobj_pat_ext), this);
58
59 /* remember my source data */
60 set_orig_str(src_str);
61
62 /* remember the compiled pattern */
63 set_pattern(pat);
64 }
65
66 /* ------------------------------------------------------------------------ */
67 /*
68 * notify of deletion
69 */
notify_delete(VMG_ int in_root_set)70 void CVmObjPattern::notify_delete(VMG_ int in_root_set)
71 {
72 /* free my extension data */
73 if (ext_ != 0)
74 {
75 /*
76 * Free my pattern, if I've compiled it. (Note that we must not
77 * call get_pattern() here, because doing so would unnecessarily
78 * create a pattern if we haven't already done so - that would be
79 * stupid, because the only reason we're asking for it is so that
80 * we can delete it.)
81 */
82 if (get_ext()->pat != 0)
83 CRegexParser::free_pattern(get_ext()->pat);
84
85 /* free the extension */
86 if (!in_root_set)
87 G_mem->get_var_heap()->free_mem(ext_);
88 }
89 }
90
91 /* ------------------------------------------------------------------------ */
92 /*
93 * Create from the stack
94 */
create_from_stack(VMG_ const uchar ** pc_ptr,uint argc)95 vm_obj_id_t CVmObjPattern::create_from_stack(VMG_ const uchar **pc_ptr,
96 uint argc)
97 {
98 const char *strval;
99 re_status_t stat;
100 re_compiled_pattern *pat;
101 vm_obj_id_t id;
102
103 /* check arguments */
104 if (argc != 1)
105 err_throw(VMERR_WRONG_NUM_OF_ARGS);
106
107 /* retrieve the string, but leave it on the stack */
108 strval = G_stk->get(0)->get_as_string(vmg0_);
109 if (strval == 0)
110 err_throw(VMERR_STRING_VAL_REQD);
111
112 /* compile the string */
113 stat = G_bif_tads_globals->rex_parser->compile_pattern(
114 strval + VMB_LEN, vmb_get_len(strval), &pat);
115
116 /* if we failed to compile the pattern, throw an error */
117 if (stat != RE_STATUS_SUCCESS)
118 err_throw(VMERR_BAD_TYPE_BIF);
119
120 /* create a new pattern object to hold the pattern */
121 id = vm_new_id(vmg_ FALSE, TRUE, FALSE);
122 new (vmg_ id) CVmObjPattern(vmg_ pat, G_stk->get(0));
123
124 /* discard arguments */
125 G_stk->discard();
126
127 /* return the new object */
128 return id;
129 }
130
131 /* ------------------------------------------------------------------------ */
132 /*
133 * set a property
134 */
set_prop(VMG_ class CVmUndo *,vm_obj_id_t,vm_prop_id_t,const vm_val_t *)135 void CVmObjPattern::set_prop(VMG_ class CVmUndo *,
136 vm_obj_id_t, vm_prop_id_t,
137 const vm_val_t *)
138 {
139 /* we have no properties to set */
140 err_throw(VMERR_INVALID_SETPROP);
141 }
142
143 /* ------------------------------------------------------------------------ */
144 /*
145 * Get a property
146 */
get_prop(VMG_ vm_prop_id_t prop,vm_val_t * val,vm_obj_id_t self,vm_obj_id_t * source_obj,uint * argc)147 int CVmObjPattern::get_prop(VMG_ vm_prop_id_t prop, vm_val_t *val,
148 vm_obj_id_t self, vm_obj_id_t *source_obj,
149 uint *argc)
150 {
151 unsigned short func_idx;
152
153 /* translate the property into a function vector index */
154 func_idx = G_meta_table
155 ->prop_to_vector_idx(metaclass_reg_->get_reg_idx(), prop);
156
157 /* call the function, if we found it */
158 if ((this->*func_table_[func_idx])(vmg_ self, val, argc))
159 {
160 *source_obj = metaclass_reg_->get_class_obj(vmg0_);
161 return TRUE;
162 }
163
164 /* not found - inherit default handling */
165 return CVmObject::get_prop(vmg_ prop, val, self, source_obj, argc);
166 }
167
168
169 /* ------------------------------------------------------------------------ */
170 /*
171 * Mark references
172 */
mark_refs(VMG_ uint state)173 void CVmObjPattern::mark_refs(VMG_ uint state)
174 {
175 const vm_val_t *valp;
176
177 /* if our source value is an object reference, mark it */
178 if (get_ext() != 0
179 && (valp = get_orig_str())->typ == VM_OBJ
180 && valp->val.obj != VM_INVALID_OBJ)
181 {
182 /* it's a reference, so mark it */
183 G_obj_table->mark_all_refs(valp->val.obj, state);
184 }
185 }
186
187 /* ------------------------------------------------------------------------ */
188 /*
189 * Load from an image file
190 */
load_from_image(VMG_ vm_obj_id_t self,const char * ptr,size_t len)191 void CVmObjPattern::load_from_image(VMG_ vm_obj_id_t self, const char *ptr,
192 size_t len)
193 {
194 /* if we don't already have an extension, allocate one */
195 if (ext_ == 0)
196 ext_ = (char *)G_mem->get_var_heap()
197 ->alloc_mem(sizeof(vmobj_pat_ext), this);
198
199 /* get our source value */
200 vmb_get_dh(ptr, &get_ext()->str);
201
202 /*
203 * We haven't compiled our pattern yet. Note that it might not be
204 * possible to obtain the text of our string at this point, because it
205 * might be another object and thus might not have been loaded yet.
206 * So, note that we have no pattern yet, and request post-load
207 * initialization, so that we can compile our pattern after we know all
208 * of the other objects have been loaded.
209 */
210 set_pattern(0);
211 G_obj_table->request_post_load_init(self);
212 }
213
214 /* ------------------------------------------------------------------------ */
215 /*
216 * Perform post-load initialization: we compile our pattern here. Note
217 * that we need to wait until now to compile our pattern, since our source
218 * string could be another object, which isn't guaranteed to have been
219 * loaded until we get here.
220 */
post_load_init(VMG_ vm_obj_id_t self)221 void CVmObjPattern::post_load_init(VMG_ vm_obj_id_t self)
222 {
223 const vm_val_t *origval;
224 const char *strval;
225
226 /* make sure the original string object is initialized */
227 origval = get_orig_str();
228 if (origval->typ == VM_OBJ)
229 G_obj_table->ensure_post_load_init(vmg_ origval->val.obj);
230
231 /* get the string value */
232 strval = get_orig_str()->get_as_string(vmg0_);
233 if (strval != 0)
234 {
235 /* if we already have a compiled pattern, delete it */
236 if (get_ext()->pat != 0)
237 CRegexParser::free_pattern(get_ext()->pat);
238
239 /* compile the pattern and store the result */
240 G_bif_tads_globals->rex_parser->compile_pattern(
241 strval + VMB_LEN, vmb_get_len(strval), &get_ext()->pat);
242 }
243 }
244
245 /* ------------------------------------------------------------------------ */
246 /*
247 * save to a file
248 */
save_to_file(VMG_ class CVmFile * fp)249 void CVmObjPattern::save_to_file(VMG_ class CVmFile *fp)
250 {
251 char buf[VMB_DATAHOLDER];
252
253 /* write the source string reference */
254 vmb_put_dh(buf, get_orig_str());
255 fp->write_bytes(buf, VMB_DATAHOLDER);
256 }
257
258 /* ------------------------------------------------------------------------ */
259 /*
260 * restore from a file
261 */
restore_from_file(VMG_ vm_obj_id_t self,class CVmFile * fp,CVmObjFixup * fixups)262 void CVmObjPattern::restore_from_file(VMG_ vm_obj_id_t self,
263 class CVmFile *fp, CVmObjFixup *fixups)
264 {
265 char buf[VMB_DATAHOLDER];
266
267 /* if we don't already have an extension, allocate one */
268 if (ext_ == 0)
269 ext_ = (char *)G_mem->get_var_heap()
270 ->alloc_mem(sizeof(vmobj_pat_ext), this);
271
272 /* read the source string reference */
273 fp->read_bytes(buf, VMB_DATAHOLDER);
274
275 /* fix it up */
276 fixups->fix_dh(vmg_ buf);
277
278 /* remember it in our extension */
279 vmb_get_dh(buf, &get_ext()->str);
280
281 /*
282 * clear out our pattern and request post-load initialization - we
283 * can't necessarily compile it yet, because we might not have loaded
284 * the source string data, so just make a note that we need to compile
285 * it the next time we need it
286 */
287 set_pattern(0);
288 G_obj_table->request_post_load_init(self);
289 }
290
291 /* ------------------------------------------------------------------------ */
292 /*
293 * property evaluator - get my original string
294 */
getp_get_str(VMG_ vm_obj_id_t self,vm_val_t * retval,uint * argc)295 int CVmObjPattern::getp_get_str(VMG_ vm_obj_id_t self,
296 vm_val_t *retval, uint *argc)
297 {
298 static CVmNativeCodeDesc desc(0);
299
300 /* check arguments */
301 if (get_prop_check_argc(retval, argc, &desc))
302 return TRUE;
303
304 /* retrieve my original string value */
305 *retval = *get_orig_str();
306
307 /* handled */
308 return TRUE;
309 }
310