/*
* Extension mechanism for the JavaScript virtual machine.
* Copyright (c) 1999-2000 Cylant Technology, LLC
*
* Author: Brian Bassett <bbassett@bbassett.net>
*/
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA
*/
/*
* $Source: /home/cvs/entity/libentitynjs/ext.c,v $
* $Id: ext.c,v 1.6 2000/07/25 05:26:00 imain Exp $
*/
#include "njs/internal.h"
#include <sys/stat.h>
#include <unistd.h>
/*
* Directory handling functions.
*/
/* Directory cache linked list manipulation functions. */
int
js_ext_purge_extdir(JSVirtualMachine *vm)
{
JSExtDirectoryList *thisPtr, *tempPtr;
thisPtr = vm->dirlist;
while(thisPtr != NULL)
{
tempPtr = thisPtr;
thisPtr = thisPtr->next;
js_free(tempPtr->dir);
js_free(tempPtr);
}
vm->dirlist = NULL;
return 1;
}
int
js_ext_resolve_modulename(JSVirtualMachine *vm, const char *module, char *buffer, int buffer_len)
{
JSExtDirectoryList *dirs = vm->dirlist;
struct stat stat_st;
char *mod, *modl;
int result;
/* compute the normalized module name */
/* I changed this from strdup to js_strdup, hopefully that's a good thing. */
mod = js_strdup(vm, module);
modl = mod;
while(*modl != '\0')
{
if(*modl == '.')
{
*modl = JS_HOST_DIR_SEP;
}
modl++;
}
/* Walk through the extension directories, looking for mod */
while(dirs != NULL)
{
/* look for a libtool .la information file first*/
js_snprintf (buffer, buffer_len, "%s%c%s.la", dirs->dir, JS_HOST_DIR_SEP, mod);
result = stat(buffer, &stat_st);
if(result == 0 && S_ISREG(stat_st.st_mode))
{
/* found mod.la */
return JS_EXT_LIBTOOL;
}
/* look for bytecode file second */
js_snprintf (buffer, buffer_len, "%s%c%s.jsc", dirs->dir, JS_HOST_DIR_SEP, mod);
result = stat(buffer, &stat_st);
if(result == 0 && S_ISREG(stat_st.st_mode))
{
/* found mod.jsc */
return JS_EXT_BYTECODE;
}
/* look for JavaScript source file */
js_snprintf (buffer, buffer_len, "%s%c%s.js", dirs->dir, JS_HOST_DIR_SEP, mod);
result = stat(buffer, &stat_st);
if(result == 0 && S_ISREG(stat_st.st_mode))
{
/* found mod.js */
return JS_EXT_SOURCE;
}
/* didn't find either, try the next directory */
dirs = dirs->next;
}
/* Didn't find anything resembling mod */
return JS_EXT_UNRESOLVED;
}
int
js_ext_add_loadedmodule(JSVirtualMachine *vm, const char *module)
{
JSLoadedModules *link;
link = js_malloc(vm, sizeof(JSLoadedModules));
link->next = vm->modules;
link->module = js_strdup(vm, module);
vm->modules = link;
return 1;
}
int
js_ext_purge_loadedmodule(JSVirtualMachine *vm)
{
JSLoadedModules *thisPtr, *tempPtr;
thisPtr = vm->modules;
while(thisPtr != NULL)
{
tempPtr = thisPtr;
thisPtr = thisPtr->next;
js_free(tempPtr->module);
js_free(tempPtr);
}
vm->modules = NULL;
return 1;
}
int
js_ext_module_loaded(JSVirtualMachine *vm, const char *module)
{
JSLoadedModules *thisPtr;
thisPtr = vm->modules;
while(thisPtr != NULL)
{
if(strcmp(thisPtr->module, module) == 0)
{
/* Found it! */
return 1;
}
thisPtr = thisPtr->next;
}
/* Didn't find it... :( */
return 0;
}
int
js_ext_vm_load_module(JSVirtualMachine *vm, const char *module)
{
int result;
char filename[1024];
FILE *file;
JSByteCode *bc;
JSNode source;
JSNode args[5];
/* See if we've already loaded the module in question. */
result = js_ext_module_loaded(vm, module);
if(result == 1)
{
/* We've already loaded this module. Silently return success. */
return 1;
}
/* Resolve the name and type of the module. */
result = js_ext_resolve_modulename(vm, module, filename, sizeof (filename));
switch(result)
{
case JS_EXT_BYTECODE:
/* Found the module as bytecode. */
file = fopen(filename, "rb");
if(file == NULL)
{
js_vm_set_err (vm, "VM: cannot open byte-code file \"%s\": %s",
filename, strerror (errno));
return 0;
}
bc = js_bc_read_file(file);
fclose(file);
if(bc == NULL)
{
/* XXX Error message */
return 0;
}
break;
case JS_EXT_SOURCE:
/* Found the module as source code. */
js_vm_make_string (vm, &source, filename, strlen (filename));
/* Let's compile the code. */
args[0].type = JS_INTEGER; /* Argument count. */
args[0].u.vinteger = 4;
JS_COPY (&args[1], &source); /* Source to compiler. */
args[2].type = JS_INTEGER; /* Flags. */
args[2].u.vinteger = 0;
args[2].u.vinteger |= JSC_FLAG_GENERATE_DEBUG_INFO;
args[2].u.vinteger |= JSC_FLAG_OPTIMIZE_PEEPHOLE;
args[2].u.vinteger |= JSC_FLAG_OPTIMIZE_JUMPS;
args[2].u.vinteger |= JSC_FLAG_WARN_WITH_CLOBBER;
args[3].type = JS_NULL; /* Assembler file. */
args[4].type = JS_NULL; /* Byte-code file. */
/* Call the compiler entry point. */
result = js_vm_apply (vm, "JSC$compile_file", NULL, 5, args);
if (result == 0)
return 0;
/*
* The resulting byte-code file is now at vm->exec_result.
*
* Note! The byte-code is a string allocated form the vm heap.
* The garbage collector can free it when it wants since the result
* isn't protected. However, we have no risk here because we
* first convert the byte-code data block to our internal
* JSByteCode block that shares no memory with the original data.
*/
assert (vm->exec_result.type == JS_STRING);
bc = js_bc_read_data (vm->exec_result.u.vstring->data,
vm->exec_result.u.vstring->len);
break;
default:
js_vm_set_err (vm, "VM: cannot resolve module %s", module);
return 0;
}
result = js_vm_execute (vm, bc);
js_bc_free (bc);
/* Add the module to the loaded module cache. */
js_ext_add_loadedmodule (vm, module);
return result;
}
int
js_ext_vm_load_module_from_symbol(JSVirtualMachine *vm, JSSymbol sym)
{
return js_ext_vm_load_module(vm, js_vm_symname(vm, sym));
}
/* Public functions. */
int
js_ext_add_directory(JSInterpPtr interp, const char *dir)
{
struct stat stat_st;
JSExtDirectoryList *thisPtr;
/* Check to make sure dir exists and is a directory. */
if(stat (dir, &stat_st) != 0)
{
/* error condition */
js_vm_set_err (interp->vm, "VM: Error with extension dir: %s", strerror(errno));
return 0;
}
if(!S_ISDIR(stat_st.st_mode))
{
/* not a dir */
js_vm_set_err (interp->vm, "VM: Directory not a directory: %s", dir);
return 0;
}
/* Search through cache to see if dir is already in cache. */
thisPtr = interp->vm->dirlist;
while (thisPtr != NULL)
{
if(strcmp (thisPtr->dir, dir) == 0)
{
/* We have already added this dir, return success. */
return 1;
}
thisPtr = thisPtr->next;
}
/* Add directory to cache. */
thisPtr = js_malloc (interp->vm, sizeof(JSExtDirectoryList));
thisPtr->dir = js_strdup (interp->vm, dir);
thisPtr->next = interp->vm->dirlist;
interp->vm->dirlist = thisPtr;
return 1; /* Success! */
}
int
js_ext_remove_directory(JSInterpPtr interp, const char *dir)
{
JSExtDirectoryList *thisPtr, *prevPtr, *tempPtr;
/* Die a flaming death if no directories in cache. */
if (interp->vm->dirlist == NULL)
{
js_vm_set_err (interp->vm, "VM: No directories in cache.");
return 0;
}
/* Loop through vm->dirlist to find dir. */
if (strcmp (interp->vm->dirlist->dir, dir) == 0)
{
/* We found dir at the head. */
tempPtr = interp->vm->dirlist;
interp->vm->dirlist = interp->vm->dirlist->next;
js_free (tempPtr->dir);
js_free (tempPtr);
return 1; /* Success! */
}
else
{
/* Loop through to find it. */
prevPtr = interp->vm->dirlist;
thisPtr = interp->vm->dirlist->next;
while(thisPtr != NULL && strcmp(thisPtr->dir, dir) != 0)
{
prevPtr = thisPtr;
thisPtr = thisPtr->next;
}
if (thisPtr != NULL)
{
tempPtr = thisPtr;
prevPtr->next = thisPtr->next;
js_free (tempPtr->dir);
js_free (tempPtr);
return 1; /* Success! */
}
}
js_vm_set_err (interp->vm, "VM: Directory not in extension path: %s", dir);
return 0;
}
int
js_ext_default_directories (JSInterpPtr interp)
{
int result;
result = js_ext_add_directory (interp, JS_EXT_DIR);
if(result == 0)
return 0;
#ifdef JS_SITE_EXT_DIR
result = js_ext_add_directory (interp, JS_SITE_EXT_DIR);
if(result == 0)
return 0;
#endif
return 1;
}
int
js_ext_load_module (JSInterpPtr interp, const char *name)
{
return js_ext_vm_load_module (interp->vm, name);
}
syntax highlighted by Code2HTML, v. 0.9.1