| | 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 | */ |
| | 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 | */ |
| | 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 | */ |
| | 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 | */ |
| | 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 | */ |
| | 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 | uint 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 | */ |
| | 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 | */ |
| | 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 | */ |
| | 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 | */ |
| | 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 | */ |
| | 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 | */ |
| | 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 | } |