cfad47cfa3/tads3/vmbif.cpp
Commiter: Nikos Chantziaras
Author: Nikos Chantziaras
Revision: cfad47cfa3
File Size: 15.3 KB
(June 01, 2009 20:54 UTC) Almost 3 years ago
Initial commit.
#ifdef RCSID
static char RCSid[] =
"$Header: d:/cvsroot/tads/tads3/vmbif.cpp,v 1.3 1999/07/11 00:46:59 MJRoberts Exp $";
#endif
/*
* Copyright (c) 1998, 2002 Michael J. Roberts. All Rights Reserved.
*
* Please see the accompanying license file, LICENSE.TXT, for information
* on using and copying this software.
*/
/*
Name
vmbif.cpp - built-in function set table implementation
Function
Notes
Modified
12/05/98 MJRoberts - Creation
*/
#include <stdlib.h>
#include <string.h>
#include "t3std.h"
#include "utf8.h"
#include "charmap.h"
#include "vmtype.h"
#include "vmerr.h"
#include "vmerrnum.h"
#include "vmglob.h"
#include "vmbif.h"
#include "vmbifreg.h"
#include "vmstr.h"
#include "vmobj.h"
#include "vmrun.h"
/* ------------------------------------------------------------------------ */
/*
* Create the function set table with a given number of initial entries
*/
CVmBifTable::CVmBifTable(size_t init_entries)
{
/* allocate space for our entries */
if (init_entries != 0)
{
/* allocate the space */
table_ = (vm_bif_entry_t **)
t3malloc(init_entries * sizeof(table_[0]));
names_ = (char **)
t3malloc(init_entries * sizeof(names_[0]));
}
else
{
/* we have no entries */
table_ = 0;
names_ = 0;
}
/* no entries are defined yet */
count_ = 0;
/* remember the allocation size */
alloc_ = init_entries;
}
/* ------------------------------------------------------------------------ */
/*
* Delete the table
*/
CVmBifTable::~CVmBifTable()
{
/* free the table, if we ever allocated one */
if (table_ != 0)
t3free(table_);
/* free the function set names list, if we allocated it */
if (names_ != 0)
{
/* clear the table to delete the entries in the 'names_' array */
clear();
/* free the table */
t3free(names_);
}
}
/* ------------------------------------------------------------------------ */
/*
* Clear all entries from the table
*/
void CVmBifTable::clear()
{
/* delete the 'names' entries, if we allocated any */
if (names_ != 0)
{
size_t i;
/* free each element */
for (i = 0 ; i < count_ ; ++i)
lib_free_str(names_[i]);
}
/*
* Reset the entry counter. Note that this doesn't affect any
* allocation; we keep a separate count of the number of table slots
* we have allocated. Table slots don't have any additional
* associated memory, so we don't need to worry about cleaning
* anything up at this point.
*/
count_ = 0;
}
/* ------------------------------------------------------------------------ */
/*
* Ensure that we have space for a given number of entries
*/
void CVmBifTable::ensure_space(size_t entries, size_t increment)
{
/* if we don't have enough space, allocate more */
if (entries >= alloc_)
{
size_t new_table_size;
size_t new_names_size;
/* increase the allocation size by the given increment */
alloc_ += increment;
/* if it's still too small, bump it up to the required size */
if (alloc_ < entries)
alloc_ = entries;
/* compute the new sizes */
new_table_size = alloc_ * sizeof(table_[0]);
new_names_size = alloc_ * sizeof(names_[0]);
/*
* if we have a table already, reallocate it at the larger size;
* otherwise, allocate a new table
*/
if (table_ != 0)
{
table_ = (vm_bif_entry_t **)t3realloc(table_, new_table_size);
names_ = (char **)t3realloc(names_, new_names_size);
}
else
{
table_ = (vm_bif_entry_t **)t3malloc(new_table_size);
names_ = (char **)t3malloc(alloc_ * new_names_size);
}
}
}
/* ------------------------------------------------------------------------ */
/*
* Add an entry to the table
*/
void CVmBifTable::add_entry(const char *func_set_id)
{
vm_bif_entry_t *entry;
const char *vsn;
size_t name_len;
/* ensure we have space for one more entry */
ensure_space(count_ + 1, 5);
/* find the version suffix in the name, if any */
vsn = lib_find_vsn_suffix(func_set_id, '/', "000000", &name_len);
/* look up the function set by name */
for (entry = G_bif_reg_table ; entry->func_set_id != 0 ; ++entry)
{
const char *entry_vsn;
size_t entry_name_len;
/* find the version number in this entry */
entry_vsn = lib_find_vsn_suffix(entry->func_set_id, '/', "000000",
&entry_name_len);
/* see if this is a match */
if (name_len == entry_name_len
&& memcmp(func_set_id, entry->func_set_id, name_len) == 0)
{
/*
* make sure the version provided in the VM is at least as
* high as the requested version
*/
if (strcmp(vsn, entry_vsn) > 0)
err_throw_a(VMERR_FUNCSET_TOO_OLD, 2,
ERR_TYPE_TEXTCHAR, func_set_id,
ERR_TYPE_TEXTCHAR, entry_vsn);
/*
* It's a match - add the new entry. Simply keep a pointer
* to the static table entry.
*/
table_[count_] = entry;
/* store the new name element as well */
names_[count_] = lib_copy_str(func_set_id);
/* count the new entry */
++count_;
/* we're done */
return;
}
}
/* we didn't find it - handle it according to our resolution mode */
add_entry_unresolved(func_set_id);
}
/* ------------------------------------------------------------------------ */
/*
* Function Set helper functions
*/
/*
* check arguments; throws an error if the argument count doesn't match
* the given value
*/
void CVmBif::check_argc(VMG_ uint argc, uint needed_argc)
{
if (argc != needed_argc)
err_throw(VMERR_WRONG_NUM_OF_ARGS);
}
/*
* check arguments; throws an error if the argument count is outside of
* the given range
*/
void CVmBif::check_argc_range(VMG_ uint argc, uint argc_min, uint argc_max)
{
if (argc < argc_min || argc > argc_max)
err_throw(VMERR_WRONG_NUM_OF_ARGS);
}
/*
* return a string value
*/
void CVmBif::retval_str(VMG_ const char *str)
{
retval_str(vmg_ str, strlen(str));
}
void CVmBif::retval_str(VMG_ const char *str, size_t len)
{
vm_obj_id_t str_obj;
/* create a string to hold the return value */
str_obj = CVmObjString::create(vmg_ FALSE, str, len);
/* return the string */
retval_obj(vmg_ str_obj);
}
/*
* return a string value that came from the UI character set
*/
void CVmBif::retval_ui_str(VMG_ const char *str)
{
retval_ui_str(vmg_ str, strlen(str));
}
void CVmBif::retval_ui_str(VMG_ const char *str, size_t len)
{
/* make a string object from the UI string, and return it */
retval_obj(vmg_ str_from_ui_str(vmg_ str, len));
}
/*
* create a new string object from a string in the UI character set
*/
vm_obj_id_t CVmBif::str_from_ui_str(VMG_ const char *str)
{
return str_from_ui_str(vmg_ str, strlen(str));
}
vm_obj_id_t CVmBif::str_from_ui_str(VMG_ const char *str, size_t len)
{
char *outp;
size_t outlen;
vm_obj_id_t str_id;
CVmObjString *str_obj;
/* figure out how much space we need */
outp = 0;
outlen = 0;
outlen = G_cmap_from_ui->map(0, &outlen, str, len);
/* allocate a string of that size */
str_id = CVmObjString::create(vmg_ FALSE, outlen);
str_obj = (CVmObjString *)vm_objp(vmg_ str_id);
/* map the string into the new string buffer */
outp = str_obj->cons_get_buf();
G_cmap_from_ui->map(&outp, &outlen, str, len);
/* return the new string object */
return str_id;
}
/*
* return an object value
*/
void CVmBif::retval_obj(VMG_ vm_obj_id_t obj)
{
if (obj == VM_INVALID_OBJ)
G_interpreter->get_r0()->set_nil();
else
G_interpreter->get_r0()->set_obj(obj);
}
/*
* return a property value
*/
void CVmBif::retval_prop(VMG_ vm_prop_id_t prop)
{
G_interpreter->get_r0()->set_propid(prop);
}
/*
* return an integer value
*/
void CVmBif::retval_int(VMG_ long val)
{
G_interpreter->get_r0()->set_int(val);
}
/*
* return true
*/
void CVmBif::retval_true(VMG0_)
{
G_interpreter->get_r0()->set_true();
}
/*
* return nil
*/
void CVmBif::retval_nil(VMG0_)
{
G_interpreter->get_r0()->set_nil();
}
/*
* return a boolean value - nil if false, true if true
*/
void CVmBif::retval_bool(VMG_ int val)
{
G_interpreter->get_r0()->set_logical(val);
}
/*
* return a function pointer value
*/
void CVmBif::retval_fnptr(VMG_ pool_ofs_t ofs)
{
G_interpreter->get_r0()->set_fnptr(ofs);
}
/*
* return a value
*/
void CVmBif::retval(VMG_ const vm_val_t *val)
{
*G_interpreter->get_r0() = *val;
}
/* ------------------------------------------------------------------------ */
/*
* Pop a string value
*/
const char *CVmBif::pop_str_val(VMG0_)
{
vm_val_t val;
CVmObject *obj;
const char *p;
/* pop the value */
G_stk->pop(&val);
/* see what we have */
switch(val.typ)
{
case VM_SSTRING:
/* it's a constant string - get the constant pool pointer */
return G_const_pool->get_ptr(val.val.ofs);
case VM_OBJ:
/* get the object */
obj = vm_objp(vmg_ val.val.obj);
/* get the string value, if it has one */
p = obj->get_as_string(vmg0_);
/* if it has a string value, return it */
if (p != 0)
return p;
/* we didn't get a string value */
break;
default:
/* other types don't have a string value */
break;
}
/* if we got here, the value isn't a string */
err_throw(VMERR_STRING_VAL_REQD);
AFTER_ERR_THROW(return 0;)
}
/* ------------------------------------------------------------------------ */
/*
* Pop a list value
*/
const char *CVmBif::pop_list_val(VMG0_)
{
vm_val_t val;
CVmObject *obj;
const char *p;
/* pop the value */
G_stk->pop(&val);
/* see what we have */
switch(val.typ)
{
case VM_LIST:
/* it's a constant list - get the constant pool pointer */
return G_const_pool->get_ptr(val.val.ofs);
case VM_OBJ:
/* get the object */
obj = vm_objp(vmg_ val.val.obj);
/* get the list value, if it has one */
p = obj->get_as_list();
/* if it has a liist value, return it */
if (p != 0)
return p;
/* we didn't get a list value */
break;
default:
/* other types don't have a list value */
break;
}
/* if we got here, the value isn't a list */
err_throw(VMERR_LIST_VAL_REQD);
AFTER_ERR_THROW(return 0;)
}
/* ------------------------------------------------------------------------ */
/*
* Pop a string into a buffer, and null-terminate the result.
*/
void CVmBif::pop_str_val_buf(VMG_ char *buf, size_t buflen)
{
const char *strp;
size_t copy_len;
/* pop the string value */
strp = pop_str_val(vmg0_);
/*
* get the length, but limit it to our buffer size, less one byte
* for null termination
*/
copy_len = vmb_get_len(strp);
if (copy_len > buflen - 1)
copy_len = utf8_ptr::s_trunc(strp + VMB_LEN, buflen - 1);
/* copy the string */
memcpy(buf, strp + VMB_LEN, copy_len);
/* null-terminate the result */
buf[copy_len] = '\0';
}
/* ------------------------------------------------------------------------ */
/*
* Pop a string into a buffer, translating the string into the filename
* character set and null-terminating the result.
*/
void CVmBif::pop_str_val_fname(VMG_ char *buf, size_t buflen)
{
const char *strp;
size_t copy_len;
/* pop the string value */
strp = pop_str_val(vmg0_);
/* get the length */
copy_len = vmb_get_len(strp);
/*
* map it into the local filename character set and store the result
* in the output buffer - reserve one byte for the null termination
* byte
*/
copy_len = G_cmap_to_fname->map_utf8(buf, buflen - 1,
strp + VMB_LEN, copy_len, 0);
/* null-terminate the result */
buf[copy_len] = '\0';
}
/*
* Pop a string into a buffer, translating the string into the user
* interface character set and null-terminating the result.
*/
char *CVmBif::pop_str_val_ui(VMG_ char *buf, size_t buflen)
{
const char *strp;
size_t copy_len;
/* pop the string value */
strp = pop_str_val(vmg0_);
/* get the length */
copy_len = vmb_get_len(strp);
/*
* if they didn't allocate any space for the buffer, allocate one on
* the caller's behalf
*/
if (buflen == 0)
{
/* figure out how much space we need */
buflen = G_cmap_to_ui->map_utf8(0, 0, strp + VMB_LEN, copy_len, 0);
/* add space for null termination */
buflen += 1;
/* allocate the buffer */
buf = (char *)t3malloc(buflen);
/* if that failed, return null */
if (buf == 0)
return 0;
}
/*
* map it into the local UI character set and store the result in
* the output buffer - reserve one byte for the null termination
* byte
*/
copy_len = G_cmap_to_ui->map_utf8(buf, buflen - 1,
strp + VMB_LEN, copy_len, 0);
/* null-terminate the result */
buf[copy_len] = '\0';
/* return the buffer */
return buf;
}
/* ------------------------------------------------------------------------ */
/*
* Pop an integer value
*/
int CVmBif::pop_int_val(VMG0_)
{
vm_val_t val;
/* pop a number */
G_interpreter->pop_int(vmg_ &val);
/* return the value */
return (int)val.val.intval;
}
/*
* Pop a long integer value
*/
int CVmBif::pop_long_val(VMG0_)
{
vm_val_t val;
/* pop a number */
G_interpreter->pop_int(vmg_ &val);
/* return the value */
return val.val.intval;
}
/*
* Pop a true/nil logical value
*/
int CVmBif::pop_bool_val(VMG0_)
{
vm_val_t val;
/* pop a value */
G_stk->pop(&val);
/* check the type */
switch(val.typ)
{
case VM_NIL:
/* nil - interpret this as false */
return FALSE;
case VM_TRUE:
/* true */
return TRUE;
case VM_INT:
/* integer - return true if it's nonzero */
return (val.val.intval != 0);
default:
/* anything else is unacceptable */
err_throw(VMERR_BAD_TYPE_BIF);
/*
* (for the compiler's benefit, which doesn't know err_throw
* doesn't return and thus might want to warn about our failure to
* return a value)
*/
AFTER_ERR_THROW(return FALSE;)
}
}
/*
* Pop an object reference value
*/
vm_obj_id_t CVmBif::pop_obj_val(VMG0_)
{
vm_val_t val;
/* pop an object reference */
G_interpreter->pop_obj(vmg_ &val);
/* return the value */
return val.val.obj;
}
/*
* Pop a property ID value
*/
vm_prop_id_t CVmBif::pop_propid_val(VMG0_)
{
vm_val_t val;
/* pop a property ID */
G_interpreter->pop_prop(vmg_ &val);
/* return the value */
return val.val.prop;
}
|