/* * Extension mechanism for the JavaScript virtual machine. * Copyright (c) 1999-2000 Cylant Technology, LLC * * Author: Brian Bassett */ /* * 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 #include /* * 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); }