Ejemplo n.º 1
0
/* create a payload item consisting of a simple name/value pair */
OS_HttpPayloadItem::OS_HttpPayloadItem(const char *name, size_t name_len,
                                       const char *val, size_t val_len)
{
    init();
    this->name = lib_copy_str(name, name_len);
    this->val = lib_copy_str(val, val_len);
}
Ejemplo n.º 2
0
/* create a payload item for a PUT/POST file upload */
OS_HttpPayloadItem::OS_HttpPayloadItem(
    const char *name, const char *filename,
    const char *mime_type, CVmDataSource *contents)
{
    init();
    this->name = lib_copy_str(name);
    this->val = lib_copy_str(filename != 0 ? filename : "");
    this->mime_type = lib_copy_str(mime_type != 0 ? mime_type : "");
    this->stream = contents;
}
Ejemplo n.º 3
0
/*
 *   initialize 
 */
CVmHostIfcStdio::CVmHostIfcStdio(const char *argv0)
{
    char buf[OSFNMAX];

    /* remember the program's argv[0], in case we need it later */
    argv0_ = lib_copy_str(argv0);

    /* 
     *   Create the resource loader for system resources (character mapping
     *   files, etc) in the same directory as the executable. 
     */
    os_get_special_path(buf, sizeof(buf), argv0, OS_GSP_T3_RES);
    sys_res_loader_ = new CResLoader(buf);

    /* set the executable filename in the loader, if available */
    if (os_get_exe_filename(buf, sizeof(buf), argv0))
        sys_res_loader_->set_exe_filename(buf);

    /* 
     *   the default safety level allows reading and writing to the current
     *   directory only 
     */
    io_safety_read_ = VM_IO_SAFETY_READWRITE_CUR;
    io_safety_write_ = VM_IO_SAFETY_READWRITE_CUR;
    net_client_safety_ = VM_NET_SAFETY_LOCALHOST;
    net_server_safety_ = VM_NET_SAFETY_LOCALHOST;
}
Ejemplo n.º 4
0
/*
 *   create a resource loader given a root directory 
 */
CResLoader::CResLoader(const char *root_dir)
{
    /* remember the root directory for file searches */
    root_dir_ = lib_copy_str(root_dir);

    /* no executable path yet */
    exe_filename_ = 0;
}
Ejemplo n.º 5
0
/*
 *   Instantiate.  We'll note the name of the library, but we don't attempt
 *   to open it at this point - we won't open the file until parse_lib() is
 *   called.  
 */
CTcLibParser::CTcLibParser(const char *lib_name)
{
    char lib_path[OSFNMAX];

    /* 
     *   Extract the library's directory path.  Since files within a library
     *   are always relative to the directory containing the library itself,
     *   we use the full path to the library as the starting point for each
     *   file found within the library.  
     */
    os_get_path_name(lib_path, sizeof(lib_path), lib_name);

    /* remember the library path */
    lib_path_ = lib_copy_str(lib_path);

    /* remember the name of the library */
    lib_name_ = lib_copy_str(lib_name);

    /* no errors yet */
    err_cnt_ = 0;

    /* no lines read yet */
    linenum_ = 0;
}
Ejemplo n.º 6
0
/*
 *   Handle adding a function set entry that's unresolvable at load-time 
 */
void CVmBifTable::add_entry_unresolved(VMG_ const char *func_set_id)
{
    /*
     *   Since this is the call-time resolver, allow loading of the image
     *   file even though this function set is unresolved.  Store a null
     *   entry in the function set table, and store the name of the
     *   function set - we'll need this in case the program attempts to
     *   invoke a function in this function set, so that we can generate
     *   an error containing the unresolved function set name. 
     */
    table_[count_] = 0;
    names_[count_] = lib_copy_str(func_set_id);

    /* count the new entry */
    ++count_;
}
Ejemplo n.º 7
0
/*
 *   Internal get-port interface
 */
int CVmObjHTTPServer::get_listener_addr(
    char *&addr, char *&ip, int &port) const
{
    /* if we have a listener, get its port number */
    vm_httpsrv_ext *ext = get_ext();
    if (ext != 0 && ext->l != 0 && ext->addr != 0
        && ext->l->get_thread()->get_local_addr(ip, port))
    {
        /* got the IP and port - also return the constructor address string */
        addr = lib_copy_str(ext->addr);
        return TRUE;
    }
    else
    {
        /* the address isn't available */
        return FALSE;
    }
}
Ejemplo n.º 8
0
    /* add a resource link */
    void add_resource(const char *fname, size_t fnamelen,
                      const char *res_name, size_t res_name_len)
    {
        /* 
         *   if we've already found a match, there's no need to consider
         *   anything else 
         */
        if (found_)
            return;

        /* check to see if this is the one we're looking for */
        if (res_name_len == respath_len_
            && memicmp(respath_, res_name, res_name_len) == 0)
        {
            /* we found it */
            found_ = TRUE;

            /* remember the link */
            link_ = lib_copy_str(fname, fnamelen);
        }
    }
Ejemplo n.º 9
0
/*
 *   Connect to the Web UI
 */
void CVmBifNet::connect_ui(VMG_ uint oargc)
{
    /* check arguments */
    check_argc(vmg_ oargc, 2);

    /* get the server object */
    vm_val_t *srv = G_stk->get(0);
    if (srv->typ != VM_OBJ
        || !CVmObjHTTPServer::is_httpsrv_obj(vmg_ srv->val.obj))
        err_throw(VMERR_BAD_TYPE_BIF);

    /* get the object pointer properly cast */
    CVmObjHTTPServer *srvp = (CVmObjHTTPServer *)vm_objp(vmg_ srv->val.obj);

    /* get the URL path */
    const char *path = G_stk->get(1)->get_as_string(vmg0_);
    if (path == 0)
        err_throw(VMERR_BAD_TYPE_BIF);

    /* make a null-terminated copy of the path */
    char *pathb = lib_copy_str(path + VMB_LEN, vmb_get_len(path));

    /* get the server network address information */
    char *errmsg = 0;
    char *addr = 0, *ip = 0;
    int port;
    int ok = srvp->get_listener_addr(addr, ip, port);

    /* 
     *   If we don't have a network configuration yet, create one.  This
     *   notifies other subsystems that we have an active web UI; for
     *   example, the presence of a network UI disables the regular console
     *   UI, since all UI actions have to go through the web UI once it's
     *   established.
     *   
     *   The interpreter startup creates a network configuration if it
     *   receives command-line information telling it that the game was
     *   launched by a Web server in response to an incoming client request.
     *   When the user launches the game in stand-alone mode directly from
     *   the operating system shell, there's no Web server launch
     *   information, so the startup code doesn't create a net config object.
     *   So, if we get here and find we don't have this object, it means that
     *   we're running in local standalone mode.  
     */
    if (G_net_config == 0)
        G_net_config = new TadsNetConfig();

    /* connect */
    if (ok)
    {
        /* connect */
        ok = osnet_connect_webui(vmg_ addr, port, pathb, &errmsg);
    }
    else
    {
        /* couldn't get the server address */
        errmsg = lib_copy_str(
            "No address information available for HTTPServer");
    }

    /* free strings */
    lib_free_str(pathb);
    lib_free_str(addr);
    lib_free_str(ip);

    /* if there's an error, throw it */
    if (!ok)
    {
        G_interpreter->push_string(vmg_ errmsg);
        lib_free_str(errmsg);
        G_interpreter->throw_new_class(vmg_ G_predef->net_exception, 1,
                                       "Error connecting to Web UI");
    }

    /* no return value */
    retval_nil(vmg0_);
}
Ejemplo n.º 10
0
    /* 
     *   Set up the thread.  All string parameters are provided in internal
     *   string format, with VMB_LEN length prefixes.  
     */
    HttpReqThread(VMG_ const vm_val_t *id, const char *url,
                  const char *verb, int32 options,
                  const char *hdrs, vm_val_t *body, const char *body_type,
                  const vm_rcdesc *rc)
    {
        /* save the VM globals */
        vmg = VMGLOB_ADDR;

        /* add a reference on the net event queue */
        if ((queue = G_net_queue) != 0)
            queue->add_ref();

        /* create a global for the ID value */
        idg = G_obj_table->create_global_var();
        idg->val = *id;

        /* save the option flags */
        this->options = options;

        /* set up to parse the URL */
        size_t urll = vmb_get_len(url);
        url += VMB_LEN;

        /* note whether the scheme is plain http or https */
        https = (urll >= 8 && memcmp(url, "https://", 8) == 0);

        /* we don't have any URL pieces yet */
        host = 0;
        resource = 0;
        port = (https ? 443 : 80);

        /* skip the scheme prefix */
        size_t pfx = (urll >= 7 && memcmp(url, "http://", 7) == 0 ? 7 :
                      urll >= 8 && memcmp(url, "https://", 8) == 0 ? 8 : 0);
        url += pfx, urll -= pfx;

        /* the host name is the part up to the ':', '/', or end of string */
        const char *start;
        for (start = url ; urll > 0 && *url != ':' && *url != '/' ;
             ++url, --urll) ;

        /* save the host name */
        host = lib_copy_str(start, url - start);

        /* parse the port, if present */
        if (urll > 0 && *url == ':')
        {
            /* parse the port number string */
            for (--urll, start = ++url, port = 0 ; urll > 0 && *url != '/' ;
                 ++url, --urll)
            {
                if (is_digit(*url))
                    port = port*10 + value_of_digit(*url);
            }
        }

        /* 
         *   The rest (including the '/') is the resource string.  If there's
         *   nothing left, the resource is implicitly '/'. 
         */
        if (urll > 0)
            resource = lib_copy_str(url, urll);
        else
            resource = lib_copy_str("/");

        /* make null-terminated copies of the various strings */
        this->verb = lib_copy_str(verb + VMB_LEN, vmb_get_len(verb));
        this->hdrs = (hdrs == 0 ? 0 :
                      lib_copy_str(hdrs + VMB_LEN, vmb_get_len(hdrs)));

        /* if there's a content body, set up the payload */
        this->body = 0;
        if (body != 0)
        {
            /* set up an empty payload */
            this->body = new OS_HttpPayload();
            
            /* 
             *   Convert the body to a stream payload, if it's a string or
             *   ByteArray.  If it's a LookupTable, it's a set of form
             *   fields.
             */
            if (body->typ == VM_OBJ
                && CVmObjLookupTable::is_lookup_table_obj(vmg_ body->val.obj))
            {
                /* 
                 *   The body is a LookupTable, so we have a set of form
                 *   fields to encode as HTML form data. 
                 */
                
                /* cast the object value */
                CVmObjLookupTable *tab =
                    (CVmObjLookupTable *)vm_objp(vmg_ body->val.obj);
                
                /* add each key in the table as a form field */
                iter_body_table_ctx ctx(this, rc);
                tab->for_each(vmg_ iter_body_table, &ctx);
            }
            else
            {
                /* 
                 *   It's not a lookup table, so it must be bytes to upload,
                 *   as a string or ByteArray.
                 */
                const char *def_mime_type = 0;
                CVmStream *stream = val_to_stream(vmg_ body, &def_mime_type);
                
                /* presume we're going to use the default mime type */
                const char *mime_type = def_mime_type;
                size_t mime_type_len =
                    (mime_type != 0 ? strlen(mime_type) : 0);

                /* if the caller specified a mime type, use it instead */
                if (body_type != 0)
                {
                    mime_type = body_type + VMB_LEN;
                    mime_type_len = vmb_get_len(body_type);
                }
                
                /* add the stream */
                this->body->add(
                    "", 0, "", 0, mime_type, mime_type_len, stream);
            }
        }
    }
Ejemplo n.º 11
0
/*
 *   create dynamically using stack arguments 
 */
vm_obj_id_t CVmObjHTTPServer::create_from_stack(
    VMG_ const uchar **pc_ptr, uint argc)
{
    vm_obj_id_t id;
    const char *errmsg;

    /* 
     *   parse arguments - new HTTPServer(addr?, port?) 
     */
    if (argc > 3)
        err_throw(VMERR_WRONG_NUM_OF_ARGS);

    /* check for the address - use "localhost" by default */
    char addr[256] = "localhost";
    if (argc >= 1)
    {
        /* get the address - this must be a string or nil */
        if (G_stk->get(0)->typ == VM_NIL)
            G_stk->discard();
        else
            CVmBif::pop_str_val_buf(vmg_ addr, sizeof(addr));
    }

    /* check for a port - use 0 by default */
    int port = 0;
    if (argc >= 2)
    {
        /* get the port number - this must be an integer or nil */
        if (G_stk->get(0)->typ == VM_NIL)
            G_stk->discard();
        else
            port = CVmBif::pop_int_val(vmg0_);
    }

    /* check for an upload size limit */
    int32_t ulim;
    if (argc >= 3)
    {
        if (G_stk->get(0)->typ == VM_NIL)
            G_stk->discard();
        else
            ulim = CVmBif::pop_long_val(vmg0_);
    }

    /* get the network safety level, to determine if this is allowed */
    int client_level, server_level;
    G_host_ifc->get_net_safety(&client_level, &server_level);

    /* check the network server safety level */
    switch (server_level)
    {
    case VM_NET_SAFETY_MINIMUM:
        /* all access allowed - proceed */
        break;

    case VM_NET_SAFETY_LOCALHOST:
        /* 
         *   localhost only - if the host isn't 'localhost' or '127.0.0.1',
         *   don't allow it 
         */
        if (stricmp(addr, "localhost") != 0
            && stricmp(addr, "127.0.0.1") != 0)
            goto access_error;

        /* allow it */
        break;

    case VM_NET_SAFETY_MAXIMUM:
    access_error:
        /* no access allowed */
        errmsg = "prohibited network access";
        G_interpreter->push_string(vmg_ errmsg);
        G_interpreter->throw_new_class(vmg_ G_predef->net_safety_exception,
                                       1, errmsg);
        AFTER_ERR_THROW(break;)
    }

    /* 
     *   allocate the object ID - this type of construction never creates a
     *   root object 
     */
    id = vm_new_id(vmg_ FALSE, FALSE, FALSE);

    /* http servers are inherently transient */
    G_obj_table->set_obj_transient(id);

    /* create the object */
    CVmObjHTTPServer *l = new (vmg_ id) CVmObjHTTPServer(vmg_ TRUE);

    /* get the extension */
    vm_httpsrv_ext *ext = l->get_ext();

    /* create the listener thread object */
    TadsHttpListenerThread *ht = new TadsHttpListenerThread(
        id, G_net_queue, ulim);

    /* launch the listener */
    ext->l = TadsListener::launch(addr, (ushort)port, ht);

    /* we're done with the thread object (the listener took it over) */
    ht->release_ref();

    /* if the launch failed, throw an error */
    if (ext->l == 0)
    {
        /* throw a network error */
        const char *errmsg = "Unable to start HTTP server";
        G_interpreter->push_string(vmg_ errmsg);
        G_interpreter->throw_new_class(vmg_ G_predef->net_exception, 1, errmsg);
    }

    /* remember my requested binding address */
    ext->addr = lib_copy_str(addr);

    /* return the new ID */
    return id;
}
Ejemplo n.º 12
0
 url_param_alo * operator =(const url_param &src)
 {
     name = lib_copy_str(src.name);
     val = lib_copy_str(src.val);
     return this;
 }
Ejemplo n.º 13
0
/* create a payload item consisting of a simple name/value pair */
OS_HttpPayloadItem::OS_HttpPayloadItem(const char *name, const char *val)
{
    init();
    this->name = lib_copy_str(name);
    this->val = lib_copy_str(val != 0 ? val : "");
}
Ejemplo n.º 14
0
/*
 *   allocate and copy a null-terminated string 
 */
char *lib_copy_str(const char *str)
{
    return (str == 0 ? 0 : lib_copy_str(str, strlen(str)));
}
Ejemplo n.º 15
0
/*
 *   Perform base initialization.  This is an internal routine called only
 *   by higher-level initialization routines; we perform all of the
 *   generic, configuration-independent initialization.
 */
void vm_init_base(vm_globals **vmg, const vm_init_options *opts)
{
    vm_globals *vmg__;
    char disp_mapname[32];
    char filename_mapname[32];
    char filecont_mapname[32];
    CResLoader *map_loader;
    int disp_map_err;
    const char *charset = opts->charset;
    
    /* 
     *   Allocate globals according to build-time configuration, then
     *   assign the global pointer to a local named vmg__.  This will
     *   ensure that the globals are accessible for all of the different
     *   build-time configurations.  
     */
    vmg__ = *vmg = vmglob_alloc();

    /* initialize the error stack */
    err_init(VM_ERR_STACK_BYTES);

    /* get the character map loader from the host interface */
    map_loader = opts->hostifc->get_cmap_res_loader();

    /* if an external message set hasn't been loaded, try loading one */
    if (!err_is_message_file_loaded() && map_loader != 0)
    {
        osfildef *fp;
        
        /* try finding a message file */
        fp = map_loader->open_res_file(VM_ERR_MSG_FNAME, 0,
                                       VM_ERR_MSG_RESTYPE);
        if (fp != 0)
        {
            /* 
             *   try loading it - if that fails, we'll just be left with
             *   the built-in messages, so we won't have lost anything for
             *   trying 
             */
            err_load_vm_message_file(fp);
            
            /* we're done with the file */
            osfcls(fp);
        }
    }

    /* remember the host interface */
    G_host_ifc = opts->hostifc;

    /* initialize the system debug log file name */
    char path[OSFNMAX];
    opts->hostifc->get_special_file_path(path, sizeof(path), OS_GSP_LOGFILE);
    os_build_full_path(G_syslogfile, sizeof(G_syslogfile),
                       path, "tadslog.txt");

    /* we don't have a resource loader for program resources yet */
    G_res_loader = 0;

    /* create the object table */
    VM_IF_ALLOC_PRE_GLOBAL(G_obj_table = new CVmObjTable());
    G_obj_table->init(vmg0_);

    /* 
     *   Create the memory manager.  Empirically, our hybrid heap allocator
     *   is faster than the standard C++ run-time library's allocator on many
     *   platforms, so use it instead of hte basic 'malloc' allocator. 
     */
    G_varheap = new CVmVarHeapHybrid(G_obj_table);
    // G_varheap = new CVmVarHeapMalloc(); to use the system 'malloc' instead
    G_mem = new CVmMemory(vmg_ G_varheap);

    /* create the undo manager */
    G_undo = new CVmUndo(VM_UNDO_MAX_RECORDS, VM_UNDO_MAX_SAVEPTS);

    /* create the metafile and function set tables */
    G_meta_table = new CVmMetaTable(5);
    G_bif_table = new CVmBifTable(5);

    /* initialize the metaclass registration tables */
    vm_register_metaclasses();

    /* initialize the TadsObject class */
    CVmObjTads::class_init(vmg0_);

    /* create the byte-code interpreter */
    VM_IFELSE_ALLOC_PRE_GLOBAL(
        G_interpreter = new CVmRun(VM_STACK_SIZE, vm_init_stack_reserve()),
        G_interpreter->init());

    /* presume we won't create debugger information */
    G_debugger = 0;
    G_srcf_table = 0;

    /* presume we don't have a network configuration */
    G_net_config = 0;

    /* initialize the debugger if present */
    vm_init_debugger(vmg0_);

    /* create the source file table */
    G_srcf_table = new CVmSrcfTable();

    /* create the pre-defined object mapper */
    VM_IFELSE_ALLOC_PRE_GLOBAL(G_predef = new CVmPredef, G_predef->reset());

    /* presume we're in normal execution mode (not preinit) */
    G_preinit_mode = FALSE;

    /* allocate the TADS intrinsic function set's globals */
    G_bif_tads_globals = new CVmBifTADSGlobals(vmg0_);

    /* allocate the BigNumber register cache */
    G_bignum_cache = new CVmBigNumCache(32);

    /* no image loader yet */
    G_image_loader = 0;

    /*
     *   If the caller explicitly specified a character set, use it.
     *   Otherwise, ask the OS layer for the default character set we
     *   should use. 
     */
    if (charset == 0)
    {
        /* the user did not specify a mapping - ask the OS for the default */
        os_get_charmap(disp_mapname, OS_CHARMAP_DISPLAY);

        /* use the name we got from the OS */
        charset = disp_mapname;

        /* there's no explicit global character set name setting to store */
        G_disp_cset_name = 0;
    }
    else
    {
        /* save the global character set name */
        G_disp_cset_name = lib_copy_str(charset);
    }

    /* create the display character maps */
    G_cmap_from_ui = CCharmapToUni::load(map_loader, charset);
    G_cmap_to_ui = CCharmapToLocal::load(map_loader, charset);

    /* create the filename character maps */
    os_get_charmap(filename_mapname, OS_CHARMAP_FILENAME);
    G_cmap_from_fname = CCharmapToUni::load(map_loader, filename_mapname);
    G_cmap_to_fname = CCharmapToLocal::load(map_loader, filename_mapname);

    /* create the file-contents character maps */
    os_get_charmap(filecont_mapname, OS_CHARMAP_FILECONTENTS);
    G_cmap_from_file = CCharmapToUni::load(map_loader, filecont_mapname);
    G_cmap_to_file = CCharmapToLocal::load(map_loader, filecont_mapname);

    /* 
     *   If the caller specified a separate log-file character set, create
     *   the mapping.  Otherwise, just use the to-file mapper for log files.
     */
    if (opts->log_charset != 0)
    {
        /* load the specified log file output mapping */
        G_cmap_to_log = CCharmapToLocal::load(map_loader, opts->log_charset);
    }
    else
    {
        /* no log file mapping is specified, so use the generic file map */
        if ((G_cmap_to_log = G_cmap_to_file) != 0)
            G_cmap_to_log->add_ref();
    }

    /* make a note of whether we had any problems loading the maps */
    disp_map_err = (G_cmap_from_ui == 0 || G_cmap_to_ui == 0);

    /* if we failed to create any of the maps, load defaults */
    if (G_cmap_from_ui == 0)
        G_cmap_from_ui = CCharmapToUni::load(map_loader, "us-ascii");
    if (G_cmap_to_ui == 0)
        G_cmap_to_ui = CCharmapToLocal::load(map_loader, "us-ascii");
    if (G_cmap_from_fname == 0)
        G_cmap_from_fname = CCharmapToUni::load(map_loader, "us-ascii");
    if (G_cmap_to_fname == 0)
        G_cmap_to_fname = CCharmapToLocal::load(map_loader, "us-ascii");
    if (G_cmap_from_file == 0)
        G_cmap_from_file = CCharmapToUni::load(map_loader, "us-ascii");
    if (G_cmap_to_file == 0)
        G_cmap_to_file = CCharmapToLocal::load(map_loader, "us-ascii");
    if (G_cmap_to_log == 0)
        G_cmap_to_log = CCharmapToLocal::load(map_loader, "us-ascii");

    /* create the primary console */
    G_console = opts->clientifc->create_console(VMGLOB_ADDR);

    /* 
     *   if we had any trouble opening the display character mapping file,
     *   make a note that we are using a default mapping 
     */
    if (disp_map_err)
    {
        const char *msg;
        char buf[256];

        /* get the message */
        msg = err_get_msg(vm_messages, vm_message_count,
                          VMERR_NO_CHARMAP_FILE, TRUE);

        /* format it */
        sprintf(buf, msg, charset);

        /* display it */
        opts->clientifc->display_error(VMGLOB_ADDR, 0, buf, TRUE);
    }
}
Ejemplo n.º 16
0
/*
 *   set up the compiler 
 */
CTcMain::CTcMain(CResLoader *res_loader, const char *default_charset)
{
    char csbuf[OSFNMAX];
    
    /* 
     *   if the caller didn't provide a default character set, ask the OS
     *   what we should use
     */
    if (default_charset == 0)
    {
        /* 
         *   ask the OS what to use for file contents, since we use this
         *   character set to translate the text we read from source files 
         */
        os_get_charmap(csbuf, OS_CHARMAP_FILECONTENTS);
        
        /* use our OS-provided character set */
        default_charset = csbuf;
    }

    /* if there's no static console output character map, create one */
    if (console_mapper_ == 0)
    {
        char mapname[32];

        /* get the console character set name */
        os_get_charmap(mapname, OS_CHARMAP_DISPLAY);

        /* create a resource loader for the console character map */
        console_mapper_ = CCharmapToLocal::load(res_loader, mapname);

        /* if that failed, create an ASCII mapper */
        if (console_mapper_ == 0)
            console_mapper_ = CCharmapToLocal::load(res_loader, "us-ascii");
    }
    
    /* remember our resource loader */
    res_loader_ = res_loader;
    
    /* 
     *   set default options - minimum verbosity, no numeric error codes,
     *   show standard warnings but not pedantic warnings, not test mode 
     */
    err_options_ = TCMAIN_ERR_WARNINGS;

    /* we have no warning suppression list yet */
    suppress_list_ = 0;
    suppress_cnt_ = 0;

    /* remember our default character set */
    default_charset_ = lib_copy_str(default_charset);

    /* create the tokenizer */
    G_tok = new CTcTokenizer(res_loader_, default_charset_);
    
    /* 
     *   Create the parser and node memory pool.  Create the memory pool
     *   first, because the parser allocates objects out of the pool. 
     */
    G_prsmem = new CTcPrsMem();
    G_prs = new CTcParser();

    /* create the generator data stream (for constant data) */
    G_ds = new CTcDataStream(TCGEN_DATA_STREAM);

    /* create the primary generator code stream */
    G_cs_main = new CTcCodeStream(TCGEN_CODE_STREAM);

    /* create the static initializer code stream */
    G_cs_static = new CTcCodeStream(TCGEN_STATIC_CODE_STREAM);

    /* make the primary code stream active */
    G_cs = G_cs_main;

    /* create the generator object data stream */
    G_os = new CTcDataStream(TCGEN_OBJECT_STREAM);

    /* create the intrinsic class modifier object data stream */
    G_icmod_stream = new CTcDataStream(TCGEN_ICMOD_STREAM);

    /* create the dictionary object data stream */
    G_dict_stream = new CTcDataStream(TCGEN_DICT_STREAM);

    /* create the grammar-production object data stream */
    G_gramprod_stream = new CTcDataStream(TCGEN_GRAMPROD_STREAM);

    /* create the BigNumber object data stream */
    G_bignum_stream = new CTcDataStream(TCGEN_BIGNUM_STREAM);

    /* create the IntrinsicClass object data stream */
    G_int_class_stream = new CTcDataStream(TCGEN_INTCLASS_STREAM);

    /* create the static initializer identifier stream */
    G_static_init_id_stream = new CTcDataStream(TCGEN_STATIC_INIT_ID_STREAM);

    /* create the target-specific code generator */
    G_cg = new CTcGenTarg();

    /* initialize the parser */
    G_prs->init();

    /* no errors or warnings yet */
    error_count_ = 0;
    warning_count_ = 0;
    first_error_ = 0;
    first_warning_ = 0;

    /* set a fairly liberal maximum error limit */
    max_error_count_ = 100;

    /* there's no disassembly output stream yet */
    G_disasm_out = 0;
}
Ejemplo n.º 17
0
/*
 *   Get the storage server API reply code and message.  Returns an allocated
 *   buffer that the caller must free with t3free().  The first
 *   space-delimited token in the return buffer is the code, and the rest is
 *   the human-readable error message.  For HTTP or network errors, the code
 *   is simply the numeric error code (positive for HTTP status codes,
 *   negative for internal network errors), with no message text.  
 */
char *vmnet_get_storagesrv_stat(VMG_ int htmlstat, CVmDataSource *reply,
                                const char *headers)
{
    /* check the HTML status */
    if (htmlstat == 200)
    {
        /* 
         *   The HTML transaction succeeded - check the reply.  Start with
         *   the headers, if provided.
         */
        if (headers != 0)
        {
            /* find the X-IFDBStorage-Status header */
            for (const char *p = headers ; ; p += 2)
            {
                /* are we at our header? */
                if (memcmp(p, "X-IFDBStorage-Status:", 21) == 0)
                {
                    /* this is our header - skip spaces and get the value */
                    for (p += 21 ; isspace(*p) ; ++p) ;

                    /* find the end of the line or end of the headers */
                    const char *nl = strstr(p, "\r\n");
                    if (nl == 0)
                        nl = p + strlen(p);

                    /* return the message text */
                    return lib_copy_str(p, nl - p);
                }

                /* not our header - skip to the end of the line */
                p = strstr(p, "\r\n");
                if (p == 0)
                    break;
            }
        }

        /* 
         *   We didn't find the header, so check the reply body.  Read the
         *   first line of the reply, since this contains the result code.  
         */
        reply->seek(0, OSFSK_SET);
        char *txt = reply->read_line_alo();

        /* remove the trailing newline */
        size_t l;
        if ((l = strlen(txt)) != 0 && txt[l-1] == '\n')
            txt[--l] = '\0';

        /* return the message text */
        return txt;
    }
    else
    {
        /* 
         *   HTML or network error.  Return a message containing the numeric
         *   status as the error code, with no text message. 
         */
        return t3sprintf_alloc("%d ", htmlstat);
    }
}
Ejemplo n.º 18
0
/*
 *   Thread main 
 */
void TadsListenerThread::thread_main()
{
    /* 
     *   keep going until we get the general application-wide 'quit' signal
     *   or our own private listener shutdown event 
     */
    while (!quit_evt->test() && !shutdown_evt->test())
    {
        /* 
         *   wait for a new connection request OR the quit signal, whichever
         *   comes first 
         */
        OS_Waitable *w[] = { port, quit_evt, shutdown_evt };
        switch (OS_Waitable::multi_wait(3, w))
        {
        case OSWAIT_EVENT + 0:
            /* the port is ready - reset the event */
            port->reset_event();

            /* read connections as long as they're available */
            for (;;)
            {
                /* check for a connection request */
                OS_Socket *s = port->accept();

                /* if we're out of requests, go back to waiting */
                if (s == 0 && port->last_error() == OS_EWOULDBLOCK)
                    break;

                /* check for other errors */
                if (s == 0)
                {
                    /* failed - flag the error and shut down */
                    errmsg = t3sprintf_alloc(
                        "Listener thread failed: error %d from accept()",
                        port->last_error());
                    shutdown_evt->signal();
                    break;
                }

                /* put the socket into non-blocking mode */
                s->set_non_blocking();

                /* create the server thread (it takes over the socket ref) */
                TadsServerThread *st = create_server_thread(s);
                st->thread_id = next_thread_id++;

                /* launch the server thread */
                if (!st->launch())
                {
                    /* failed - flag the error and shut down */
                    errmsg = lib_copy_str("Listener thread failed: "
                                          "couldn't launch server thread");
                    shutdown_evt->signal();

                    /* release our reference on the thread */
                    st->release_ref();

                    /* done */
                    break;
                }

                /* we're done with our reference to the thread */
                st->release_ref();
            }
            break;

        case OSWAIT_EVENT + 1:
            /* 
             *   The quit signal fired - the whole app is terminating.
             *   Signal our internal shutdown event and abort. 
             */
            shutdown_evt->signal();
            break;

        case OSWAIT_EVENT + 2:
            /* shutdown signal fired - the listener is terminating; abort */
            break;
        }
    }

    /* wait for our server threads to exit */
    for (;;)
    {
        TadsServerThread *st;
        
        /* get the first thread from the list */
        mutex->lock();
        if ((st = servers) != 0)
            st->add_ref();
        mutex->unlock();

        /* if we're out of threads, we're done */
        if (st == 0)
            break;

        /* wait for this thread */
        st->wait();

        /* we're done with this thread */
        st->release_ref();
    }
}