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