File: vmpat.cpp

package info (click to toggle)
qtads 2.1.6-1.1
  • links: PTS
  • area: main
  • in suites: stretch
  • size: 16,156 kB
  • ctags: 18,767
  • sloc: cpp: 133,078; ansic: 26,048; xml: 18; makefile: 11
file content (305 lines) | stat: -rw-r--r-- 9,026 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
/* 
 *   Copyright (c) 2002 by Michael J. Roberts.  All Rights Reserved.
 *   
 *   Please see the accompanying license file, LICENSE.TXT, for information
 *   on using and copying this software.  
 */
/*
Name
  vmpat.cpp - regular-expression compiled pattern object
Function
  
Notes
  
Modified
  08/27/02 MJRoberts  - Creation
*/

#include <stdlib.h>
#include <os.h>
#include "vmtype.h"
#include "vmobj.h"
#include "vmmeta.h"
#include "vmglob.h"
#include "vmregex.h"
#include "vmpat.h"
#include "vmstack.h"
#include "vmbif.h"
#include "vmbiftad.h"
#include "vmfile.h"
#include "vmrun.h"


/* ------------------------------------------------------------------------ */
/*
 *   Statics 
 */
static CVmMetaclassPattern metaclass_reg_obj;
CVmMetaclass *CVmObjPattern::metaclass_reg_ = &metaclass_reg_obj;

/* function table */
int (CVmObjPattern::
     *CVmObjPattern::func_table_[])(VMG_ vm_obj_id_t self,
                                    vm_val_t *retval, uint *argc) =
{
    &CVmObjPattern::getp_undef,
    &CVmObjPattern::getp_get_str
};

/* ------------------------------------------------------------------------ */
/*
 *   create 
 */
CVmObjPattern::CVmObjPattern(VMG_ re_compiled_pattern *pat,
                             const vm_val_t *src_str)
{
    /* allocate my extension data */
    ext_ = (char *)G_mem->get_var_heap()
           ->alloc_mem(sizeof(vmobj_pat_ext), this);

    /* remember my source data */
    set_orig_str(src_str);

    /* remember the compiled pattern */
    set_pattern(pat);
}

/* ------------------------------------------------------------------------ */
/*
 *   notify of deletion 
 */
void CVmObjPattern::notify_delete(VMG_ int in_root_set)
{
    /* free my extension data */
    if (ext_ != 0)
    {
        /* 
         *   Free my pattern, if I've compiled it.  (Note that we must not
         *   call get_pattern() here, because doing so would unnecessarily
         *   create a pattern if we haven't already done so - that would be
         *   stupid, because the only reason we're asking for it is so that
         *   we can delete it.)  
         */
        if (get_ext()->pat != 0)
            CRegexParser::free_pattern(get_ext()->pat);

        /* free the extension */
        if (!in_root_set)
            G_mem->get_var_heap()->free_mem(ext_);
    }
}

/* ------------------------------------------------------------------------ */
/*
 *   Create from the stack 
 */
vm_obj_id_t CVmObjPattern::create_from_stack(VMG_ const uchar **pc_ptr,
                                             uint argc)
{
    const char *strval;
    re_status_t stat;
    re_compiled_pattern *pat;
    vm_obj_id_t id;

    /* check arguments */
    if (argc != 1)
        err_throw(VMERR_WRONG_NUM_OF_ARGS);

    /* retrieve the string, but leave it on the stack */
    strval = G_stk->get(0)->get_as_string(vmg0_);
    if (strval == 0)
        err_throw(VMERR_STRING_VAL_REQD);

    /* compile the string */
    stat = G_bif_tads_globals->rex_parser->compile_pattern(
        strval + VMB_LEN, vmb_get_len(strval), &pat);

    /* if we failed to compile the pattern, throw an error */
    if (stat != RE_STATUS_SUCCESS)
        err_throw(VMERR_BAD_TYPE_BIF);

    /* create a new pattern object to hold the pattern */
    id = vm_new_id(vmg_ FALSE, TRUE, FALSE);
    new (vmg_ id) CVmObjPattern(vmg_ pat, G_stk->get(0));

    /* discard arguments */
    G_stk->discard();

    /* return the new object */
    return id;
}

/* ------------------------------------------------------------------------ */
/* 
 *   set a property 
 */
void CVmObjPattern::set_prop(VMG_ class CVmUndo *,
                             vm_obj_id_t, vm_prop_id_t,
                             const vm_val_t *)
{
    /* we have no properties to set */
    err_throw(VMERR_INVALID_SETPROP);
}

/* ------------------------------------------------------------------------ */
/*
 *   Get a property 
 */
int CVmObjPattern::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)
{
    uint func_idx;
    
    /* translate the property into a function vector index */
    func_idx = G_meta_table
               ->prop_to_vector_idx(metaclass_reg_->get_reg_idx(), prop);

    /* call the function, if we found it */
    if ((this->*func_table_[func_idx])(vmg_ self, val, argc))
    {
        *source_obj = metaclass_reg_->get_class_obj(vmg0_);
        return TRUE;
    }

    /* not found - inherit default handling */
    return CVmObject::get_prop(vmg_ prop, val, self, source_obj, argc);
}


/* ------------------------------------------------------------------------ */
/*
 *   Mark references 
 */
void CVmObjPattern::mark_refs(VMG_ uint state)
{
    const vm_val_t *valp;
    
    /* if our source value is an object reference, mark it */
    if (get_ext() != 0
        && (valp = get_orig_str())->typ == VM_OBJ
        && valp->val.obj != VM_INVALID_OBJ)
    {
        /* it's a reference, so mark it */
        G_obj_table->mark_all_refs(valp->val.obj, state);
    }
}

/* ------------------------------------------------------------------------ */
/*
 *   Load from an image file 
 */
void CVmObjPattern::load_from_image(VMG_ vm_obj_id_t self, const char *ptr,
                                    size_t len)
{
    /* if we don't already have an extension, allocate one */
    if (ext_ == 0)
        ext_ = (char *)G_mem->get_var_heap()
               ->alloc_mem(sizeof(vmobj_pat_ext), this);

    /* get our source value */
    vmb_get_dh(ptr, &get_ext()->str);

    /* 
     *   We haven't compiled our pattern yet.  Note that it might not be
     *   possible to obtain the text of our string at this point, because it
     *   might be another object and thus might not have been loaded yet.
     *   So, note that we have no pattern yet, and request post-load
     *   initialization, so that we can compile our pattern after we know all
     *   of the other objects have been loaded.  
     */
    set_pattern(0);
    G_obj_table->request_post_load_init(self);
}

/* ------------------------------------------------------------------------ */
/*
 *   Perform post-load initialization: we compile our pattern here.  Note
 *   that we need to wait until now to compile our pattern, since our source
 *   string could be another object, which isn't guaranteed to have been
 *   loaded until we get here.  
 */
void CVmObjPattern::post_load_init(VMG_ vm_obj_id_t self)
{
    /* make sure the original string object is initialized */
    const vm_val_t *origval = get_orig_str();
    if (origval->typ == VM_OBJ)
        G_obj_table->ensure_post_load_init(vmg_ origval->val.obj);

    /* get the string value */
    const char *strval = get_orig_str()->get_as_string(vmg0_);
    if (strval != 0)
    {
        /* if we already have a compiled pattern, delete it */
        if (get_ext()->pat != 0)
            CRegexParser::free_pattern(get_ext()->pat);

        /* compile the pattern and store the result */
        G_bif_tads_globals->rex_parser->compile_pattern(
            strval + VMB_LEN, vmb_get_len(strval), &get_ext()->pat);
    }
}

/* ------------------------------------------------------------------------ */
/* 
 *   save to a file 
 */
void CVmObjPattern::save_to_file(VMG_ class CVmFile *fp)
{
    /* write the source string reference */
    char buf[VMB_DATAHOLDER];
    vmb_put_dh(buf, get_orig_str());
    fp->write_bytes(buf, VMB_DATAHOLDER);
}

/* ------------------------------------------------------------------------ */
/* 
 *   restore from a file 
 */
void CVmObjPattern::restore_from_file(VMG_ vm_obj_id_t self,
                                      class CVmFile *fp, CVmObjFixup *fixups)
{
    /* if we don't already have an extension, allocate one */
    if (ext_ == 0)
        ext_ = (char *)G_mem->get_var_heap()
               ->alloc_mem(sizeof(vmobj_pat_ext), this);

    /* read the source string reference */
    char buf[VMB_DATAHOLDER];
    fp->read_bytes(buf, VMB_DATAHOLDER);

    /* fix it up */
    fixups->fix_dh(vmg_ buf);

    /* remember it in our extension */
    vmb_get_dh(buf, &get_ext()->str);

    /* 
     *   clear out our pattern and request post-load initialization - we
     *   can't necessarily compile it yet, because we might not have loaded
     *   the source string data, so just make a note that we need to compile
     *   it the next time we need it 
     */
    set_pattern(0);
    G_obj_table->request_post_load_init(self);
}

/* ------------------------------------------------------------------------ */
/* 
 *   property evaluator - get my original string 
 */
int CVmObjPattern::getp_get_str(VMG_ vm_obj_id_t self,
                                vm_val_t *retval, uint *argc)
{
    static CVmNativeCodeDesc desc(0);

    /* check arguments */
    if (get_prop_check_argc(retval, argc, &desc))
        return TRUE;

    /* retrieve my original string value */
    *retval = *get_orig_str();

    /* handled */
    return TRUE;
}