Compare commits
1 Commits
tags/STABL
...
tags/Last1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
973a54719f |
5
mozilla/js/src/liveconnect/MANIFEST
Normal file
5
mozilla/js/src/liveconnect/MANIFEST
Normal file
@@ -0,0 +1,5 @@
|
||||
# This is a list of local files which get copied to the mozilla:dist directory
|
||||
#
|
||||
|
||||
jsjava.h
|
||||
nsILiveconnect.h
|
||||
89
mozilla/js/src/liveconnect/Makefile
Normal file
89
mozilla/js/src/liveconnect/Makefile
Normal file
@@ -0,0 +1,89 @@
|
||||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "NPL"); you may not use this file except in
|
||||
# compliance with the NPL. You may obtain a copy of the NPL at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
# for the specific language governing rights and limitations under the
|
||||
# NPL.
|
||||
#
|
||||
# The Initial Developer of this code under the NPL is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
# Reserved.
|
||||
|
||||
|
||||
|
||||
DEPTH = ../../..
|
||||
|
||||
include $(DEPTH)/config/config.mk
|
||||
|
||||
ifdef NSJVM
|
||||
DIRS = classes
|
||||
endif
|
||||
|
||||
MODULE = java
|
||||
LIBRARY_NAME = jsj
|
||||
|
||||
REQUIRES = java js applet nspr img util layer xpcom
|
||||
|
||||
CSRCS = jsj.c \
|
||||
jsj_JSObject.c \
|
||||
jsj_JavaArray.c \
|
||||
jsj_JavaClass.c \
|
||||
jsj_JavaMember.c \
|
||||
jsj_JavaObject.c \
|
||||
jsj_JavaPackage.c \
|
||||
jsj_array.c \
|
||||
jsj_class.c \
|
||||
jsj_convert.c \
|
||||
jsj_field.c \
|
||||
jsj_hash.c \
|
||||
jsj_method.c \
|
||||
jsj_utils.c \
|
||||
nsCLiveconnect.c \
|
||||
nsCLiveconnectFactory.c
|
||||
|
||||
|
||||
LLIBS=$(LIBNSPR) $(DIST)/lib/js$(MOZ_BITS)$(VERSION_NUMBER).lib \
|
||||
$(DIST)/lib/xpcom32.lib
|
||||
|
||||
|
||||
ifdef NSJVM
|
||||
JNI_GEN = netscape.javascript.JSObject netscape.javascript.JSException
|
||||
endif
|
||||
|
||||
EXPORTS = jsjava.h \
|
||||
$(JNI_GEN_DIR)/netscape_javascript_JSObject.h \
|
||||
$(JNI_GEN_DIR)/netscape_javascript_JSException.h \
|
||||
nsILiveconnect.h \
|
||||
$(NULL)
|
||||
|
||||
|
||||
|
||||
include $(DEPTH)/config/rules.mk
|
||||
|
||||
######################################################################
|
||||
|
||||
# Generate jsj_nodl.c (so that you can check it in)
|
||||
# These make rules only works on IRIX...sigh
|
||||
|
||||
ifeq ($(OS_ARCH),IRIX)
|
||||
jsj_nodl.c: $(OBJDIR)/stubs.o Makefile $(DEPTH)/config/nodl.pl
|
||||
rm -f $@
|
||||
$(PERL) $(DEPTH)/config/nodl.pl "jsj_nodl_tab" \
|
||||
`nm -Bn $(OBJDIR)/stubs.o | egrep Java_.*_stub | awk '{print $$3;}'` > $@
|
||||
endif
|
||||
|
||||
ifdef JAVA_OR_OJI
|
||||
$(OBJDIR)/stubs.o: \
|
||||
$(JNI_GEN_DIR)/netscape_javascript_JSObject.c \
|
||||
$(JNI_GEN_DIR)/netscape_javascript_JSException.c \
|
||||
$(NULL)
|
||||
else
|
||||
$(OBJDIR)/stubs.o:
|
||||
endif
|
||||
|
||||
90
mozilla/js/src/liveconnect/Makefile.in
Normal file
90
mozilla/js/src/liveconnect/Makefile.in
Normal file
@@ -0,0 +1,90 @@
|
||||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "NPL"); you may not use this file except in
|
||||
# compliance with the NPL. You may obtain a copy of the NPL at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
# for the specific language governing rights and limitations under the
|
||||
# NPL.
|
||||
#
|
||||
# The Initial Developer of this code under the NPL is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
# Reserved.
|
||||
|
||||
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
||||
ifdef NSJVM
|
||||
DIRS = classes
|
||||
endif
|
||||
|
||||
|
||||
MODULE = java
|
||||
LIBRARY_NAME = jsj
|
||||
|
||||
REQUIRES = java js applet nspr img util layer xpcom caps oji plugin
|
||||
|
||||
CSRCS = jsj.c \
|
||||
jsj_JSObject.c \
|
||||
jsj_JavaArray.c \
|
||||
jsj_JavaClass.c \
|
||||
jsj_JavaMember.c \
|
||||
jsj_JavaObject.c \
|
||||
jsj_JavaPackage.c \
|
||||
jsj_array.c \
|
||||
jsj_class.c \
|
||||
jsj_convert.c \
|
||||
jsj_field.c \
|
||||
jsj_hash.c \
|
||||
jsj_method.c \
|
||||
jsj_utils.c
|
||||
nsCLiveconnect.c \
|
||||
nsCLiveconnectFactory.c
|
||||
|
||||
|
||||
ifdef NSJVM
|
||||
JNI_GEN = netscape.javascript.JSObject netscape.javascript.JSException
|
||||
endif
|
||||
|
||||
EXPORTS = $(srcdir)/jsjava.h \
|
||||
$(srcdir)/$(JNI_GEN_DIR)/netscape_javascript_JSObject.h \
|
||||
$(srcdir)/$(JNI_GEN_DIR)/netscape_javascript_JSException.h \
|
||||
$(NULL)
|
||||
|
||||
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
######################################################################
|
||||
|
||||
# Generate jsj_nodl.c (so that you can check it in)
|
||||
# These make rules only works on IRIX...sigh
|
||||
|
||||
ifeq ($(OS_ARCH),IRIX)
|
||||
jsj_nodl.c: $(OBJDIR)/stubs.o Makefile $(topsrcdir)/config/nodl.pl
|
||||
rm -f $@
|
||||
$(PERL) $(topsrcdir)/config/nodl.pl "jsj_nodl_tab" \
|
||||
`nm -Bn $(OBJDIR)/stubs.o | egrep Java_.*_stub | awk '{print $$3;}'` > $@
|
||||
endif
|
||||
|
||||
ifdef JAVA_OR_OJI
|
||||
$(OBJDIR)/stubs.o: \
|
||||
$(JRI_GEN_DIR)/netscape_javascript_JSObject.c \
|
||||
$(JRI_GEN_DIR)/netscape_javascript_JSException.c \
|
||||
$(NULL)
|
||||
else
|
||||
$(OBJDIR)/stubs.o:
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include "jni.h"
|
||||
|
||||
/* Header for class netscape_javascript_JSException */
|
||||
|
||||
#ifndef _Included_netscape_javascript_JSException
|
||||
#define _Included_netscape_javascript_JSException
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
102
mozilla/js/src/liveconnect/_jni/netscape_javascript_JSObject.h
Normal file
102
mozilla/js/src/liveconnect/_jni/netscape_javascript_JSObject.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include "jni.h"
|
||||
|
||||
/* Header for class netscape_javascript_JSObject */
|
||||
|
||||
#ifndef _Included_netscape_javascript_JSObject
|
||||
#define _Included_netscape_javascript_JSObject
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: initClass
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_initClass
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: getMember
|
||||
* Signature: (Ljava/lang/String;)Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_getMember
|
||||
(JNIEnv *, jobject, jstring);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: getSlot
|
||||
* Signature: (I)Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_getSlot
|
||||
(JNIEnv *, jobject, jint);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: setMember
|
||||
* Signature: (Ljava/lang/String;Ljava/lang/Object;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_setMember
|
||||
(JNIEnv *, jobject, jstring, jobject);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: setSlot
|
||||
* Signature: (ILjava/lang/Object;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_setSlot
|
||||
(JNIEnv *, jobject, jint, jobject);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: removeMember
|
||||
* Signature: (Ljava/lang/String;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_removeMember
|
||||
(JNIEnv *, jobject, jstring);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: call
|
||||
* Signature: (Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_call
|
||||
(JNIEnv *, jobject, jstring, jobjectArray);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: eval
|
||||
* Signature: (Ljava/lang/String;)Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_eval
|
||||
(JNIEnv *, jobject, jstring);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: toString
|
||||
* Signature: ()Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_netscape_javascript_JSObject_toString
|
||||
(JNIEnv *, jobject);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: getWindow
|
||||
* Signature: (Ljava/applet/Applet;)Lnetscape/javascript/JSObject;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_getWindow
|
||||
(JNIEnv *, jclass, jobject);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: finalize
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_finalize
|
||||
(JNIEnv *, jobject);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
65
mozilla/js/src/liveconnect/classes/Makefile
Normal file
65
mozilla/js/src/liveconnect/classes/Makefile
Normal file
@@ -0,0 +1,65 @@
|
||||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "NPL"); you may not use this file except in
|
||||
# compliance with the NPL. You may obtain a copy of the NPL at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
# for the specific language governing rights and limitations under the
|
||||
# NPL.
|
||||
#
|
||||
# The Initial Developer of this code under the NPL is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
# Reserved.
|
||||
|
||||
|
||||
|
||||
DEPTH = ../../../..
|
||||
|
||||
MODULE = java
|
||||
|
||||
#
|
||||
# the idea is that the install phase for those modules will
|
||||
# make their own signed jar files
|
||||
# there are some exceptions here that we deal with
|
||||
# stuff in modules and in ns/js/jsj
|
||||
#
|
||||
JMODS = netscape/javascript netscape/javascript/adapters
|
||||
|
||||
#
|
||||
# JDIRS is dependant on JAVA_DESTPATH in config/rules.m[a]k.
|
||||
# Be sure to touch that directory if you add a new directory to
|
||||
# JDIRS, or else it will not build. FIXME
|
||||
#
|
||||
JDIRS = $(JMODS)
|
||||
|
||||
JAR_JSJ = jsj10.jar
|
||||
JAR_JSJ_CLASSES = $(JMODS)
|
||||
|
||||
#
|
||||
# jars to build at install time
|
||||
#
|
||||
JARS = $(JAR_JSJ)
|
||||
|
||||
include $(DEPTH)/config/rules.mk
|
||||
|
||||
JAVA_SOURCEPATH = $(DEPTH)/js/src/liveconnect/classes
|
||||
|
||||
doc::
|
||||
$(JAVADOC) -d $(DIST)/doc netscape.javascript
|
||||
|
||||
natives_list:: FORCE
|
||||
rm -rf $@
|
||||
find . -name "*.class" -print | sed 's@\./\(.*\)\.class$$@\1@' | \
|
||||
sed 's@/@.@g' | xargs $(JVH) -natives | sort > $@
|
||||
|
||||
check_natives:: natives_list
|
||||
rm -f found_natives
|
||||
nm -B ../$(OBJDIR)/*.o \
|
||||
| egrep "Java.*_stub" | awk '{ print $$3; }' | sort > found_natives
|
||||
diff found_natives natives_list
|
||||
|
||||
FORCE:
|
||||
70
mozilla/js/src/liveconnect/classes/Makefile.in
Normal file
70
mozilla/js/src/liveconnect/classes/Makefile.in
Normal file
@@ -0,0 +1,70 @@
|
||||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "NPL"); you may not use this file except in
|
||||
# compliance with the NPL. You may obtain a copy of the NPL at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
# for the specific language governing rights and limitations under the
|
||||
# NPL.
|
||||
#
|
||||
# The Initial Developer of this code under the NPL is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
# Reserved.
|
||||
|
||||
|
||||
|
||||
DEPTH = ../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = java
|
||||
|
||||
#
|
||||
# the idea is that the install phase for those modules will
|
||||
# make their own signed jar files
|
||||
# there are some exceptions here that we deal with
|
||||
# stuff in modules and in ns/js/jsj
|
||||
#
|
||||
JMODS = netscape/javascript netscape/javascript/adapters
|
||||
|
||||
#
|
||||
# JDIRS is dependant on JAVA_DESTPATH in config/rules.m[a]k.
|
||||
# Be sure to touch that directory if you add a new directory to
|
||||
# JDIRS, or else it will not build. FIXME
|
||||
#
|
||||
JDIRS = $(JMODS)
|
||||
|
||||
JAR_JSJ = jsj10.jar
|
||||
JAR_JSJ_CLASSES = $(JMODS)
|
||||
|
||||
#
|
||||
# jars to build at install time
|
||||
#
|
||||
JARS = $(JAR_JSJ)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
JAVA_SOURCEPATH = $(topsrcdir)/js/src/liveconnect/classes
|
||||
|
||||
doc::
|
||||
$(JAVADOC) -d $(DIST)/doc netscape.javascript
|
||||
|
||||
natives_list:: FORCE
|
||||
rm -rf $@
|
||||
find . -name "*.class" -print | sed 's@\./\(.*\)\.class$$@\1@' | \
|
||||
sed 's@/@.@g' | xargs $(JVH) -natives | sort > $@
|
||||
|
||||
check_natives:: natives_list
|
||||
rm -f found_natives
|
||||
nm -B ../$(OBJDIR)/*.o \
|
||||
| egrep "Java.*_stub" | awk '{ print $$3; }' | sort > found_natives
|
||||
diff found_natives natives_list
|
||||
|
||||
FORCE:
|
||||
78
mozilla/js/src/liveconnect/classes/makefile.win
Normal file
78
mozilla/js/src/liveconnect/classes/makefile.win
Normal file
@@ -0,0 +1,78 @@
|
||||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "NPL"); you may not use this file except in
|
||||
# compliance with the NPL. You may obtain a copy of the NPL at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
# for the specific language governing rights and limitations under the
|
||||
# NPL.
|
||||
#
|
||||
# The Initial Developer of this code under the NPL is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
# Reserved.
|
||||
|
||||
IGNORE_MANIFEST=1
|
||||
#
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Makefile to build the JavaScript-Java tree
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
|
||||
DEPTH = ..\..\..\..
|
||||
|
||||
JAVA_SOURCEPATH=$(DEPTH)\js\src\liveconnect\classes
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Define the files necessary to build the target (ie. OBJS)
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
include <$(DEPTH)\config\config.mak>
|
||||
|
||||
JMOZ = \
|
||||
netscape/javascript \
|
||||
$(NULL)
|
||||
|
||||
|
||||
all::
|
||||
|
||||
MODULE=java
|
||||
JMODS=netscape/javascript
|
||||
!ifdef JAVA_OR_NSJVM
|
||||
JDIRS=$(JMODS)
|
||||
JAR_JSJ_CLASSES=$(JMODS)
|
||||
JAR_NAME = jsj10.jar
|
||||
!endif
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
|
||||
!ifdef JAVA_OR_NSJVM
|
||||
install::
|
||||
cd $(JAVA_DESTPATH)
|
||||
@echo +++ building/updating $(JAR_NAME)
|
||||
-for %i in ($(JAR_JSJ_CLASSES:/=\)) do @$(ZIP_PROG) $(ZIP_FLAGS) $(JAR_NAME) %i\*.class
|
||||
cd $(MAKEDIR)
|
||||
|
||||
!ifdef REGENERATE
|
||||
install::
|
||||
cd $(JAVA_DESTPATH)
|
||||
@echo +++ updating $(DEPTH)\nav-java\stubs\classes\$(JAR_NAME) for checkin
|
||||
-for %i in ($(JAR_JSJ_CLASSES:/=\)) do @$(ZIP_PROG) $(ZIP_FLAGS) ..\..\nav-java\stubs\classes\$(JAR_NAME) %i\*.class
|
||||
cd $(MAKEDIR)
|
||||
!endif
|
||||
!endif
|
||||
|
||||
javadoc:
|
||||
-mkdir $(XPDIST)\javadoc 2> NUL
|
||||
echo $(JAVADOC) -sourcepath . -d $(XPDIST)\javadoc $(JDIRS:/=.)
|
||||
$(JAVADOC) -sourcepath . -d $(XPDIST)\javadoc $(JDIRS:/=.)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/* Insert copyright and license here 19** */
|
||||
|
||||
package netscape.javascript;
|
||||
|
||||
/**
|
||||
* JSException is an exception which is thrown when JavaScript code
|
||||
* returns an error.
|
||||
*/
|
||||
|
||||
public
|
||||
class JSException extends Exception {
|
||||
String filename;
|
||||
int lineno;
|
||||
String source;
|
||||
int tokenIndex;
|
||||
|
||||
/**
|
||||
* Constructs a JSException without a detail message.
|
||||
* A detail message is a String that describes this particular exception.
|
||||
*/
|
||||
public JSException() {
|
||||
super();
|
||||
filename = "unknown";
|
||||
lineno = 0;
|
||||
source = "";
|
||||
tokenIndex = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a JSException with a detail message.
|
||||
* A detail message is a String that describes this particular exception.
|
||||
* @param s the detail message
|
||||
*/
|
||||
public JSException(String s) {
|
||||
super(s);
|
||||
filename = "unknown";
|
||||
lineno = 0;
|
||||
source = "";
|
||||
tokenIndex = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a JSException with a detail message and all the
|
||||
* other info that usually comes with a JavaScript error.
|
||||
* @param s the detail message
|
||||
*/
|
||||
public JSException(String s, String filename, int lineno,
|
||||
String source, int tokenIndex) {
|
||||
super(s);
|
||||
this.filename = filename;
|
||||
this.lineno = lineno;
|
||||
this.source = source;
|
||||
this.tokenIndex = tokenIndex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
/* -*- Mode: C; tab-width: 4; -*- */
|
||||
|
||||
/* Insert copyright and license here 19** */
|
||||
|
||||
/* more doc todo:
|
||||
* threads
|
||||
* gc
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package netscape.javascript;
|
||||
|
||||
import java.applet.Applet;
|
||||
|
||||
/**
|
||||
* JSObject allows Java to manipulate objects that are
|
||||
* defined in JavaScript.
|
||||
* Values passed from Java to JavaScript are converted as
|
||||
* follows:<ul>
|
||||
* <li>JSObject is converted to the original JavaScript object
|
||||
* <li>Any other Java object is converted to a JavaScript wrapper,
|
||||
* which can be used to access methods and fields of the java object.
|
||||
* Converting this wrapper to a string will call the toString method
|
||||
* on the original object, converting to a number will call the
|
||||
* floatValue method if possible and fail otherwise. Converting
|
||||
* to a boolean will try to call the booleanValue method in the
|
||||
* same way.
|
||||
* <li>Java arrays are wrapped with a JavaScript object that understands
|
||||
* array.length and array[index]
|
||||
* <li>A Java boolean is converted to a JavaScript boolean
|
||||
* <li>Java byte, char, short, int, long, float, and double are converted
|
||||
* to JavaScript numbers
|
||||
* </ul>
|
||||
* Values passed from JavaScript to Java are converted as follows:<ul>
|
||||
* <li>objects which are wrappers around java objects are unwrapped
|
||||
* <li>other objects are wrapped with a JSObject
|
||||
* <li>strings, numbers and booleans are converted to String, Float,
|
||||
* and Boolean objects respectively
|
||||
* </ul>
|
||||
* This means that all JavaScript values show up as some kind
|
||||
* of java.lang.Object in Java. In order to make much use of them,
|
||||
* you will have to cast them to the appropriate subclass of Object,
|
||||
* e.g. <code>(String) window.getMember("name");</code> or
|
||||
* <code>(JSObject) window.getMember("document");</code>.
|
||||
*/
|
||||
public final class JSObject {
|
||||
/* the internal object data */
|
||||
private int internal;
|
||||
|
||||
/**
|
||||
* initialize
|
||||
*/
|
||||
private static native void initClass();
|
||||
static {
|
||||
// On MRJ, this property won't exist, because the library is preloaded.
|
||||
String liveConnectLibrary = System.getProperty("netscape.jsj.dll", null);
|
||||
if (liveConnectLibrary != null) {
|
||||
System.loadLibrary(liveConnectLibrary);
|
||||
initClass();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* it is illegal to construct a JSObject manually
|
||||
*/
|
||||
private JSObject(int jsobj_addr) {
|
||||
internal = jsobj_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a named member of a JavaScript object.
|
||||
* Equivalent to "this.<i>name</i>" in JavaScript.
|
||||
*/
|
||||
public native Object getMember(String name);
|
||||
|
||||
/**
|
||||
* Retrieves an indexed member of a JavaScript object.
|
||||
* Equivalent to "this[<i>index</i>]" in JavaScript.
|
||||
*/
|
||||
// public Object getMember(int index) { return getSlot(index); }
|
||||
public native Object getSlot(int index);
|
||||
|
||||
/**
|
||||
* Sets a named member of a JavaScript object.
|
||||
* Equivalent to "this.<i>name</i> = <i>value</i>" in JavaScript.
|
||||
*/
|
||||
public native void setMember(String name, Object value);
|
||||
|
||||
/**
|
||||
* Sets an indexed member of a JavaScript object.
|
||||
* Equivalent to "this[<i>index</i>] = <i>value</i>" in JavaScript.
|
||||
*/
|
||||
// public void setMember(int index, Object value) {
|
||||
// setSlot(index, value);
|
||||
// }
|
||||
public native void setSlot(int index, Object value);
|
||||
|
||||
/**
|
||||
* Removes a named member of a JavaScript object.
|
||||
*/
|
||||
public native void removeMember(String name);
|
||||
|
||||
/**
|
||||
* Calls a JavaScript method.
|
||||
* Equivalent to "this.<i>methodName</i>(<i>args</i>[0], <i>args</i>[1], ...)" in JavaScript.
|
||||
*/
|
||||
public native Object call(String methodName, Object args[]);
|
||||
|
||||
/**
|
||||
* Evaluates a JavaScript expression. The expression is a string
|
||||
* of JavaScript source code which will be evaluated in the context
|
||||
* given by "this".
|
||||
*/
|
||||
public native Object eval(String s);
|
||||
|
||||
/**
|
||||
* Converts a JSObject to a String.
|
||||
*/
|
||||
public native String toString();
|
||||
|
||||
// should use some sort of identifier rather than String
|
||||
// is "property" the right word?
|
||||
// native String[] listProperties();
|
||||
|
||||
|
||||
/**
|
||||
* get a JSObject for the window containing the given applet
|
||||
*/
|
||||
public static native JSObject getWindow(Applet applet);
|
||||
|
||||
/**
|
||||
* Finalization decrements the reference count on the corresponding
|
||||
* JavaScript object.
|
||||
*/
|
||||
protected native void finalize();
|
||||
|
||||
/**
|
||||
* Override java.lang.Object.equals() because identity is not preserved
|
||||
* with instances of JSObject.
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
JSObject jsobj;
|
||||
|
||||
if (!(obj instanceof JSObject))
|
||||
return false;
|
||||
jsobj = (JSObject)obj;
|
||||
return (internal == jsobj.internal);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
/* ** */
|
||||
/**
|
||||
* The JSProxy interface allows applets and plugins to
|
||||
* share javascript contexts.
|
||||
*/
|
||||
|
||||
package netscape.javascript;
|
||||
import java.applet.Applet;
|
||||
|
||||
public interface JSProxy {
|
||||
Object getMember(JSObject jso, String name);
|
||||
Object getSlot(JSObject jso, int index);
|
||||
void setMember(JSObject jso, String name, Object value);
|
||||
void setSlot(JSObject jso, int index, Object value);
|
||||
void removeMember(JSObject jso, String name);
|
||||
Object call(JSObject jso, String methodName, Object args[]);
|
||||
Object eval(JSObject jso, String s);
|
||||
String toString(JSObject jso);
|
||||
JSObject getWindow(Applet applet);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package netscape.javascript;
|
||||
|
||||
/**
|
||||
* Runs a JavaScript object with a run() method in a separate thread.
|
||||
*/
|
||||
public class JSRunnable implements Runnable {
|
||||
private JSObject runnable;
|
||||
|
||||
public JSRunnable(JSObject runnable) {
|
||||
this.runnable = runnable;
|
||||
synchronized(this) {
|
||||
new Thread(this).start();
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException ie) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
runnable.call("run", null);
|
||||
synchronized(this) {
|
||||
notifyAll();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
System.err.println(t);
|
||||
t.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
/* ** */
|
||||
|
||||
package netscape.javascript;
|
||||
import java.io.*;
|
||||
|
||||
public class JSUtil {
|
||||
|
||||
/* Return the stack trace of an exception or error as a String */
|
||||
public static String getStackTrace(Throwable t) {
|
||||
ByteArrayOutputStream captureStream;
|
||||
PrintStream p;
|
||||
|
||||
captureStream = new ByteArrayOutputStream();
|
||||
p = new PrintStream(captureStream);
|
||||
|
||||
t.printStackTrace(p);
|
||||
p.flush();
|
||||
|
||||
return captureStream.toString();
|
||||
}
|
||||
}
|
||||
876
mozilla/js/src/liveconnect/jsj.c
Normal file
876
mozilla/js/src/liveconnect/jsj.c
Normal file
@@ -0,0 +1,876 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the top-level initialization code and the implementation of the
|
||||
* public API.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jsj_private.h" /* LiveConnect internals */
|
||||
#include "jsjava.h" /* LiveConnect external API */
|
||||
|
||||
/*
|
||||
* At certain times during initialization, there may be no JavaScript context
|
||||
* available to direct error reports to, in which case the error messages
|
||||
* are sent to this function. The caller is responsible for free'ing
|
||||
* the js_error_msg argument.
|
||||
*/
|
||||
static void
|
||||
report_java_initialization_error(JNIEnv *jEnv, const char *js_error_msg)
|
||||
{
|
||||
const char *error_msg, *java_error_msg;
|
||||
|
||||
java_error_msg = NULL;
|
||||
#if 0 /* This can never work here, because jsj_GetJavaErrorMessage relies on
|
||||
jlThrowable_toString which is set up by the initialization that calls
|
||||
this function. */
|
||||
if (jEnv) {
|
||||
java_error_msg = jsj_GetJavaErrorMessage(jEnv);
|
||||
(*jEnv)->ExceptionClear(jEnv);
|
||||
}
|
||||
#endif
|
||||
if (java_error_msg) {
|
||||
error_msg = PR_smprintf("initialization error: %s (%s)\n",
|
||||
js_error_msg, java_error_msg);
|
||||
free((void*)java_error_msg);
|
||||
} else {
|
||||
error_msg = PR_smprintf("initialization error: %s\n",
|
||||
js_error_msg);
|
||||
}
|
||||
|
||||
jsj_LogError(error_msg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Opaque JVM handles to Java classes and methods required for Java reflection.
|
||||
* These are computed and cached during initialization.
|
||||
*/
|
||||
|
||||
jclass jlObject; /* java.lang.Object */
|
||||
jclass jlrMethod; /* java.lang.reflect.Method */
|
||||
jclass jlrField; /* java.lang.reflect.Field */
|
||||
jclass jlVoid; /* java.lang.Void */
|
||||
jclass jlrConstructor; /* java.lang.reflect.Constructor */
|
||||
jclass jlThrowable; /* java.lang.Throwable */
|
||||
jclass jlSystem; /* java.lang.System */
|
||||
jclass jlClass; /* java.lang.Class */
|
||||
jclass jlBoolean; /* java.lang.Boolean */
|
||||
jclass jlDouble; /* java.lang.Double */
|
||||
jclass jlString; /* java.lang.String */
|
||||
jclass njJSObject; /* netscape.javascript.JSObject */
|
||||
jclass njJSException; /* netscape.javascript.JSException */
|
||||
jclass njJSUtil; /* netscape.javascript.JSUtil */
|
||||
|
||||
jmethodID jlClass_getMethods; /* java.lang.Class.getMethods() */
|
||||
jmethodID jlClass_getConstructors; /* java.lang.Class.getConstructors() */
|
||||
jmethodID jlClass_getFields; /* java.lang.Class.getFields() */
|
||||
jmethodID jlClass_getName; /* java.lang.Class.getName() */
|
||||
jmethodID jlClass_getComponentType; /* java.lang.Class.getComponentType() */
|
||||
jmethodID jlClass_getModifiers; /* java.lang.Class.getModifiers() */
|
||||
jmethodID jlClass_isArray; /* java.lang.Class.isArray() */
|
||||
|
||||
jmethodID jlrMethod_getName; /* java.lang.reflect.Method.getName() */
|
||||
jmethodID jlrMethod_getParameterTypes; /* java.lang.reflect.Method.getParameterTypes() */
|
||||
jmethodID jlrMethod_getReturnType; /* java.lang.reflect.Method.getReturnType() */
|
||||
jmethodID jlrMethod_getModifiers; /* java.lang.reflect.Method.getModifiers() */
|
||||
|
||||
jmethodID jlrConstructor_getParameterTypes; /* java.lang.reflect.Constructor.getParameterTypes() */
|
||||
jmethodID jlrConstructor_getModifiers; /* java.lang.reflect.Constructor.getModifiers() */
|
||||
|
||||
jmethodID jlrField_getName; /* java.lang.reflect.Field.getName() */
|
||||
jmethodID jlrField_getType; /* java.lang.reflect.Field.getType() */
|
||||
jmethodID jlrField_getModifiers; /* java.lang.reflect.Field.getModifiers() */
|
||||
|
||||
jmethodID jlBoolean_Boolean; /* java.lang.Boolean constructor */
|
||||
jmethodID jlBoolean_booleanValue; /* java.lang.Boolean.booleanValue() */
|
||||
jmethodID jlDouble_Double; /* java.lang.Double constructor */
|
||||
jmethodID jlDouble_doubleValue; /* java.lang.Double.doubleValue() */
|
||||
|
||||
jmethodID jlThrowable_toString; /* java.lang.Throwable.toString() */
|
||||
jmethodID jlThrowable_getMessage; /* java.lang.Throwable.getMessage() */
|
||||
|
||||
jmethodID jlSystem_identityHashCode; /* java.lang.System.identityHashCode() */
|
||||
|
||||
jobject jlVoid_TYPE; /* java.lang.Void.TYPE value */
|
||||
|
||||
jmethodID njJSException_JSException; /* netscape.javascript.JSexception constructor */
|
||||
jmethodID njJSObject_JSObject; /* netscape.javascript.JSObject constructor */
|
||||
jmethodID njJSUtil_getStackTrace; /* netscape.javascript.JSUtil.getStackTrace() */
|
||||
jfieldID njJSObject_internal; /* netscape.javascript.JSObject.internal */
|
||||
jfieldID njJSException_lineno; /* netscape.javascript.JSException.lineno */
|
||||
jfieldID njJSException_tokenIndex; /* netscape.javascript.JSException.tokenIndex */
|
||||
jfieldID njJSException_source; /* netscape.javascript.JSException.source */
|
||||
jfieldID njJSException_filename; /* netscape.javascript.JSException.filename */
|
||||
|
||||
/* Obtain a reference to a Java class */
|
||||
#define LOAD_CLASS(qualified_name, class) \
|
||||
{ \
|
||||
jclass _##class = (*jEnv)->FindClass(jEnv, #qualified_name); \
|
||||
if (_##class == 0) { \
|
||||
(*jEnv)->ExceptionClear(jEnv); \
|
||||
report_java_initialization_error(jEnv, \
|
||||
"Can't load class " #qualified_name); \
|
||||
return JS_FALSE; \
|
||||
} \
|
||||
class = (*jEnv)->NewGlobalRef(jEnv, _##class); \
|
||||
}
|
||||
|
||||
/* Obtain a methodID reference to a Java method or constructor */
|
||||
#define _LOAD_METHOD(qualified_class, method, mvar, signature, class, is_static)\
|
||||
if (is_static) { \
|
||||
class##_##mvar = \
|
||||
(*jEnv)->GetStaticMethodID(jEnv, class, #method, signature); \
|
||||
} else { \
|
||||
class##_##mvar = \
|
||||
(*jEnv)->GetMethodID(jEnv, class, #method, signature); \
|
||||
} \
|
||||
if (class##_##mvar == 0) { \
|
||||
report_java_initialization_error(jEnv, \
|
||||
"Can't get mid for " #qualified_class "." #method "()"); \
|
||||
return JS_FALSE; \
|
||||
}
|
||||
|
||||
/* Obtain a methodID reference to a Java instance method */
|
||||
#define LOAD_METHOD(qualified_class, method, signature, class) \
|
||||
_LOAD_METHOD(qualified_class, method, method, signature, class, JS_FALSE)
|
||||
|
||||
/* Obtain a methodID reference to a Java static method */
|
||||
#define LOAD_STATIC_METHOD(qualified_class, method, signature, class) \
|
||||
_LOAD_METHOD(qualified_class, method, method, signature, class, JS_TRUE)
|
||||
|
||||
/* Obtain a methodID reference to a Java constructor */
|
||||
#define LOAD_CONSTRUCTOR(qualified_class, method, signature, class) \
|
||||
_LOAD_METHOD(qualified_class,<init>, method, signature, class, JS_FALSE)
|
||||
|
||||
/* Obtain a fieldID reference to a Java instance or static field */
|
||||
#define _LOAD_FIELDID(qualified_class, field, signature, class, is_static) \
|
||||
if (is_static) { \
|
||||
class##_##field = (*jEnv)->GetStaticFieldID(jEnv, class, #field, signature);\
|
||||
} else { \
|
||||
class##_##field = (*jEnv)->GetFieldID(jEnv, class, #field, signature);\
|
||||
} \
|
||||
if (class##_##field == 0) { \
|
||||
report_java_initialization_error(jEnv, \
|
||||
"Can't get fid for " #qualified_class "." #field); \
|
||||
return JS_FALSE; \
|
||||
}
|
||||
|
||||
/* Obtain a fieldID reference to a Java instance field */
|
||||
#define LOAD_FIELDID(qualified_class, field, signature, class) \
|
||||
_LOAD_FIELDID(qualified_class, field, signature, class, JS_FALSE)
|
||||
|
||||
/* Obtain the value of a static field in a Java class */
|
||||
#define LOAD_FIELD_VAL(qualified_class, field, signature, class, type) \
|
||||
{ \
|
||||
jfieldID field_id; \
|
||||
field_id = (*jEnv)->GetStaticFieldID(jEnv, class, #field, signature);\
|
||||
if (field_id == 0) { \
|
||||
report_java_initialization_error(jEnv, \
|
||||
"Can't get fid for " #qualified_class "." #field); \
|
||||
return JS_FALSE; \
|
||||
} \
|
||||
class##_##field = \
|
||||
(*jEnv)->GetStatic##type##Field(jEnv, class, field_id); \
|
||||
if (class##_##field == 0) { \
|
||||
report_java_initialization_error(jEnv, \
|
||||
"Can't read static field " #qualified_class "." #field); \
|
||||
return JS_FALSE; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Obtain the value of a static field in a Java class, which is known to
|
||||
contain an object value. */
|
||||
#define LOAD_FIELD_OBJ(qualified_class, field, signature, class) \
|
||||
LOAD_FIELD_VAL(qualified_class, field, signature, class, Object); \
|
||||
class##_##field = (*jEnv)->NewGlobalRef(jEnv, class##_##field);
|
||||
|
||||
/*
|
||||
* Load the Java classes, and the method and field descriptors required for Java reflection.
|
||||
* Returns JS_TRUE on success, JS_FALSE on failure.
|
||||
*/
|
||||
static JSBool
|
||||
init_java_VM_reflection(JSJavaVM *jsjava_vm, JNIEnv *jEnv)
|
||||
{
|
||||
/* Load Java system classes and method, including java.lang.reflect classes */
|
||||
LOAD_CLASS(java/lang/Object, jlObject);
|
||||
LOAD_CLASS(java/lang/Class, jlClass);
|
||||
LOAD_CLASS(java/lang/reflect/Method, jlrMethod);
|
||||
LOAD_CLASS(java/lang/reflect/Constructor, jlrConstructor);
|
||||
LOAD_CLASS(java/lang/reflect/Field, jlrField);
|
||||
LOAD_CLASS(java/lang/Throwable, jlThrowable);
|
||||
LOAD_CLASS(java/lang/System, jlSystem);
|
||||
LOAD_CLASS(java/lang/Boolean, jlBoolean);
|
||||
LOAD_CLASS(java/lang/Double, jlDouble);
|
||||
LOAD_CLASS(java/lang/String, jlString);
|
||||
LOAD_CLASS(java/lang/Void, jlVoid);
|
||||
|
||||
LOAD_METHOD(java.lang.Class, getMethods, "()[Ljava/lang/reflect/Method;",jlClass);
|
||||
LOAD_METHOD(java.lang.Class, getConstructors, "()[Ljava/lang/reflect/Constructor;",jlClass);
|
||||
LOAD_METHOD(java.lang.Class, getFields, "()[Ljava/lang/reflect/Field;", jlClass);
|
||||
LOAD_METHOD(java.lang.Class, getName, "()Ljava/lang/String;", jlClass);
|
||||
LOAD_METHOD(java.lang.Class, isArray, "()Z", jlClass);
|
||||
LOAD_METHOD(java.lang.Class, getComponentType, "()Ljava/lang/Class;", jlClass);
|
||||
LOAD_METHOD(java.lang.Class, getModifiers, "()I", jlClass);
|
||||
|
||||
LOAD_METHOD(java.lang.reflect.Method, getName, "()Ljava/lang/String;", jlrMethod);
|
||||
LOAD_METHOD(java.lang.reflect.Method, getParameterTypes, "()[Ljava/lang/Class;", jlrMethod);
|
||||
LOAD_METHOD(java.lang.reflect.Method, getReturnType, "()Ljava/lang/Class;", jlrMethod);
|
||||
LOAD_METHOD(java.lang.reflect.Method, getModifiers, "()I", jlrMethod);
|
||||
|
||||
LOAD_METHOD(java.lang.reflect.Constructor, getParameterTypes, "()[Ljava/lang/Class;", jlrConstructor);
|
||||
LOAD_METHOD(java.lang.reflect.Constructor, getModifiers, "()I", jlrConstructor);
|
||||
|
||||
LOAD_METHOD(java.lang.reflect.Field, getName, "()Ljava/lang/String;", jlrField);
|
||||
LOAD_METHOD(java.lang.reflect.Field, getType, "()Ljava/lang/Class;", jlrField);
|
||||
LOAD_METHOD(java.lang.reflect.Field, getModifiers, "()I", jlrField);
|
||||
|
||||
LOAD_METHOD(java.lang.Throwable, toString, "()Ljava/lang/String;", jlThrowable);
|
||||
LOAD_METHOD(java.lang.Throwable, getMessage, "()Ljava/lang/String;", jlThrowable);
|
||||
|
||||
LOAD_METHOD(java.lang.Double, doubleValue, "()D", jlDouble);
|
||||
|
||||
LOAD_METHOD(java.lang.Boolean, booleanValue, "()Z", jlBoolean);
|
||||
|
||||
LOAD_STATIC_METHOD(java.lang.System, identityHashCode, "(Ljava/lang/Object;)I", jlSystem);
|
||||
|
||||
LOAD_CONSTRUCTOR(java.lang.Boolean, Boolean, "(Z)V", jlBoolean);
|
||||
LOAD_CONSTRUCTOR(java.lang.Double, Double, "(D)V", jlDouble);
|
||||
|
||||
LOAD_FIELD_OBJ(java.lang.Void, TYPE, "Ljava/lang/Class;", jlVoid);
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
#if XP_MAC
|
||||
|
||||
/**
|
||||
* Workaround for the fact that MRJ loads a different instance of the shared library.
|
||||
*/
|
||||
|
||||
#include "netscape_javascript_JSObject.h"
|
||||
|
||||
static JSObject_RegisterNativeMethods(JNIEnv* jEnv)
|
||||
{
|
||||
// Manually load the required native methods.
|
||||
static JNINativeMethod nativeMethods[] = {
|
||||
"initClass", "()V", (void*)&Java_netscape_javascript_JSObject_initClass,
|
||||
"getMember", "(Ljava/lang/String;)Ljava/lang/Object;", (void*)&Java_netscape_javascript_JSObject_getMember,
|
||||
"getSlot", "(I)Ljava/lang/Object;", (void*)&Java_netscape_javascript_JSObject_getSlot,
|
||||
"setMember", "(Ljava/lang/String;Ljava/lang/Object;)V", (void*)&Java_netscape_javascript_JSObject_setMember,
|
||||
"setSlot", "(ILjava/lang/Object;)V", (void*)&Java_netscape_javascript_JSObject_setSlot,
|
||||
"removeMember", "(Ljava/lang/String;)V", (void*)&Java_netscape_javascript_JSObject_removeMember,
|
||||
"call", "(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;", (void*)&Java_netscape_javascript_JSObject_call,
|
||||
"eval", "(Ljava/lang/String;)Ljava/lang/Object;", (void*)&Java_netscape_javascript_JSObject_eval,
|
||||
|
||||
"toString", "()Ljava/lang/String;", (void*)&Java_netscape_javascript_JSObject_toString,
|
||||
"getWindow", "(Ljava/applet/Applet;)Lnetscape/javascript/JSObject;", (void*)&Java_netscape_javascript_JSObject_getWindow,
|
||||
"finalize", "()V", (void*)&Java_netscape_javascript_JSObject_finalize,
|
||||
/* "equals", "(Ljava/lang/Object;)Z", (void*)&Java_netscape_javascript_JSObject_equals */
|
||||
};
|
||||
(*jEnv)->RegisterNatives(jEnv, njJSObject, nativeMethods, sizeof(nativeMethods) / sizeof(JNINativeMethod));
|
||||
if ((*jEnv)->ExceptionOccurred(jEnv)) {
|
||||
report_java_initialization_error(jEnv, "Couldn't initialize JSObject native methods.");
|
||||
(*jEnv)->ExceptionClear(jEnv);
|
||||
}
|
||||
/* call the initClass method, since we nailed the static initializer for testing. */
|
||||
Java_netscape_javascript_JSObject_initClass(jEnv, njJSObject);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Load Netscape-specific Java extension classes, methods, and fields */
|
||||
static JSBool
|
||||
init_netscape_java_classes(JSJavaVM *jsjava_vm, JNIEnv *jEnv)
|
||||
{
|
||||
LOAD_CLASS(netscape/javascript/JSObject, njJSObject);
|
||||
LOAD_CLASS(netscape/javascript/JSException, njJSException);
|
||||
LOAD_CLASS(netscape/javascript/JSUtil, njJSUtil);
|
||||
|
||||
#if XP_MAC
|
||||
JSObject_RegisterNativeMethods(jEnv);
|
||||
#endif
|
||||
|
||||
LOAD_CONSTRUCTOR(netscape.javascript.JSObject,
|
||||
JSObject, "(I)V", njJSObject);
|
||||
LOAD_CONSTRUCTOR(netscape.javascript.JSException,
|
||||
JSException, "(Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;I)V",
|
||||
njJSException);
|
||||
LOAD_FIELDID(netscape.javascript.JSObject,
|
||||
internal, "I", njJSObject);
|
||||
LOAD_FIELDID(netscape.javascript.JSException,
|
||||
lineno, "I", njJSException);
|
||||
LOAD_FIELDID(netscape.javascript.JSException,
|
||||
tokenIndex, "I", njJSException);
|
||||
LOAD_FIELDID(netscape.javascript.JSException,
|
||||
source, "Ljava/lang/String;", njJSException);
|
||||
LOAD_FIELDID(netscape.javascript.JSException,
|
||||
filename, "Ljava/lang/String;", njJSException);
|
||||
|
||||
LOAD_STATIC_METHOD(netscape.javascript.JSUtil,
|
||||
getStackTrace, "(Ljava/lang/Throwable;)Ljava/lang/String;",
|
||||
njJSUtil);
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSJavaVM *jsjava_vm_list = NULL;
|
||||
|
||||
/*
|
||||
* Called once per Java VM, this function initializes the classes, fields, and
|
||||
* methods required for Java reflection. If java_vm is NULL, a new Java VM is
|
||||
* created, using the provided classpath in addition to any default classpath.
|
||||
* The classpath argument is ignored, however, if java_vm_arg is non-NULL.
|
||||
*/
|
||||
JSJavaVM *
|
||||
JSJ_ConnectToJavaVM(SystemJavaVM *java_vm_arg, void* initargs)
|
||||
{
|
||||
SystemJavaVM* java_vm;
|
||||
JSJavaVM *jsjava_vm;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
PR_ASSERT(JSJ_callbacks);
|
||||
PR_ASSERT(JSJ_callbacks->attach_current_thread);
|
||||
PR_ASSERT(JSJ_callbacks->detach_current_thread);
|
||||
PR_ASSERT(JSJ_callbacks->get_java_vm);
|
||||
|
||||
jsjava_vm = (JSJavaVM*)malloc(sizeof(JSJavaVM));
|
||||
if (!jsjava_vm)
|
||||
return NULL;
|
||||
memset(jsjava_vm, 0, sizeof(JSJavaVM));
|
||||
|
||||
java_vm = java_vm_arg;
|
||||
|
||||
/* If a Java VM was passed in, try to attach to it on the current thread. */
|
||||
if (java_vm) {
|
||||
jEnv = JSJ_callbacks->attach_current_thread(java_vm);
|
||||
if (jEnv == NULL) {
|
||||
jsj_LogError("Failed to attach to Java VM thread\n");
|
||||
free(jsjava_vm);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
PRBool ok;
|
||||
PR_ASSERT(JSJ_callbacks->create_java_vm);
|
||||
PR_ASSERT(JSJ_callbacks->destroy_java_vm);
|
||||
|
||||
ok = JSJ_callbacks->create_java_vm(&java_vm, &jEnv, initargs);
|
||||
if (!ok || java_vm == NULL) {
|
||||
jsj_LogError("Failed to create Java VM\n");
|
||||
free(jsjava_vm);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Remember that we created the VM so that we know to destroy it later */
|
||||
jsjava_vm->jsj_created_java_vm = JS_TRUE;
|
||||
}
|
||||
|
||||
jsjava_vm->java_vm = java_vm;
|
||||
jsjava_vm->main_thread_env = jEnv;
|
||||
|
||||
/* Load the Java classes, and the method and field descriptors required for
|
||||
Java reflection. */
|
||||
if (!init_java_VM_reflection(jsjava_vm, jEnv)) {
|
||||
JSJ_DisconnectFromJavaVM(jsjava_vm);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* JVM initialization for netscape.javascript.JSObject is performed
|
||||
* independently of the other classes that are initialized in
|
||||
* init_java_VM_reflection, because we allow it to fail. In the case
|
||||
* of failure, LiveConnect is still operative, but only when calling
|
||||
* from JS to Java and not vice-versa.
|
||||
*/
|
||||
init_netscape_java_classes(jsjava_vm, jEnv);
|
||||
|
||||
/* Put this VM on the list of all created VMs */
|
||||
jsjava_vm->next = jsjava_vm_list;
|
||||
jsjava_vm_list = jsjava_vm;
|
||||
|
||||
return jsjava_vm;
|
||||
}
|
||||
|
||||
JSJCallbacks *JSJ_callbacks = NULL;
|
||||
|
||||
/* Called once to set up callbacks for all instances of LiveConnect */
|
||||
void
|
||||
JSJ_Init(JSJCallbacks *callbacks)
|
||||
{
|
||||
PR_ASSERT(callbacks);
|
||||
JSJ_callbacks = callbacks;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the provided JSContext by setting up the JS classes necessary for
|
||||
* reflection and by defining JavaPackage objects for the default Java packages
|
||||
* as properties of global_obj. Additional packages may be pre-defined by
|
||||
* setting the predefined_packages argument. (Pre-defining a Java package at
|
||||
* initialization time is not necessary, but it will make package lookup faster
|
||||
* and, more importantly, will avoid unnecessary network accesses if classes
|
||||
* are being loaded over the network.)
|
||||
*/
|
||||
JSBool
|
||||
JSJ_InitJSContext(JSContext *cx, JSObject *global_obj,
|
||||
JavaPackageDef *predefined_packages)
|
||||
{
|
||||
/* Initialize the JavaScript classes used for reflection */
|
||||
if (!jsj_init_JavaObject(cx, global_obj))
|
||||
return JS_FALSE;
|
||||
|
||||
/* if (!jsj_init_JavaMember(cx, global_obj))
|
||||
return JS_FALSE; */
|
||||
|
||||
if (!jsj_init_JavaPackage(cx, global_obj, predefined_packages))
|
||||
return JS_FALSE;
|
||||
|
||||
if (!jsj_init_JavaClass(cx, global_obj))
|
||||
return JS_FALSE;
|
||||
|
||||
if (!jsj_init_JavaArray(cx, global_obj))
|
||||
return JS_FALSE;
|
||||
|
||||
if (!jsj_init_JavaMember(cx, global_obj))
|
||||
return JS_FALSE;
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* Eliminate a reference to a Java class */
|
||||
#define UNLOAD_CLASS(qualified_name, class) \
|
||||
if (class) { \
|
||||
(*jEnv)->DeleteGlobalRef(jEnv, class); \
|
||||
class = NULL; \
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine severs the connection to a Java VM, freeing all related resources.
|
||||
* It shouldn't be called until the global scope has been cleared in all related
|
||||
* JSContexts (so that all LiveConnect objects are finalized) and a JavaScript
|
||||
* GC is performed. Otherwise, accessed to free'ed memory could result.
|
||||
*/
|
||||
void
|
||||
JSJ_DisconnectFromJavaVM(JSJavaVM *jsjava_vm)
|
||||
{
|
||||
JNIEnv *jEnv;
|
||||
SystemJavaVM *java_vm;
|
||||
JSJavaVM *j, **jp;
|
||||
|
||||
java_vm = jsjava_vm->java_vm;
|
||||
jEnv = jsjava_vm->main_thread_env;
|
||||
|
||||
/* Drop all references to Java objects and classes */
|
||||
jsj_DiscardJavaObjReflections(jEnv);
|
||||
jsj_DiscardJavaClassReflections(jEnv);
|
||||
|
||||
if (jsjava_vm->jsj_created_java_vm) {
|
||||
(void)JSJ_callbacks->destroy_java_vm(java_vm, jEnv);
|
||||
} else {
|
||||
UNLOAD_CLASS(java/lang/Object, jlObject);
|
||||
UNLOAD_CLASS(java/lang/Class, jlClass);
|
||||
UNLOAD_CLASS(java/lang/reflect/Method, jlrMethod);
|
||||
UNLOAD_CLASS(java/lang/reflect/Constructor, jlrConstructor);
|
||||
UNLOAD_CLASS(java/lang/reflect/Field, jlrField);
|
||||
UNLOAD_CLASS(java/lang/Throwable, jlThrowable);
|
||||
UNLOAD_CLASS(java/lang/System, jlSystem);
|
||||
UNLOAD_CLASS(java/lang/Boolean, jlBoolean);
|
||||
UNLOAD_CLASS(java/lang/Double, jlDouble);
|
||||
UNLOAD_CLASS(java/lang/String, jlString);
|
||||
UNLOAD_CLASS(java/lang/Void, jlVoid);
|
||||
UNLOAD_CLASS(netscape/javascript/JSObject, njJSObject);
|
||||
UNLOAD_CLASS(netscape/javascript/JSException, njJSException);
|
||||
UNLOAD_CLASS(netscape/javascript/JSUtil, njJSUtil);
|
||||
}
|
||||
|
||||
|
||||
/* Remove this VM from the list of all JSJavaVM objects. */
|
||||
for (jp = &jsjava_vm_list; (j = *jp) != NULL; jp = &j->next) {
|
||||
if (j == jsjava_vm) {
|
||||
*jp = jsjava_vm->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
PR_ASSERT(j);
|
||||
|
||||
free(jsjava_vm);
|
||||
}
|
||||
|
||||
static JSJavaThreadState *thread_list = NULL;
|
||||
|
||||
static JSJavaThreadState *
|
||||
new_jsjava_thread_state(JSJavaVM *jsjava_vm, const char *thread_name, JNIEnv *jEnv)
|
||||
{
|
||||
JSJavaThreadState *jsj_env;
|
||||
|
||||
jsj_env = (JSJavaThreadState *)malloc(sizeof(JSJavaThreadState));
|
||||
if (!jsj_env)
|
||||
return NULL;
|
||||
memset(jsj_env, 0, sizeof(JSJavaThreadState));
|
||||
|
||||
jsj_env->jEnv = jEnv;
|
||||
jsj_env->jsjava_vm = jsjava_vm;
|
||||
if (thread_name)
|
||||
jsj_env->name = strdup(thread_name);
|
||||
|
||||
/* THREADSAFETY - need to protect against races */
|
||||
jsj_env->next = thread_list;
|
||||
thread_list = jsj_env;
|
||||
|
||||
return jsj_env;
|
||||
}
|
||||
|
||||
static JSJavaThreadState *
|
||||
find_jsjava_thread(JNIEnv *jEnv)
|
||||
{
|
||||
JSJavaThreadState *e, **p, *jsj_env;
|
||||
jsj_env = NULL;
|
||||
|
||||
/* THREADSAFETY - need to protect against races in manipulating the thread list */
|
||||
|
||||
/* Search for the thread state among the list of all created
|
||||
LiveConnect threads */
|
||||
for (p = &thread_list; (e = *p) != NULL; p = &(e->next)) {
|
||||
if (e->jEnv == jEnv) {
|
||||
jsj_env = e;
|
||||
*p = jsj_env->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Move a found thread to head of list for faster search next time. */
|
||||
if (jsj_env)
|
||||
thread_list = jsj_env;
|
||||
|
||||
return jsj_env;
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(JSJavaThreadState *)
|
||||
JSJ_AttachCurrentThreadToJava(JSJavaVM *jsjava_vm, const char *name, JNIEnv **java_envp)
|
||||
{
|
||||
JNIEnv *jEnv;
|
||||
SystemJavaVM *java_vm;
|
||||
JSJavaThreadState *jsj_env;
|
||||
|
||||
/* Try to attach a Java thread to the current native thread */
|
||||
java_vm = jsjava_vm->java_vm;
|
||||
jEnv = JSJ_callbacks->attach_current_thread(java_vm);
|
||||
if (jEnv == NULL)
|
||||
return NULL;
|
||||
|
||||
/* If we found an existing thread state, just return it. */
|
||||
jsj_env = find_jsjava_thread(jEnv);
|
||||
if (jsj_env)
|
||||
return jsj_env;
|
||||
|
||||
/* Create a new wrapper around the thread/VM state */
|
||||
jsj_env = new_jsjava_thread_state(jsjava_vm, name, jEnv);
|
||||
|
||||
if (java_envp)
|
||||
*java_envp = jEnv;
|
||||
return jsj_env;
|
||||
}
|
||||
|
||||
static JSJavaVM *
|
||||
map_java_vm_to_jsjava_vm(SystemJavaVM *java_vm)
|
||||
{
|
||||
JSJavaVM *v;
|
||||
for (v = jsjava_vm_list; v; v = v->next) {
|
||||
if (v->java_vm == java_vm)
|
||||
return v;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unfortunately, there's no standard means to associate any private data with
|
||||
* a JNI thread environment, so we need to use the Java environment pointer as
|
||||
* the key in a lookup table that maps it to a JSJavaThreadState structure,
|
||||
* where we store all our per-thread private data. If no existing thread state
|
||||
* is found, a new one is created.
|
||||
*
|
||||
* If an error occurs, returns NULL and sets the errp argument to an error
|
||||
* message, which the caller is responsible for free'ing.
|
||||
*/
|
||||
JSJavaThreadState *
|
||||
jsj_MapJavaThreadToJSJavaThreadState(JNIEnv *jEnv, char **errp)
|
||||
{
|
||||
JSJavaThreadState *jsj_env;
|
||||
SystemJavaVM *java_vm;
|
||||
JSJavaVM *jsjava_vm;
|
||||
|
||||
/* If we found an existing thread state, just return it. */
|
||||
jsj_env = find_jsjava_thread(jEnv);
|
||||
if (jsj_env)
|
||||
return jsj_env;
|
||||
|
||||
/* No one set up a LiveConnect thread state for a given Java thread.
|
||||
Invoke the callback to create one on-the-fly. */
|
||||
|
||||
/* First, figure out which Java VM is calling us */
|
||||
java_vm = JSJ_callbacks->get_java_vm(jEnv);
|
||||
if (jsjava_vm == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Get our private JavaVM data */
|
||||
jsjava_vm = map_java_vm_to_jsjava_vm(java_vm);
|
||||
if (!jsjava_vm) {
|
||||
*errp = PR_smprintf("Total weirdness: No JSJavaVM wrapper ever created "
|
||||
"for JavaVM 0x%08x", java_vm);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jsj_env = new_jsjava_thread_state(jsjava_vm, NULL, jEnv);
|
||||
if (!jsj_env)
|
||||
return NULL;
|
||||
|
||||
return jsj_env;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is used to specify a particular JSContext as *the* JavaScript
|
||||
* execution environment to be used when LiveConnect is accessed from the given
|
||||
* Java thread, i.e. by using one of the methods of netscape.javascript.JSObject.
|
||||
* (There can only be one such JS context for a given Java thread. To
|
||||
* multiplex JSContexts among a single thread, this function must be called
|
||||
* before Java is invoked on that thread.) The return value is the previous
|
||||
* context associated with the given Java thread.
|
||||
*/
|
||||
PR_IMPLEMENT(JSContext *)
|
||||
JSJ_SetDefaultJSContextForJavaThread(JSContext *cx, JSJavaThreadState *jsj_env)
|
||||
{
|
||||
JSContext *old_context;
|
||||
old_context = jsj_env->cx;
|
||||
jsj_env->cx = cx;
|
||||
return old_context;
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(JSBool)
|
||||
JSJ_DetachCurrentThreadFromJava(JSJavaThreadState *jsj_env)
|
||||
{
|
||||
SystemJavaVM *java_vm;
|
||||
JNIEnv* jEnv;
|
||||
JSJavaThreadState *e, **p;
|
||||
|
||||
/* Disassociate the current native thread from its corresponding Java thread */
|
||||
java_vm = jsj_env->jsjava_vm->java_vm;
|
||||
jEnv = jsj_env->jEnv;
|
||||
if (!JSJ_callbacks->detach_current_thread(java_vm, jEnv))
|
||||
return JS_FALSE;
|
||||
|
||||
/* Destroy the LiveConnect execution environment passed in */
|
||||
jsj_ClearPendingJSErrors(jsj_env);
|
||||
|
||||
/* THREADSAFETY - need to protect against races */
|
||||
for (p = &thread_list; (e = *p) != NULL; p = &(e->next)) {
|
||||
if (e == jsj_env) {
|
||||
*p = jsj_env->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(jsj_env);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSBool
|
||||
JSJ_ConvertJavaObjectToJSValue(JSContext *cx, jobject java_obj, jsval *vp)
|
||||
{
|
||||
JNIEnv *jEnv;
|
||||
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
return jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_obj, vp);
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
|
||||
#ifndef MOZILLA_CLIENT
|
||||
|
||||
/* The convenience functions below present a complete, but simplified
|
||||
LiveConnect API which is designed to handle the special case of a single
|
||||
Java-VM, single-threaded operation, and use of only one JSContext. */
|
||||
|
||||
/* We can get away with global variables in our single-threaded,
|
||||
single-JSContext case. */
|
||||
static JSJavaVM * the_jsj_vm = NULL;
|
||||
static JSContext * the_cx = NULL;
|
||||
static JSJavaThreadState * the_jsj_thread = NULL;
|
||||
static JSObject * the_global_js_obj = NULL;
|
||||
|
||||
/* Trivial implementation of callback function */
|
||||
static JSJavaThreadState *
|
||||
default_map_js_context_to_jsj_thread(JSContext *cx, char **errp)
|
||||
{
|
||||
return the_jsj_thread;
|
||||
}
|
||||
|
||||
/* Trivial implementation of callback function */
|
||||
static JSContext *
|
||||
default_map_jsj_thread_to_js_context(JSJavaThreadState *jsj_env, JNIEnv *jEnv, char **errp)
|
||||
{
|
||||
return the_cx;
|
||||
}
|
||||
|
||||
/* Trivial implementation of callback function */
|
||||
static JSObject *
|
||||
default_map_java_object_to_js_object(JNIEnv *jEnv, jobject hint, char **errp)
|
||||
{
|
||||
return the_global_js_obj;
|
||||
}
|
||||
|
||||
static PRBool PR_CALLBACK
|
||||
default_create_java_vm(SystemJavaVM* *jvm, JNIEnv* *initialEnv, void* initargs)
|
||||
{
|
||||
jint err;
|
||||
const char* user_classpath = (const char*)initargs;
|
||||
|
||||
/* No Java VM supplied, so create our own */
|
||||
JDK1_1InitArgs vm_args;
|
||||
|
||||
/* Magic constant indicates JRE version 1.1 */
|
||||
vm_args.version = 0x00010001;
|
||||
JNI_GetDefaultJavaVMInitArgs(&vm_args);
|
||||
|
||||
/* Prepend the classpath argument to the default JVM classpath */
|
||||
if (user_classpath) {
|
||||
#ifdef XP_UNIX
|
||||
const char *full_classpath = PR_smprintf("%s:%s", user_classpath, vm_args.classpath);
|
||||
#else
|
||||
const char *full_classpath = PR_smprintf("%s;%s", user_classpath, vm_args.classpath);
|
||||
#endif
|
||||
if (!full_classpath) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
vm_args.classpath = (char*)full_classpath;
|
||||
}
|
||||
|
||||
err = JNI_CreateJavaVM((JavaVM**)jvm, initialEnv, &vm_args);
|
||||
return err == 0;
|
||||
}
|
||||
|
||||
static PRBool PR_CALLBACK
|
||||
default_destroy_java_vm(SystemJavaVM* jvm, JNIEnv* initialEnv)
|
||||
{
|
||||
JavaVM* java_vm = (JavaVM*)jvm;
|
||||
jint err = (*java_vm)->DestroyJavaVM(java_vm);
|
||||
return err == 0;
|
||||
}
|
||||
|
||||
static JNIEnv* PR_CALLBACK
|
||||
default_attach_current_thread(SystemJavaVM* jvm)
|
||||
{
|
||||
JavaVM* java_vm = (JavaVM*)jvm;
|
||||
JNIEnv* env = NULL;
|
||||
jint err = (*java_vm)->AttachCurrentThread(java_vm, &env, NULL);
|
||||
return env;
|
||||
}
|
||||
|
||||
static PRBool PR_CALLBACK
|
||||
default_detach_current_thread(SystemJavaVM* jvm, JNIEnv* env)
|
||||
{
|
||||
JavaVM* java_vm = (JavaVM*)jvm;
|
||||
/* assert that env is the JNIEnv of the current thread */
|
||||
jint err = (*java_vm)->DetachCurrentThread(java_vm);
|
||||
return err == 0;
|
||||
}
|
||||
|
||||
static SystemJavaVM* PR_CALLBACK
|
||||
default_get_java_vm(JNIEnv* env)
|
||||
{
|
||||
JavaVM* java_vm = NULL;
|
||||
jint err = (*env)->GetJavaVM(env, &java_vm);
|
||||
return (SystemJavaVM*)java_vm;
|
||||
}
|
||||
|
||||
/* Trivial implementations of callback functions */
|
||||
JSJCallbacks jsj_default_callbacks = {
|
||||
default_map_jsj_thread_to_js_context,
|
||||
default_map_js_context_to_jsj_thread,
|
||||
default_map_java_object_to_js_object,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
default_create_java_vm,
|
||||
default_destroy_java_vm,
|
||||
default_attach_current_thread,
|
||||
default_detach_current_thread,
|
||||
default_get_java_vm
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize the provided JSContext by setting up the JS classes necessary for
|
||||
* reflection and by defining JavaPackage objects for the default Java packages
|
||||
* as properties of global_obj. If java_vm is NULL, a new Java VM is
|
||||
* created, using the provided classpath in addition to any default classpath.
|
||||
* The classpath argument is ignored, however, if java_vm is non-NULL.
|
||||
*/
|
||||
JSBool
|
||||
JSJ_SimpleInit(JSContext *cx, JSObject *global_obj, SystemJavaVM *java_vm, const char *classpath)
|
||||
{
|
||||
JNIEnv *jEnv;
|
||||
|
||||
PR_ASSERT(!the_jsj_vm);
|
||||
the_jsj_vm = JSJ_ConnectToJavaVM(java_vm, (void*)classpath);
|
||||
if (!the_jsj_vm)
|
||||
return JS_FALSE;
|
||||
|
||||
JSJ_Init(&jsj_default_callbacks);
|
||||
|
||||
if (!JSJ_InitJSContext(cx, global_obj, NULL))
|
||||
goto error;
|
||||
the_cx = cx;
|
||||
the_global_js_obj = global_obj;
|
||||
|
||||
the_jsj_thread = JSJ_AttachCurrentThreadToJava(the_jsj_vm, "main thread", &jEnv);
|
||||
if (!the_jsj_thread)
|
||||
goto error;
|
||||
JSJ_SetDefaultJSContextForJavaThread(cx, the_jsj_thread);
|
||||
return JS_TRUE;
|
||||
|
||||
error:
|
||||
JSJ_SimpleShutdown();
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free up all LiveConnect resources. Destroy the Java VM if it was
|
||||
* created by LiveConnect.
|
||||
*/
|
||||
PR_IMPLEMENT(void)
|
||||
JSJ_SimpleShutdown()
|
||||
{
|
||||
PR_ASSERT(the_jsj_vm);
|
||||
JSJ_DisconnectFromJavaVM(the_jsj_vm);
|
||||
the_jsj_vm = NULL;
|
||||
the_cx = NULL;
|
||||
the_global_js_obj = NULL;
|
||||
the_jsj_thread = NULL;
|
||||
}
|
||||
|
||||
#endif /* MOZILLA_CLIENT */
|
||||
76
mozilla/js/src/liveconnect/jsj1640.rc
Normal file
76
mozilla/js/src/liveconnect/jsj1640.rc
Normal file
@@ -0,0 +1,76 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
// Version stamp for this .DLL
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <ver.h>
|
||||
|
||||
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
|
||||
FILEVERSION 4 // major, minor, release (alpha 1), build #
|
||||
|
||||
PRODUCTVERSION 4
|
||||
|
||||
FILEFLAGSMASK 0
|
||||
|
||||
FILEFLAGS 0 // final version
|
||||
|
||||
FILEOS VOS_DOS_WINDOWS16
|
||||
|
||||
FILETYPE VFT_DLL
|
||||
|
||||
FILESUBTYPE 0 // not used
|
||||
|
||||
BEGIN
|
||||
|
||||
BLOCK "StringFileInfo"
|
||||
|
||||
BEGIN
|
||||
|
||||
BLOCK "040904E4" // Lang=US English, CharSet=Windows Multilingual
|
||||
|
||||
BEGIN
|
||||
|
||||
VALUE "CompanyName", "Netscape Communications Corporation\0"
|
||||
|
||||
VALUE "FileDescription", "Netscape 16-bit JavaScript-Java Module\0"
|
||||
|
||||
VALUE "FileVersion", "4.0\0"
|
||||
|
||||
VALUE "InternalName", "JSJ1640\0"
|
||||
|
||||
VALUE "LegalCopyright", "Copyright Netscape Communications. 1994-96\0"
|
||||
|
||||
VALUE "LegalTrademarks", "Netscape, Mozilla\0"
|
||||
|
||||
VALUE "OriginalFilename","JSJ1640.DLL\0"
|
||||
|
||||
VALUE "ProductName", "NETSCAPE\0"
|
||||
|
||||
VALUE "ProductVersion", "4.0\0"
|
||||
|
||||
END
|
||||
|
||||
END
|
||||
|
||||
END
|
||||
|
||||
1243
mozilla/js/src/liveconnect/jsj_JSObject.c
Normal file
1243
mozilla/js/src/liveconnect/jsj_JSObject.c
Normal file
File diff suppressed because it is too large
Load Diff
403
mozilla/js/src/liveconnect/jsj_JavaArray.c
Normal file
403
mozilla/js/src/liveconnect/jsj_JavaArray.c
Normal file
@@ -0,0 +1,403 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the definition of the JavaScript JavaArray class.
|
||||
* Instances of JavaArray are used to reflect Java arrays.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jsj_private.h" /* LiveConnect internals */
|
||||
|
||||
/* Shorthands for ASCII (7-bit) decimal and hex conversion. */
|
||||
#define JS7_ISDEC(c) (((c) >= '0') && ((c) <= '9'))
|
||||
#define JS7_UNDEC(c) ((c) - '0')
|
||||
|
||||
/*
|
||||
* Convert any jsval v to an integer jsval if ToString(v)
|
||||
* contains a base-10 integer that fits into 31 bits.
|
||||
* Otherwise return v.
|
||||
*/
|
||||
static jsval
|
||||
try_convert_to_jsint(JSContext *cx, jsval idval)
|
||||
{
|
||||
const jschar *cp;
|
||||
JSString *jsstr;
|
||||
|
||||
jsstr = JS_ValueToString(cx, idval);
|
||||
if (!jsstr)
|
||||
return idval;
|
||||
|
||||
cp = JS_GetStringChars(jsstr);
|
||||
if (JS7_ISDEC(*cp)) {
|
||||
jsuint index = JS7_UNDEC(*cp++);
|
||||
jsuint oldIndex = 0;
|
||||
jsuint c = 0;
|
||||
if (index != 0) {
|
||||
while (JS7_ISDEC(*cp)) {
|
||||
oldIndex = index;
|
||||
c = JS7_UNDEC(*cp);
|
||||
index = 10*index + c;
|
||||
cp++;
|
||||
}
|
||||
}
|
||||
if (*cp == 0 &&
|
||||
(oldIndex < (JSVAL_INT_MAX / 10) ||
|
||||
(oldIndex == (JSVAL_INT_MAX / 10) && c < (JSVAL_INT_MAX % 10)))) {
|
||||
return INT_TO_JSVAL(index);
|
||||
}
|
||||
}
|
||||
return idval;
|
||||
}
|
||||
|
||||
|
||||
static JSBool
|
||||
access_java_array_element(JSContext *cx,
|
||||
JNIEnv *jEnv,
|
||||
JSObject *obj,
|
||||
jsid id,
|
||||
jsval *vp,
|
||||
JSBool do_assignment)
|
||||
{
|
||||
jsval idval;
|
||||
jarray java_array;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
jsize array_length, index;
|
||||
JavaSignature *array_component_signature;
|
||||
|
||||
/* printf("In JavaArray_getProperty\n"); */
|
||||
|
||||
java_wrapper = JS_GetPrivate(cx, obj);
|
||||
if (!java_wrapper) {
|
||||
const char *property_name;
|
||||
if (JS_IdToValue(cx, id, &idval) && JSVAL_IS_STRING(idval) &&
|
||||
(property_name = JS_GetStringBytes(JSVAL_TO_STRING(idval))) != NULL) {
|
||||
if (!strcmp(property_name, "constructor")) {
|
||||
*vp = JSVAL_VOID;
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
JS_ReportError(cx, "illegal operation on JavaArray prototype object");
|
||||
return JS_FALSE;
|
||||
}
|
||||
class_descriptor = java_wrapper->class_descriptor;
|
||||
java_array = java_wrapper->java_obj;
|
||||
|
||||
PR_ASSERT(class_descriptor->type == JAVA_SIGNATURE_ARRAY);
|
||||
|
||||
JS_IdToValue(cx, id, &idval);
|
||||
|
||||
if (!JSVAL_IS_INT(idval))
|
||||
idval = try_convert_to_jsint(cx, idval);
|
||||
|
||||
if (!JSVAL_IS_INT(idval)) {
|
||||
/*
|
||||
* Usually, properties of JavaArray objects are indexed by integers, but
|
||||
* Java arrays also inherit all the methods of java.lang.Object, so a
|
||||
* string-valued property is also possible.
|
||||
*/
|
||||
if (JSVAL_IS_STRING(idval)) {
|
||||
const char *member_name;
|
||||
|
||||
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
|
||||
|
||||
if (do_assignment) {
|
||||
JSVersion version = JS_GetVersion(cx);
|
||||
|
||||
if (!JSVERSION_IS_ECMA(version)) {
|
||||
|
||||
JS_ReportError(cx, "Attempt to write to invalid Java array "
|
||||
"element \"%s\"", member_name);
|
||||
return JS_FALSE;
|
||||
} else {
|
||||
*vp = JSVAL_VOID;
|
||||
return JS_TRUE;
|
||||
}
|
||||
} else {
|
||||
if (!strcmp(member_name, "length")) {
|
||||
array_length = jsj_GetJavaArrayLength(cx, jEnv, java_array);
|
||||
if (array_length < 0)
|
||||
return JS_FALSE;
|
||||
if (vp)
|
||||
*vp = INT_TO_JSVAL(array_length);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* Check to see if we're reflecting a Java array method */
|
||||
return JavaObject_getPropertyById(cx, obj, id, vp);
|
||||
}
|
||||
}
|
||||
|
||||
JS_ReportError(cx, "invalid Java array index expression");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
index = JSVAL_TO_INT(idval);
|
||||
|
||||
#if 0
|
||||
array_length = jsj_GetJavaArrayLength(cx, jEnv, java_array);
|
||||
if (array_length < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
/* Just let Java throw an exception instead of checking array bounds here */
|
||||
if (index < 0 || index >= array_length) {
|
||||
JS_ReportError(cx, "Java array index %d out of range", index);
|
||||
return JS_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
array_component_signature = class_descriptor->array_component_signature;
|
||||
|
||||
if (!vp)
|
||||
return JS_TRUE;
|
||||
|
||||
if (do_assignment) {
|
||||
return jsj_SetJavaArrayElement(cx, jEnv, java_array, index,
|
||||
array_component_signature, *vp);
|
||||
} else {
|
||||
return jsj_GetJavaArrayElement(cx, jEnv, java_array, index,
|
||||
array_component_signature, vp);
|
||||
}
|
||||
}
|
||||
|
||||
PR_STATIC_CALLBACK(JSBool)
|
||||
JavaArray_getPropertyById(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
||||
{
|
||||
JNIEnv *jEnv;
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
return access_java_array_element(cx, jEnv, obj, id, vp, JS_FALSE);
|
||||
}
|
||||
|
||||
PR_STATIC_CALLBACK(JSBool)
|
||||
JavaArray_setPropertyById(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
||||
{
|
||||
JNIEnv *jEnv;
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
return access_java_array_element(cx, jEnv, obj, id, vp, JS_TRUE);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaArray_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSObject **objp, JSProperty **propp
|
||||
#if defined JS_THREADSAFE && defined DEBUG
|
||||
, const char *file, uintN line
|
||||
#endif
|
||||
)
|
||||
{
|
||||
JNIEnv *jEnv;
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
return access_java_array_element(cx, jEnv, obj, id, NULL, JS_FALSE);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaArray_defineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
|
||||
JSPropertyOp getter, JSPropertyOp setter,
|
||||
uintN attrs, JSProperty **propp)
|
||||
{
|
||||
JS_ReportError(cx, "Cannot define a new property in a JavaArray");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaArray_getAttributes(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSProperty *prop, uintN *attrsp)
|
||||
{
|
||||
/* We don't maintain JS property attributes for Java class members */
|
||||
*attrsp = JSPROP_PERMANENT|JSPROP_ENUMERATE;
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaArray_setAttributes(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSProperty *prop, uintN *attrsp)
|
||||
{
|
||||
/* We don't maintain JS property attributes for Java class members */
|
||||
if (*attrsp != (JSPROP_PERMANENT|JSPROP_ENUMERATE)) {
|
||||
PR_ASSERT(0);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Silently ignore all setAttribute attempts */
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaArray_deleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
{
|
||||
JSVersion version = JS_GetVersion(cx);
|
||||
|
||||
*vp = JSVAL_FALSE;
|
||||
|
||||
if (!JSVERSION_IS_ECMA(version)) {
|
||||
JS_ReportError(cx, "Properties of JavaArray objects may not be deleted");
|
||||
return JS_FALSE;
|
||||
} else {
|
||||
/* Attempts to delete permanent properties are silently ignored
|
||||
by ECMAScript. */
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaArray_defaultValue(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
||||
{
|
||||
/* printf("In JavaArray_defaultValue()\n"); */
|
||||
return JavaObject_convert(cx, obj, JSTYPE_STRING, vp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaArray_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
|
||||
jsval *statep, jsid *idp)
|
||||
{
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
JNIEnv *jEnv;
|
||||
jsize array_length, index;
|
||||
|
||||
java_wrapper = JS_GetPrivate(cx, obj);
|
||||
/* Check for prototype object */
|
||||
if (!java_wrapper) {
|
||||
*statep = JSVAL_NULL;
|
||||
if (idp)
|
||||
*idp = INT_TO_JSVAL(0);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
array_length = jsj_GetJavaArrayLength(cx, jEnv, java_wrapper->java_obj);
|
||||
if (array_length < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
switch(enum_op) {
|
||||
case JSENUMERATE_INIT:
|
||||
*statep = INT_TO_JSVAL(0);
|
||||
|
||||
if (idp)
|
||||
*idp = INT_TO_JSVAL(array_length);
|
||||
return JS_TRUE;
|
||||
|
||||
case JSENUMERATE_NEXT:
|
||||
index = JSVAL_TO_INT(*statep);
|
||||
if (index < array_length) {
|
||||
JS_ValueToId(cx, INT_TO_JSVAL(index), idp);
|
||||
index++;
|
||||
*statep = INT_TO_JSVAL(index);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* Fall through ... */
|
||||
|
||||
case JSENUMERATE_DESTROY:
|
||||
*statep = JSVAL_NULL;
|
||||
return JS_TRUE;
|
||||
|
||||
default:
|
||||
PR_ASSERT(0);
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaArray_checkAccess(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSAccessMode mode, jsval *vp, uintN *attrsp)
|
||||
{
|
||||
switch (mode) {
|
||||
case JSACC_WATCH:
|
||||
JS_ReportError(cx, "Cannot place watchpoints on JavaArray object properties");
|
||||
return JS_FALSE;
|
||||
|
||||
case JSACC_IMPORT:
|
||||
JS_ReportError(cx, "Cannot export a JavaArray object's properties");
|
||||
return JS_FALSE;
|
||||
|
||||
default:
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
JSObjectOps JavaArray_ops = {
|
||||
/* Mandatory non-null function pointer members. */
|
||||
NULL, /* newObjectMap */
|
||||
NULL, /* destroyObjectMap */
|
||||
JavaArray_lookupProperty,
|
||||
JavaArray_defineProperty,
|
||||
JavaArray_getPropertyById, /* getProperty */
|
||||
JavaArray_setPropertyById, /* setProperty */
|
||||
JavaArray_getAttributes,
|
||||
JavaArray_setAttributes,
|
||||
JavaArray_deleteProperty,
|
||||
JavaArray_defaultValue,
|
||||
JavaArray_newEnumerate,
|
||||
JavaArray_checkAccess,
|
||||
|
||||
/* Optionally non-null members start here. */
|
||||
NULL, /* thisObject */
|
||||
NULL, /* dropProperty */
|
||||
NULL, /* call */
|
||||
NULL, /* construct */
|
||||
NULL, /* xdrObject */
|
||||
NULL /* hasInstance */
|
||||
};
|
||||
|
||||
static JSObjectOps *
|
||||
JavaArray_getObjectOps(JSContext *cx, JSClass *clazz)
|
||||
{
|
||||
return &JavaArray_ops;
|
||||
}
|
||||
|
||||
JSClass JavaArray_class = {
|
||||
"JavaArray", JSCLASS_HAS_PRIVATE,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, JavaObject_convert, JavaObject_finalize,
|
||||
JavaArray_getObjectOps,
|
||||
};
|
||||
|
||||
extern PR_IMPORT_DATA(JSObjectOps) js_ObjectOps;
|
||||
|
||||
|
||||
/* Initialize the JS JavaArray class */
|
||||
JSBool
|
||||
jsj_init_JavaArray(JSContext *cx, JSObject *global_obj)
|
||||
{
|
||||
JavaArray_ops.newObjectMap = js_ObjectOps.newObjectMap;
|
||||
JavaArray_ops.destroyObjectMap = js_ObjectOps.destroyObjectMap;
|
||||
|
||||
if (!JS_InitClass(cx, global_obj,
|
||||
0, &JavaArray_class, 0, 0,
|
||||
0, 0, 0, 0))
|
||||
return JS_FALSE;
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
586
mozilla/js/src/liveconnect/jsj_JavaClass.c
Normal file
586
mozilla/js/src/liveconnect/jsj_JavaClass.c
Normal file
@@ -0,0 +1,586 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the native code implementation of JS's JavaClass class.
|
||||
*
|
||||
* A JavaClass is JavaScript's representation of a Java class.
|
||||
* Its parent JS object is always a JavaPackage object. A JavaClass is not an
|
||||
* exact reflection of Java's corresponding java.lang.Class object. Rather,
|
||||
* the properties of a JavaClass are the static methods and properties of the
|
||||
* corresponding Java class.
|
||||
*
|
||||
* Note that there is no runtime equivalent to the JavaClass class in Java.
|
||||
* (Although there are instances of java.lang.String and there are static
|
||||
* methods of java.lang.String that can be invoked, there's no such thing as
|
||||
* a first-class object that can be referenced simply as "java.lang.String".)
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jsj_private.h" /* LiveConnect internals */
|
||||
|
||||
static JSBool
|
||||
JavaClass_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
||||
{
|
||||
char *name;
|
||||
JSString *str;
|
||||
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
|
||||
class_descriptor = JS_GetPrivate(cx, obj);
|
||||
if (!class_descriptor)
|
||||
return JS_FALSE;
|
||||
|
||||
switch(type) {
|
||||
|
||||
|
||||
case JSTYPE_STRING:
|
||||
/* Convert '/' to '.' so that it looks like Java language syntax. */
|
||||
if (!class_descriptor->name)
|
||||
break;
|
||||
name = PR_smprintf("[JavaClass %s]", class_descriptor->name);
|
||||
if (!name) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
str = JS_NewString(cx, name, strlen(name));
|
||||
if (!str) {
|
||||
free(name);
|
||||
/* It's not necessary to call JS_ReportOutOfMemory(), as
|
||||
JS_NewString() will do so on failure. */
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
*vp = STRING_TO_JSVAL(str);
|
||||
return JS_TRUE;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
lookup_static_member_by_id(JSContext *cx, JNIEnv *jEnv, JSObject *obj,
|
||||
JavaClassDescriptor **class_descriptorp,
|
||||
jsid id, JavaMemberDescriptor **memberp)
|
||||
{
|
||||
jsval idval;
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
const char *member_name;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
|
||||
class_descriptor = JS_GetPrivate(cx, obj);
|
||||
if (!class_descriptor) {
|
||||
*class_descriptorp = NULL;
|
||||
*memberp = NULL;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
if (class_descriptorp)
|
||||
*class_descriptorp = class_descriptor;
|
||||
|
||||
member_descriptor = jsj_LookupJavaStaticMemberDescriptorById(cx, jEnv, class_descriptor, id);
|
||||
if (!member_descriptor) {
|
||||
JS_IdToValue(cx, id, &idval);
|
||||
if (!JSVAL_IS_STRING(idval)) {
|
||||
JS_ReportError(cx, "invalid JavaClass property expression. "
|
||||
"(methods and fields of a JavaClass object can only be identified by their name)");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
|
||||
|
||||
/* Why do we have to do this ? */
|
||||
if (!strcmp(member_name, "prototype")) {
|
||||
*memberp = NULL;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JS_ReportError(cx, "Java class %s has no public static field or method named \"%s\"",
|
||||
class_descriptor->name, member_name);
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (memberp)
|
||||
*memberp = member_descriptor;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
PR_STATIC_CALLBACK(JSBool)
|
||||
JavaClass_getPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
{
|
||||
jsval idval;
|
||||
jclass java_class;
|
||||
const char *member_name;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
/* printf("In JavaClass_getProperty\n"); */
|
||||
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
if (!lookup_static_member_by_id(cx, jEnv, obj, &class_descriptor, id, &member_descriptor))
|
||||
return JS_FALSE;
|
||||
if (!member_descriptor) {
|
||||
*vp = JSVAL_VOID;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
java_class = class_descriptor->java_class;
|
||||
|
||||
if (member_descriptor->field) {
|
||||
if (!member_descriptor->methods) {
|
||||
return jsj_GetJavaFieldValue(cx, jEnv, member_descriptor->field, java_class, vp);
|
||||
} else {
|
||||
PR_ASSERT(0);
|
||||
}
|
||||
} else {
|
||||
JSFunction *function;
|
||||
|
||||
/* TODO - eliminate JSFUN_BOUND_METHOD */
|
||||
JS_IdToValue(cx, id, &idval);
|
||||
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
|
||||
function = JS_NewFunction(cx, jsj_JavaStaticMethodWrapper, 0,
|
||||
JSFUN_BOUND_METHOD, obj, member_name);
|
||||
if (!function)
|
||||
return JS_FALSE;
|
||||
|
||||
*vp = OBJECT_TO_JSVAL(JS_GetFunctionObject(function));
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
PR_STATIC_CALLBACK(JSBool)
|
||||
JavaClass_setPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
{
|
||||
jclass java_class;
|
||||
const char *member_name;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
jsval idval;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
/* printf("In JavaClass_setProperty\n"); */
|
||||
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
if (!lookup_static_member_by_id(cx, jEnv, obj, &class_descriptor, id, &member_descriptor))
|
||||
return JS_FALSE;
|
||||
|
||||
/* Check for the case where there is a method with the given name, but no field
|
||||
with that name */
|
||||
if (!member_descriptor->field)
|
||||
goto no_such_field;
|
||||
|
||||
/* Silently fail if field value is final (immutable), as required by ECMA spec */
|
||||
if (member_descriptor->field->modifiers & ACC_FINAL)
|
||||
return JS_TRUE;
|
||||
|
||||
java_class = class_descriptor->java_class;
|
||||
return jsj_SetJavaFieldValue(cx, jEnv, member_descriptor->field, java_class, *vp);
|
||||
|
||||
no_such_field:
|
||||
JS_IdToValue(cx, id, &idval);
|
||||
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
|
||||
JS_ReportError(cx, "No static field named \"%s\" in Java class %s",
|
||||
member_name, class_descriptor->name);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the private native data associated with the JavaPackage object.
|
||||
*/
|
||||
PR_STATIC_CALLBACK(void)
|
||||
JavaClass_finalize(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
JNIEnv *jEnv;
|
||||
|
||||
JavaClassDescriptor *class_descriptor = JS_GetPrivate(cx, obj);
|
||||
if (!class_descriptor)
|
||||
return;
|
||||
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return;
|
||||
|
||||
/* printf("Finalizing %s\n", class_descriptor->name); */
|
||||
jsj_ReleaseJavaClassDescriptor(cx, jEnv, class_descriptor);
|
||||
}
|
||||
|
||||
|
||||
static JSBool
|
||||
JavaClass_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSObject **objp, JSProperty **propp
|
||||
#if defined JS_THREADSAFE && defined DEBUG
|
||||
, const char *file, uintN line
|
||||
#endif
|
||||
)
|
||||
{
|
||||
JNIEnv *jEnv;
|
||||
JSErrorReporter old_reporter;
|
||||
|
||||
/* printf("In JavaClass_lookupProperty()\n"); */
|
||||
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
old_reporter = JS_SetErrorReporter(cx, NULL);
|
||||
if (lookup_static_member_by_id(cx, jEnv, obj, NULL, id, NULL)) {
|
||||
*objp = obj;
|
||||
*propp = (JSProperty*)1;
|
||||
} else {
|
||||
*objp = NULL;
|
||||
*propp = NULL;
|
||||
}
|
||||
|
||||
JS_SetErrorReporter(cx, old_reporter);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaClass_defineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
|
||||
JSPropertyOp getter, JSPropertyOp setter,
|
||||
uintN attrs, JSProperty **propp)
|
||||
{
|
||||
JS_ReportError(cx, "Cannot define a new property in a JavaClass");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaClass_getAttributes(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSProperty *prop, uintN *attrsp)
|
||||
{
|
||||
/* We don't maintain JS property attributes for Java class members */
|
||||
*attrsp = JSPROP_PERMANENT|JSPROP_ENUMERATE;
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaClass_setAttributes(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSProperty *prop, uintN *attrsp)
|
||||
{
|
||||
/* We don't maintain JS property attributes for Java class members */
|
||||
if (*attrsp != (JSPROP_PERMANENT|JSPROP_ENUMERATE)) {
|
||||
PR_ASSERT(0);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Silently ignore all setAttribute attempts */
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaClass_deleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
{
|
||||
JSVersion version = JS_GetVersion(cx);
|
||||
|
||||
*vp = JSVAL_FALSE;
|
||||
|
||||
if (!JSVERSION_IS_ECMA(version)) {
|
||||
JS_ReportError(cx, "Properties of JavaClass objects may not be deleted");
|
||||
return JS_FALSE;
|
||||
} else {
|
||||
/* Attempts to delete permanent properties are silently ignored
|
||||
by ECMAScript. */
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaClass_defaultValue(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
||||
{
|
||||
/* printf("In JavaClass_defaultValue()\n"); */
|
||||
return JavaClass_convert(cx, obj, JSTYPE_STRING, vp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaClass_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
|
||||
jsval *statep, jsid *idp)
|
||||
{
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
class_descriptor = JS_GetPrivate(cx, obj);
|
||||
|
||||
/* Check for prototype JavaClass object */
|
||||
if (!class_descriptor) {
|
||||
*statep = JSVAL_NULL;
|
||||
if (idp)
|
||||
*idp = INT_TO_JSVAL(0);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
switch(enum_op) {
|
||||
case JSENUMERATE_INIT:
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
member_descriptor = jsj_GetClassStaticMembers(cx, jEnv, class_descriptor);
|
||||
*statep = PRIVATE_TO_JSVAL(member_descriptor);
|
||||
if (idp)
|
||||
*idp = INT_TO_JSVAL(class_descriptor->num_instance_members);
|
||||
return JS_TRUE;
|
||||
|
||||
case JSENUMERATE_NEXT:
|
||||
member_descriptor = JSVAL_TO_PRIVATE(*statep);
|
||||
if (member_descriptor) {
|
||||
*idp = member_descriptor->id;
|
||||
*statep = PRIVATE_TO_JSVAL(member_descriptor->next);
|
||||
return JS_TRUE;
|
||||
}
|
||||
/* Fall through ... */
|
||||
|
||||
case JSENUMERATE_DESTROY:
|
||||
*statep = JSVAL_NULL;
|
||||
return JS_TRUE;
|
||||
|
||||
default:
|
||||
PR_ASSERT(0);
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaClass_checkAccess(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSAccessMode mode, jsval *vp, uintN *attrsp)
|
||||
{
|
||||
switch (mode) {
|
||||
case JSACC_WATCH:
|
||||
JS_ReportError(cx, "Cannot place watchpoints on JavaClass object properties");
|
||||
return JS_FALSE;
|
||||
|
||||
case JSACC_IMPORT:
|
||||
JS_ReportError(cx, "Cannot export a JavaClass object's properties");
|
||||
return JS_FALSE;
|
||||
|
||||
default:
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement the JavaScript instanceof operator for JavaClass objects by using
|
||||
* the equivalent Java instanceof operation.
|
||||
*/
|
||||
static JSBool
|
||||
JavaClass_hasInstance(JSContext *cx, JSObject *obj, jsval candidate_jsval,
|
||||
JSBool *has_instancep)
|
||||
{
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
JSClass *js_class;
|
||||
JSBool has_instance;
|
||||
JSObject *candidate_obj;
|
||||
jclass java_class;
|
||||
jobject java_obj;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
has_instance = JS_FALSE;
|
||||
class_descriptor = JS_GetPrivate(cx, obj);
|
||||
if (!class_descriptor) {
|
||||
JS_ReportError(cx, "illegal operation on JavaClass prototype object");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure that the thing to the left of the instanceof operator is a
|
||||
* Java object.
|
||||
*/
|
||||
if (!JSVAL_IS_OBJECT(candidate_jsval))
|
||||
goto done;
|
||||
candidate_obj = JSVAL_TO_OBJECT(candidate_jsval);
|
||||
js_class = JS_GetClass(candidate_obj);
|
||||
if ((js_class != &JavaObject_class) && (js_class != &JavaArray_class))
|
||||
goto done;
|
||||
|
||||
java_class = class_descriptor->java_class;
|
||||
java_wrapper = JS_GetPrivate(cx, candidate_obj);
|
||||
if (!java_wrapper) {
|
||||
JS_ReportError(cx, "illegal operation on prototype object");
|
||||
return JS_FALSE;
|
||||
}
|
||||
java_obj = java_wrapper->java_obj;
|
||||
/* Get JNI pointer */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
has_instance = (*jEnv)->IsInstanceOf(jEnv, java_obj, java_class);
|
||||
|
||||
done:
|
||||
*has_instancep = has_instance;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSObjectOps JavaClass_ops = {
|
||||
/* Mandatory non-null function pointer members. */
|
||||
NULL, /* newObjectMap */
|
||||
NULL, /* destroyObjectMap */
|
||||
JavaClass_lookupProperty,
|
||||
JavaClass_defineProperty,
|
||||
JavaClass_getPropertyById, /* getProperty */
|
||||
JavaClass_setPropertyById, /* setProperty */
|
||||
JavaClass_getAttributes,
|
||||
JavaClass_setAttributes,
|
||||
JavaClass_deleteProperty,
|
||||
JavaClass_defaultValue,
|
||||
JavaClass_newEnumerate,
|
||||
JavaClass_checkAccess,
|
||||
|
||||
/* Optionally non-null members start here. */
|
||||
NULL, /* thisObject */
|
||||
NULL, /* dropProperty */
|
||||
jsj_JavaConstructorWrapper, /* call */
|
||||
jsj_JavaConstructorWrapper, /* construct */
|
||||
NULL, /* xdrObject */
|
||||
JavaClass_hasInstance, /* hasInstance */
|
||||
};
|
||||
|
||||
static JSObjectOps *
|
||||
JavaClass_getObjectOps(JSContext *cx, JSClass *clazz)
|
||||
{
|
||||
return &JavaClass_ops;
|
||||
}
|
||||
|
||||
JSClass JavaClass_class = {
|
||||
"JavaClass", JSCLASS_HAS_PRIVATE,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, JavaClass_convert, JavaClass_finalize,
|
||||
JavaClass_getObjectOps,
|
||||
};
|
||||
|
||||
static JSObject *
|
||||
jsj_new_JavaClass(JSContext *cx, JNIEnv *jEnv, JSObject* parent_obj,
|
||||
JavaClassDescriptor *class_descriptor)
|
||||
{
|
||||
JSObject *JavaClass_obj;
|
||||
|
||||
JavaClass_obj = JS_NewObject(cx, &JavaClass_class, 0, parent_obj);
|
||||
if (!JavaClass_obj)
|
||||
return NULL;
|
||||
|
||||
JS_SetPrivate(cx, JavaClass_obj, (void *)class_descriptor);
|
||||
|
||||
#ifdef DEBUG
|
||||
/* printf("JavaClass \'%s\' created\n", class_descriptor->name); */
|
||||
#endif
|
||||
|
||||
return JavaClass_obj;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
jsj_define_JavaClass(JSContext *cx, JNIEnv *jEnv, JSObject* parent_obj,
|
||||
const char *simple_class_name,
|
||||
jclass java_class)
|
||||
{
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
JSObject *JavaClass_obj;
|
||||
|
||||
class_descriptor = jsj_GetJavaClassDescriptor(cx, jEnv, java_class);
|
||||
if (!class_descriptor)
|
||||
return NULL;
|
||||
|
||||
JavaClass_obj = jsj_new_JavaClass(cx, jEnv, parent_obj, class_descriptor);
|
||||
if (!JavaClass_obj)
|
||||
return NULL;
|
||||
|
||||
if (!JS_DefineProperty(cx, parent_obj, simple_class_name,
|
||||
OBJECT_TO_JSVAL(JavaClass_obj), 0, 0,
|
||||
JSPROP_PERMANENT|JSPROP_READONLY|JSPROP_ENUMERATE))
|
||||
return NULL;
|
||||
return JavaClass_obj;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The getClass() native JS method is defined as a property of the global
|
||||
* object. Given a JavaObject it returns the corresponding JavaClass. This
|
||||
* is useful for accessing static methods and fields.
|
||||
*
|
||||
* js> getClass(new java.lang.String("foo"))
|
||||
* [JavaClass java.lang.String]
|
||||
*/
|
||||
static JSBool
|
||||
getClass(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
JSObject *obj_arg, *JavaClass_obj;
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
if (argc != 1 ||
|
||||
!JSVAL_IS_OBJECT(argv[0]) ||
|
||||
!(obj_arg = JSVAL_TO_OBJECT(argv[0])) ||
|
||||
(!JS_InstanceOf(cx, obj_arg, &JavaObject_class, 0) &&
|
||||
!JS_InstanceOf(cx, obj_arg, &JavaArray_class, 0))) {
|
||||
JS_ReportError(cx, "getClass expects a Java object argument");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
java_wrapper = JS_GetPrivate(cx, obj_arg);
|
||||
if (!java_wrapper) {
|
||||
JS_ReportError(cx, "getClass called on prototype object");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
class_descriptor = java_wrapper->class_descriptor;
|
||||
|
||||
JavaClass_obj = jsj_new_JavaClass(cx, jEnv, NULL, class_descriptor);
|
||||
if (!JavaClass_obj)
|
||||
return JS_FALSE;
|
||||
*rval = OBJECT_TO_JSVAL(JavaClass_obj);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
extern PR_IMPORT_DATA(JSObjectOps) js_ObjectOps;
|
||||
|
||||
JSBool
|
||||
jsj_init_JavaClass(JSContext *cx, JSObject *global_obj)
|
||||
{
|
||||
JavaClass_ops.newObjectMap = js_ObjectOps.newObjectMap;
|
||||
JavaClass_ops.destroyObjectMap = js_ObjectOps.destroyObjectMap;
|
||||
|
||||
/* Define JavaClass class */
|
||||
if (!JS_InitClass(cx, global_obj, 0, &JavaClass_class, 0, 0, 0, 0, 0, 0))
|
||||
return JS_FALSE;
|
||||
|
||||
if (!JS_DefineFunction(cx, global_obj, "getClass", getClass, 0,
|
||||
JSPROP_READONLY))
|
||||
return JS_FALSE;
|
||||
|
||||
return jsj_InitJavaClassReflectionsTable();
|
||||
}
|
||||
|
||||
134
mozilla/js/src/liveconnect/jsj_JavaMember.c
Normal file
134
mozilla/js/src/liveconnect/jsj_JavaMember.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/* -*- Mode: C; tab-width: 8 -*-
|
||||
* Copyright (C) 1998 Netscape Communications Corporation, All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the native code implementation of JS's JavaMember class.
|
||||
* JavaMember's are a strange beast required only to handle the special case
|
||||
* of a public field and a public method that appear in the same class and
|
||||
* have the same name. When such a field/method is used in Java, the compiler
|
||||
* can statically determine from context whether the field or the method is
|
||||
* being referenced, but that is not possible with JavaScript. For example:
|
||||
*
|
||||
* ambiguousVal = javaObj.fieldOrMethod; // ambiguousVal is a JavaMember object
|
||||
* a = ambiguousVal(); // ambiguousVal used as a method value
|
||||
* b = ambiguousVal + 4; // ambiguousVal used as a field value
|
||||
*
|
||||
* A JavaMember instance carries both the captured value of the Java field and
|
||||
* the method value until the context that the value is to be used in is known,
|
||||
* at which point conversion forces the use of one or the other.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jsj_private.h" /* LiveConnect internals */
|
||||
|
||||
/* Private, native portion of a JavaMember */
|
||||
typedef struct JavaMethodOrFieldValue {
|
||||
jsval method_val;
|
||||
jsval field_val;
|
||||
} JavaMethodOrFieldValue;
|
||||
|
||||
JSObject *
|
||||
jsj_CreateJavaMember(JSContext *cx, jsval method_val, jsval field_val)
|
||||
{
|
||||
JavaMethodOrFieldValue *member_val;
|
||||
JSObject *JavaMember_obj;
|
||||
|
||||
member_val = (JavaMethodOrFieldValue *)JS_malloc(cx, sizeof(*member_val));
|
||||
if (!member_val)
|
||||
return NULL;
|
||||
|
||||
JavaMember_obj = JS_NewObject(cx, &JavaMember_class, 0, 0);
|
||||
if (!JavaMember_obj) {
|
||||
JS_free(cx, member_val);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JS_SetPrivate(cx, JavaMember_obj, (void *)member_val);
|
||||
member_val->method_val = method_val;
|
||||
JS_AddRoot(cx, &member_val->method_val);
|
||||
member_val->field_val = field_val;
|
||||
if (JSVAL_IS_GCTHING(field_val))
|
||||
JS_AddRoot(cx, &member_val->field_val);
|
||||
|
||||
return JavaMember_obj;
|
||||
}
|
||||
|
||||
static void
|
||||
JavaMember_finalize(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
JavaMethodOrFieldValue *member_val;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return;
|
||||
|
||||
member_val = JS_GetPrivate(cx, obj);
|
||||
if (!member_val)
|
||||
return;
|
||||
JS_RemoveRoot(cx, &member_val->method_val);
|
||||
if (JSVAL_IS_GCTHING(member_val->method_val))
|
||||
JS_RemoveRoot(cx, &member_val->method_val);
|
||||
JS_free(cx, member_val);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaMember_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
||||
{
|
||||
JavaMethodOrFieldValue *member_val;
|
||||
|
||||
member_val = JS_GetPrivate(cx, obj);
|
||||
if (!member_val) {
|
||||
if (type == JSTYPE_OBJECT) {
|
||||
*vp = OBJECT_TO_JSVAL(obj);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JS_ReportError(cx, "illegal operation on JavaObject prototype object");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case JSTYPE_VOID:
|
||||
case JSTYPE_STRING:
|
||||
case JSTYPE_NUMBER:
|
||||
case JSTYPE_BOOLEAN:
|
||||
case JSTYPE_OBJECT:
|
||||
*vp = member_val->field_val;
|
||||
return JS_TRUE;
|
||||
|
||||
case JSTYPE_FUNCTION:
|
||||
*vp = member_val->method_val;
|
||||
return JS_TRUE;
|
||||
|
||||
default:
|
||||
PR_ASSERT(0);
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
JSClass JavaMember_class = {
|
||||
"JavaMember", JSCLASS_HAS_PRIVATE,
|
||||
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
|
||||
JS_EnumerateStub, JS_ResolveStub,
|
||||
JavaMember_convert, JavaMember_finalize
|
||||
};
|
||||
|
||||
extern PR_IMPORT_DATA(JSObjectOps) js_ObjectOps;
|
||||
|
||||
JSBool
|
||||
jsj_init_JavaMember(JSContext *cx, JSObject *global_obj)
|
||||
{
|
||||
if (!JS_InitClass(cx, global_obj,
|
||||
0, &JavaMember_class, 0, 0,
|
||||
0, 0,
|
||||
0, 0))
|
||||
return JS_FALSE;
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
686
mozilla/js/src/liveconnect/jsj_JavaObject.c
Normal file
686
mozilla/js/src/liveconnect/jsj_JavaObject.c
Normal file
@@ -0,0 +1,686 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the native code implementation of JS's JavaObject class.
|
||||
*
|
||||
* An instance of JavaObject is the JavaScript reflection of a Java object.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jsj_private.h" /* LiveConnect internals */
|
||||
#include "jsj_hash.h" /* Hash table with Java object as key */
|
||||
|
||||
|
||||
/*
|
||||
* This is a hash table that maps from Java objects to JS objects.
|
||||
* It is used to ensure that the same JS object is obtained when a Java
|
||||
* object is reflected more than once, so that JS object equality tests
|
||||
* work in the expected manner, i.e. the "==" and "===" operators.
|
||||
*
|
||||
* The table entry keys are Java objects (of type jobject) and the entry values
|
||||
* are JSObject pointers. Because the jobject type is an opaque handle and
|
||||
* not necessarily a pointer, the hashing and key comparison functions must
|
||||
* invoke the appropriate JVM functions.
|
||||
*
|
||||
* When the corresponding JS object instance is finalized, the entry is
|
||||
* removed from the table, and a Java GC root for the Java object is removed.
|
||||
*/
|
||||
static JSJHashTable *java_obj_reflections = NULL;
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
static PRMonitor *java_obj_reflections_monitor = NULL;
|
||||
#endif
|
||||
|
||||
static JSBool
|
||||
init_java_obj_reflections_table()
|
||||
{
|
||||
java_obj_reflections =
|
||||
JSJ_NewHashTable(512, jsj_HashJavaObject, jsj_JavaObjectComparator,
|
||||
NULL, NULL, NULL);
|
||||
if (!java_obj_reflections)
|
||||
return JS_FALSE;
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
java_obj_reflections_monitor = PR_NewNamedMonitor("java_obj_reflections");
|
||||
if (!java_obj_reflections_monitor) {
|
||||
PR_HashTableDestroy(java_obj_reflections);
|
||||
return JS_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
jsj_WrapJavaObject(JSContext *cx,
|
||||
JNIEnv *jEnv,
|
||||
jobject java_obj,
|
||||
jclass java_class)
|
||||
{
|
||||
JSJHashNumber hash_code;
|
||||
JSClass *js_class;
|
||||
JSObject *js_wrapper_obj;
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
JSJHashEntry *he, **hep;
|
||||
|
||||
js_wrapper_obj = NULL;
|
||||
|
||||
hash_code = jsj_HashJavaObject((void*)java_obj, (void*)jEnv);
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
PR_EnterMonitor(java_obj_reflections_monitor);
|
||||
#endif
|
||||
|
||||
hep = JSJ_HashTableRawLookup(java_obj_reflections,
|
||||
hash_code, java_obj, (void*)jEnv);
|
||||
he = *hep;
|
||||
if (he) {
|
||||
js_wrapper_obj = (JSObject *)he->value;
|
||||
if (js_wrapper_obj)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* No existing reflection found. Construct a new one */
|
||||
class_descriptor = jsj_GetJavaClassDescriptor(cx, jEnv, java_class);
|
||||
if (!class_descriptor)
|
||||
goto done;
|
||||
if (class_descriptor->type == JAVA_SIGNATURE_ARRAY) {
|
||||
js_class = &JavaArray_class;
|
||||
} else {
|
||||
PR_ASSERT(class_descriptor->type == JAVA_SIGNATURE_CLASS);
|
||||
js_class = &JavaObject_class;
|
||||
}
|
||||
|
||||
/* Create new JS object to reflect Java object */
|
||||
js_wrapper_obj = JS_NewObject(cx, js_class, NULL, NULL);
|
||||
if (!js_wrapper_obj)
|
||||
goto done;
|
||||
|
||||
/* Create private, native portion of JavaObject */
|
||||
java_wrapper =
|
||||
(JavaObjectWrapper *)JS_malloc(cx, sizeof(JavaObjectWrapper));
|
||||
if (!java_wrapper) {
|
||||
jsj_ReleaseJavaClassDescriptor(cx, jEnv, class_descriptor);
|
||||
goto done;
|
||||
}
|
||||
JS_SetPrivate(cx, js_wrapper_obj, java_wrapper);
|
||||
java_wrapper->class_descriptor = class_descriptor;
|
||||
|
||||
java_obj = (*jEnv)->NewGlobalRef(jEnv, java_obj);
|
||||
java_wrapper->java_obj = java_obj;
|
||||
if (!java_obj)
|
||||
goto out_of_memory;
|
||||
|
||||
/* Add the JavaObject to the hash table */
|
||||
he = JSJ_HashTableRawAdd(java_obj_reflections, hep, hash_code,
|
||||
java_obj, js_wrapper_obj, (void*)jEnv);
|
||||
if (!he) {
|
||||
(*jEnv)->DeleteGlobalRef(jEnv, java_obj);
|
||||
goto out_of_memory;
|
||||
}
|
||||
|
||||
done:
|
||||
#ifdef JS_THREADSAFE
|
||||
PR_ExitMonitor(java_obj_reflections_monitor);
|
||||
#endif
|
||||
|
||||
return js_wrapper_obj;
|
||||
|
||||
out_of_memory:
|
||||
/* No need to free js_wrapper_obj, as it will be finalized by GC. */
|
||||
JS_ReportOutOfMemory(cx);
|
||||
js_wrapper_obj = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
static void
|
||||
remove_java_obj_reflection_from_hashtable(jobject java_obj, JNIEnv *jEnv)
|
||||
{
|
||||
JSJHashNumber hash_code;
|
||||
JSJHashEntry *he, **hep;
|
||||
|
||||
hash_code = jsj_HashJavaObject((void*)java_obj, (void*)jEnv);
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
PR_EnterMonitor(java_obj_reflections_monitor);
|
||||
#endif
|
||||
|
||||
hep = JSJ_HashTableRawLookup(java_obj_reflections, hash_code,
|
||||
java_obj, (void*)jEnv);
|
||||
he = *hep;
|
||||
|
||||
PR_ASSERT(he);
|
||||
if (he)
|
||||
JSJ_HashTableRawRemove(java_obj_reflections, hep, he, (void*)jEnv);
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
PR_ExitMonitor(java_obj_reflections_monitor);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
JavaObject_finalize(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
jobject java_obj;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return;
|
||||
|
||||
java_wrapper = JS_GetPrivate(cx, obj);
|
||||
if (!java_wrapper)
|
||||
return;
|
||||
java_obj = java_wrapper->java_obj;
|
||||
|
||||
if (java_obj) {
|
||||
remove_java_obj_reflection_from_hashtable(java_obj, jEnv);
|
||||
(*jEnv)->DeleteGlobalRef(jEnv, java_obj);
|
||||
}
|
||||
jsj_ReleaseJavaClassDescriptor(cx, jEnv, java_wrapper->class_descriptor);
|
||||
JS_free(cx, java_wrapper);
|
||||
}
|
||||
|
||||
/* Trivial helper for jsj_DiscardJavaObjReflections(), below */
|
||||
static PRIntn
|
||||
enumerate_remove_java_obj(JSJHashEntry *he, PRIntn i, void *arg)
|
||||
{
|
||||
JNIEnv *jEnv = (JNIEnv*)arg;
|
||||
jobject java_obj;
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
JSObject *java_wrapper_obj;
|
||||
|
||||
java_wrapper_obj = (JSObject *)he->value;
|
||||
java_wrapper = JS_GetPrivate(NULL, java_wrapper_obj);
|
||||
java_obj = java_wrapper->java_obj;
|
||||
(*jEnv)->DeleteGlobalRef(jEnv, java_obj);
|
||||
java_wrapper->java_obj = NULL;
|
||||
return HT_ENUMERATE_REMOVE;
|
||||
}
|
||||
|
||||
/* This shutdown routine discards all JNI references to Java objects
|
||||
that have been reflected into JS, even if there are still references
|
||||
to them from JS. */
|
||||
void
|
||||
jsj_DiscardJavaObjReflections(JNIEnv *jEnv)
|
||||
{
|
||||
if (java_obj_reflections) {
|
||||
JSJ_HashTableEnumerateEntries(java_obj_reflections,
|
||||
enumerate_remove_java_obj,
|
||||
(void*)jEnv);
|
||||
JSJ_HashTableDestroy(java_obj_reflections);
|
||||
java_obj_reflections = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
PR_CALLBACK JSBool
|
||||
JavaObject_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
||||
{
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
jobject java_obj;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
java_wrapper = JS_GetPrivate(cx, obj);
|
||||
if (!java_wrapper) {
|
||||
if (type == JSTYPE_OBJECT) {
|
||||
*vp = OBJECT_TO_JSVAL(obj);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JS_ReportError(cx, "illegal operation on JavaObject prototype object");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
java_obj = java_wrapper->java_obj;
|
||||
class_descriptor = java_wrapper->class_descriptor;
|
||||
|
||||
switch (type) {
|
||||
case JSTYPE_OBJECT:
|
||||
*vp = OBJECT_TO_JSVAL(obj);
|
||||
return JS_TRUE;
|
||||
|
||||
case JSTYPE_FUNCTION:
|
||||
JS_ReportError(cx, "can't convert Java object to function");
|
||||
return JS_FALSE;
|
||||
|
||||
case JSTYPE_VOID:
|
||||
case JSTYPE_STRING:
|
||||
/* Either extract a C-string from the java.lang.String object
|
||||
or call the Java toString() method */
|
||||
return jsj_ConvertJavaObjectToJSString(cx, jEnv, class_descriptor, java_obj, vp);
|
||||
|
||||
case JSTYPE_NUMBER:
|
||||
/* Call Java doubleValue() method, if applicable */
|
||||
return jsj_ConvertJavaObjectToJSNumber(cx, jEnv, class_descriptor, java_obj, vp);
|
||||
|
||||
case JSTYPE_BOOLEAN:
|
||||
/* Call booleanValue() method, if applicable */
|
||||
return jsj_ConvertJavaObjectToJSBoolean(cx, jEnv, class_descriptor, java_obj, vp);
|
||||
|
||||
default:
|
||||
PR_ASSERT(0);
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static JSBool
|
||||
lookup_member_by_id(JSContext *cx, JNIEnv *jEnv, JSObject *obj,
|
||||
JavaObjectWrapper **java_wrapperp,
|
||||
jsid id,
|
||||
JavaMemberDescriptor **member_descriptorp)
|
||||
{
|
||||
jsval idval;
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
const char *member_name, *property_name;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
|
||||
java_wrapper = JS_GetPrivate(cx, obj);
|
||||
if (!java_wrapper) {
|
||||
if (JS_IdToValue(cx, id, &idval) && JSVAL_IS_STRING(idval) &&
|
||||
(property_name = JS_GetStringBytes(JSVAL_TO_STRING(idval))) != NULL) {
|
||||
if (!strcmp(property_name, "constructor")) {
|
||||
*java_wrapperp = NULL;
|
||||
*member_descriptorp = NULL;
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
JS_ReportError(cx, "illegal operation on JavaObject prototype object");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
class_descriptor = java_wrapper->class_descriptor;
|
||||
PR_ASSERT(class_descriptor->type == JAVA_SIGNATURE_CLASS ||
|
||||
class_descriptor->type == JAVA_SIGNATURE_ARRAY);
|
||||
|
||||
member_descriptor = jsj_LookupJavaMemberDescriptorById(cx, jEnv, class_descriptor, id);
|
||||
if (!member_descriptor) {
|
||||
JS_IdToValue(cx, id, &idval);
|
||||
if (!JSVAL_IS_STRING(idval)) {
|
||||
JS_ReportError(cx, "invalid JavaObject property expression. "
|
||||
"(methods and field properties of a JavaObject object can only be strings)");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
|
||||
|
||||
JS_ReportError(cx, "Java class %s has no public instance field or "
|
||||
"method named \"%s\"",
|
||||
class_descriptor->name, member_name);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Success. Handle the multiple return values */
|
||||
if (java_wrapperp)
|
||||
*java_wrapperp = java_wrapper;
|
||||
if (member_descriptorp)
|
||||
*member_descriptorp = member_descriptor;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
PR_CALLBACK JSBool
|
||||
JavaObject_getPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
{
|
||||
jobject java_obj;
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
JNIEnv *jEnv;
|
||||
JSObject *funobj;
|
||||
jsval field_val, method_val;
|
||||
JSBool success;
|
||||
|
||||
/* printf("In JavaObject_getProperty\n"); */
|
||||
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
if (!lookup_member_by_id(cx, jEnv, obj, &java_wrapper, id, &member_descriptor))
|
||||
return JS_FALSE;
|
||||
|
||||
/* Handle access to "constructor" property of prototype object with
|
||||
silent failure. */
|
||||
if (!member_descriptor) {
|
||||
*vp = JSVAL_VOID;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
java_obj = java_wrapper->java_obj;
|
||||
field_val = method_val = JSVAL_VOID;
|
||||
|
||||
/* If a field member, get the value of the field */
|
||||
if (member_descriptor->field) {
|
||||
success = jsj_GetJavaFieldValue(cx, jEnv, member_descriptor->field, java_obj, &field_val);
|
||||
if (!success)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* If a method member, build a wrapper around the Java method */
|
||||
if (member_descriptor->methods) {
|
||||
/* Create a function object with this JavaObject as its parent, so that
|
||||
JSFUN_BOUND_METHOD binds it as the default 'this' for the function. */
|
||||
funobj = JS_CloneFunctionObject(cx, member_descriptor->invoke_func_obj, obj);
|
||||
if (!funobj)
|
||||
return JS_FALSE;
|
||||
method_val = OBJECT_TO_JSVAL(funobj);
|
||||
}
|
||||
|
||||
#if TEST_JAVAMEMBER
|
||||
/* Always create a JavaMember object, even though it's inefficient */
|
||||
obj = jsj_CreateJavaMember(cx, method_val, field_val);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
*vp = OBJECT_TO_JSVAL(obj);
|
||||
#else /* !TEST_JAVAMEMBER */
|
||||
|
||||
if (member_descriptor->field) {
|
||||
if (!member_descriptor->methods) {
|
||||
/* Return value of Java field */
|
||||
*vp = field_val;
|
||||
} else {
|
||||
/* Handle special case of access to a property that could refer
|
||||
to either a Java field or a method that share the same name.
|
||||
In Java, such ambiguity is not possible because the compiler
|
||||
can statically determine which is being accessed. */
|
||||
obj = jsj_CreateJavaMember(cx, method_val, field_val);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
*vp = OBJECT_TO_JSVAL(obj);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Return wrapper around Java method */
|
||||
*vp = method_val;
|
||||
}
|
||||
|
||||
#endif /* !TEST_JAVAMEMBER */
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
PR_STATIC_CALLBACK(JSBool)
|
||||
JavaObject_setPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
{
|
||||
jobject java_obj;
|
||||
const char *member_name;
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
jsval idval;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
/* printf("In JavaObject_setProperty\n"); */
|
||||
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
if (!lookup_member_by_id(cx, jEnv, obj, &java_wrapper, id, &member_descriptor))
|
||||
return JS_FALSE;
|
||||
|
||||
/* Check for the case where there is a method with the give name, but no field
|
||||
with that name */
|
||||
if (!member_descriptor->field)
|
||||
goto no_such_field;
|
||||
|
||||
/* Silently fail if field value is final (immutable), as required by ECMA spec */
|
||||
if (member_descriptor->field->modifiers & ACC_FINAL)
|
||||
return JS_TRUE;
|
||||
|
||||
java_obj = java_wrapper->java_obj;
|
||||
return jsj_SetJavaFieldValue(cx, jEnv, member_descriptor->field, java_obj, *vp);
|
||||
|
||||
no_such_field:
|
||||
JS_IdToValue(cx, id, &idval);
|
||||
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
|
||||
class_descriptor = java_wrapper->class_descriptor;
|
||||
JS_ReportError(cx, "No instance field named \"%s\" in Java class %s",
|
||||
member_name, class_descriptor->name);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaObject_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSObject **objp, JSProperty **propp
|
||||
#if defined JS_THREADSAFE && defined DEBUG
|
||||
, const char *file, uintN line
|
||||
#endif
|
||||
)
|
||||
{
|
||||
JNIEnv *jEnv;
|
||||
JSErrorReporter old_reporter;
|
||||
|
||||
/* printf("In JavaObject_lookupProperty()\n"); */
|
||||
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
old_reporter = JS_SetErrorReporter(cx, NULL);
|
||||
if (lookup_member_by_id(cx, jEnv, obj, NULL, id, NULL)) {
|
||||
*objp = obj;
|
||||
*propp = (JSProperty*)1;
|
||||
} else {
|
||||
*objp = NULL;
|
||||
*propp = NULL;
|
||||
}
|
||||
|
||||
JS_SetErrorReporter(cx, old_reporter);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaObject_defineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
|
||||
JSPropertyOp getter, JSPropertyOp setter,
|
||||
uintN attrs, JSProperty **propp)
|
||||
{
|
||||
JS_ReportError(cx, "Cannot define a new property in a JavaObject");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaObject_getAttributes(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSProperty *prop, uintN *attrsp)
|
||||
{
|
||||
/* We don't maintain JS property attributes for Java class members */
|
||||
*attrsp = JSPROP_PERMANENT|JSPROP_ENUMERATE;
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaObject_setAttributes(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSProperty *prop, uintN *attrsp)
|
||||
{
|
||||
/* We don't maintain JS property attributes for Java class members */
|
||||
if (*attrsp != (JSPROP_PERMANENT|JSPROP_ENUMERATE)) {
|
||||
PR_ASSERT(0);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Silently ignore all setAttribute attempts */
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaObject_deleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
{
|
||||
JSVersion version = JS_GetVersion(cx);
|
||||
|
||||
*vp = JSVAL_FALSE;
|
||||
|
||||
if (!JSVERSION_IS_ECMA(version)) {
|
||||
JS_ReportError(cx, "Properties of JavaObject objects may not be deleted");
|
||||
return JS_FALSE;
|
||||
} else {
|
||||
/* Attempts to delete permanent properties are silently ignored
|
||||
by ECMAScript. */
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaObject_defaultValue(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
||||
{
|
||||
/* printf("In JavaObject_defaultValue()\n"); */
|
||||
return JavaObject_convert(cx, obj, type, vp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaObject_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
|
||||
jsval *statep, jsid *idp)
|
||||
{
|
||||
JavaObjectWrapper *java_wrapper;
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
java_wrapper = JS_GetPrivate(cx, obj);
|
||||
/* Check for prototype object */
|
||||
if (!java_wrapper) {
|
||||
*statep = JSVAL_NULL;
|
||||
if (idp)
|
||||
*idp = INT_TO_JSVAL(0);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
class_descriptor = java_wrapper->class_descriptor;
|
||||
|
||||
switch(enum_op) {
|
||||
case JSENUMERATE_INIT:
|
||||
|
||||
/* Get the Java per-thread environment pointer for this JSContext */
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
member_descriptor = jsj_GetClassInstanceMembers(cx, jEnv, class_descriptor);
|
||||
*statep = PRIVATE_TO_JSVAL(member_descriptor);
|
||||
if (idp)
|
||||
*idp = INT_TO_JSVAL(class_descriptor->num_instance_members);
|
||||
return JS_TRUE;
|
||||
|
||||
case JSENUMERATE_NEXT:
|
||||
member_descriptor = JSVAL_TO_PRIVATE(*statep);
|
||||
if (member_descriptor) {
|
||||
*idp = member_descriptor->id;
|
||||
*statep = PRIVATE_TO_JSVAL(member_descriptor->next);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* Fall through ... */
|
||||
|
||||
case JSENUMERATE_DESTROY:
|
||||
*statep = JSVAL_NULL;
|
||||
return JS_TRUE;
|
||||
|
||||
default:
|
||||
PR_ASSERT(0);
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaObject_checkAccess(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSAccessMode mode, jsval *vp, uintN *attrsp)
|
||||
{
|
||||
switch (mode) {
|
||||
case JSACC_WATCH:
|
||||
JS_ReportError(cx, "Cannot place watchpoints on JavaObject object properties");
|
||||
return JS_FALSE;
|
||||
|
||||
case JSACC_IMPORT:
|
||||
JS_ReportError(cx, "Cannot export a JavaObject object's properties");
|
||||
return JS_FALSE;
|
||||
|
||||
default:
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
JSObjectOps JavaObject_ops = {
|
||||
/* Mandatory non-null function pointer members. */
|
||||
NULL, /* newObjectMap */
|
||||
NULL, /* destroyObjectMap */
|
||||
JavaObject_lookupProperty,
|
||||
JavaObject_defineProperty,
|
||||
JavaObject_getPropertyById, /* getProperty */
|
||||
JavaObject_setPropertyById, /* setProperty */
|
||||
JavaObject_getAttributes,
|
||||
JavaObject_setAttributes,
|
||||
JavaObject_deleteProperty,
|
||||
JavaObject_defaultValue,
|
||||
JavaObject_newEnumerate,
|
||||
JavaObject_checkAccess,
|
||||
|
||||
/* Optionally non-null members start here. */
|
||||
NULL, /* thisObject */
|
||||
NULL, /* dropProperty */
|
||||
NULL, /* call */
|
||||
NULL, /* construct */
|
||||
NULL, /* xdrObject */
|
||||
NULL, /* hasInstance */
|
||||
};
|
||||
|
||||
static JSObjectOps *
|
||||
JavaObject_getObjectOps(JSContext *cx, JSClass *clazz)
|
||||
{
|
||||
return &JavaObject_ops;
|
||||
}
|
||||
|
||||
JSClass JavaObject_class = {
|
||||
"JavaObject", JSCLASS_HAS_PRIVATE,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, JavaObject_convert, JavaObject_finalize,
|
||||
JavaObject_getObjectOps,
|
||||
};
|
||||
|
||||
extern PR_IMPORT_DATA(JSObjectOps) js_ObjectOps;
|
||||
|
||||
|
||||
JSBool
|
||||
jsj_init_JavaObject(JSContext *cx, JSObject *global_obj)
|
||||
{
|
||||
JavaObject_ops.newObjectMap = js_ObjectOps.newObjectMap;
|
||||
JavaObject_ops.destroyObjectMap = js_ObjectOps.destroyObjectMap;
|
||||
|
||||
if (!JS_InitClass(cx, global_obj,
|
||||
0, &JavaObject_class, 0, 0,
|
||||
0, 0,
|
||||
0, 0))
|
||||
return JS_FALSE;
|
||||
|
||||
return init_java_obj_reflections_table();
|
||||
}
|
||||
500
mozilla/js/src/liveconnect/jsj_JavaPackage.c
Normal file
500
mozilla/js/src/liveconnect/jsj_JavaPackage.c
Normal file
@@ -0,0 +1,500 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the native code implementation of the JavaPackage class.
|
||||
*
|
||||
* A JavaPackage is JavaScript's representation of a Java package. The
|
||||
* JavaPackage object contains only a string, which is the path to the package,
|
||||
* e.g. "java/lang". The JS properties of a JavaPackage are either nested packages
|
||||
* or a JavaClass object, which represents the path to a Java class.
|
||||
*
|
||||
* Note that there is no equivalent to a JavaPackage object in Java. Example:
|
||||
* Although there are instances of java.lang.String and there are static methods
|
||||
* of java.lang.String that can be invoked, there's no such thing as a java.lang
|
||||
* object in Java that exists at run time.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jsj_private.h" /* LiveConnect internals */
|
||||
#include "jsjava.h"
|
||||
|
||||
|
||||
JSClass JavaPackage_class; /* Forward declaration */
|
||||
|
||||
/*
|
||||
* The native part of a JavaPackage object. It gets stored in the object's
|
||||
* private slot.
|
||||
*/
|
||||
typedef struct {
|
||||
const char * path; /* e.g. "java/lang" or NULL if top level package */
|
||||
int flags; /* e.g. PKG_SYSTEM, PKG_CLASS */
|
||||
} JavaPackage_Private;
|
||||
|
||||
static JSObject *
|
||||
define_JavaPackage(JSContext *cx, JSObject *parent_obj,
|
||||
const char *obj_name, const char *path, int flags)
|
||||
{
|
||||
JSObject *package_obj;
|
||||
JavaPackage_Private *package;
|
||||
|
||||
package_obj = JS_DefineObject(cx, parent_obj, obj_name, &JavaPackage_class, 0,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY);
|
||||
if (!package_obj)
|
||||
return NULL;
|
||||
|
||||
/* Attach private, native data to the JS object */
|
||||
package = (JavaPackage_Private *)JS_malloc(cx, sizeof(JavaPackage_Private));
|
||||
JS_SetPrivate(cx, package_obj, (void *)package);
|
||||
if (path)
|
||||
package->path = JS_strdup(cx, path);
|
||||
else
|
||||
package->path = "";
|
||||
|
||||
package->flags = flags;
|
||||
|
||||
/* Check for OOM */
|
||||
if (!package->path) {
|
||||
JS_DeleteProperty(cx, parent_obj, obj_name);
|
||||
JS_free(cx, package);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return package_obj;
|
||||
}
|
||||
|
||||
/* JavaPackage uses standard JS getProperty */
|
||||
|
||||
/*
|
||||
* Don't allow user-defined properties to be set on Java package objects, e.g.
|
||||
* it is illegal to write "java.lang.myProperty = 4". We probably could relax
|
||||
* this restriction, but it's potentially confusing and not clearly useful.
|
||||
*/
|
||||
static JSBool
|
||||
JavaPackage_setProperty(JSContext *cx, JSObject *obj, jsval slot, jsval *vp)
|
||||
{
|
||||
JavaPackage_Private *package = JS_GetPrivate(cx, obj);
|
||||
if (!package) {
|
||||
JS_ReportError(cx, "illegal attempt to add property to "
|
||||
"JavaPackage prototype object");
|
||||
return JS_FALSE;
|
||||
}
|
||||
JS_ReportError(cx, "You may not add properties to a JavaPackage object");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static JSBool quiet_resolve_failure;
|
||||
|
||||
/*
|
||||
* Resolve a component name to be either the name of a class or a package.
|
||||
*/
|
||||
static JSBool
|
||||
JavaPackage_resolve(JSContext *cx, JSObject *obj, jsval id)
|
||||
{
|
||||
JavaPackage_Private *package;
|
||||
JSBool ok = JS_TRUE;
|
||||
jclass jclazz;
|
||||
char *subPath, *newPath;
|
||||
const char *path;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
package = (JavaPackage_Private *)JS_GetPrivate(cx, obj);
|
||||
if (!package)
|
||||
return JS_TRUE;
|
||||
|
||||
if (!JSVAL_IS_STRING(id))
|
||||
return JS_TRUE;
|
||||
subPath = JS_GetStringBytes(JSVAL_TO_STRING(id));
|
||||
|
||||
/*
|
||||
* There will be an attempt to invoke the toString() method when producing
|
||||
* the string representation of a JavaPackage. When this occurs, avoid
|
||||
* creating a bogus toString package. (This means that no one can ever
|
||||
* create a package with the simple name "toString", but we'll live with
|
||||
* that limitation.)
|
||||
*/
|
||||
if (!strcmp(subPath, "toString"))
|
||||
return JS_FALSE;
|
||||
|
||||
path = package->path;
|
||||
newPath = PR_smprintf("%s%s%s", path, (path[0] ? "/" : ""), subPath);
|
||||
if (!newPath) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
jsj_MapJSContextToJSJThread(cx, &jEnv);
|
||||
if (!jEnv)
|
||||
return JS_FALSE;
|
||||
|
||||
/*
|
||||
Unfortunately, Java provides no way to find out whether a particular
|
||||
name is a package or not. The only way to tell is to try to load the
|
||||
name as a class file and, if that fails, assume it's a package. This
|
||||
makes things work as expected for the most part, but it has three
|
||||
noticeable problems that keep coming up:
|
||||
|
||||
- You can refer to a package like java.lang.i.buried.paul without
|
||||
generating a complaint. Of course, you'll never be able to refer to
|
||||
any classes through it.
|
||||
|
||||
- An annoying consequence of the above is that misspelling a class name
|
||||
results in a cryptic error about packages.
|
||||
|
||||
- In a browser context, i.e. where applets are involved, figuring out
|
||||
whether something is a class may require looking for it over the net
|
||||
using the current classloader. This means that the first time you
|
||||
refer to java.lang.System in a js context, there will be an attempt
|
||||
to search for [[DOCBASE]]/java.class on the server.
|
||||
|
||||
A solution is to explicitly tell jsjava the names of all the (local)
|
||||
packages on the CLASSPATH. (Not implemented yet.)
|
||||
|
||||
*/
|
||||
jclazz = (*jEnv)->FindClass(jEnv, newPath);
|
||||
if (jclazz) {
|
||||
JSObject *newClass;
|
||||
|
||||
newClass = jsj_define_JavaClass(cx, jEnv, obj, subPath, jclazz);
|
||||
if (!newClass) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
|
||||
/* We assume that any failed attempt to load a class is because it
|
||||
doesn't exist. If we wanted to do a better job, we would check
|
||||
the exception type and make sure that it's NoClassDefFoundError */
|
||||
(*jEnv)->ExceptionClear(jEnv);
|
||||
|
||||
/* beard: this has to be done here, so built-in classes will be defined. */
|
||||
/* Painful hack for pre_define_java_packages() */
|
||||
if (quiet_resolve_failure) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there's no class of the given name, then we must be referring to
|
||||
* a package. However, don't allow bogus sub-packages of pre-defined
|
||||
* system packages to be created.
|
||||
*/
|
||||
if (JS_InstanceOf(cx, obj, &JavaPackage_class, NULL)) {
|
||||
JavaPackage_Private *package;
|
||||
|
||||
package = JS_GetPrivate(cx, obj);
|
||||
if (package->flags & PKG_SYSTEM) {
|
||||
char *msg, *cp;
|
||||
|
||||
msg = PR_smprintf("No Java system package with name \"%s\" was identified "
|
||||
"and no Java class with that name exists either",
|
||||
newPath);
|
||||
|
||||
/* Check for OOM */
|
||||
if (msg) {
|
||||
/* Convert package of form "java/lang" to "java.lang" */
|
||||
for (cp = msg; *cp != '\0'; cp++)
|
||||
if (*cp == '/')
|
||||
*cp = '.';
|
||||
JS_ReportError(cx, msg);
|
||||
free((char*)msg);
|
||||
}
|
||||
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!define_JavaPackage(cx, obj, subPath, newPath, 0)) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
/* printf("JavaPackage \'%s\' created\n", newPath); */
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
out:
|
||||
free(newPath);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaPackage_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
||||
{
|
||||
JSString *str;
|
||||
char *name, *cp;
|
||||
|
||||
JavaPackage_Private *package = JS_GetPrivate(cx, obj);
|
||||
if (!package) {
|
||||
fprintf(stderr, "JavaPackage_resolve: no private data!\n");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
|
||||
/* Pretty-printing of JavaPackage */
|
||||
case JSTYPE_VOID: /* Default value */
|
||||
case JSTYPE_NUMBER:
|
||||
case JSTYPE_STRING:
|
||||
/* Convert '/' to '.' so that it looks like Java language syntax. */
|
||||
if (!package->path)
|
||||
break;
|
||||
name = PR_smprintf("[JavaPackage %s]", package->path);
|
||||
if (!name) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return JS_FALSE;
|
||||
}
|
||||
for (cp = name; *cp != '\0'; cp++)
|
||||
if (*cp == '/')
|
||||
*cp = '.';
|
||||
str = JS_NewString(cx, name, strlen(name));
|
||||
if (!str) {
|
||||
free(name);
|
||||
/* It's not necessary to call JS_ReportOutOfMemory(), as
|
||||
JS_NewString() will do so on failure. */
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
*vp = STRING_TO_JSVAL(str);
|
||||
break;
|
||||
|
||||
case JSTYPE_OBJECT:
|
||||
*vp = OBJECT_TO_JSVAL(obj);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the private native data associated with the JavaPackage object.
|
||||
*/
|
||||
static void
|
||||
JavaPackage_finalize(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
JavaPackage_Private *package = JS_GetPrivate(cx, obj);
|
||||
if (!package)
|
||||
return;
|
||||
|
||||
if (package->path)
|
||||
JS_free(cx, (char *)package->path);
|
||||
JS_free(cx, package);
|
||||
}
|
||||
|
||||
/*
|
||||
* The definition of the JavaPackage class
|
||||
*/
|
||||
JSClass JavaPackage_class = {
|
||||
"JavaPackage", JSCLASS_HAS_PRIVATE,
|
||||
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JavaPackage_setProperty,
|
||||
JS_EnumerateStub, JavaPackage_resolve,
|
||||
JavaPackage_convert, JavaPackage_finalize
|
||||
};
|
||||
|
||||
JavaPackageDef
|
||||
standard_java_packages[] = {
|
||||
{"java", NULL, PKG_USER},
|
||||
{"java.applet", NULL, PKG_USER},
|
||||
{"java.awt", NULL, PKG_USER},
|
||||
{"java.awt.datatransfer",
|
||||
NULL, PKG_SYSTEM},
|
||||
{"java.awt.event", NULL, PKG_SYSTEM},
|
||||
{"java.awt.image", NULL, PKG_SYSTEM},
|
||||
{"java.awt.peer", NULL, PKG_SYSTEM},
|
||||
{"java.beans", NULL, PKG_USER},
|
||||
{"java.io", NULL, PKG_SYSTEM},
|
||||
{"java.lang", NULL, PKG_USER},
|
||||
{"java.lang.reflect", NULL, PKG_SYSTEM},
|
||||
{"java.math", NULL, PKG_SYSTEM},
|
||||
{"java.net", NULL, PKG_USER},
|
||||
{"java.rmi", NULL, PKG_USER},
|
||||
{"java.rmi.dgc", NULL, PKG_USER},
|
||||
{"java.rmi.user", NULL, PKG_USER},
|
||||
{"java.rmi.registry", NULL, PKG_USER},
|
||||
{"java.rmi.server", NULL, PKG_USER},
|
||||
{"java.security", NULL, PKG_USER},
|
||||
{"java.security.acl", NULL, PKG_SYSTEM},
|
||||
{"java.security.interfaces",
|
||||
NULL, PKG_SYSTEM},
|
||||
{"java.sql", NULL, PKG_USER},
|
||||
{"java.text", NULL, PKG_USER},
|
||||
{"java.text.resources", NULL, PKG_SYSTEM},
|
||||
{"java.util", NULL, PKG_USER},
|
||||
{"java.util.zip", NULL, PKG_SYSTEM},
|
||||
|
||||
{"netscape", NULL, PKG_USER},
|
||||
{"netscape.applet", NULL, PKG_SYSTEM},
|
||||
{"netscape.application",NULL, PKG_SYSTEM},
|
||||
{"netscape.debug", NULL, PKG_SYSTEM},
|
||||
{"netscape.javascript", NULL, PKG_SYSTEM},
|
||||
{"netscape.ldap", NULL, PKG_SYSTEM},
|
||||
{"netscape.misc", NULL, PKG_SYSTEM},
|
||||
{"netscape.net", NULL, PKG_SYSTEM},
|
||||
{"netscape.plugin", NULL, PKG_SYSTEM},
|
||||
{"netscape.util", NULL, PKG_SYSTEM},
|
||||
{"netscape.secfile", NULL, PKG_SYSTEM},
|
||||
{"netscape.security", NULL, PKG_SYSTEM},
|
||||
{"netscape.WAI", NULL, PKG_SYSTEM},
|
||||
|
||||
{"sun", NULL, PKG_USER},
|
||||
{"Packages", "", PKG_USER},
|
||||
|
||||
{NULL, NULL, 0}
|
||||
};
|
||||
|
||||
/*
|
||||
* Pre-define a hierarchy of JavaPackage objects.
|
||||
* Pre-defining a Java package at initialization time is not necessary, but
|
||||
* it will make package lookup faster and, more importantly, will avoid
|
||||
* unnecessary network accesses if classes are being loaded over the network.
|
||||
*/
|
||||
static JSBool
|
||||
pre_define_java_packages(JSContext *cx, JSObject *global_obj,
|
||||
JavaPackageDef *predefined_packages)
|
||||
{
|
||||
JSBool package_exists;
|
||||
JSObject *parent_obj;
|
||||
JavaPackageDef *package_def;
|
||||
char *simple_name, *cp, *package_name, *path;
|
||||
int flags;
|
||||
|
||||
if (!predefined_packages)
|
||||
return JS_TRUE;
|
||||
|
||||
/* Iterate over all pre-defined Java packages */
|
||||
for (package_def = predefined_packages; package_def->name; package_def++) {
|
||||
package_name = path = NULL;
|
||||
|
||||
parent_obj = global_obj;
|
||||
package_name = strdup(package_def->name);
|
||||
if (!package_name)
|
||||
goto out_of_memory;
|
||||
|
||||
/* Walk the chain of JavaPackage objects to get to the parent of the
|
||||
rightmost sub-package in the fully-qualified package name. */
|
||||
for (simple_name = strtok(package_name, "."); 1; simple_name = strtok(NULL, ".")) {
|
||||
jsval v;
|
||||
|
||||
if (!simple_name) {
|
||||
JS_ReportError(cx, "Package %s defined twice ?", package_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Check to see if the sub-package already exists */
|
||||
quiet_resolve_failure = JS_TRUE;
|
||||
package_exists = JS_LookupProperty(cx, parent_obj, simple_name, &v) && JSVAL_IS_OBJECT(v);
|
||||
quiet_resolve_failure = JS_FALSE;
|
||||
|
||||
if (package_exists) {
|
||||
parent_obj = JSVAL_TO_OBJECT(v);
|
||||
continue;
|
||||
} else {
|
||||
/* New package objects should only be created at the terminal
|
||||
sub-package in a fully-qualified package-name */
|
||||
if (strtok(NULL, ".")) {
|
||||
JS_ReportError(cx, "Illegal predefined package definition for %s",
|
||||
package_def->name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (package_def->path) {
|
||||
path = strdup(package_def->path);
|
||||
if (!path)
|
||||
goto out_of_memory;
|
||||
} else {
|
||||
|
||||
/*
|
||||
* The default path is specified, so create it from the
|
||||
* fully-qualified package name.
|
||||
*/
|
||||
path = strdup(package_def->name);
|
||||
if (!path)
|
||||
goto out_of_memory;
|
||||
/* Transform package name, e.g. "java.lang" ==> "java/lang" */
|
||||
for (cp = path; *cp != '\0'; cp++) {
|
||||
if (*cp == '.')
|
||||
*cp = '/';
|
||||
}
|
||||
}
|
||||
flags = package_def->flags;
|
||||
parent_obj = define_JavaPackage(cx, parent_obj, simple_name, path, flags);
|
||||
if (!parent_obj)
|
||||
goto error;
|
||||
|
||||
free(path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(package_name);
|
||||
}
|
||||
return JS_TRUE;
|
||||
|
||||
out_of_memory:
|
||||
JS_ReportOutOfMemory(cx);
|
||||
|
||||
error:
|
||||
JS_FREE_IF(cx, package_name);
|
||||
JS_FREE_IF(cx, path);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JavaPackage_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
jsval *rval)
|
||||
{
|
||||
if (!JS_InstanceOf(cx, obj, &JavaPackage_class, argv))
|
||||
return JS_FALSE;
|
||||
return JavaPackage_convert(cx, obj, JSTYPE_STRING, rval);
|
||||
}
|
||||
|
||||
static JSFunctionSpec JavaPackage_methods[] = {
|
||||
{"toString", JavaPackage_toString, 0},
|
||||
{0}
|
||||
};
|
||||
|
||||
/*
|
||||
* One-time initialization for the JavaPackage class. (This is not
|
||||
* run once per thread, rather it's run once for a given JSContext.)
|
||||
*/
|
||||
JSBool
|
||||
jsj_init_JavaPackage(JSContext *cx, JSObject *global_obj,
|
||||
JavaPackageDef *additional_predefined_packages) {
|
||||
|
||||
/* Define JavaPackage class */
|
||||
if (!JS_InitClass(cx, global_obj, 0, &JavaPackage_class,
|
||||
0, 0, 0, JavaPackage_methods, 0, 0))
|
||||
return JS_FALSE;
|
||||
|
||||
/* Add top-level packages, e.g. : java, netscape, sun */
|
||||
if (!pre_define_java_packages(cx, global_obj, standard_java_packages))
|
||||
return JS_FALSE;
|
||||
if (!pre_define_java_packages(cx, global_obj, additional_predefined_packages))
|
||||
return JS_FALSE;
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
180
mozilla/js/src/liveconnect/jsj_array.c
Normal file
180
mozilla/js/src/liveconnect/jsj_array.c
Normal file
@@ -0,0 +1,180 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the code for reading and writing elements of a Java array.
|
||||
*/
|
||||
|
||||
#include "jsj_private.h" /* LiveConnect internals */
|
||||
|
||||
/*
|
||||
* Read the Java value at a given index into a Java array and convert it
|
||||
* to a JS value. The array_component_signature describes the type of
|
||||
* the resulting Java value, which can be a primitive type or an object type.
|
||||
* More specifically it can be an array type in the case of multidimensional
|
||||
* arrays.
|
||||
*/
|
||||
JSBool
|
||||
jsj_GetJavaArrayElement(JSContext *cx, JNIEnv *jEnv, jarray java_array, jsize index,
|
||||
JavaSignature *array_component_signature,
|
||||
jsval *vp)
|
||||
{
|
||||
jvalue java_value;
|
||||
JavaSignatureChar component_type;
|
||||
|
||||
#define GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Type,member) \
|
||||
(*jEnv)->Get##Type##ArrayRegion(jEnv, java_array, index, 1, \
|
||||
&java_value.member); \
|
||||
if ((*jEnv)->ExceptionOccurred(jEnv)) { \
|
||||
jsj_ReportJavaError(cx, jEnv, "Error reading element of " \
|
||||
"Java primitive array"); \
|
||||
return JS_FALSE; \
|
||||
}
|
||||
|
||||
component_type = array_component_signature->type;
|
||||
switch(component_type) {
|
||||
case JAVA_SIGNATURE_BYTE:
|
||||
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Byte,b);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_CHAR:
|
||||
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Char,c);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_SHORT:
|
||||
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Short,s);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_INT:
|
||||
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Int,i);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_BOOLEAN:
|
||||
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Boolean,z);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_LONG:
|
||||
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Long,j);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_FLOAT:
|
||||
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Float,f);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_DOUBLE:
|
||||
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Double,d);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_CLASS:
|
||||
case JAVA_SIGNATURE_ARRAY:
|
||||
java_value.l = (*jEnv)->GetObjectArrayElement(jEnv, java_array, index);
|
||||
if ((*jEnv)->ExceptionOccurred(jEnv)) {
|
||||
jsj_ReportJavaError(cx, jEnv, "Error reading Java object array");
|
||||
return JS_FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
#undef GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY
|
||||
default:
|
||||
PR_ASSERT(0); /* Unknown java type signature */
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
return jsj_ConvertJavaValueToJSValue(cx, jEnv, array_component_signature, &java_value, vp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
jsj_SetJavaArrayElement(JSContext *cx, JNIEnv *jEnv, jarray java_array, jsize index,
|
||||
JavaSignature *array_component_signature,
|
||||
jsval js_val)
|
||||
{
|
||||
int dummy_cost;
|
||||
jvalue java_value;
|
||||
JavaSignatureChar component_type;
|
||||
JSBool is_local_ref;
|
||||
|
||||
if (!jsj_ConvertJSValueToJavaValue(cx, jEnv, js_val, array_component_signature,
|
||||
&dummy_cost, &java_value, &is_local_ref))
|
||||
return JS_FALSE;
|
||||
|
||||
#define SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Type,member) \
|
||||
(*jEnv)->Set##Type##ArrayRegion(jEnv, java_array, index, 1, \
|
||||
&java_value.member); \
|
||||
if ((*jEnv)->ExceptionOccurred(jEnv)) { \
|
||||
jsj_ReportJavaError(cx, jEnv, "Error assigning to element of " \
|
||||
"Java primitive array"); \
|
||||
return JS_FALSE; \
|
||||
}
|
||||
|
||||
component_type = array_component_signature->type;
|
||||
switch(component_type) {
|
||||
case JAVA_SIGNATURE_BYTE:
|
||||
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Byte,b);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_CHAR:
|
||||
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Char,c);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_SHORT:
|
||||
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Short,s);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_INT:
|
||||
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Int,i);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_BOOLEAN:
|
||||
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Boolean,z);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_LONG:
|
||||
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Long,j);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_FLOAT:
|
||||
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Float,f);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_DOUBLE:
|
||||
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Double,d);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_CLASS:
|
||||
case JAVA_SIGNATURE_ARRAY:
|
||||
(*jEnv)->SetObjectArrayElement(jEnv, java_array, index, java_value.l);
|
||||
if (is_local_ref) \
|
||||
(*jEnv)->DeleteLocalRef(jEnv, java_value.l);
|
||||
if ((*jEnv)->ExceptionOccurred(jEnv)) {
|
||||
jsj_ReportJavaError(cx, jEnv, "Error assigning to Java object array");
|
||||
return JS_FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
#undef SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY
|
||||
default:
|
||||
PR_ASSERT(0); /* Unknown java type signature */
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
605
mozilla/js/src/liveconnect/jsj_class.c
Normal file
605
mozilla/js/src/liveconnect/jsj_class.c
Normal file
@@ -0,0 +1,605 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the code that constructs and manipulates JavaClassDescriptor
|
||||
* structs, which are the native wrappers for Java classes.
|
||||
* JavaClassDescriptors are used to describe the signatures of methods and
|
||||
* fields. There is a JavaClassDescriptor associated with the reflection of
|
||||
* each Java Object.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jsj_private.h" /* LiveConnect internals */
|
||||
#include "jsj_hash.h" /* Hash tables */
|
||||
|
||||
/* A one-to-one mapping between all referenced java.lang.Class objects and
|
||||
their corresponding JavaClassDescriptor objects */
|
||||
static JSJHashTable *java_class_reflections;
|
||||
|
||||
/*
|
||||
* Given a JVM handle to a java.lang.Class object, malloc a C-string
|
||||
* containing the UTF8 encoding of the fully qualified name of the class.
|
||||
* It's the caller's responsibility to free the returned string.
|
||||
*
|
||||
* If an error occurs, NULL is returned and the error reporter called.
|
||||
*/
|
||||
const char *
|
||||
jsj_GetJavaClassName(JSContext *cx, JNIEnv *jEnv, jclass java_class)
|
||||
{
|
||||
jstring java_class_name_jstr;
|
||||
const char *java_class_name;
|
||||
|
||||
/* Get java.lang.String object containing class name */
|
||||
java_class_name_jstr =
|
||||
(*jEnv)->CallObjectMethod(jEnv, java_class, jlClass_getName);
|
||||
|
||||
|
||||
if (!java_class_name_jstr)
|
||||
goto error;
|
||||
|
||||
/* Convert to UTF8 encoding and copy */
|
||||
java_class_name = jsj_DupJavaStringUTF(cx, jEnv, java_class_name_jstr);
|
||||
if (!java_class_name)
|
||||
return NULL;
|
||||
|
||||
return java_class_name;
|
||||
|
||||
error:
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "Can't get Java class name using"
|
||||
"java.lang.Class.getName()");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert in-place a string of the form "java.lang.String" into "java/lang/String".
|
||||
* Though the former style is conventionally used by Java programmers, the latter is
|
||||
* what the JNI functions require.
|
||||
*/
|
||||
void
|
||||
jsj_MakeJNIClassname(char * class_name)
|
||||
{
|
||||
char * c;
|
||||
for (c = class_name; *c; c++)
|
||||
if (*c == '.')
|
||||
*c = '/';
|
||||
}
|
||||
|
||||
/*
|
||||
* Classify an instance of java.lang.Class as either one of the primitive
|
||||
* types, e.g. int, char, etc., as an array type or as a non-array object type
|
||||
* (subclass of java.lang.Object) by returning the appropriate enum member.
|
||||
*
|
||||
*/
|
||||
static JavaSignatureChar
|
||||
get_signature_type(JSContext *cx, JavaClassDescriptor *class_descriptor)
|
||||
{
|
||||
JavaSignatureChar type;
|
||||
const char *java_class_name;
|
||||
|
||||
/* Get UTF8 encoding of class name */
|
||||
java_class_name = class_descriptor->name;
|
||||
PR_ASSERT(java_class_name);
|
||||
if (!java_class_name)
|
||||
return JAVA_SIGNATURE_UNKNOWN;
|
||||
|
||||
if (!strcmp(java_class_name, "byte"))
|
||||
type = JAVA_SIGNATURE_BYTE;
|
||||
else if (!strcmp(java_class_name, "char"))
|
||||
type = JAVA_SIGNATURE_CHAR;
|
||||
else if (!strcmp(java_class_name, "float"))
|
||||
type = JAVA_SIGNATURE_FLOAT;
|
||||
else if (!strcmp(java_class_name, "double"))
|
||||
type = JAVA_SIGNATURE_DOUBLE;
|
||||
else if (!strcmp(java_class_name, "int"))
|
||||
type = JAVA_SIGNATURE_INT;
|
||||
else if (!strcmp(java_class_name, "long"))
|
||||
type = JAVA_SIGNATURE_LONG;
|
||||
else if (!strcmp(java_class_name, "short"))
|
||||
type = JAVA_SIGNATURE_SHORT;
|
||||
else if (!strcmp(java_class_name, "boolean"))
|
||||
type = JAVA_SIGNATURE_BOOLEAN;
|
||||
else if (!strcmp(java_class_name, "void"))
|
||||
type = JAVA_SIGNATURE_VOID;
|
||||
else
|
||||
/* Well, I guess it's a Java class, then. */
|
||||
type = JAVA_SIGNATURE_CLASS;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
is_java_array_class(JNIEnv *jEnv, jclass java_class)
|
||||
{
|
||||
return (*jEnv)->CallBooleanMethod(jEnv, java_class, jlClass_isArray);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the class of a Java array's component type. This is not the same
|
||||
* as the array's element type. For example, the component type of an array
|
||||
* of type SomeType[][][] is SomeType[][], but its element type is SomeType.
|
||||
*
|
||||
* If an error occurs, NULL is returned and an error reported.
|
||||
*/
|
||||
static jclass
|
||||
get_java_array_component_class(JSContext *cx, JNIEnv *jEnv, jclass java_class)
|
||||
{
|
||||
jclass result;
|
||||
result = (*jEnv)->CallObjectMethod(jEnv, java_class, jlClass_getComponentType);
|
||||
if (!result) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv,
|
||||
"Can't get Java array component class using "
|
||||
"java.lang.Class.getComponentType()");
|
||||
return NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a Java class, fill in the signature structure that describes the class.
|
||||
* If an error occurs, JS_FALSE is returned and the error reporter called.
|
||||
*/
|
||||
static JSBool
|
||||
compute_java_class_signature(JSContext *cx, JNIEnv *jEnv, JavaSignature *signature)
|
||||
{
|
||||
jclass java_class = signature->java_class;
|
||||
|
||||
if (is_java_array_class(jEnv, java_class)) {
|
||||
jclass component_class;
|
||||
|
||||
signature->type = JAVA_SIGNATURE_ARRAY;
|
||||
|
||||
component_class = get_java_array_component_class(cx, jEnv, java_class);
|
||||
if (!component_class)
|
||||
return JS_FALSE;
|
||||
|
||||
signature->array_component_signature =
|
||||
jsj_GetJavaClassDescriptor(cx, jEnv, component_class);
|
||||
if (!signature->array_component_signature)
|
||||
return JS_FALSE;
|
||||
} else {
|
||||
signature->type = get_signature_type(cx, signature);
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a JavaSignature object into a string format as used by
|
||||
* the JNI functions, e.g. java.lang.Object ==> "Ljava/lang/Object;"
|
||||
* The caller is responsible for freeing the resulting string.
|
||||
*
|
||||
* If an error is encountered, NULL is returned and an error reported.
|
||||
*/
|
||||
const char *
|
||||
jsj_ConvertJavaSignatureToString(JSContext *cx, JavaSignature *signature)
|
||||
{
|
||||
char *sig;
|
||||
|
||||
if (signature->type == JAVA_SIGNATURE_CLASS) {
|
||||
/* A non-array object class */
|
||||
sig = PR_smprintf("L%s;", signature->name);
|
||||
if (sig)
|
||||
jsj_MakeJNIClassname(sig);
|
||||
|
||||
} else if (signature->type == JAVA_SIGNATURE_ARRAY) {
|
||||
/* An array class */
|
||||
const char *component_signature_string;
|
||||
|
||||
component_signature_string =
|
||||
jsj_ConvertJavaSignatureToString(cx, signature->array_component_signature);
|
||||
if (!component_signature_string)
|
||||
return NULL;
|
||||
sig = PR_smprintf("[%s", component_signature_string);
|
||||
JS_free(cx, (char*)component_signature_string);
|
||||
|
||||
} else {
|
||||
/* A primitive class */
|
||||
sig = PR_smprintf("%c", (char)signature->type);
|
||||
}
|
||||
|
||||
if (!sig) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
}
|
||||
return sig;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a JavaSignature object into a human-readable string format as seen
|
||||
* in Java source files, e.g. "byte", or "int[][]" or "java.lang.String".
|
||||
* The caller is responsible for freeing the resulting string.
|
||||
*
|
||||
* If an error is encountered, NULL is returned and an error reported.
|
||||
*/
|
||||
const char *
|
||||
jsj_ConvertJavaSignatureToHRString(JSContext *cx,
|
||||
JavaSignature *signature)
|
||||
{
|
||||
char *sig;
|
||||
JavaSignature *acs;
|
||||
|
||||
if (signature->type == JAVA_SIGNATURE_ARRAY) {
|
||||
/* An array class */
|
||||
const char *component_signature_string;
|
||||
acs = signature->array_component_signature;
|
||||
component_signature_string =
|
||||
jsj_ConvertJavaSignatureToHRString(cx, acs);
|
||||
if (!component_signature_string)
|
||||
return NULL;
|
||||
sig = PR_smprintf("%s[]", component_signature_string);
|
||||
JS_free(cx, (char*)component_signature_string);
|
||||
|
||||
} else {
|
||||
/* A primitive class or a non-array object class */
|
||||
sig = JS_strdup(cx, signature->name);
|
||||
}
|
||||
|
||||
if (!sig) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
}
|
||||
return sig;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_java_member_descriptor(JSContext *cx, JNIEnv *jEnv, JavaMemberDescriptor *member_descriptor)
|
||||
{
|
||||
JavaMethodSpec *method, *next_method;
|
||||
if (member_descriptor->field)
|
||||
jsj_DestroyFieldSpec(cx, jEnv, member_descriptor->field);
|
||||
|
||||
method = member_descriptor->methods;
|
||||
while (method) {
|
||||
next_method = method->next;
|
||||
jsj_DestroyMethodSpec(cx, jEnv, method);
|
||||
method = next_method;
|
||||
}
|
||||
|
||||
if (member_descriptor->invoke_func_obj)
|
||||
JS_RemoveRoot(cx, &member_descriptor->invoke_func_obj);
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_class_member_descriptors(JSContext *cx, JNIEnv *jEnv, JavaMemberDescriptor *member_descriptor)
|
||||
{
|
||||
JavaMemberDescriptor *next_member;
|
||||
|
||||
while (member_descriptor) {
|
||||
next_member = member_descriptor->next;
|
||||
destroy_java_member_descriptor(cx, jEnv, member_descriptor);
|
||||
member_descriptor = next_member;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_class_descriptor(JSContext *cx, JNIEnv *jEnv, JavaClassDescriptor *class_descriptor)
|
||||
{
|
||||
JS_FREE_IF(cx, (char *)class_descriptor->name);
|
||||
if (class_descriptor->java_class) {
|
||||
JSJ_HashTableRemove(java_class_reflections,
|
||||
class_descriptor->java_class, (void*)jEnv);
|
||||
(*jEnv)->DeleteGlobalRef(jEnv, class_descriptor->java_class);
|
||||
}
|
||||
|
||||
if (class_descriptor->array_component_signature)
|
||||
jsj_ReleaseJavaClassDescriptor(cx, jEnv, class_descriptor->array_component_signature);
|
||||
|
||||
destroy_class_member_descriptors(cx, jEnv, class_descriptor->instance_members);
|
||||
destroy_class_member_descriptors(cx, jEnv, class_descriptor->static_members);
|
||||
destroy_class_member_descriptors(cx, jEnv, class_descriptor->constructors);
|
||||
JS_free(cx, class_descriptor);
|
||||
}
|
||||
|
||||
static JavaClassDescriptor *
|
||||
new_class_descriptor(JSContext *cx, JNIEnv *jEnv, jclass java_class)
|
||||
{
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
|
||||
class_descriptor = (JavaClassDescriptor *)JS_malloc(cx, sizeof(JavaClassDescriptor));
|
||||
if (!class_descriptor)
|
||||
return NULL;
|
||||
memset(class_descriptor, 0, sizeof(JavaClassDescriptor));
|
||||
|
||||
class_descriptor->name = jsj_GetJavaClassName(cx, jEnv, java_class);
|
||||
if (!class_descriptor->name)
|
||||
goto error;
|
||||
|
||||
java_class = (*jEnv)->NewGlobalRef(jEnv, java_class);
|
||||
if (!java_class) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "Unable to reference Java class");
|
||||
goto error;
|
||||
}
|
||||
class_descriptor->java_class = java_class;
|
||||
|
||||
if (!compute_java_class_signature(cx, jEnv, class_descriptor))
|
||||
goto error;
|
||||
|
||||
class_descriptor->modifiers =
|
||||
(*jEnv)->CallIntMethod(jEnv, java_class, jlClass_getModifiers);
|
||||
class_descriptor->ref_count = 1;
|
||||
|
||||
if (!JSJ_HashTableAdd(java_class_reflections, java_class, class_descriptor,
|
||||
(void*)jEnv))
|
||||
goto error;
|
||||
|
||||
return class_descriptor;
|
||||
|
||||
error:
|
||||
destroy_class_descriptor(cx, jEnv, class_descriptor);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Trivial helper for jsj_DiscardJavaClassReflections(), below */
|
||||
static PRIntn
|
||||
enumerate_remove_java_class(JSJHashEntry *he, PRIntn i, void *arg)
|
||||
{
|
||||
JNIEnv *jEnv = (JNIEnv*)arg;
|
||||
jclass java_class;
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
|
||||
class_descriptor = (JavaClassDescriptor*)he->value;
|
||||
|
||||
java_class = class_descriptor->java_class;
|
||||
(*jEnv)->DeleteGlobalRef(jEnv, java_class);
|
||||
class_descriptor->java_class = NULL;
|
||||
|
||||
return HT_ENUMERATE_REMOVE;
|
||||
}
|
||||
|
||||
/* This shutdown routine discards all JNI references to Java objects
|
||||
that have been reflected into JS, even if there are still references
|
||||
to them from JS. */
|
||||
void
|
||||
jsj_DiscardJavaClassReflections(JNIEnv *jEnv)
|
||||
{
|
||||
if (java_class_reflections) {
|
||||
JSJ_HashTableEnumerateEntries(java_class_reflections,
|
||||
enumerate_remove_java_class,
|
||||
(void*)jEnv);
|
||||
JSJ_HashTableDestroy(java_class_reflections);
|
||||
java_class_reflections = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
extern JavaClassDescriptor *
|
||||
jsj_GetJavaClassDescriptor(JSContext *cx, JNIEnv *jEnv, jclass java_class)
|
||||
{
|
||||
JavaClassDescriptor *class_descriptor;
|
||||
class_descriptor = JSJ_HashTableLookup(java_class_reflections,
|
||||
(const void *)java_class,
|
||||
(void*)jEnv);
|
||||
if (!class_descriptor)
|
||||
return new_class_descriptor(cx, jEnv, java_class);
|
||||
|
||||
PR_ASSERT(class_descriptor->ref_count > 0);
|
||||
class_descriptor->ref_count++;
|
||||
return class_descriptor;
|
||||
}
|
||||
|
||||
void
|
||||
jsj_ReleaseJavaClassDescriptor(JSContext *cx, JNIEnv *jEnv, JavaClassDescriptor *class_descriptor)
|
||||
{
|
||||
if (!--class_descriptor->ref_count)
|
||||
destroy_class_descriptor(cx, jEnv, class_descriptor);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
reflect_java_methods_and_fields(JSContext *cx,
|
||||
JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
JSBool reflect_statics_only)
|
||||
{
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
|
||||
if (reflect_statics_only)
|
||||
class_descriptor->static_members_reflected = JS_TRUE;
|
||||
else
|
||||
class_descriptor->instance_members_reflected = JS_TRUE;
|
||||
|
||||
if (!jsj_ReflectJavaMethods(cx, jEnv, class_descriptor, reflect_statics_only))
|
||||
return JS_FALSE;
|
||||
if (!jsj_ReflectJavaFields(cx, jEnv, class_descriptor, reflect_statics_only))
|
||||
return JS_FALSE;
|
||||
|
||||
if (reflect_statics_only) {
|
||||
member_descriptor = class_descriptor->static_members;
|
||||
while (member_descriptor) {
|
||||
class_descriptor->num_static_members++;
|
||||
member_descriptor = member_descriptor->next;
|
||||
}
|
||||
} else {
|
||||
member_descriptor = class_descriptor->instance_members;
|
||||
while (member_descriptor) {
|
||||
class_descriptor->num_instance_members++;
|
||||
member_descriptor = member_descriptor->next;
|
||||
}
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JavaMemberDescriptor *
|
||||
jsj_GetClassStaticMembers(JSContext *cx,
|
||||
JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor)
|
||||
{
|
||||
if (!class_descriptor->static_members_reflected)
|
||||
reflect_java_methods_and_fields(cx, jEnv, class_descriptor, JS_TRUE);
|
||||
return class_descriptor->static_members;
|
||||
}
|
||||
|
||||
JavaMemberDescriptor *
|
||||
jsj_GetClassInstanceMembers(JSContext *cx,
|
||||
JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor)
|
||||
{
|
||||
if (!class_descriptor->instance_members_reflected)
|
||||
reflect_java_methods_and_fields(cx, jEnv, class_descriptor, JS_FALSE);
|
||||
return class_descriptor->instance_members;
|
||||
}
|
||||
|
||||
JavaMemberDescriptor *
|
||||
jsj_LookupJavaStaticMemberDescriptorById(JSContext *cx,
|
||||
JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jsid id)
|
||||
{
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
|
||||
member_descriptor = jsj_GetClassStaticMembers(cx, jEnv, class_descriptor);
|
||||
while (member_descriptor) {
|
||||
if (id == member_descriptor->id)
|
||||
return member_descriptor;
|
||||
member_descriptor = member_descriptor->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JavaMemberDescriptor *
|
||||
jsj_GetJavaStaticMemberDescriptor(JSContext *cx,
|
||||
JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jstring member_name_jstr)
|
||||
{
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
jsid id;
|
||||
|
||||
if (!JavaStringToId(cx, jEnv, member_name_jstr, &id))
|
||||
return NULL;
|
||||
|
||||
member_descriptor = jsj_LookupJavaStaticMemberDescriptorById(cx, jEnv, class_descriptor, id);
|
||||
if (member_descriptor)
|
||||
return member_descriptor;
|
||||
|
||||
member_descriptor = JS_malloc(cx, sizeof(JavaMemberDescriptor));
|
||||
if (!member_descriptor)
|
||||
return NULL;
|
||||
memset(member_descriptor, 0, sizeof(JavaMemberDescriptor));
|
||||
|
||||
member_descriptor->name = jsj_DupJavaStringUTF(cx, jEnv, member_name_jstr);
|
||||
if (!member_descriptor->name) {
|
||||
JS_free(cx, member_descriptor);
|
||||
return NULL;
|
||||
}
|
||||
member_descriptor->id = id;
|
||||
|
||||
member_descriptor->next = class_descriptor->static_members;
|
||||
class_descriptor->static_members = member_descriptor;
|
||||
|
||||
return member_descriptor;
|
||||
}
|
||||
|
||||
JavaMemberDescriptor *
|
||||
jsj_GetJavaClassConstructors(JSContext *cx,
|
||||
JavaClassDescriptor *class_descriptor)
|
||||
{
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
|
||||
if (class_descriptor->constructors)
|
||||
return class_descriptor->constructors;
|
||||
|
||||
member_descriptor = JS_malloc(cx, sizeof(JavaMemberDescriptor));
|
||||
if (!member_descriptor)
|
||||
return NULL;
|
||||
memset(member_descriptor, 0, sizeof(JavaMemberDescriptor));
|
||||
|
||||
member_descriptor->name = JS_strdup(cx, "<init>");
|
||||
if (!member_descriptor->name) {
|
||||
JS_free(cx, member_descriptor);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
class_descriptor->constructors = member_descriptor;
|
||||
|
||||
return member_descriptor;
|
||||
}
|
||||
|
||||
JavaMemberDescriptor *
|
||||
jsj_LookupJavaClassConstructors(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor)
|
||||
{
|
||||
if (!class_descriptor->static_members_reflected)
|
||||
reflect_java_methods_and_fields(cx, jEnv, class_descriptor, JS_TRUE);
|
||||
return class_descriptor->constructors;
|
||||
}
|
||||
|
||||
JavaMemberDescriptor *
|
||||
jsj_LookupJavaMemberDescriptorById(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jsid id)
|
||||
{
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
|
||||
member_descriptor = jsj_GetClassInstanceMembers(cx, jEnv, class_descriptor);
|
||||
while (member_descriptor) {
|
||||
if (id == member_descriptor->id)
|
||||
return member_descriptor;
|
||||
member_descriptor = member_descriptor->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JavaMemberDescriptor *
|
||||
jsj_GetJavaMemberDescriptor(JSContext *cx,
|
||||
JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jstring member_name_jstr)
|
||||
{
|
||||
JavaMemberDescriptor *member_descriptor;
|
||||
jsid id;
|
||||
|
||||
if (!JavaStringToId(cx, jEnv, member_name_jstr, &id))
|
||||
return NULL;
|
||||
|
||||
member_descriptor = jsj_LookupJavaMemberDescriptorById(cx, jEnv, class_descriptor, id);
|
||||
if (member_descriptor)
|
||||
return member_descriptor;
|
||||
|
||||
member_descriptor = JS_malloc(cx, sizeof(JavaMemberDescriptor));
|
||||
if (!member_descriptor)
|
||||
return NULL;
|
||||
memset(member_descriptor, 0, sizeof(JavaMemberDescriptor));
|
||||
|
||||
member_descriptor->name = jsj_DupJavaStringUTF(cx, jEnv, member_name_jstr);
|
||||
if (!member_descriptor->name) {
|
||||
JS_free(cx, member_descriptor);
|
||||
return NULL;
|
||||
}
|
||||
member_descriptor->id = id;
|
||||
|
||||
member_descriptor->next = class_descriptor->instance_members;
|
||||
class_descriptor->instance_members = member_descriptor;
|
||||
|
||||
return member_descriptor;
|
||||
}
|
||||
|
||||
JSBool
|
||||
jsj_InitJavaClassReflectionsTable()
|
||||
{
|
||||
java_class_reflections =
|
||||
JSJ_NewHashTable(64, jsj_HashJavaObject, jsj_JavaObjectComparator,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
if (!java_class_reflections)
|
||||
return JS_FALSE;
|
||||
return JS_TRUE;
|
||||
}
|
||||
806
mozilla/js/src/liveconnect/jsj_convert.c
Normal file
806
mozilla/js/src/liveconnect/jsj_convert.c
Normal file
@@ -0,0 +1,806 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* Below is the code that converts between Java and JavaScript values of all
|
||||
* types.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jsj_private.h" /* LiveConnect internals */
|
||||
|
||||
/* Floating-point double utilities, stolen from jsnum.h */
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[1])
|
||||
#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[0])
|
||||
#else
|
||||
#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[0])
|
||||
#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[1])
|
||||
#endif
|
||||
#define JSDOUBLE_HI32_SIGNBIT 0x80000000
|
||||
#define JSDOUBLE_HI32_EXPMASK 0x7ff00000
|
||||
#define JSDOUBLE_HI32_MANTMASK 0x000fffff
|
||||
|
||||
#define JSDOUBLE_IS_NaN(x) \
|
||||
((JSDOUBLE_HI32(x) & JSDOUBLE_HI32_EXPMASK) == JSDOUBLE_HI32_EXPMASK && \
|
||||
(JSDOUBLE_LO32(x) || (JSDOUBLE_HI32(x) & JSDOUBLE_HI32_MANTMASK)))
|
||||
|
||||
#define JSDOUBLE_IS_INFINITE(x) \
|
||||
((JSDOUBLE_HI32(x) & ~JSDOUBLE_HI32_SIGNBIT) == JSDOUBLE_HI32_EXPMASK && \
|
||||
!JSDOUBLE_LO32(x))
|
||||
|
||||
static JSBool
|
||||
convert_js_obj_to_JSObject_wrapper(JSContext *cx, JNIEnv *jEnv, JSObject *js_obj,
|
||||
JavaSignature *signature,
|
||||
int *cost, jobject *java_value)
|
||||
{
|
||||
if (!njJSObject) {
|
||||
if (java_value)
|
||||
JS_ReportError(cx, "Couldn't convert JavaScript object to an "
|
||||
"instance of netscape.javascript.JSObject "
|
||||
"because that class could not be loaded.");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
if (!(*jEnv)->IsAssignableFrom(jEnv, njJSObject, signature->java_class))
|
||||
return JS_FALSE;
|
||||
|
||||
if (!java_value)
|
||||
return JS_TRUE;
|
||||
|
||||
*java_value = jsj_WrapJSObject(cx, jEnv, js_obj);
|
||||
|
||||
return (*java_value != NULL);
|
||||
}
|
||||
|
||||
jstring
|
||||
jsj_ConvertJSStringToJavaString(JSContext *cx, JNIEnv *jEnv, JSString *js_str)
|
||||
{
|
||||
jstring result;
|
||||
result = (*jEnv)->NewString(jEnv, JS_GetStringChars(js_str),
|
||||
JS_GetStringLength(js_str));
|
||||
if (!result) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "Couldn't construct instance "
|
||||
"of java.lang.String");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a JS value to an instance of java.lang.Object or one of its subclasses,
|
||||
* performing any necessary type coercion. If non-trivial coercion is required,
|
||||
* the cost value is incremented. If the java_value pass-by-reference argument
|
||||
* is non-NULL, the resulting Java value is stored there.
|
||||
*
|
||||
* Returns JS_TRUE if the conversion is possible, JS_FALSE otherwise
|
||||
*/
|
||||
JSBool
|
||||
jsj_ConvertJSValueToJavaObject(JSContext *cx, JNIEnv *jEnv, jsval v, JavaSignature *signature,
|
||||
int *cost, jobject *java_value, JSBool *is_local_refp)
|
||||
{
|
||||
JSString *jsstr;
|
||||
jclass target_java_class;
|
||||
|
||||
PR_ASSERT(signature->type == JAVA_SIGNATURE_CLASS ||
|
||||
signature->type == JAVA_SIGNATURE_ARRAY);
|
||||
|
||||
/* Initialize to default case, in which no new Java object is
|
||||
synthesized to perform the conversion and, therefore, no JNI local
|
||||
references are being held. */
|
||||
*is_local_refp = JS_FALSE;
|
||||
|
||||
/* Get the Java type of the target value */
|
||||
target_java_class = signature->java_class;
|
||||
|
||||
if (JSVAL_IS_OBJECT(v)) {
|
||||
JSObject *js_obj = JSVAL_TO_OBJECT(v);
|
||||
|
||||
/* JS null is always assignable to a Java object */
|
||||
if (!js_obj) {
|
||||
if (java_value)
|
||||
*java_value = NULL;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
if (JS_InstanceOf(cx, js_obj, &JavaObject_class, 0) ||
|
||||
JS_InstanceOf(cx, js_obj, &JavaArray_class, 0)) {
|
||||
|
||||
/* The source value is a Java object wrapped inside a JavaScript
|
||||
object. Unwrap the JS object and return the original Java
|
||||
object if it's class makes it assignment-compatible with the
|
||||
target class using Java's assignability rules. */
|
||||
JavaObjectWrapper *java_wrapper = JS_GetPrivate(cx, js_obj);
|
||||
jobject java_obj = java_wrapper->java_obj;
|
||||
|
||||
if ((*jEnv)->IsInstanceOf(jEnv, java_obj, target_java_class)) {
|
||||
if (java_value)
|
||||
*java_value = java_obj;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
#ifdef LIVECONNECT_IMPROVEMENTS
|
||||
/* Don't allow wrapped Java objects to be converted to strings */
|
||||
goto conversion_error;
|
||||
#else
|
||||
/* Fall through, to attempt conversion to a Java string */
|
||||
#endif
|
||||
|
||||
} else if (JS_InstanceOf(cx, js_obj, &JavaClass_class, 0)) {
|
||||
/* We're dealing with the reflection of a Java class */
|
||||
JavaClassDescriptor *java_class_descriptor = JS_GetPrivate(cx, js_obj);
|
||||
|
||||
/* Check if target type is java.lang.Class class */
|
||||
if ((*jEnv)->IsAssignableFrom(jEnv, jlClass, target_java_class)) {
|
||||
if (java_value)
|
||||
*java_value = java_class_descriptor->java_class;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* Check if target type is netscape.javascript.JSObject wrapper class */
|
||||
if (convert_js_obj_to_JSObject_wrapper(cx, jEnv, js_obj, signature, cost, java_value)) {
|
||||
if (*java_value)
|
||||
*is_local_refp = JS_TRUE;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* Fall through, to attempt conversion to a Java string */
|
||||
|
||||
} else if (JS_InstanceOf(cx, js_obj, &JavaMember_class, 0)) {
|
||||
|
||||
if (!JS_ConvertValue(cx, v, JSTYPE_OBJECT, &v))
|
||||
return JS_FALSE;
|
||||
return jsj_ConvertJSValueToJavaObject(cx, jEnv, v, signature, cost,
|
||||
java_value, is_local_refp);
|
||||
|
||||
} else {
|
||||
/* Otherwise, see if the target type is the netscape.javascript.JSObject
|
||||
wrapper class or one of its subclasses, in which case a
|
||||
reference is passed to the original JS object by wrapping it
|
||||
inside an instance of netscape.javascript.JSObject */
|
||||
if (convert_js_obj_to_JSObject_wrapper(cx, jEnv, js_obj, signature, cost, java_value)) {
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* Fall through, to attempt conversion to a Java string */
|
||||
}
|
||||
|
||||
} else if (JSVAL_IS_NUMBER(v)) {
|
||||
/* JS numbers, integral or not, can be converted to instances of java.lang.Double */
|
||||
if ((*jEnv)->IsAssignableFrom(jEnv, jlDouble, target_java_class)) {
|
||||
if (java_value) {
|
||||
jsdouble d;
|
||||
if (!JS_ValueToNumber(cx, v, &d))
|
||||
goto conversion_error;
|
||||
*java_value = (*jEnv)->NewObject(jEnv, jlDouble, jlDouble_Double, d);
|
||||
if (*java_value) {
|
||||
*is_local_refp = JS_TRUE;
|
||||
} else {
|
||||
jsj_UnexpectedJavaError(cx, jEnv,
|
||||
"Couldn't construct instance of java.lang.Double");
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
#ifdef LIVECONNECT_IMPROVEMENTS
|
||||
(*cost)++;
|
||||
#endif
|
||||
return JS_TRUE;
|
||||
}
|
||||
/* Fall through, to attempt conversion to a java.lang.String ... */
|
||||
|
||||
} else if (JSVAL_IS_BOOLEAN(v)) {
|
||||
/* JS boolean values can be converted to instances of java.lang.Boolean */
|
||||
if ((*jEnv)->IsAssignableFrom(jEnv, jlBoolean, target_java_class)) {
|
||||
if (java_value) {
|
||||
JSBool b;
|
||||
if (!JS_ValueToBoolean(cx, v, &b))
|
||||
goto conversion_error;
|
||||
*java_value =
|
||||
(*jEnv)->NewObject(jEnv, jlBoolean, jlBoolean_Boolean, b);
|
||||
if (*java_value) {
|
||||
*is_local_refp = JS_TRUE;
|
||||
} else {
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "Couldn't construct instance "
|
||||
"of java.lang.Boolean");
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
#ifdef LIVECONNECT_IMPROVEMENTS
|
||||
(*cost)++;
|
||||
#endif
|
||||
return JS_TRUE;
|
||||
}
|
||||
/* Fall through, to attempt conversion to a java.lang.String ... */
|
||||
}
|
||||
|
||||
/* If no other conversion is possible, see if the target type is java.lang.String */
|
||||
if ((*jEnv)->IsAssignableFrom(jEnv, jlString, target_java_class)) {
|
||||
#ifdef LIVECONNECT_IMPROVEMENTS
|
||||
JSBool is_string = JSVAL_IS_STRING(v);
|
||||
#endif
|
||||
|
||||
/* Convert to JS string, if necessary, and then to a Java Unicode string */
|
||||
jsstr = JS_ValueToString(cx, v);
|
||||
if (jsstr) {
|
||||
if (java_value) {
|
||||
*java_value = jsj_ConvertJSStringToJavaString(cx, jEnv, jsstr);
|
||||
if (*java_value) {
|
||||
*is_local_refp = JS_TRUE;
|
||||
} else {
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
#ifdef LIVECONNECT_IMPROVEMENTS
|
||||
if (!is_string)
|
||||
(*cost)++;
|
||||
#endif
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
conversion_error:
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Valid ranges for Java numeric types */
|
||||
#define jbyte_MAX_VALUE 127.0
|
||||
#define jbyte_MIN_VALUE -128.0
|
||||
#define jchar_MAX_VALUE 65535.0
|
||||
#define jchar_MIN_VALUE 0.0
|
||||
#define jshort_MAX_VALUE 32767.0
|
||||
#define jshort_MIN_VALUE -32768.0
|
||||
#define jint_MAX_VALUE 2147483647.0
|
||||
#define jint_MIN_VALUE -2147483648.0
|
||||
#define jlong_MAX_VALUE 9223372036854775807.0
|
||||
#define jlong_MIN_VALUE -9223372036854775808.0
|
||||
|
||||
/* Utility macro for jsj_ConvertJSValueToJavaValue(), below */
|
||||
#define JSVAL_TO_INTEGRAL_JVALUE(type_name, member_name, member_type, jsval, java_value) \
|
||||
if (!JSVAL_IS_NUMBER(v)) { \
|
||||
if (!JS_ConvertValue(cx, v, JSTYPE_NUMBER, &v)) \
|
||||
goto conversion_error; \
|
||||
(*cost)++; \
|
||||
} \
|
||||
{ \
|
||||
member_type member_name; \
|
||||
\
|
||||
if (JSVAL_IS_INT(v)) { \
|
||||
jsint ival = JSVAL_TO_INT(v); \
|
||||
member_name = (member_type) ival; \
|
||||
\
|
||||
/* Check to see if the jsval's magnitude is too large to be \
|
||||
representable in the target java type */ \
|
||||
if (member_name != ival) \
|
||||
goto numeric_conversion_error; \
|
||||
} else { \
|
||||
jdouble dval = *JSVAL_TO_DOUBLE(v); \
|
||||
\
|
||||
/* NaN becomes zero when converted to integral value */ \
|
||||
if (JSDOUBLE_IS_NaN(dval)) \
|
||||
member_name = 0; \
|
||||
\
|
||||
/* Unrepresentably large numbers, including infinities, */ \
|
||||
/* cause an error. */ \
|
||||
else if ((dval > member_type ## _MAX_VALUE) || \
|
||||
(dval < member_type ## _MIN_VALUE)) { \
|
||||
goto numeric_conversion_error; \
|
||||
} else \
|
||||
member_name = (member_type) dval; \
|
||||
\
|
||||
/* Don't allow a non-integral number to be converted \
|
||||
to an integral type */ \
|
||||
/* Actually, we have to allow this for LC1 compatibility */ \
|
||||
/* if ((jdouble)member_name != dval) \
|
||||
(*cost)++; */ \
|
||||
} \
|
||||
if (java_value) \
|
||||
java_value->member_name = member_name; \
|
||||
}
|
||||
|
||||
#if XP_MAC
|
||||
|
||||
/* on MRJ jlong is typedef'd to wide, which is a struct. */
|
||||
#include <Math64.h>
|
||||
|
||||
static jsint jlong_to_jsint(jlong lvalue)
|
||||
{
|
||||
SInt64 val = WideToSInt64(lvalue);
|
||||
return S32Set(val);
|
||||
}
|
||||
|
||||
static jlong jsint_to_jlong(jsint ivalue)
|
||||
{
|
||||
SInt64 val = S64Set(ivalue);
|
||||
wide wval =SInt64ToWide(val);
|
||||
return *(jlong*)&wval;
|
||||
}
|
||||
|
||||
static jdouble jlong_to_jdouble(jlong lvalue)
|
||||
{
|
||||
SInt64 val = WideToSInt64(lvalue);
|
||||
return SInt64ToLongDouble(val);
|
||||
}
|
||||
|
||||
static jlong jdouble_to_jlong(jdouble dvalue)
|
||||
{
|
||||
SInt64 val = LongDoubleToSInt64(dvalue);
|
||||
wide wval = SInt64ToWide(val);
|
||||
return *(jlong*)&wval;
|
||||
}
|
||||
|
||||
/* Mac utility macro for jsj_ConvertJSValueToJavaValue(), below */
|
||||
#define JSVAL_TO_JLONG_JVALUE(member_name, member_type, jsvalue, java_value) \
|
||||
if (!JSVAL_IS_NUMBER(jsvalue)) { \
|
||||
if (!JS_ConvertValue(cx, jsvalue, JSTYPE_NUMBER, &jsvalue)) \
|
||||
goto conversion_error; \
|
||||
(*cost)++; \
|
||||
} \
|
||||
{ \
|
||||
member_type member_name; \
|
||||
\
|
||||
if (JSVAL_IS_INT(jsvalue)) { \
|
||||
jsint ival = JSVAL_TO_INT(jsvalue); \
|
||||
member_name = jsint_to_jlong(ival); \
|
||||
\
|
||||
} else { \
|
||||
jdouble dval = *JSVAL_TO_DOUBLE(jsvalue); \
|
||||
\
|
||||
/* NaN becomes zero when converted to integral value */ \
|
||||
if (JSDOUBLE_IS_NaN(dval)) \
|
||||
member_name = jsint_to_jlong(0); \
|
||||
\
|
||||
/* Unrepresentably large numbers, including infinities, */ \
|
||||
/* cause an error. */ \
|
||||
else if ((dval > member_type ## _MAX_VALUE) || \
|
||||
(dval < member_type ## _MIN_VALUE)) { \
|
||||
goto numeric_conversion_error; \
|
||||
} else \
|
||||
member_name = jdouble_to_jlong(dval); \
|
||||
\
|
||||
/* Don't allow a non-integral number to be converted \
|
||||
to an integral type */ \
|
||||
/* Actually, we have to allow this for LC1 compatibility */ \
|
||||
/*if (jlong_to_jdouble(member_name) != dval) \
|
||||
(*cost)++;*/ \
|
||||
} \
|
||||
if (java_value) \
|
||||
java_value->member_name = member_name; \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define jlong_to_jdouble(lvalue) ((jdouble) lvalue)
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Convert a JS value to a Java value of the given type signature. The cost
|
||||
* variable is incremented if coercion is required, e.g. the source value is
|
||||
* a string, but the target type is a boolean.
|
||||
*
|
||||
* Returns JS_FALSE if no conversion is possible, either because the jsval has
|
||||
* a type that is wholly incompatible with the Java value, or because a scalar
|
||||
* jsval can't be represented in a variable of the target type without loss of
|
||||
* precision, e.g. the source value is "4.2" but the destination type is byte.
|
||||
* If conversion is not possible and java_value is non-NULL, the JS error
|
||||
* reporter is called with an appropriate message.
|
||||
*/
|
||||
JSBool
|
||||
jsj_ConvertJSValueToJavaValue(JSContext *cx, JNIEnv *jEnv, jsval v,
|
||||
JavaSignature *signature,
|
||||
int *cost, jvalue *java_value, JSBool *is_local_refp)
|
||||
{
|
||||
JavaSignatureChar type;
|
||||
JSBool success = JS_FALSE;
|
||||
|
||||
/* Initialize to default case, in which no new Java object is
|
||||
synthesized to perform the conversion and, therefore, no JNI local
|
||||
references are being held. */
|
||||
*is_local_refp = JS_FALSE;
|
||||
|
||||
type = signature->type;
|
||||
switch (type) {
|
||||
case JAVA_SIGNATURE_BOOLEAN:
|
||||
if (!JSVAL_IS_BOOLEAN(v)) {
|
||||
if (!JS_ConvertValue(cx, v, JSTYPE_BOOLEAN, &v))
|
||||
goto conversion_error;
|
||||
(*cost)++;
|
||||
}
|
||||
if (java_value)
|
||||
java_value->z = (jboolean)(JSVAL_TO_BOOLEAN(v) == JS_TRUE);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_SHORT:
|
||||
JSVAL_TO_INTEGRAL_JVALUE(short, s, jshort, v, java_value);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_BYTE:
|
||||
JSVAL_TO_INTEGRAL_JVALUE(byte, b, jbyte, v, java_value);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_CHAR:
|
||||
/* A one-character string can be converted into a character */
|
||||
if (JSVAL_IS_STRING(v) && (JS_GetStringLength(JSVAL_TO_STRING(v)) == 1)) {
|
||||
v = INT_TO_JSVAL(*JS_GetStringChars(JSVAL_TO_STRING(v)));
|
||||
}
|
||||
JSVAL_TO_INTEGRAL_JVALUE(char, c, jchar, v, java_value);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_INT:
|
||||
JSVAL_TO_INTEGRAL_JVALUE(int, i, jint, v, java_value);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_LONG:
|
||||
#if XP_MAC
|
||||
JSVAL_TO_JLONG_JVALUE(j, jlong, v, java_value);
|
||||
#else
|
||||
JSVAL_TO_INTEGRAL_JVALUE(long, j, jlong, v, java_value);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_FLOAT:
|
||||
if (!JSVAL_IS_NUMBER(v)) {
|
||||
if (!JS_ConvertValue(cx, v, JSTYPE_NUMBER, &v))
|
||||
goto conversion_error;
|
||||
(*cost)++;
|
||||
}
|
||||
if (java_value) {
|
||||
if (JSVAL_IS_INT(v))
|
||||
java_value->f = (jfloat) JSVAL_TO_INT(v);
|
||||
else
|
||||
java_value->f = (jfloat) *JSVAL_TO_DOUBLE(v);
|
||||
}
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_DOUBLE:
|
||||
if (!JSVAL_IS_NUMBER(v)) {
|
||||
if (!JS_ConvertValue(cx, v, JSTYPE_NUMBER, &v))
|
||||
goto conversion_error;
|
||||
(*cost)++;
|
||||
}
|
||||
if (java_value) {
|
||||
if (JSVAL_IS_INT(v))
|
||||
java_value->d = (jdouble) JSVAL_TO_INT(v);
|
||||
else
|
||||
java_value->d = (jdouble) *JSVAL_TO_DOUBLE(v);
|
||||
}
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_CLASS:
|
||||
case JAVA_SIGNATURE_ARRAY:
|
||||
if (!jsj_ConvertJSValueToJavaObject(cx, jEnv, v, signature, cost,
|
||||
&java_value->l, is_local_refp))
|
||||
goto conversion_error;
|
||||
break;
|
||||
|
||||
default:
|
||||
PR_ASSERT(0);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
return JS_TRUE;
|
||||
|
||||
numeric_conversion_error:
|
||||
success = JS_TRUE;
|
||||
/* Fall through ... */
|
||||
|
||||
conversion_error:
|
||||
|
||||
if (java_value) {
|
||||
const char *jsval_string;
|
||||
JSString *jsstr;
|
||||
|
||||
jsval_string = NULL;
|
||||
jsstr = JS_ValueToString(cx, v);
|
||||
if (jsstr)
|
||||
jsval_string = JS_GetStringBytes(jsstr);
|
||||
if (!jsval_string)
|
||||
jsval_string = "";
|
||||
|
||||
JS_ReportError(cx, "Unable to convert JavaScript value %s to "
|
||||
"Java value of type %s",
|
||||
jsval_string, signature->name);
|
||||
return JS_FALSE;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* A utility routine to create a JavaScript Unicode string from a
|
||||
* java.lang.String (Unicode) string.
|
||||
*/
|
||||
JSString *
|
||||
jsj_ConvertJavaStringToJSString(JSContext *cx, JNIEnv *jEnv, jstring java_str)
|
||||
{
|
||||
JSString *js_str;
|
||||
jboolean is_copy;
|
||||
const jchar *ucs2_str;
|
||||
jchar *copy_ucs2_str;
|
||||
jsize ucs2_str_len, num_bytes;
|
||||
|
||||
ucs2_str_len = (*jEnv)->GetStringLength(jEnv, java_str);
|
||||
ucs2_str = (*jEnv)->GetStringChars(jEnv, java_str, &is_copy);
|
||||
if (!ucs2_str) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv,
|
||||
"Unable to extract native Unicode from Java string");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
js_str = NULL;
|
||||
|
||||
/* The string data passed into JS_NewUCString() is
|
||||
not copied, so make a copy of the Unicode character vector. */
|
||||
num_bytes = ucs2_str_len * sizeof(jchar);
|
||||
copy_ucs2_str = (jchar*)JS_malloc(cx, num_bytes);
|
||||
if (!copy_ucs2_str)
|
||||
goto done;
|
||||
memcpy(copy_ucs2_str, ucs2_str, num_bytes);
|
||||
|
||||
js_str = JS_NewUCString(cx, (jschar*)copy_ucs2_str, ucs2_str_len);
|
||||
|
||||
done:
|
||||
(*jEnv)->ReleaseStringChars(jEnv, java_str, ucs2_str);
|
||||
return js_str;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to obtain a JS string representation of a Java object.
|
||||
* The java_obj argument must be of type java.lang.Object or a subclass.
|
||||
* If java_obj is a Java string, it's value is simply extracted and
|
||||
* copied into a JS string. Otherwise, the toString() method is called
|
||||
* on java_obj.
|
||||
*/
|
||||
JSBool
|
||||
jsj_ConvertJavaObjectToJSString(JSContext *cx,
|
||||
JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jobject java_obj, jsval *vp)
|
||||
{
|
||||
JSString *js_str;
|
||||
jstring java_str;
|
||||
jmethodID toString;
|
||||
|
||||
/* Create a Java string, unless java_obj is already a java.lang.String */
|
||||
if ((*jEnv)->IsInstanceOf(jEnv, java_obj, jlString)) {
|
||||
java_str = java_obj;
|
||||
} else {
|
||||
jclass java_class;
|
||||
|
||||
java_class = class_descriptor->java_class;
|
||||
toString = (*jEnv)->GetMethodID(jEnv, java_class, "toString",
|
||||
"()Ljava/lang/String;");
|
||||
if (!toString) {
|
||||
/* All Java objects have a toString method */
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "No toString() method for class %s!",
|
||||
class_descriptor->name);
|
||||
return JS_FALSE;
|
||||
}
|
||||
java_str = (*jEnv)->CallObjectMethod(jEnv, java_obj, toString);
|
||||
if (!java_str) {
|
||||
jsj_ReportJavaError(cx, jEnv, "toString() method failed");
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Extract Unicode from java.lang.String instance and convert to JS string */
|
||||
js_str = jsj_ConvertJavaStringToJSString(cx, jEnv, java_str);
|
||||
if (!js_str)
|
||||
return JS_FALSE;
|
||||
|
||||
*vp = STRING_TO_JSVAL(js_str);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a Java object to a number by attempting to call the
|
||||
* doubleValue() method on a Java object to get a double result.
|
||||
* This usually only works on instances of java.lang.Double, but the code
|
||||
* is generalized to work with any Java object that supports this method.
|
||||
*
|
||||
* Returns JS_TRUE if the call was successful.
|
||||
* Returns JS_FALSE if conversion is not possible or an error occurs.
|
||||
*/
|
||||
JSBool
|
||||
jsj_ConvertJavaObjectToJSNumber(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jobject java_obj, jsval *vp)
|
||||
{
|
||||
jdouble d;
|
||||
jmethodID doubleValue;
|
||||
jclass java_class;
|
||||
|
||||
java_class = class_descriptor->java_class;
|
||||
doubleValue = (*jEnv)->GetMethodID(jEnv, java_class, "doubleValue", "()D");
|
||||
if (!doubleValue) {
|
||||
/* There is no doubleValue() method for the object. Try toString()
|
||||
instead and the JS engine will attempt to convert the result to
|
||||
a number. */
|
||||
(*jEnv)->ExceptionClear(jEnv);
|
||||
return jsj_ConvertJavaObjectToJSString(cx, jEnv, class_descriptor,
|
||||
java_obj, vp);
|
||||
}
|
||||
|
||||
d = (*jEnv)->CallDoubleMethod(jEnv, java_obj, doubleValue);
|
||||
if ((*jEnv)->ExceptionOccurred(jEnv)) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "doubleValue() method failed");
|
||||
return JS_FALSE;
|
||||
}
|
||||
return JS_NewDoubleValue(cx, d, vp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a Java object to a boolean by attempting to call the
|
||||
* booleanValue() method on a Java object to get a boolean result.
|
||||
* This usually only works on instances of java.lang.Boolean, but the code
|
||||
* is generalized to work with any Java object that supports this method.
|
||||
*
|
||||
* Returns JS_TRUE if the call was successful.
|
||||
* Returns JS_FALSE if conversion is not possible or an error occurs.
|
||||
*/
|
||||
extern JSBool
|
||||
jsj_ConvertJavaObjectToJSBoolean(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jobject java_obj, jsval *vp)
|
||||
{
|
||||
jboolean b;
|
||||
jmethodID booleanValue;
|
||||
jclass java_class;
|
||||
|
||||
/* Null converts to false. */
|
||||
if (!java_obj) {
|
||||
*vp = JSVAL_FALSE;
|
||||
return JS_TRUE;
|
||||
}
|
||||
java_class = class_descriptor->java_class;
|
||||
booleanValue = (*jEnv)->GetMethodID(jEnv, java_obj, "booleanValue", "()Z");
|
||||
|
||||
/* Non-null Java object does not have a booleanValue() method, so
|
||||
it converts to true. */
|
||||
if (!booleanValue) {
|
||||
(*jEnv)->ExceptionClear(jEnv);
|
||||
*vp = JSVAL_TRUE;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
b = (*jEnv)->CallBooleanMethod(jEnv, java_obj, booleanValue);
|
||||
if ((*jEnv)->ExceptionOccurred(jEnv)) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "booleanValue() method failed");
|
||||
return JS_FALSE;
|
||||
}
|
||||
*vp = BOOLEAN_TO_JSVAL(b);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reflect a Java object into a JS value. The source object, java_obj, must
|
||||
* be of type java.lang.Object or a subclass and may, therefore, be an array.
|
||||
*/
|
||||
JSBool
|
||||
jsj_ConvertJavaObjectToJSValue(JSContext *cx, JNIEnv *jEnv,
|
||||
jobject java_obj, jsval *vp)
|
||||
{
|
||||
jclass java_class;
|
||||
JSObject *js_obj;
|
||||
|
||||
/* A null in Java-land is also null in JS */
|
||||
if (!java_obj) {
|
||||
*vp = JSVAL_NULL;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
java_class = (*jEnv)->GetObjectClass(jEnv, java_obj);
|
||||
|
||||
/*
|
||||
* If it's an instance of netscape.javascript.JSObject, i.e. a wrapper
|
||||
* around a JS object that has been passed into the Java world, unwrap
|
||||
* it to obtain the original JS object.
|
||||
*/
|
||||
if (njJSObject && (*jEnv)->IsInstanceOf(jEnv, java_obj, njJSObject)) {
|
||||
#ifdef PRESERVE_JSOBJECT_IDENTITY
|
||||
js_obj = (JSObject *)((*jEnv)->GetIntField(jEnv, java_obj, njJSObject_internal));
|
||||
#else
|
||||
js_obj = jsj_UnwrapJSObjectWrapper(jEnv, java_obj);
|
||||
#endif
|
||||
PR_ASSERT(js_obj);
|
||||
if (!js_obj)
|
||||
return JS_FALSE;
|
||||
*vp = OBJECT_TO_JSVAL(js_obj);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Instances of java.lang.String are wrapped so we can call methods on
|
||||
* them, but they convert to a JS string if used in a string context.
|
||||
*/
|
||||
/* TODO - let's get rid of this annoying "feature" */
|
||||
|
||||
/* otherwise, wrap it inside a JavaObject */
|
||||
js_obj = jsj_WrapJavaObject(cx, jEnv, java_obj, java_class);
|
||||
if (!js_obj)
|
||||
return JS_FALSE;
|
||||
*vp = OBJECT_TO_JSVAL(js_obj);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a Java value (primitive or object) to a JS value.
|
||||
*
|
||||
* This is usually an infallible operation, but JS_FALSE is returned
|
||||
* on an out-of-memory condition and the error reporter is called.
|
||||
*/
|
||||
JSBool
|
||||
jsj_ConvertJavaValueToJSValue(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaSignature *signature,
|
||||
jvalue *java_value,
|
||||
jsval *vp)
|
||||
{
|
||||
int32 ival32;
|
||||
|
||||
switch (signature->type) {
|
||||
case JAVA_SIGNATURE_VOID:
|
||||
*vp = JSVAL_VOID;
|
||||
return JS_TRUE;
|
||||
|
||||
case JAVA_SIGNATURE_BYTE:
|
||||
*vp = INT_TO_JSVAL((jsint)java_value->b);
|
||||
return JS_TRUE;
|
||||
|
||||
case JAVA_SIGNATURE_CHAR:
|
||||
*vp = INT_TO_JSVAL((jsint)java_value->c);
|
||||
return JS_TRUE;
|
||||
|
||||
case JAVA_SIGNATURE_SHORT:
|
||||
*vp = INT_TO_JSVAL((jsint)java_value->s);
|
||||
return JS_TRUE;
|
||||
|
||||
case JAVA_SIGNATURE_INT:
|
||||
ival32 = java_value->i;
|
||||
if (INT_FITS_IN_JSVAL(ival32)) {
|
||||
*vp = INT_TO_JSVAL((jsint) ival32);
|
||||
return JS_TRUE;
|
||||
} else {
|
||||
return JS_NewDoubleValue(cx, ival32, vp);
|
||||
}
|
||||
|
||||
case JAVA_SIGNATURE_BOOLEAN:
|
||||
*vp = BOOLEAN_TO_JSVAL((JSBool) java_value->z);
|
||||
return JS_TRUE;
|
||||
|
||||
case JAVA_SIGNATURE_LONG:
|
||||
return JS_NewDoubleValue(cx, jlong_to_jdouble(java_value->j), vp);
|
||||
|
||||
case JAVA_SIGNATURE_FLOAT:
|
||||
return JS_NewDoubleValue(cx, java_value->f, vp);
|
||||
|
||||
case JAVA_SIGNATURE_DOUBLE:
|
||||
return JS_NewDoubleValue(cx, java_value->d, vp);
|
||||
|
||||
case JAVA_SIGNATURE_CLASS:
|
||||
case JAVA_SIGNATURE_ARRAY:
|
||||
return jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_value->l, vp);
|
||||
|
||||
default:
|
||||
PR_ASSERT(0);
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
383
mozilla/js/src/liveconnect/jsj_field.c
Normal file
383
mozilla/js/src/liveconnect/jsj_field.c
Normal file
@@ -0,0 +1,383 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the code used to reflect Java fields as properties of
|
||||
* JavaObject objects and the code to access those fields.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "jsj_private.h" /* LiveConnect internals */
|
||||
|
||||
/*
|
||||
* Add a single field, described by java_field, to the JavaMemberDescriptor
|
||||
* named by field_name within the given JavaClassDescriptor.
|
||||
*
|
||||
* Returns JS_TRUE on success. Otherwise, returns JS_FALSE and reports an error.
|
||||
*/
|
||||
static JSBool
|
||||
add_java_field_to_class_descriptor(JSContext *cx,
|
||||
JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jstring field_name_jstr,
|
||||
jobject java_field, /* a java.lang.reflect.Field */
|
||||
jint modifiers)
|
||||
{
|
||||
jclass fieldType;
|
||||
jfieldID fieldID;
|
||||
jclass java_class;
|
||||
|
||||
JSBool is_static_field;
|
||||
JavaMemberDescriptor *member_descriptor = NULL;
|
||||
const char *sig_cstr = NULL;
|
||||
const char *field_name = NULL;
|
||||
JavaSignature *signature = NULL;
|
||||
JavaFieldSpec *field_spec = NULL;
|
||||
|
||||
is_static_field = modifiers & ACC_STATIC;
|
||||
if (is_static_field) {
|
||||
member_descriptor = jsj_GetJavaStaticMemberDescriptor(cx, jEnv, class_descriptor, field_name_jstr);
|
||||
} else {
|
||||
member_descriptor = jsj_GetJavaMemberDescriptor(cx, jEnv, class_descriptor, field_name_jstr);
|
||||
}
|
||||
if (!member_descriptor)
|
||||
goto error;
|
||||
|
||||
field_spec = (JavaFieldSpec*)JS_malloc(cx, sizeof(JavaFieldSpec));
|
||||
if (!field_spec)
|
||||
goto error;
|
||||
|
||||
field_spec->modifiers = modifiers;
|
||||
|
||||
/* Get the Java class corresponding to the type of the field */
|
||||
fieldType = (*jEnv)->CallObjectMethod(jEnv, java_field, jlrField_getType);
|
||||
if (!fieldType) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv,
|
||||
"Unable to determine type of field using"
|
||||
" java.lang.reflect.Field.getType()");
|
||||
goto error;
|
||||
}
|
||||
|
||||
signature = jsj_GetJavaClassDescriptor(cx, jEnv, fieldType);
|
||||
if (!signature)
|
||||
goto error;
|
||||
field_spec->signature = signature;
|
||||
|
||||
field_name = jsj_DupJavaStringUTF(cx, jEnv, field_name_jstr);
|
||||
if (!field_name)
|
||||
goto error;
|
||||
field_spec->name = field_name;
|
||||
|
||||
/* Compute the JNI-style (string-based) signature of the field type */
|
||||
sig_cstr = jsj_ConvertJavaSignatureToString(cx, signature);
|
||||
if (!sig_cstr)
|
||||
goto error;
|
||||
|
||||
/* Compute the JNI fieldID and cache it for quick field access */
|
||||
java_class = class_descriptor->java_class;
|
||||
if (is_static_field)
|
||||
fieldID = (*jEnv)->GetStaticFieldID(jEnv, java_class, field_name, sig_cstr);
|
||||
else
|
||||
fieldID = (*jEnv)->GetFieldID(jEnv, java_class, field_name, sig_cstr);
|
||||
if (!fieldID) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv,
|
||||
"Can't get Java field ID for class %s, field %s (sig=%s)",
|
||||
class_descriptor->name, field_name, sig_cstr);
|
||||
goto error;
|
||||
}
|
||||
field_spec->fieldID = fieldID;
|
||||
|
||||
JS_free(cx, (char*)sig_cstr);
|
||||
|
||||
member_descriptor->field = field_spec;
|
||||
|
||||
/* Success */
|
||||
return JS_TRUE;
|
||||
|
||||
error:
|
||||
if (field_spec) {
|
||||
JS_FREE_IF(cx, (char*)field_spec->name);
|
||||
JS_free(cx, field_spec);
|
||||
}
|
||||
JS_FREE_IF(cx, (char*)sig_cstr);
|
||||
if (signature)
|
||||
jsj_ReleaseJavaClassDescriptor(cx, jEnv, signature);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free up a JavaFieldSpec and all its resources.
|
||||
*/
|
||||
void
|
||||
jsj_DestroyFieldSpec(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field)
|
||||
{
|
||||
JS_FREE_IF(cx, (char*)field->name);
|
||||
jsj_ReleaseJavaClassDescriptor(cx, jEnv, field->signature);
|
||||
JS_free(cx, field);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a JavaMemberDescriptor to the collection of members in class_descriptor
|
||||
* for every public field of the identified Java class. (A separate collection
|
||||
* is kept in class_descriptor for static and instance members.)
|
||||
* If reflect_only_static_fields is set, instance fields are not reflected. If
|
||||
* it isn't set, only instance fields are reflected and static fields are not
|
||||
* reflected.
|
||||
*
|
||||
* Returns JS_TRUE on success. Otherwise, returns JS_FALSE and reports an error.
|
||||
*/
|
||||
JSBool
|
||||
jsj_ReflectJavaFields(JSContext *cx, JNIEnv *jEnv, JavaClassDescriptor *class_descriptor,
|
||||
JSBool reflect_only_static_fields)
|
||||
{
|
||||
int i;
|
||||
JSBool ok;
|
||||
jint modifiers;
|
||||
jobject java_field;
|
||||
jstring field_name_jstr;
|
||||
jarray joFieldArray;
|
||||
jsize num_fields;
|
||||
jclass java_class;
|
||||
|
||||
/* Get a java array of java.lang.reflect.Field objects, by calling
|
||||
java.lang.Class.getFields(). */
|
||||
java_class = class_descriptor->java_class;
|
||||
joFieldArray = (*jEnv)->CallObjectMethod(jEnv, java_class, jlClass_getFields);
|
||||
if (!joFieldArray) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv,
|
||||
"Can't determine Java object's fields "
|
||||
"using java.lang.Class.getFields()");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Iterate over the class fields */
|
||||
num_fields = (*jEnv)->GetArrayLength(jEnv, joFieldArray);
|
||||
for (i = 0; i < num_fields; i++) {
|
||||
|
||||
/* Get the i'th reflected field */
|
||||
java_field = (*jEnv)->GetObjectArrayElement(jEnv, joFieldArray, i);
|
||||
if (!java_field) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "Can't access a Field[] array");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Get the field modifiers, e.g. static, public, private, etc. */
|
||||
modifiers = (*jEnv)->CallIntMethod(jEnv, java_field, jlrField_getModifiers);
|
||||
if ((*jEnv)->ExceptionOccurred(jEnv)) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv,
|
||||
"Can't access a Field's modifiers using"
|
||||
"java.lang.reflect.Field.getModifiers()");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Don't allow access to private or protected Java fields. */
|
||||
if (!(modifiers & ACC_PUBLIC))
|
||||
continue;
|
||||
|
||||
/* Reflect all instance fields or all static fields, but not both */
|
||||
if (reflect_only_static_fields != ((modifiers & ACC_STATIC) != 0))
|
||||
continue;
|
||||
|
||||
/* Determine the unqualified name of the field */
|
||||
field_name_jstr = (*jEnv)->CallObjectMethod(jEnv, java_field, jlrField_getName);
|
||||
if (!field_name_jstr) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv,
|
||||
"Can't obtain a Field's name"
|
||||
"java.lang.reflect.Field.getName()");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Add a JavaFieldSpec object to the JavaClassDescriptor */
|
||||
ok = add_java_field_to_class_descriptor(cx, jEnv, class_descriptor, field_name_jstr,
|
||||
java_field, modifiers);
|
||||
if (!ok)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the value of a Java field and return it as a JavaScript value.
|
||||
* If the field is static, then java_obj is a Java class, otherwise
|
||||
* it's a Java instance object.
|
||||
*
|
||||
* Returns JS_TRUE on success. Otherwise, returns JS_FALSE and reports an error.
|
||||
*/
|
||||
JSBool
|
||||
jsj_GetJavaFieldValue(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field_spec,
|
||||
jobject java_obj, jsval *vp)
|
||||
{
|
||||
JSBool is_static_field;
|
||||
jvalue java_value;
|
||||
JavaSignature *signature;
|
||||
JavaSignatureChar field_type;
|
||||
jfieldID fieldID = field_spec->fieldID;
|
||||
|
||||
is_static_field = field_spec->modifiers & ACC_STATIC;
|
||||
|
||||
#define GET_JAVA_FIELD(Type,member) \
|
||||
PR_BEGIN_MACRO \
|
||||
if (is_static_field) \
|
||||
java_value.member = \
|
||||
(*jEnv)->GetStatic##Type##Field(jEnv, java_obj, fieldID); \
|
||||
else \
|
||||
java_value.member = \
|
||||
(*jEnv)->Get##Type##Field(jEnv, java_obj, fieldID); \
|
||||
if ((*jEnv)->ExceptionOccurred(jEnv)) { \
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "Error reading Java field"); \
|
||||
return JS_FALSE; \
|
||||
} \
|
||||
PR_END_MACRO
|
||||
|
||||
signature = field_spec->signature;
|
||||
field_type = signature->type;
|
||||
switch(field_type) {
|
||||
case JAVA_SIGNATURE_BYTE:
|
||||
GET_JAVA_FIELD(Byte,b);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_CHAR:
|
||||
GET_JAVA_FIELD(Char,c);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_SHORT:
|
||||
GET_JAVA_FIELD(Short,s);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_INT:
|
||||
GET_JAVA_FIELD(Int,i);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_BOOLEAN:
|
||||
GET_JAVA_FIELD(Boolean,z);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_LONG:
|
||||
GET_JAVA_FIELD(Long,j);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_FLOAT:
|
||||
GET_JAVA_FIELD(Float,f);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_DOUBLE:
|
||||
GET_JAVA_FIELD(Double,d);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_CLASS:
|
||||
case JAVA_SIGNATURE_ARRAY:
|
||||
GET_JAVA_FIELD(Object,l);
|
||||
break;
|
||||
|
||||
#undef GET_JAVA_FIELD
|
||||
default:
|
||||
PR_ASSERT(0); /* Unknown java type signature */
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
return jsj_ConvertJavaValueToJSValue(cx, jEnv, signature, &java_value, vp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
jsj_SetJavaFieldValue(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field_spec,
|
||||
jclass java_obj, jsval js_val)
|
||||
{
|
||||
JSBool is_static_field, is_local_ref;
|
||||
int dummy_cost;
|
||||
jvalue java_value;
|
||||
JavaSignature *signature;
|
||||
JavaSignatureChar field_type;
|
||||
jfieldID fieldID = field_spec->fieldID;
|
||||
|
||||
is_static_field = field_spec->modifiers & ACC_STATIC;
|
||||
|
||||
#define SET_JAVA_FIELD(Type,member) \
|
||||
PR_BEGIN_MACRO \
|
||||
if (is_static_field) { \
|
||||
(*jEnv)->SetStatic##Type##Field(jEnv, java_obj, fieldID, \
|
||||
java_value.member); \
|
||||
} else { \
|
||||
(*jEnv)->Set##Type##Field(jEnv, java_obj, fieldID,java_value.member);\
|
||||
} \
|
||||
if ((*jEnv)->ExceptionOccurred(jEnv)) { \
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "Error assigning to Java field"); \
|
||||
return JS_FALSE; \
|
||||
} \
|
||||
PR_END_MACRO
|
||||
|
||||
signature = field_spec->signature;
|
||||
if (!jsj_ConvertJSValueToJavaValue(cx, jEnv, js_val, signature, &dummy_cost,
|
||||
&java_value, &is_local_ref))
|
||||
return JS_FALSE;
|
||||
|
||||
field_type = signature->type;
|
||||
switch(field_type) {
|
||||
case JAVA_SIGNATURE_BYTE:
|
||||
SET_JAVA_FIELD(Byte,b);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_CHAR:
|
||||
SET_JAVA_FIELD(Char,c);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_SHORT:
|
||||
SET_JAVA_FIELD(Short,s);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_INT:
|
||||
SET_JAVA_FIELD(Int,i);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_BOOLEAN:
|
||||
SET_JAVA_FIELD(Boolean,z);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_LONG:
|
||||
SET_JAVA_FIELD(Long,j);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_FLOAT:
|
||||
SET_JAVA_FIELD(Float,f);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_DOUBLE:
|
||||
SET_JAVA_FIELD(Double,d);
|
||||
break;
|
||||
|
||||
case JAVA_SIGNATURE_CLASS:
|
||||
case JAVA_SIGNATURE_ARRAY:
|
||||
SET_JAVA_FIELD(Object,l);
|
||||
if (is_local_ref)
|
||||
(*jEnv)->DeleteLocalRef(jEnv, java_value.l);
|
||||
break;
|
||||
|
||||
#undef SET_JAVA_FIELD
|
||||
default:
|
||||
PR_ASSERT(0); /* Unknown java type signature */
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
487
mozilla/js/src/liveconnect/jsj_hash.c
Normal file
487
mozilla/js/src/liveconnect/jsj_hash.c
Normal file
@@ -0,0 +1,487 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a copy of the NSPR hash-table library, but it has been slightly
|
||||
* modified to allow an additional argument to be passed into the hash
|
||||
* key-comparision function. This is used to maintain thread-safety by
|
||||
* passing in a JNIEnv pointer to the key-comparison function rather
|
||||
* than storing it in a global. All types,function names, etc. have
|
||||
* been renamed from their original NSPR names to protect the innocent.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jsj_hash.h"
|
||||
#include "prtypes.h"
|
||||
#ifdef NSPR20
|
||||
# include "prlog.h"
|
||||
# include "prbit.h"
|
||||
#else
|
||||
# include "prassert.h"
|
||||
#endif
|
||||
|
||||
/* Compute the number of buckets in ht */
|
||||
#define NBUCKETS(ht) (1 << (JSJ_HASH_BITS - (ht)->shift))
|
||||
|
||||
/* The smallest table has 16 buckets */
|
||||
#define MINBUCKETSLOG2 4
|
||||
#define MINBUCKETS (1 << MINBUCKETSLOG2)
|
||||
|
||||
/* Compute the maximum entries given n buckets that we will tolerate, ~90% */
|
||||
#define OVERLOADED(n) ((n) - ((n) >> 3))
|
||||
|
||||
/* Compute the number of entries below which we shrink the table by half */
|
||||
#define UNDERLOADED(n) (((n) > MINBUCKETS) ? ((n) >> 2) : 0)
|
||||
|
||||
/*
|
||||
** Stubs for default hash allocator ops.
|
||||
*/
|
||||
static void *
|
||||
DefaultAllocTable(void *pool, size_t size)
|
||||
{
|
||||
#if defined(XP_MAC)
|
||||
#pragma unused (pool)
|
||||
#endif
|
||||
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static void
|
||||
DefaultFreeTable(void *pool, void *item)
|
||||
{
|
||||
#if defined(XP_MAC)
|
||||
#pragma unused (pool)
|
||||
#endif
|
||||
|
||||
free(item);
|
||||
}
|
||||
|
||||
static JSJHashEntry *
|
||||
DefaultAllocEntry(void *pool, const void *key)
|
||||
{
|
||||
#if defined(XP_MAC)
|
||||
#pragma unused (pool,key)
|
||||
#endif
|
||||
|
||||
return malloc(sizeof(JSJHashEntry));
|
||||
}
|
||||
|
||||
static void
|
||||
DefaultFreeEntry(void *pool, JSJHashEntry *he, PRUintn flag)
|
||||
{
|
||||
#if defined(XP_MAC)
|
||||
#pragma unused (pool)
|
||||
#endif
|
||||
|
||||
if (flag == HT_FREE_ENTRY)
|
||||
free(he);
|
||||
}
|
||||
|
||||
static JSJHashAllocOps defaultHashAllocOps = {
|
||||
DefaultAllocTable, DefaultFreeTable,
|
||||
DefaultAllocEntry, DefaultFreeEntry
|
||||
};
|
||||
|
||||
PR_IMPLEMENT(JSJHashTable *)
|
||||
JSJ_NewHashTable(PRUint32 n, JSJHashFunction keyHash,
|
||||
JSJHashComparator keyCompare, JSJHashComparator valueCompare,
|
||||
JSJHashAllocOps *allocOps, void *allocPriv)
|
||||
{
|
||||
JSJHashTable *ht;
|
||||
PRUint32 nb;
|
||||
|
||||
if (n <= MINBUCKETS) {
|
||||
n = MINBUCKETSLOG2;
|
||||
} else {
|
||||
n = PR_CeilingLog2(n);
|
||||
if ((PRInt32)n < 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!allocOps) allocOps = &defaultHashAllocOps;
|
||||
|
||||
ht = (*allocOps->allocTable)(allocPriv, sizeof *ht);
|
||||
if (!ht)
|
||||
return 0;
|
||||
memset(ht, 0, sizeof *ht);
|
||||
ht->shift = JSJ_HASH_BITS - n;
|
||||
n = 1 << n;
|
||||
#if defined(XP_PC) && !defined(_WIN32)
|
||||
if (n > 16000) {
|
||||
(*allocOps->freeTable)(allocPriv, ht);
|
||||
return 0;
|
||||
}
|
||||
#endif /* WIN16 */
|
||||
nb = n * sizeof(JSJHashEntry *);
|
||||
ht->buckets = (*allocOps->allocTable)(allocPriv, nb);
|
||||
if (!ht->buckets) {
|
||||
(*allocOps->freeTable)(allocPriv, ht);
|
||||
return 0;
|
||||
}
|
||||
memset(ht->buckets, 0, nb);
|
||||
|
||||
ht->keyHash = keyHash;
|
||||
ht->keyCompare = keyCompare;
|
||||
ht->valueCompare = valueCompare;
|
||||
ht->allocOps = allocOps;
|
||||
ht->allocPriv = allocPriv;
|
||||
return ht;
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(void)
|
||||
JSJ_HashTableDestroy(JSJHashTable *ht)
|
||||
{
|
||||
PRUint32 i, n;
|
||||
JSJHashEntry *he, *next;
|
||||
JSJHashAllocOps *allocOps = ht->allocOps;
|
||||
void *allocPriv = ht->allocPriv;
|
||||
|
||||
n = NBUCKETS(ht);
|
||||
for (i = 0; i < n; i++) {
|
||||
for (he = ht->buckets[i]; he; he = next) {
|
||||
next = he->next;
|
||||
(*allocOps->freeEntry)(allocPriv, he, HT_FREE_ENTRY);
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
memset(ht->buckets, 0xDB, n * sizeof ht->buckets[0]);
|
||||
#endif
|
||||
(*allocOps->freeTable)(allocPriv, ht->buckets);
|
||||
#ifdef DEBUG
|
||||
memset(ht, 0xDB, sizeof *ht);
|
||||
#endif
|
||||
(*allocOps->freeTable)(allocPriv, ht);
|
||||
}
|
||||
|
||||
/*
|
||||
** Multiplicative hash, from Knuth 6.4.
|
||||
*/
|
||||
#define GOLDEN_RATIO 0x9E3779B9U
|
||||
|
||||
PR_IMPLEMENT(JSJHashEntry **)
|
||||
JSJ_HashTableRawLookup(JSJHashTable *ht, JSJHashNumber keyHash, const void *key, void *arg)
|
||||
{
|
||||
JSJHashEntry *he, **hep, **hep0;
|
||||
JSJHashNumber h;
|
||||
|
||||
#ifdef HASHMETER
|
||||
ht->nlookups++;
|
||||
#endif
|
||||
h = keyHash * GOLDEN_RATIO;
|
||||
h >>= ht->shift;
|
||||
hep = hep0 = &ht->buckets[h];
|
||||
while ((he = *hep) != 0) {
|
||||
if (he->keyHash == keyHash && (*ht->keyCompare)(key, he->key, arg)) {
|
||||
/* Move to front of chain if not already there */
|
||||
if (hep != hep0) {
|
||||
*hep = he->next;
|
||||
he->next = *hep0;
|
||||
*hep0 = he;
|
||||
}
|
||||
return hep0;
|
||||
}
|
||||
hep = &he->next;
|
||||
#ifdef HASHMETER
|
||||
ht->nsteps++;
|
||||
#endif
|
||||
}
|
||||
return hep;
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(JSJHashEntry *)
|
||||
JSJ_HashTableRawAdd(JSJHashTable *ht, JSJHashEntry **hep,
|
||||
JSJHashNumber keyHash, const void *key, void *value,
|
||||
void *arg)
|
||||
{
|
||||
PRUint32 i, n;
|
||||
JSJHashEntry *he, *next, **oldbuckets;
|
||||
PRUint32 nb;
|
||||
|
||||
/* Grow the table if it is overloaded */
|
||||
n = NBUCKETS(ht);
|
||||
if (ht->nentries >= OVERLOADED(n)) {
|
||||
#ifdef HASHMETER
|
||||
ht->ngrows++;
|
||||
#endif
|
||||
ht->shift--;
|
||||
oldbuckets = ht->buckets;
|
||||
#if defined(XP_PC) && !defined(_WIN32)
|
||||
if (2 * n > 16000)
|
||||
return 0;
|
||||
#endif /* WIN16 */
|
||||
nb = 2 * n * sizeof(JSJHashEntry *);
|
||||
ht->buckets = (*ht->allocOps->allocTable)(ht->allocPriv, nb);
|
||||
if (!ht->buckets) {
|
||||
ht->buckets = oldbuckets;
|
||||
return 0;
|
||||
}
|
||||
memset(ht->buckets, 0, nb);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
for (he = oldbuckets[i]; he; he = next) {
|
||||
next = he->next;
|
||||
hep = JSJ_HashTableRawLookup(ht, he->keyHash, he->key, arg);
|
||||
PR_ASSERT(*hep == 0);
|
||||
he->next = 0;
|
||||
*hep = he;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
memset(oldbuckets, 0xDB, n * sizeof oldbuckets[0]);
|
||||
#endif
|
||||
(*ht->allocOps->freeTable)(ht->allocPriv, oldbuckets);
|
||||
hep = JSJ_HashTableRawLookup(ht, keyHash, key, arg);
|
||||
}
|
||||
|
||||
/* Make a new key value entry */
|
||||
he = (*ht->allocOps->allocEntry)(ht->allocPriv, key);
|
||||
if (!he)
|
||||
return 0;
|
||||
he->keyHash = keyHash;
|
||||
he->key = key;
|
||||
he->value = value;
|
||||
he->next = *hep;
|
||||
*hep = he;
|
||||
ht->nentries++;
|
||||
return he;
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(JSJHashEntry *)
|
||||
JSJ_HashTableAdd(JSJHashTable *ht, const void *key, void *value, void *arg)
|
||||
{
|
||||
JSJHashNumber keyHash;
|
||||
JSJHashEntry *he, **hep;
|
||||
|
||||
keyHash = (*ht->keyHash)(key, arg);
|
||||
hep = JSJ_HashTableRawLookup(ht, keyHash, key, arg);
|
||||
if ((he = *hep) != 0) {
|
||||
/* Hit; see if values match */
|
||||
if ((*ht->valueCompare)(he->value, value, arg)) {
|
||||
/* key,value pair is already present in table */
|
||||
return he;
|
||||
}
|
||||
if (he->value)
|
||||
(*ht->allocOps->freeEntry)(ht->allocPriv, he, HT_FREE_VALUE);
|
||||
he->value = value;
|
||||
return he;
|
||||
}
|
||||
return JSJ_HashTableRawAdd(ht, hep, keyHash, key, value, arg);
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(void)
|
||||
JSJ_HashTableRawRemove(JSJHashTable *ht, JSJHashEntry **hep, JSJHashEntry *he, void *arg)
|
||||
{
|
||||
PRUint32 i, n;
|
||||
JSJHashEntry *next, **oldbuckets;
|
||||
PRUint32 nb;
|
||||
|
||||
*hep = he->next;
|
||||
(*ht->allocOps->freeEntry)(ht->allocPriv, he, HT_FREE_ENTRY);
|
||||
|
||||
/* Shrink table if it's underloaded */
|
||||
n = NBUCKETS(ht);
|
||||
if (--ht->nentries < UNDERLOADED(n)) {
|
||||
#ifdef HASHMETER
|
||||
ht->nshrinks++;
|
||||
#endif
|
||||
ht->shift++;
|
||||
oldbuckets = ht->buckets;
|
||||
nb = n * sizeof(JSJHashEntry*) / 2;
|
||||
ht->buckets = (*ht->allocOps->allocTable)(ht->allocPriv, nb);
|
||||
if (!ht->buckets) {
|
||||
ht->buckets = oldbuckets;
|
||||
return;
|
||||
}
|
||||
memset(ht->buckets, 0, nb);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
for (he = oldbuckets[i]; he; he = next) {
|
||||
next = he->next;
|
||||
hep = JSJ_HashTableRawLookup(ht, he->keyHash, he->key, arg);
|
||||
PR_ASSERT(*hep == 0);
|
||||
he->next = 0;
|
||||
*hep = he;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
memset(oldbuckets, 0xDB, n * sizeof oldbuckets[0]);
|
||||
#endif
|
||||
(*ht->allocOps->freeTable)(ht->allocPriv, oldbuckets);
|
||||
}
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(PRBool)
|
||||
JSJ_HashTableRemove(JSJHashTable *ht, const void *key, void *arg)
|
||||
{
|
||||
JSJHashNumber keyHash;
|
||||
JSJHashEntry *he, **hep;
|
||||
|
||||
keyHash = (*ht->keyHash)(key, arg);
|
||||
hep = JSJ_HashTableRawLookup(ht, keyHash, key, arg);
|
||||
if ((he = *hep) == 0)
|
||||
return PR_FALSE;
|
||||
|
||||
/* Hit; remove element */
|
||||
JSJ_HashTableRawRemove(ht, hep, he, arg);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(void *)
|
||||
JSJ_HashTableLookup(JSJHashTable *ht, const void *key, void *arg)
|
||||
{
|
||||
JSJHashNumber keyHash;
|
||||
JSJHashEntry *he, **hep;
|
||||
|
||||
keyHash = (*ht->keyHash)(key, arg);
|
||||
hep = JSJ_HashTableRawLookup(ht, keyHash, key, arg);
|
||||
if ((he = *hep) != 0) {
|
||||
return he->value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Iterate over the entries in the hash table calling func for each
|
||||
** entry found. Stop if "f" says to (return value & PR_ENUMERATE_STOP).
|
||||
** Return a count of the number of elements scanned.
|
||||
*/
|
||||
PR_IMPLEMENT(int)
|
||||
JSJ_HashTableEnumerateEntries(JSJHashTable *ht, JSJHashEnumerator f, void *arg)
|
||||
{
|
||||
JSJHashEntry *he, **hep;
|
||||
PRUint32 i, nbuckets;
|
||||
int rv, n = 0;
|
||||
JSJHashEntry *todo = 0;
|
||||
|
||||
nbuckets = NBUCKETS(ht);
|
||||
for (i = 0; i < nbuckets; i++) {
|
||||
hep = &ht->buckets[i];
|
||||
while ((he = *hep) != 0) {
|
||||
rv = (*f)(he, n, arg);
|
||||
n++;
|
||||
if (rv & (HT_ENUMERATE_REMOVE | HT_ENUMERATE_UNHASH)) {
|
||||
*hep = he->next;
|
||||
if (rv & HT_ENUMERATE_REMOVE) {
|
||||
he->next = todo;
|
||||
todo = he;
|
||||
}
|
||||
} else {
|
||||
hep = &he->next;
|
||||
}
|
||||
if (rv & HT_ENUMERATE_STOP) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
hep = &todo;
|
||||
while ((he = *hep) != 0) {
|
||||
JSJ_HashTableRawRemove(ht, hep, he, arg);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
#ifdef HASHMETER
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
PR_IMPLEMENT(void)
|
||||
JSJ_HashTableDumpMeter(JSJHashTable *ht, JSJHashEnumerator dump, FILE *fp)
|
||||
{
|
||||
double mean, variance;
|
||||
PRUint32 nchains, nbuckets;
|
||||
PRUint32 i, n, maxChain, maxChainLen;
|
||||
JSJHashEntry *he;
|
||||
|
||||
variance = 0;
|
||||
nchains = 0;
|
||||
maxChainLen = 0;
|
||||
nbuckets = NBUCKETS(ht);
|
||||
for (i = 0; i < nbuckets; i++) {
|
||||
he = ht->buckets[i];
|
||||
if (!he)
|
||||
continue;
|
||||
nchains++;
|
||||
for (n = 0; he; he = he->next)
|
||||
n++;
|
||||
variance += n * n;
|
||||
if (n > maxChainLen) {
|
||||
maxChainLen = n;
|
||||
maxChain = i;
|
||||
}
|
||||
}
|
||||
mean = (double)ht->nentries / nchains;
|
||||
variance = fabs(variance / nchains - mean * mean);
|
||||
|
||||
fprintf(fp, "\nHash table statistics:\n");
|
||||
fprintf(fp, " number of lookups: %u\n", ht->nlookups);
|
||||
fprintf(fp, " number of entries: %u\n", ht->nentries);
|
||||
fprintf(fp, " number of grows: %u\n", ht->ngrows);
|
||||
fprintf(fp, " number of shrinks: %u\n", ht->nshrinks);
|
||||
fprintf(fp, " mean steps per hash: %g\n", (double)ht->nsteps
|
||||
/ ht->nlookups);
|
||||
fprintf(fp, "mean hash chain length: %g\n", mean);
|
||||
fprintf(fp, " standard deviation: %g\n", sqrt(variance));
|
||||
fprintf(fp, " max hash chain length: %u\n", maxChainLen);
|
||||
fprintf(fp, " max hash chain: [%u]\n", maxChain);
|
||||
|
||||
for (he = ht->buckets[maxChain], i = 0; he; he = he->next, i++)
|
||||
if ((*dump)(he, i, fp) != HT_ENUMERATE_NEXT)
|
||||
break;
|
||||
}
|
||||
#endif /* HASHMETER */
|
||||
|
||||
PR_IMPLEMENT(int)
|
||||
JSJ_HashTableDump(JSJHashTable *ht, JSJHashEnumerator dump, FILE *fp)
|
||||
{
|
||||
int count;
|
||||
|
||||
count = JSJ_HashTableEnumerateEntries(ht, dump, fp);
|
||||
#ifdef HASHMETER
|
||||
JSJ_HashTableDumpMeter(ht, dump, fp);
|
||||
#endif
|
||||
return count;
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(JSJHashNumber)
|
||||
JSJ_HashString(const void *key)
|
||||
{
|
||||
JSJHashNumber h;
|
||||
const unsigned char *s;
|
||||
|
||||
h = 0;
|
||||
for (s = key; *s; s++)
|
||||
h = (h >> 28) ^ (h << 4) ^ *s;
|
||||
return h;
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(int)
|
||||
JSJ_CompareStrings(const void *v1, const void *v2)
|
||||
{
|
||||
return strcmp(v1, v2) == 0;
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(int)
|
||||
JSJ_CompareValues(const void *v1, const void *v2)
|
||||
{
|
||||
return v1 == v2;
|
||||
}
|
||||
141
mozilla/js/src/liveconnect/jsj_hash.h
Normal file
141
mozilla/js/src/liveconnect/jsj_hash.h
Normal file
@@ -0,0 +1,141 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a copy of the NSPR hash-table library, but it has been slightly
|
||||
* modified to allow an additional argument to be passed into the hash
|
||||
* key-comparision function. This is used to maintain thread-safety by
|
||||
* passing in a JNIEnv pointer to the key-comparison function rather
|
||||
* than storing it in a global. All types,function names, etc. have
|
||||
* been renamed from their original NSPR names to protect the innocent.
|
||||
*/
|
||||
|
||||
#ifndef jsj_hash_h___
|
||||
#define jsj_hash_h___
|
||||
/*
|
||||
* API to portable hash table code.
|
||||
*/
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include "prtypes.h"
|
||||
|
||||
PR_BEGIN_EXTERN_C
|
||||
|
||||
typedef struct JSJHashEntry JSJHashEntry;
|
||||
typedef struct JSJHashTable JSJHashTable;
|
||||
typedef PRUint32 JSJHashNumber;
|
||||
#define JSJ_HASH_BITS 32
|
||||
typedef JSJHashNumber (*JSJHashFunction)(const void *key, void *arg);
|
||||
typedef PRIntn (*JSJHashComparator)(const void *v1, const void *v2, void *arg);
|
||||
typedef PRIntn (*JSJHashEnumerator)(JSJHashEntry *he, PRIntn i, void *arg);
|
||||
|
||||
/* Flag bits in JSJHashEnumerator's return value */
|
||||
#define HT_ENUMERATE_NEXT 0 /* continue enumerating entries */
|
||||
#define HT_ENUMERATE_STOP 1 /* stop enumerating entries */
|
||||
#define HT_ENUMERATE_REMOVE 2 /* remove and free the current entry */
|
||||
#define HT_ENUMERATE_UNHASH 4 /* just unhash the current entry */
|
||||
|
||||
typedef struct JSJHashAllocOps {
|
||||
void * (*allocTable)(void *pool, size_t size);
|
||||
void (*freeTable)(void *pool, void *item);
|
||||
JSJHashEntry * (*allocEntry)(void *pool, const void *key);
|
||||
void (*freeEntry)(void *pool, JSJHashEntry *he, PRUintn flag);
|
||||
} JSJHashAllocOps;
|
||||
|
||||
#define HT_FREE_VALUE 0 /* just free the entry's value */
|
||||
#define HT_FREE_ENTRY 1 /* free value and entire entry */
|
||||
|
||||
struct JSJHashEntry {
|
||||
JSJHashEntry *next; /* hash chain linkage */
|
||||
JSJHashNumber keyHash; /* key hash function result */
|
||||
const void *key; /* ptr to opaque key */
|
||||
void *value; /* ptr to opaque value */
|
||||
};
|
||||
|
||||
struct JSJHashTable {
|
||||
JSJHashEntry **buckets; /* vector of hash buckets */
|
||||
PRUint32 nentries; /* number of entries in table */
|
||||
PRUint32 shift; /* multiplicative hash shift */
|
||||
JSJHashFunction keyHash; /* key hash function */
|
||||
JSJHashComparator keyCompare; /* key comparison function */
|
||||
JSJHashComparator valueCompare; /* value comparison function */
|
||||
JSJHashAllocOps *allocOps; /* allocation operations */
|
||||
void *allocPriv; /* allocation private data */
|
||||
#ifdef HASHMETER
|
||||
PRUint32 nlookups; /* total number of lookups */
|
||||
PRUint32 nsteps; /* number of hash chains traversed */
|
||||
PRUint32 ngrows; /* number of table expansions */
|
||||
PRUint32 nshrinks; /* number of table contractions */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* Create a new hash table.
|
||||
* If allocOps is null, use default allocator ops built on top of malloc().
|
||||
*/
|
||||
PR_EXTERN(JSJHashTable *)
|
||||
JSJ_NewHashTable(PRUint32 n, JSJHashFunction keyHash,
|
||||
JSJHashComparator keyCompare, JSJHashComparator valueCompare,
|
||||
JSJHashAllocOps *allocOps, void *allocPriv);
|
||||
|
||||
PR_EXTERN(void)
|
||||
JSJ_HashTableDestroy(JSJHashTable *ht);
|
||||
|
||||
/* Low level access methods */
|
||||
PR_EXTERN(JSJHashEntry **)
|
||||
JSJ_HashTableRawLookup(JSJHashTable *ht, JSJHashNumber keyHash, const void *key, void *arg);
|
||||
|
||||
PR_EXTERN(JSJHashEntry *)
|
||||
JSJ_HashTableRawAdd(JSJHashTable *ht, JSJHashEntry **hep, JSJHashNumber keyHash,
|
||||
const void *key, void *value, void *arg);
|
||||
|
||||
PR_EXTERN(void)
|
||||
JSJ_HashTableRawRemove(JSJHashTable *ht, JSJHashEntry **hep, JSJHashEntry *he, void *arg);
|
||||
|
||||
/* Higher level access methods */
|
||||
PR_EXTERN(JSJHashEntry *)
|
||||
JSJ_HashTableAdd(JSJHashTable *ht, const void *key, void *value, void *arg);
|
||||
|
||||
PR_EXTERN(PRBool)
|
||||
JSJ_HashTableRemove(JSJHashTable *ht, const void *key, void *arg);
|
||||
|
||||
PR_EXTERN(PRIntn)
|
||||
JSJ_HashTableEnumerateEntries(JSJHashTable *ht, JSJHashEnumerator f, void *arg);
|
||||
|
||||
PR_EXTERN(void *)
|
||||
JSJ_HashTableLookup(JSJHashTable *ht, const void *key, void *arg);
|
||||
|
||||
PR_EXTERN(PRIntn)
|
||||
JSJ_HashTableDump(JSJHashTable *ht, JSJHashEnumerator dump, FILE *fp);
|
||||
|
||||
/* General-purpose C string hash function. */
|
||||
PR_EXTERN(JSJHashNumber)
|
||||
JSJ_HashString(const void *key);
|
||||
|
||||
/* Compare strings using strcmp(), return true if equal. */
|
||||
PR_EXTERN(int)
|
||||
JSJ_CompareStrings(const void *v1, const void *v2);
|
||||
|
||||
/* Stub function just returns v1 == v2 */
|
||||
PR_EXTERN(PRIntn)
|
||||
JSJ_CompareValues(const void *v1, const void *v2);
|
||||
|
||||
PR_END_EXTERN_C
|
||||
|
||||
#endif /* jsj_hash_h___ */
|
||||
1164
mozilla/js/src/liveconnect/jsj_method.c
Normal file
1164
mozilla/js/src/liveconnect/jsj_method.c
Normal file
File diff suppressed because it is too large
Load Diff
0
mozilla/js/src/liveconnect/jsj_nodl.c
Normal file
0
mozilla/js/src/liveconnect/jsj_nodl.c
Normal file
552
mozilla/js/src/liveconnect/jsj_private.h
Normal file
552
mozilla/js/src/liveconnect/jsj_private.h
Normal file
@@ -0,0 +1,552 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* Declarations of private (internal) functions/data/types for
|
||||
* JavaScript <==> Java communication.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _JSJAVA_PVT_H
|
||||
#define _JSJAVA_PVT_H
|
||||
|
||||
#include "prtypes.h"
|
||||
|
||||
/* NSPR1 compatibility definitions */
|
||||
#ifdef NSPR20
|
||||
# include "prprf.h"
|
||||
# include "prlog.h"
|
||||
# include "plhash.h" /* NSPR hash-tables */
|
||||
#else
|
||||
# include "prprintf.h"
|
||||
# include "prassert.h"
|
||||
# include "prhash.h" /* NSPR hash-tables */
|
||||
# define PRHashNumber prhashcode
|
||||
#endif
|
||||
|
||||
#ifdef XP_MAC
|
||||
# include "prosdep.h"
|
||||
#endif
|
||||
|
||||
#include "jsj_hash.h" /* Hash tables */
|
||||
#include "jni.h" /* Java Native Interface */
|
||||
#include "jsapi.h" /* JavaScript engine API */
|
||||
#include "jsjava.h" /* LiveConnect public API */
|
||||
|
||||
|
||||
/*************************** Type Declarations ******************************/
|
||||
|
||||
/* Forward type declarations */
|
||||
typedef struct JavaMemberDescriptor JavaMemberDescriptor;
|
||||
typedef struct JavaMethodSpec JavaMethodSpec;
|
||||
typedef struct JavaClassDescriptor JavaClassDescriptor;
|
||||
typedef struct JavaClassDescriptor JavaSignature;
|
||||
typedef struct CapturedJSError CapturedJSError;
|
||||
typedef struct JavaMemberVal JavaMemberVal;
|
||||
|
||||
/*
|
||||
* This enum uses the same character encoding used by the JDK to encode
|
||||
* Java type signatures, but the enum is easier to debug/compile with.
|
||||
*/
|
||||
typedef enum {
|
||||
JAVA_SIGNATURE_ARRAY = '[',
|
||||
JAVA_SIGNATURE_BYTE = 'B',
|
||||
JAVA_SIGNATURE_CHAR = 'C',
|
||||
JAVA_SIGNATURE_CLASS = 'L',
|
||||
JAVA_SIGNATURE_FLOAT = 'F',
|
||||
JAVA_SIGNATURE_DOUBLE = 'D',
|
||||
JAVA_SIGNATURE_INT = 'I',
|
||||
JAVA_SIGNATURE_LONG = 'J',
|
||||
JAVA_SIGNATURE_SHORT = 'S',
|
||||
JAVA_SIGNATURE_VOID = 'V',
|
||||
JAVA_SIGNATURE_BOOLEAN = 'Z',
|
||||
JAVA_SIGNATURE_UNKNOWN = 0
|
||||
} JavaSignatureChar;
|
||||
|
||||
/* The signature of a Java method consists of the signatures of all its
|
||||
arguments and its return type signature. */
|
||||
typedef struct JavaMethodSignature {
|
||||
jsize num_args; /* Length of arg_signatures array */
|
||||
JavaSignature ** arg_signatures; /* Array of argument signatures */
|
||||
JavaSignature * return_val_signature; /* Return type signature */
|
||||
} JavaMethodSignature;
|
||||
|
||||
/* A descriptor for the reflection of a single Java field */
|
||||
typedef struct JavaFieldSpec {
|
||||
jfieldID fieldID; /* JVM opaque access handle for field */
|
||||
JavaSignature * signature; /* Java type of field */
|
||||
int modifiers; /* Bitfield indicating field qualifiers */
|
||||
const char * name; /* UTF8; TODO - Should support Unicode field names */
|
||||
} JavaFieldSpec;
|
||||
|
||||
/* A descriptor for the reflection of a single Java method.
|
||||
Each overloaded method has a separate corresponding JavaMethodSpec. */
|
||||
struct JavaMethodSpec {
|
||||
jmethodID methodID; /* JVM opaque access handle for method */
|
||||
JavaMethodSignature signature;
|
||||
const char * name; /* UTF8; TODO - Should support Unicode method names */
|
||||
JavaMethodSpec * next; /* next method in chain of overloaded methods */
|
||||
};
|
||||
|
||||
/*
|
||||
* A descriptor for the reflection of a single member of a Java object.
|
||||
* This can represent one or more Java methods and/or a single field.
|
||||
* (When there is more than one method attached to a single JavaMemberDescriptor
|
||||
* they are overloaded methods sharing the same simple name.) This same
|
||||
* descriptor type is used for both static or instance members.
|
||||
*/
|
||||
struct JavaMemberDescriptor {
|
||||
const char * name; /* simple name of field and/or method */
|
||||
jsid id; /* hashed name for quick JS property lookup */
|
||||
JavaFieldSpec * field; /* field with the given name, if any */
|
||||
JavaMethodSpec * methods; /* Overloaded methods which share the same name, if any */
|
||||
JavaMemberDescriptor * next; /* next descriptor in same defining class */
|
||||
JSObject * invoke_func_obj; /* If non-null, JSFunction obj to invoke method */
|
||||
};
|
||||
|
||||
/* This is the native portion of a reflected Java class */
|
||||
struct JavaClassDescriptor {
|
||||
const char * name; /* Name of class, e.g. "java/lang/Byte" */
|
||||
JavaSignatureChar type; /* class category: primitive type, object, array */
|
||||
jclass java_class; /* Opaque JVM handle to corresponding java.lang.Class */
|
||||
int num_instance_members;
|
||||
int num_static_members;
|
||||
JSBool instance_members_reflected;
|
||||
JavaMemberDescriptor * instance_members;
|
||||
JSBool static_members_reflected;
|
||||
JavaMemberDescriptor * static_members;
|
||||
JavaMemberDescriptor * constructors;
|
||||
int modifiers; /* Class declaration qualifiers,
|
||||
e.g. abstract, private */
|
||||
int ref_count; /* # of references to this struct */
|
||||
JavaSignature * array_component_signature; /* Only non-NULL for array classes */
|
||||
};
|
||||
|
||||
/* This is the native portion of a reflected Java method or field */
|
||||
struct JavaMemberVal {
|
||||
jsval field_val; /* Captured value of Java field */
|
||||
jsval invoke_method_func_val; /* JSFunction wrapper around Java method invoker */
|
||||
JavaMemberDescriptor * descriptor;
|
||||
JavaMemberVal * next;
|
||||
};
|
||||
|
||||
/* This is the native portion of a reflected Java object */
|
||||
typedef struct JavaObjectWrapper {
|
||||
jobject java_obj; /* Opaque JVM ref to Java object */
|
||||
JavaClassDescriptor * class_descriptor; /* Java class info */
|
||||
} JavaObjectWrapper;
|
||||
|
||||
/* These are definitions of the Java class/method/field modifier bits.
|
||||
These really shouldn't be hard-coded here. Rather,
|
||||
they should be read from java.lang.reflect.Modifier */
|
||||
#define ACC_PUBLIC 0x0001 /* visible to everyone */
|
||||
#define ACC_STATIC 0x0008 /* instance variable is static */
|
||||
#define ACC_FINAL 0x0010 /* no further subclassing,overriding */
|
||||
#define ACC_INTERFACE 0x0200 /* class is an interface */
|
||||
#define ACC_ABSTRACT 0x0400 /* no definition provided */
|
||||
|
||||
/* A JSJavaVM structure must be created for each Java VM that is accessed
|
||||
via LiveConnect */
|
||||
struct JSJavaVM {
|
||||
/* TODO - all LiveConnect global variables should be migrated into this
|
||||
structure in order to allow more than one LiveConnect-enabled
|
||||
Java VM to exist within the same process. */
|
||||
SystemJavaVM * java_vm;
|
||||
JNIEnv * main_thread_env; /* Main-thread Java environment */
|
||||
JSBool jsj_created_java_vm;
|
||||
int num_attached_threads;
|
||||
JSJavaVM * next; /* next VM among all created VMs */
|
||||
};
|
||||
|
||||
/* Per-thread state that encapsulates the connection to the Java VM */
|
||||
struct JSJavaThreadState {
|
||||
const char * name; /* Thread name, for debugging */
|
||||
JSJavaVM * jsjava_vm; /* All per-JVM state */
|
||||
JNIEnv * jEnv; /* Per-thread opaque handle to Java VM */
|
||||
CapturedJSError * pending_js_errors; /* JS errors to be thrown as Java exceptions */
|
||||
JSContext * cx; /* current JS context for thread */
|
||||
JSJavaThreadState * next; /* next thread state among all created threads */
|
||||
};
|
||||
|
||||
struct JavaToJSSavedState {
|
||||
JSErrorReporter error_reporter;
|
||||
JSJavaThreadState* java_jsj_env;
|
||||
};
|
||||
typedef struct JavaToJSSavedState JavaToJSSavedState;
|
||||
|
||||
|
||||
|
||||
/******************************** Globals ***********************************/
|
||||
|
||||
extern JSJCallbacks *JSJ_callbacks;
|
||||
|
||||
/* JavaScript classes that reflect Java objects */
|
||||
extern JSClass JavaObject_class;
|
||||
extern JSClass JavaArray_class;
|
||||
extern JSClass JavaClass_class;
|
||||
extern JSClass JavaMember_class;
|
||||
|
||||
/*
|
||||
* Opaque JVM handles to Java classes, methods and objects required for
|
||||
* Java reflection. These are computed and cached during initialization.
|
||||
* TODO: These should be moved inside the JSJavaVM struct
|
||||
*/
|
||||
extern jclass jlObject; /* java.lang.Object */
|
||||
extern jclass jlrConstructor; /* java.lang.reflect.Constructor */
|
||||
extern jclass jlThrowable; /* java.lang.Throwable */
|
||||
extern jclass jlSystem; /* java.lang.System */
|
||||
extern jclass jlClass; /* java.lang.Class */
|
||||
extern jclass jlBoolean; /* java.lang.Boolean */
|
||||
extern jclass jlDouble; /* java.lang.Double */
|
||||
extern jclass jlString; /* java.lang.String */
|
||||
extern jclass njJSObject; /* netscape.javascript.JSObject */
|
||||
extern jclass njJSException; /* netscape.javascript.JSException */
|
||||
extern jclass njJSUtil; /* netscape.javascript.JSUtil */
|
||||
|
||||
extern jmethodID jlClass_getMethods; /* java.lang.Class.getMethods() */
|
||||
extern jmethodID jlClass_getConstructors; /* java.lang.Class.getConstructors() */
|
||||
extern jmethodID jlClass_getFields; /* java.lang.Class.getFields() */
|
||||
extern jmethodID jlClass_getName; /* java.lang.Class.getName() */
|
||||
extern jmethodID jlClass_getComponentType; /* java.lang.Class.getComponentType() */
|
||||
extern jmethodID jlClass_getModifiers; /* java.lang.Class.getModifiers() */
|
||||
extern jmethodID jlClass_isArray; /* java.lang.Class.isArray() */
|
||||
|
||||
extern jmethodID jlrMethod_getName; /* java.lang.reflect.Method.getName() */
|
||||
extern jmethodID jlrMethod_getParameterTypes; /* java.lang.reflect.Method.getParameterTypes() */
|
||||
extern jmethodID jlrMethod_getReturnType; /* java.lang.reflect.Method.getReturnType() */
|
||||
extern jmethodID jlrMethod_getModifiers; /* java.lang.reflect.Method.getModifiers() */
|
||||
|
||||
extern jmethodID jlrConstructor_getParameterTypes; /* java.lang.reflect.Constructor.getParameterTypes() */
|
||||
extern jmethodID jlrConstructor_getModifiers; /* java.lang.reflect.Constructor.getModifiers() */
|
||||
|
||||
extern jmethodID jlrField_getName; /* java.lang.reflect.Field.getName() */
|
||||
extern jmethodID jlrField_getType; /* java.lang.reflect.Field.getType() */
|
||||
extern jmethodID jlrField_getModifiers; /* java.lang.reflect.Field.getModifiers() */
|
||||
|
||||
extern jmethodID jlThrowable_getMessage; /* java.lang.Throwable.getMessage() */
|
||||
extern jmethodID jlThrowable_toString; /* java.lang.Throwable.toString() */
|
||||
|
||||
extern jmethodID jlBoolean_Boolean; /* java.lang.Boolean constructor */
|
||||
extern jmethodID jlBoolean_booleanValue; /* java.lang.Boolean.booleanValue() */
|
||||
extern jmethodID jlDouble_Double; /* java.lang.Double constructor */
|
||||
extern jmethodID jlDouble_doubleValue; /* java.lang.Double.doubleValue() */
|
||||
|
||||
extern jmethodID jlSystem_identityHashCode; /* java.lang.System.identityHashCode() */
|
||||
|
||||
extern jobject jlVoid_TYPE; /* java.lang.Void.TYPE value */
|
||||
|
||||
extern jmethodID njJSException_JSException; /* netscape.javascipt.JSexception constructor */
|
||||
extern jmethodID njJSObject_JSObject; /* netscape.javascript.JSObject constructor */
|
||||
extern jmethodID njJSUtil_getStackTrace; /* netscape.javascript.JSUtil.getStackTrace() */
|
||||
extern jfieldID njJSObject_internal; /* netscape.javascript.JSObject.internal */
|
||||
extern jfieldID njJSException_lineno; /* netscape.javascript.JSException.lineno */
|
||||
extern jfieldID njJSException_tokenIndex; /* netscape.javascript.JSException.tokenIndex */
|
||||
extern jfieldID njJSException_source; /* netscape.javascript.JSException.source */
|
||||
extern jfieldID njJSException_filename; /* netscape.javascript.JSException.filename */
|
||||
|
||||
|
||||
/**************** Java <==> JS conversions and Java types *******************/
|
||||
extern JSBool
|
||||
jsj_ComputeJavaClassSignature(JSContext *cx,
|
||||
JavaSignature *signature,
|
||||
jclass java_class);
|
||||
|
||||
extern const char *
|
||||
jsj_ConvertJavaSignatureToString(JSContext *cx, JavaSignature *signature);
|
||||
extern const char *
|
||||
jsj_ConvertJavaSignatureToHRString(JSContext *cx,
|
||||
JavaSignature *signature);
|
||||
extern JavaMethodSignature *
|
||||
jsj_InitJavaMethodSignature(JSContext *cx, JNIEnv *jEnv, jobject method,
|
||||
JavaMethodSignature *method_signature);
|
||||
|
||||
extern const char *
|
||||
jsj_ConvertJavaMethodSignatureToString(JSContext *cx,
|
||||
JavaMethodSignature *method_signature);
|
||||
extern const char *
|
||||
jsj_ConvertJavaMethodSignatureToHRString(JSContext *cx,
|
||||
const char *method_name,
|
||||
JavaMethodSignature *method_signature);
|
||||
extern void
|
||||
jsj_PurgeJavaMethodSignature(JSContext *cx, JNIEnv *jEnv, JavaMethodSignature *signature);
|
||||
|
||||
extern JSBool
|
||||
jsj_ConvertJSValueToJavaValue(JSContext *cx, JNIEnv *jEnv, jsval v, JavaSignature *signature,
|
||||
int *cost, jvalue *java_value, JSBool *is_local_refp);
|
||||
extern JSBool
|
||||
jsj_ConvertJSValueToJavaObject(JSContext *cx, JNIEnv *jEnv, jsval v, JavaSignature *signature,
|
||||
int *cost, jobject *java_value, JSBool *is_local_refp);
|
||||
extern jstring
|
||||
jsj_ConvertJSStringToJavaString(JSContext *cx, JNIEnv *jEnv, JSString *js_str);
|
||||
|
||||
extern JSBool
|
||||
jsj_ConvertJavaValueToJSValue(JSContext *cx, JNIEnv *jEnv, JavaSignature *signature,
|
||||
jvalue *java_value, jsval *vp);
|
||||
extern JSBool
|
||||
jsj_ConvertJavaObjectToJSValue(JSContext *cx, JNIEnv *jEnv,
|
||||
jobject java_obj, jsval *vp);
|
||||
|
||||
extern JSString *
|
||||
jsj_ConvertJavaStringToJSString(JSContext *cx, JNIEnv *jEnv, jstring java_str);
|
||||
|
||||
extern JSBool
|
||||
jsj_ConvertJavaObjectToJSString(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jobject java_obj, jsval *vp);
|
||||
extern JSBool
|
||||
jsj_ConvertJavaObjectToJSNumber(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jobject java_obj, jsval *vp);
|
||||
extern JSBool
|
||||
jsj_ConvertJavaObjectToJSBoolean(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jobject java_obj, jsval *vp);
|
||||
extern JSJavaThreadState *
|
||||
jsj_enter_js(JNIEnv *jEnv, jobject java_wrapper_obj,
|
||||
JSContext **cxp, JSObject **js_objp, JavaToJSSavedState* saved_state);
|
||||
extern JSBool
|
||||
jsj_exit_js(JSContext *cx, JSJavaThreadState *jsj_env, JavaToJSSavedState* original_state);
|
||||
|
||||
extern JavaClassDescriptor *
|
||||
jsj_get_jlObject_descriptor(JSContext *cx, JNIEnv *jEnv);
|
||||
|
||||
extern JSBool
|
||||
jsj_remove_js_obj_reflection_from_hashtable(JSContext *cx, JSObject *js_obj);
|
||||
|
||||
extern JSBool
|
||||
jsj_init_js_obj_reflections_table();
|
||||
|
||||
/************************ Java package reflection **************************/
|
||||
extern JSBool
|
||||
jsj_init_JavaPackage(JSContext *, JSObject *,
|
||||
JavaPackageDef *predefined_packages);
|
||||
|
||||
/************************* Java class reflection ***************************/
|
||||
extern JSBool
|
||||
jsj_init_JavaClass(JSContext *cx, JSObject *global_obj);
|
||||
|
||||
extern void
|
||||
jsj_DiscardJavaClassReflections(JNIEnv *jEnv);
|
||||
|
||||
extern const char *
|
||||
jsj_GetJavaClassName(JSContext *cx, JNIEnv *jEnv, jclass java_class);
|
||||
|
||||
extern JavaClassDescriptor *
|
||||
jsj_GetJavaClassDescriptor(JSContext *cx, JNIEnv *jEnv, jclass java_class);
|
||||
|
||||
extern void
|
||||
jsj_ReleaseJavaClassDescriptor(JSContext *cx, JNIEnv *jEnv, JavaClassDescriptor *class_descriptor);
|
||||
|
||||
extern JSObject *
|
||||
jsj_define_JavaClass(JSContext *cx, JNIEnv *jEnv, JSObject *obj,
|
||||
const char *unqualified_class_name,
|
||||
jclass jclazz);
|
||||
|
||||
extern JavaMemberDescriptor *
|
||||
jsj_GetJavaMemberDescriptor(JSContext *cx,
|
||||
JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jstring member_name);
|
||||
|
||||
extern JavaMemberDescriptor *
|
||||
jsj_LookupJavaMemberDescriptorById(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jsid id);
|
||||
|
||||
extern JavaMemberDescriptor *
|
||||
jsj_LookupJavaStaticMemberDescriptorById(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jsid id);
|
||||
|
||||
extern JavaMemberDescriptor *
|
||||
jsj_GetJavaStaticMemberDescriptor(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
jstring member_name);
|
||||
|
||||
extern JavaMemberDescriptor *
|
||||
jsj_GetJavaClassConstructors(JSContext *cx,
|
||||
JavaClassDescriptor *class_descriptor);
|
||||
|
||||
extern JavaMemberDescriptor *
|
||||
jsj_LookupJavaClassConstructors(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor);
|
||||
|
||||
extern JavaMemberDescriptor *
|
||||
jsj_GetClassInstanceMembers(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor);
|
||||
|
||||
extern JavaMemberDescriptor *
|
||||
jsj_GetClassStaticMembers(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor);
|
||||
|
||||
extern JSBool
|
||||
jsj_InitJavaClassReflectionsTable();
|
||||
|
||||
/************************* Java field reflection ***************************/
|
||||
|
||||
extern JSBool
|
||||
jsj_GetJavaFieldValue(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field_spec,
|
||||
jobject java_obj, jsval *vp);
|
||||
extern JSBool
|
||||
jsj_SetJavaFieldValue(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field_spec,
|
||||
jobject java_obj, jsval js_val);
|
||||
extern JSBool
|
||||
jsj_ReflectJavaFields(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
JSBool reflect_only_static_fields);
|
||||
extern void
|
||||
jsj_DestroyFieldSpec(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field);
|
||||
|
||||
/************************* Java method reflection ***************************/
|
||||
extern JSBool
|
||||
jsj_JavaInstanceMethodWrapper(JSContext *cx, JSObject *obj,
|
||||
uintN argc, jsval *argv, jsval *vp);
|
||||
extern JSBool
|
||||
jsj_JavaStaticMethodWrapper(JSContext *cx, JSObject *obj,
|
||||
uintN argc, jsval *argv, jsval *vp);
|
||||
extern JSBool
|
||||
jsj_JavaConstructorWrapper(JSContext *cx, JSObject *obj,
|
||||
uintN argc, jsval *argv, jsval *vp);
|
||||
extern JSBool
|
||||
jsj_ReflectJavaMethods(JSContext *cx, JNIEnv *jEnv,
|
||||
JavaClassDescriptor *class_descriptor,
|
||||
JSBool reflect_only_static_methods);
|
||||
extern void
|
||||
jsj_DestroyMethodSpec(JSContext *cx, JNIEnv *jEnv, JavaMethodSpec *method_spec);
|
||||
|
||||
/************************* Java member reflection ***************************/
|
||||
extern JSBool
|
||||
jsj_init_JavaMember(JSContext *, JSObject *);
|
||||
|
||||
extern JSBool
|
||||
jsj_ReflectJavaMethodsAndFields(JSContext *cx, JavaClassDescriptor *class_descriptor,
|
||||
JSBool reflect_only_statics);
|
||||
|
||||
extern JSObject *
|
||||
jsj_CreateJavaMember(JSContext *cx, jsval method_val, jsval field_val);
|
||||
|
||||
/************************* Java object reflection **************************/
|
||||
extern JSBool
|
||||
jsj_init_JavaObject(JSContext *, JSObject *);
|
||||
|
||||
extern JSObject *
|
||||
jsj_WrapJavaObject(JSContext *cx, JNIEnv *jEnv, jobject java_obj, jclass java_class);
|
||||
|
||||
extern void
|
||||
jsj_DiscardJavaObjReflections(JNIEnv *jEnv);
|
||||
|
||||
extern JSBool
|
||||
JavaObject_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp);
|
||||
|
||||
extern void
|
||||
JavaObject_finalize(JSContext *cx, JSObject *obj);
|
||||
|
||||
extern JSBool
|
||||
JavaObject_resolve(JSContext *cx, JSObject *obj, jsval id);
|
||||
|
||||
extern JSBool
|
||||
JavaObject_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
|
||||
|
||||
extern JSBool
|
||||
JavaObject_getPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
|
||||
|
||||
/************************* Java array reflection ***************************/
|
||||
extern JSBool
|
||||
jsj_init_JavaArray(JSContext *cx, JSObject *global_obj);
|
||||
|
||||
extern JSBool
|
||||
jsj_GetJavaArrayElement(JSContext *cx, JNIEnv *jEnv, jarray java_array,
|
||||
jsize index, JavaSignature *array_component_signature,
|
||||
jsval *vp);
|
||||
|
||||
extern JSBool
|
||||
jsj_SetJavaArrayElement(JSContext *cx, JNIEnv *jEnv, jarray java_array,
|
||||
jsize index, JavaSignature *array_component_signature,
|
||||
jsval js_val);
|
||||
|
||||
/********************* JavaScript object reflection ************************/
|
||||
extern jobject
|
||||
jsj_WrapJSObject(JSContext *cx, JNIEnv *jEnv, JSObject *js_obj);
|
||||
|
||||
extern JSObject *
|
||||
jsj_UnwrapJSObjectWrapper(JNIEnv *jEnv, jobject java_wrapper_obj);
|
||||
|
||||
extern void
|
||||
jsj_ClearPendingJSErrors(JSJavaThreadState *jsj_env);
|
||||
|
||||
extern JSBool
|
||||
jsj_ReportUncaughtJSException(JSContext *cx, JNIEnv *jEnv, jthrowable java_exception);
|
||||
|
||||
/**************************** Utilities ************************************/
|
||||
extern void
|
||||
jsj_ReportJavaError(JSContext *cx, JNIEnv *env, const char *format, ...);
|
||||
|
||||
extern void
|
||||
jsj_UnexpectedJavaError(JSContext *cx, JNIEnv *env, const char *format, ...);
|
||||
|
||||
extern const char *
|
||||
jsj_GetJavaErrorMessage(JNIEnv *env);
|
||||
|
||||
extern void
|
||||
jsj_LogError(const char *error_msg);
|
||||
|
||||
PR_CALLBACK JSJHashNumber
|
||||
jsj_HashJavaObject(const void *key, void* env);
|
||||
|
||||
PR_CALLBACK intN
|
||||
jsj_JavaObjectComparator(const void *v1, const void *v2, void *arg);
|
||||
|
||||
extern JSJavaThreadState *
|
||||
jsj_MapJavaThreadToJSJavaThreadState(JNIEnv *jEnv, char **errp);
|
||||
|
||||
extern void
|
||||
jsj_MakeJNIClassname(char *jClassName);
|
||||
|
||||
extern const char *
|
||||
jsj_ClassNameOfJavaObject(JSContext *cx, JNIEnv *jEnv, jobject java_object);
|
||||
|
||||
extern jsize
|
||||
jsj_GetJavaArrayLength(JSContext *cx, JNIEnv *jEnv, jarray java_array);
|
||||
|
||||
extern JSBool
|
||||
JavaStringToId(JSContext *cx, JNIEnv *jEnv, jstring jstr, jsid *idp);
|
||||
|
||||
extern const char *
|
||||
jsj_DupJavaStringUTF(JSContext *cx, JNIEnv *jEnv, jstring jstr);
|
||||
|
||||
JSJavaThreadState *
|
||||
jsj_MapJSContextToJSJThread(JSContext *cx, JNIEnv **envp);
|
||||
|
||||
JSJavaThreadState *
|
||||
jsj_SetJavaJSJEnv(JSJavaThreadState* java_jsj_env);
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUG_LOG(args) printf args
|
||||
#endif
|
||||
|
||||
#define JS_FREE_IF(cx, x) \
|
||||
PR_BEGIN_MACRO \
|
||||
if (x) \
|
||||
JS_free(cx, x); \
|
||||
PR_END_MACRO
|
||||
|
||||
#endif /* _JSJAVA_PVT_H */
|
||||
361
mozilla/js/src/liveconnect/jsj_utils.c
Normal file
361
mozilla/js/src/liveconnect/jsj_utils.c
Normal file
@@ -0,0 +1,361 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains low-level utility code.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jsj_private.h" /* LiveConnect internals */
|
||||
#include "jsjava.h" /* External LiveConnect API */
|
||||
|
||||
|
||||
/*
|
||||
* This is a hash-table utility routine that computes the hash code of a Java
|
||||
* object by calling java.lang.System.identityHashCode()
|
||||
*/
|
||||
PR_CALLBACK JSJHashNumber
|
||||
jsj_HashJavaObject(const void *key, void* env)
|
||||
{
|
||||
PRHashNumber hash_code;
|
||||
jobject java_obj;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
java_obj = (jobject)key;
|
||||
jEnv = (JNIEnv*) env;
|
||||
hash_code = (*jEnv)->CallStaticIntMethod(jEnv, jlSystem,
|
||||
jlSystem_identityHashCode, java_obj);
|
||||
PR_ASSERT(!(*jEnv)->ExceptionOccurred(jEnv));
|
||||
return hash_code;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a hash-table utility routine for comparing two Java objects.
|
||||
* It's not possible to use the == operator to directly compare two jobject's,
|
||||
* since they're opaque references and aren't guaranteed to be simple pointers
|
||||
* or handles (though they may be in some JVM implementations). Instead,
|
||||
* use the JNI routine for comparing the two objects.
|
||||
*/
|
||||
PR_CALLBACK intN
|
||||
jsj_JavaObjectComparator(const void *v1, const void *v2, void *arg)
|
||||
{
|
||||
jobject java_obj1, java_obj2;
|
||||
JNIEnv *jEnv;
|
||||
|
||||
jEnv = (JNIEnv*)arg;
|
||||
java_obj1 = (jobject)v1;
|
||||
java_obj2 = (jobject)v2;
|
||||
|
||||
if (java_obj1 == java_obj2)
|
||||
return 1;
|
||||
return (*jEnv)->IsSameObject(jEnv, java_obj1, java_obj2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a UTF8, null-terminated encoding of a Java string. The string must
|
||||
* be free'ed by the caller.
|
||||
*
|
||||
* If an error occurs, returns NULL and calls the JS error reporter.
|
||||
*/
|
||||
const char *
|
||||
jsj_DupJavaStringUTF(JSContext *cx, JNIEnv *jEnv, jstring jstr)
|
||||
{
|
||||
const char *str, *retval;
|
||||
|
||||
str = (*jEnv)->GetStringUTFChars(jEnv, jstr, 0);
|
||||
if (!str) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "Can't get UTF8 characters from "
|
||||
"Java string");
|
||||
return NULL;
|
||||
}
|
||||
retval = JS_strdup(cx, str);
|
||||
(*jEnv)->ReleaseStringUTFChars(jEnv, jstr, str);
|
||||
return retval;
|
||||
}
|
||||
|
||||
JSBool
|
||||
JavaStringToId(JSContext *cx, JNIEnv *jEnv, jstring jstr, jsid *idp)
|
||||
{
|
||||
const jschar *ucs2;
|
||||
JSString *jsstr;
|
||||
jsize ucs2_len;
|
||||
jsval val;
|
||||
|
||||
ucs2 = (*jEnv)->GetStringChars(jEnv, jstr, 0);
|
||||
if (!ucs2) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "Couldn't obtain Unicode characters"
|
||||
"from Java string");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
ucs2_len = (*jEnv)->GetStringLength(jEnv, jstr);
|
||||
jsstr = JS_InternUCStringN(cx, ucs2, ucs2_len);
|
||||
(*jEnv)->ReleaseStringChars(jEnv, jstr, ucs2);
|
||||
if (!jsstr)
|
||||
return JS_FALSE;
|
||||
|
||||
val = STRING_TO_JSVAL(jsstr);
|
||||
JS_ValueToId(cx, STRING_TO_JSVAL(jsstr), idp);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* Not used ?
|
||||
const char *
|
||||
jsj_ClassNameOfJavaObject(JSContext *cx, JNIEnv *jEnv, jobject java_object)
|
||||
{
|
||||
jobject java_class;
|
||||
|
||||
java_class = (*jEnv)->GetObjectClass(jEnv, java_object);
|
||||
|
||||
if (!java_class) {
|
||||
PR_ASSERT(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return jsj_GetJavaClassName(cx, jEnv, java_class);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* Return, as a C string, the error message associated with a Java exception
|
||||
* that occurred as a result of a JNI call, preceded by the class name of
|
||||
* the exception. As a special case, if the class of the exception is
|
||||
* netscape.javascript.JSException, the exception class name is omitted.
|
||||
*
|
||||
* NULL is returned if no Java exception is pending. The caller is
|
||||
* responsible for free'ing the returned string. On exit, the Java exception
|
||||
* is *not* cleared.
|
||||
*/
|
||||
const char *
|
||||
jsj_GetJavaErrorMessage(JNIEnv *jEnv)
|
||||
{
|
||||
const char *java_error_msg;
|
||||
char *error_msg = NULL;
|
||||
jthrowable exception;
|
||||
jstring java_exception_jstring;
|
||||
|
||||
exception = (*jEnv)->ExceptionOccurred(jEnv);
|
||||
if (exception && jlThrowable_toString) {
|
||||
java_exception_jstring =
|
||||
(*jEnv)->CallObjectMethod(jEnv, exception, jlThrowable_toString);
|
||||
java_error_msg = (*jEnv)->GetStringUTFChars(jEnv, java_exception_jstring, NULL);
|
||||
error_msg = strdup((char*)java_error_msg);
|
||||
(*jEnv)->ReleaseStringUTFChars(jEnv, java_exception_jstring, java_error_msg);
|
||||
|
||||
#ifdef DEBUG
|
||||
/* (*jEnv)->ExceptionDescribe(jEnv); */
|
||||
#endif
|
||||
}
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return, as a C string, the JVM stack trace associated with a Java
|
||||
* exception, as would be printed by java.lang.Throwable.printStackTrace().
|
||||
* The caller is responsible for free'ing the returned string.
|
||||
*
|
||||
* Returns NULL if an error occurs.
|
||||
*/
|
||||
static const char *
|
||||
get_java_stack_trace(JSContext *cx, JNIEnv *jEnv, jthrowable java_exception)
|
||||
{
|
||||
const char *backtrace;
|
||||
jstring backtrace_jstr;
|
||||
|
||||
backtrace = NULL;
|
||||
if (java_exception && njJSUtil_getStackTrace) {
|
||||
backtrace_jstr = (*jEnv)->CallStaticObjectMethod(jEnv, njJSUtil,
|
||||
njJSUtil_getStackTrace,
|
||||
java_exception);
|
||||
if (!backtrace_jstr) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "Unable to get exception stack trace");
|
||||
return NULL;
|
||||
}
|
||||
backtrace = jsj_DupJavaStringUTF(cx, jEnv, backtrace_jstr);
|
||||
}
|
||||
return backtrace;
|
||||
}
|
||||
|
||||
/* Full Java backtrace when Java exceptions reported to JavaScript */
|
||||
#define REPORT_JAVA_EXCEPTION_STACK_TRACE
|
||||
|
||||
/*
|
||||
* This is a wrapper around JS_ReportError(), useful when an error condition
|
||||
* is the result of a JVM failure or exception condition. It appends the
|
||||
* message associated with the pending Java exception to the passed in
|
||||
* printf-style format string and arguments.
|
||||
*/
|
||||
static void
|
||||
vreport_java_error(JSContext *cx, JNIEnv *jEnv, const char *format, va_list ap)
|
||||
{
|
||||
char *error_msg, *js_error_msg;
|
||||
const char *java_stack_trace;
|
||||
const char *java_error_msg;
|
||||
jthrowable java_exception;
|
||||
|
||||
java_error_msg = NULL;
|
||||
java_exception = (*jEnv)->ExceptionOccurred(jEnv);
|
||||
if (java_exception && njJSException &&
|
||||
(*jEnv)->IsInstanceOf(jEnv, java_exception, njJSException)) {
|
||||
(*jEnv)->ExceptionClear(jEnv);
|
||||
jsj_ReportUncaughtJSException(cx, jEnv, java_exception);
|
||||
return;
|
||||
}
|
||||
|
||||
js_error_msg = PR_vsmprintf(format, ap);
|
||||
|
||||
if (!js_error_msg) {
|
||||
PR_ASSERT(0); /* Out-of-memory */
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef REPORT_JAVA_EXCEPTION_STACK_TRACE
|
||||
|
||||
java_stack_trace = get_java_stack_trace(cx, jEnv, java_exception);
|
||||
if (java_stack_trace) {
|
||||
error_msg = PR_smprintf("%s\n%s", js_error_msg, java_stack_trace);
|
||||
free((char*)java_stack_trace);
|
||||
if (!error_msg) {
|
||||
PR_ASSERT(0); /* Out-of-memory */
|
||||
return;
|
||||
}
|
||||
} else
|
||||
|
||||
#endif
|
||||
{
|
||||
java_error_msg = jsj_GetJavaErrorMessage(jEnv);
|
||||
if (java_error_msg) {
|
||||
error_msg = PR_smprintf("%s (%s)\n", js_error_msg, java_error_msg);
|
||||
free((char*)java_error_msg);
|
||||
free(js_error_msg);
|
||||
} else {
|
||||
error_msg = js_error_msg;
|
||||
}
|
||||
}
|
||||
|
||||
JS_ReportError(cx, error_msg);
|
||||
|
||||
/* Important: the Java exception must not be cleared until the reporter
|
||||
has been called, because the capture_js_error_reports_for_java(),
|
||||
called from JS_ReportError(), needs to read the exception from the JVM */
|
||||
(*jEnv)->ExceptionClear(jEnv);
|
||||
free(error_msg);
|
||||
}
|
||||
|
||||
void
|
||||
jsj_ReportJavaError(JSContext *cx, JNIEnv *env, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
vreport_java_error(cx, env, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Same as jsj_ReportJavaError, except "internal error: " is prepended
|
||||
* to message.
|
||||
*/
|
||||
void
|
||||
jsj_UnexpectedJavaError(JSContext *cx, JNIEnv *env, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
const char *format2;
|
||||
|
||||
va_start(ap, format);
|
||||
format2 = PR_smprintf("internal error: %s", format);
|
||||
if (format2) {
|
||||
vreport_java_error(cx, env, format2, ap);
|
||||
free((void*)format2);
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Most LiveConnect errors are signaled by calling JS_ReportError(),
|
||||
* but in some circumstances, the target JSContext for such errors
|
||||
* is not determinable, e.g. during initialization. In such cases
|
||||
* any error messages are routed to this function.
|
||||
*/
|
||||
void
|
||||
jsj_LogError(const char *error_msg)
|
||||
{
|
||||
if (JSJ_callbacks && JSJ_callbacks->error_print)
|
||||
JSJ_callbacks->error_print(error_msg);
|
||||
else
|
||||
fputs(error_msg, stderr);
|
||||
}
|
||||
|
||||
jsize
|
||||
jsj_GetJavaArrayLength(JSContext *cx, JNIEnv *jEnv, jarray java_array)
|
||||
{
|
||||
jsize array_length = (*jEnv)->GetArrayLength(jEnv, java_array);
|
||||
if ((*jEnv)->ExceptionOccurred(jEnv)) {
|
||||
jsj_UnexpectedJavaError(cx, jEnv, "Couldn't obtain array length");
|
||||
return -1;
|
||||
}
|
||||
return array_length;
|
||||
}
|
||||
|
||||
static JSJavaThreadState *the_java_jsj_env = NULL;
|
||||
|
||||
JSJavaThreadState *
|
||||
jsj_MapJSContextToJSJThread(JSContext *cx, JNIEnv **envp)
|
||||
{
|
||||
JSJavaThreadState *jsj_env;
|
||||
char *err_msg;
|
||||
|
||||
*envp = NULL;
|
||||
err_msg = NULL;
|
||||
|
||||
jsj_env = the_java_jsj_env;
|
||||
if (jsj_env == NULL)
|
||||
jsj_env = JSJ_callbacks->map_js_context_to_jsj_thread(cx, &err_msg);
|
||||
if (!jsj_env) {
|
||||
if (err_msg) {
|
||||
JS_ReportError(cx, err_msg);
|
||||
free(err_msg);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if (envp)
|
||||
*envp = jsj_env->jEnv;
|
||||
return jsj_env;
|
||||
}
|
||||
|
||||
/**
|
||||
* Since only one Java thread is allowed to enter JavaScript, this function is
|
||||
* used to enforce the use of that thread's state. The static global the_java_jsj_env
|
||||
* overrides using JSJ_callbacks->map_js_context_to_jsj_thread, which maps
|
||||
* native threads to JSJavaThreadStates. This isn't appropriate when Java calls
|
||||
* JavaScript, as there can be a many to one mapping from Java threads to native
|
||||
* threads.
|
||||
*/
|
||||
JSJavaThreadState *
|
||||
jsj_SetJavaJSJEnv(JSJavaThreadState* java_jsj_env)
|
||||
{
|
||||
JSJavaThreadState *old_jsj_env = the_java_jsj_env;
|
||||
the_java_jsj_env = java_jsj_env;
|
||||
return old_jsj_env;
|
||||
}
|
||||
264
mozilla/js/src/liveconnect/jsjava.h
Normal file
264
mozilla/js/src/liveconnect/jsjava.h
Normal file
@@ -0,0 +1,264 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* Publicly exported functions for JavaScript <==> Java communication.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _JSJAVA_H
|
||||
#define _JSJAVA_H
|
||||
|
||||
#ifndef prtypes_h___
|
||||
#include "prtypes.h"
|
||||
#endif
|
||||
|
||||
PR_BEGIN_EXTERN_C
|
||||
|
||||
#include "jni.h" /* Java Native Interface */
|
||||
#include "jsapi.h" /* JavaScript engine API */
|
||||
|
||||
/*
|
||||
* A JSJavaVM structure is a wrapper around a JavaVM which incorporates
|
||||
* additional LiveConnect state.
|
||||
*/
|
||||
typedef struct JSJavaVM JSJavaVM;
|
||||
|
||||
/* LiveConnect and Java state, one per thread */
|
||||
typedef struct JSJavaThreadState JSJavaThreadState;
|
||||
|
||||
/*
|
||||
* An opaque type that represents the connection to the Java VM. In stand-alone
|
||||
* Java environments, this may be a JNI JavaVM object; in the browser environment
|
||||
* it is a reference to a JVM plugin. A set of callbacks in the JSJCallbacks
|
||||
* struct allow it to be manipulated.
|
||||
*/
|
||||
typedef struct SystemJavaVM SystemJavaVM;
|
||||
|
||||
/*
|
||||
* This callback table provides hooks to external functions that implement
|
||||
* functionality specific to the embedding. For example, these callbacks are
|
||||
* necessary in multi-threaded environments or to implement a security
|
||||
* policy.
|
||||
*/
|
||||
typedef struct JSJCallbacks {
|
||||
|
||||
/* This callback is invoked when there is no JavaScript execution
|
||||
environment (JSContext) associated with the current Java thread and
|
||||
a call is made from Java into JavaScript. (A JSContext is associated
|
||||
with a Java thread by calling the JSJ_SetJSContextForJavaThread()
|
||||
function.) This callback is only invoked when Java spontaneously calls
|
||||
into JavaScript, i.e. it is not called when JS calls into Java which
|
||||
calls back into JS.
|
||||
|
||||
This callback can be used to create a JSContext lazily, or obtain
|
||||
one from a pool of available JSContexts. The implementation of this
|
||||
callback can call JSJ_SetJSContextForJavaThread() to avoid any further
|
||||
callbacks of this type for this Java thread. */
|
||||
JSContext * (*map_jsj_thread_to_js_context)(JSJavaThreadState *jsj_env,
|
||||
JNIEnv *jEnv,
|
||||
char **errp);
|
||||
|
||||
/* This callback is invoked whenever a call is made into Java from
|
||||
JavaScript. It's responsible for mapping from a JavaScript execution
|
||||
environment (JSContext) to a Java thread. (A JavaContext can only
|
||||
be associated with one Java thread at a time.) */
|
||||
JSJavaThreadState * (*map_js_context_to_jsj_thread)(JSContext *cx,
|
||||
char **errp);
|
||||
|
||||
/* This callback implements netscape.javascript.JSObject.getWindow(),
|
||||
a method named for its behavior in the browser environment, where it
|
||||
returns the JS "Window" object corresponding to the HTML window that an
|
||||
applet is embedded within. More generally, it's a way for Java to get
|
||||
hold of a JS object that has not been explicitly passed to it. */
|
||||
JSObject * (*map_java_object_to_js_object)(JNIEnv *jEnv, void *pJavaObject,
|
||||
char **errp);
|
||||
|
||||
/* An interim callback function until the LiveConnect security story is
|
||||
straightened out. This function pointer can be set to NULL. */
|
||||
JSPrincipals * (*get_JSPrincipals_from_java_caller)(JNIEnv *jEnv, JSContext *pJSContext);
|
||||
|
||||
/* The following two callbacks sandwich any JS evaluation performed
|
||||
from Java. They may be used to implement concurrency constraints, e.g.
|
||||
by suspending the current thread until some condition is met. In the
|
||||
browser embedding, these are used to maintain the run-to-completion
|
||||
semantics of JavaScript. It is acceptable for either function pointer
|
||||
to be NULL. */
|
||||
JSBool (*enter_js_from_java)(JNIEnv *jEnv, char **errp);
|
||||
void (*exit_js)(JNIEnv *jEnv);
|
||||
|
||||
/* Most LiveConnect errors are signaled by calling JS_ReportError(), but in
|
||||
some circumstances, the target JSContext for such errors is not
|
||||
determinable, e.g. during initialization. In such cases any error
|
||||
messages are routed to this function. If the function pointer is set to
|
||||
NULL, error messages are sent to stderr. */
|
||||
void (*error_print)(const char *error_msg);
|
||||
|
||||
/* This enables liveconnect to ask the VM for a java wrapper so that VM gets a chance to
|
||||
store a mapping between a jsobject and java wrapper. So the unwrapping can be done on the
|
||||
VM side before calling nsILiveconnect apis. This saves on a round trip request. */
|
||||
jobject (*get_java_wrapper)(JNIEnv *jEnv, jint jsobject);
|
||||
|
||||
/* The following set of methods abstract over the JavaVM object. */
|
||||
PRBool (*create_java_vm)(SystemJavaVM* *jvm, JNIEnv* *initialEnv, void* initargs);
|
||||
PRBool (*destroy_java_vm)(SystemJavaVM* jvm, JNIEnv* initialEnv);
|
||||
JNIEnv* (*attach_current_thread)(SystemJavaVM* jvm);
|
||||
PRBool (*detach_current_thread)(SystemJavaVM* jvm, JNIEnv* env);
|
||||
SystemJavaVM* (*get_java_vm)(JNIEnv* env);
|
||||
|
||||
/* Reserved for future use */
|
||||
void * reserved[10];
|
||||
} JSJCallbacks;
|
||||
|
||||
/*===========================================================================*/
|
||||
|
||||
/* A flag that denotes that a Java package has no sub-packages other than those
|
||||
explicitly pre-defined at the time of initialization. An access
|
||||
to a simple name within such a package, therefore, must either correspond to
|
||||
one of these explicitly pre-defined sub-packages or to a class within this
|
||||
package. It is reasonable for LiveConnect to signal an error if a simple
|
||||
name does not comply with these criteria. */
|
||||
#define PKG_SYSTEM 1
|
||||
|
||||
/* A flag that denotes that a Java package which might contain sub-packages
|
||||
that are not pre-defined at initialization time, because the sub-packages
|
||||
may not be the same in all installations. Therefore, an access to a simple
|
||||
name within such a a package which does not correspond to either a
|
||||
pre-defined sub-package or to a class, must be assummed to refer to an
|
||||
unknown sub-package. This behavior may cause bogus JavaPackage objects to be
|
||||
created if a package name is misspelled, e.g. sun.oi.net. */
|
||||
#define PKG_USER 2
|
||||
|
||||
/* A Java package defined at initialization time. */
|
||||
typedef struct JavaPackageDef {
|
||||
const char * name; /* e.g. "java.lang" */
|
||||
const char * path; /* e.g. "java/lang", or NULL for default */
|
||||
int flags; /* PKG_USER, PKG_SYSTEM, etc. */
|
||||
} JavaPackageDef;
|
||||
|
||||
/*===========================================================================*/
|
||||
|
||||
/* The following two convenience functions present a complete, but simplified
|
||||
LiveConnect API which is designed to handle the special case of a single
|
||||
Java-VM, with single-threaded operation, and the use of only one JSContext.
|
||||
The full API is in the section below. */
|
||||
|
||||
/* Initialize the provided JSContext by setting up the JS classes necessary for
|
||||
reflection and by defining JavaPackage objects for the default Java packages
|
||||
as properties of global_obj. If java_vm is NULL, a new Java VM is
|
||||
created, using the provided classpath in addition to any default classpath.
|
||||
The classpath argument is ignored, however, if java_vm is non-NULL. */
|
||||
PR_IMPLEMENT(JSBool)
|
||||
JSJ_SimpleInit(JSContext *cx, JSObject *global_obj,
|
||||
SystemJavaVM *java_vm, const char *classpath);
|
||||
|
||||
/* Free up all resources. Destroy the Java VM if it was created by LiveConnect */
|
||||
PR_IMPLEMENT(void)
|
||||
JSJ_SimpleShutdown();
|
||||
|
||||
/*===========================================================================*/
|
||||
|
||||
/* The "full" LiveConnect API, required when more than one thread, Java VM, or
|
||||
JSContext is involved. Initialization pseudocode might go roughly like
|
||||
this:
|
||||
|
||||
JSJ_Init() // Setup callbacks
|
||||
for each JavaVM {
|
||||
JSJ_ConnectToJavaVM(...)
|
||||
}
|
||||
for each JSContext {
|
||||
JSJ_InitJSContext(...)
|
||||
}
|
||||
for each JS evaluation {
|
||||
run JavaScript code in the JSContext;
|
||||
}
|
||||
*/
|
||||
|
||||
/* Called once for all instances of LiveConnect to set up callbacks */
|
||||
PR_IMPLEMENT(void)
|
||||
JSJ_Init(JSJCallbacks *callbacks);
|
||||
|
||||
/* Called once per Java VM, this function initializes the classes, fields, and
|
||||
methods required for Java reflection. If java_vm is NULL, a new Java VM is
|
||||
created according to the create_java_vm callback in the JSJCallbacks,
|
||||
using the provided classpath in addition to any default initargs.
|
||||
The initargs argument is ignored, however, if java_vm is non-NULL. */
|
||||
PR_IMPLEMENT(JSJavaVM *)
|
||||
JSJ_ConnectToJavaVM(SystemJavaVM *java_vm, void* initargs);
|
||||
|
||||
/* Initialize the provided JSContext by setting up the JS classes necessary for
|
||||
reflection and by defining JavaPackage objects for the default Java packages
|
||||
as properties of global_obj. Additional packages may be pre-defined by
|
||||
setting the predefined_packages argument. (Pre-defining a Java package at
|
||||
initialization time is not necessary, but it will make package lookup faster
|
||||
and, more importantly, will avoid unnecessary network accesses if classes
|
||||
are being loaded over the network.) */
|
||||
PR_IMPLEMENT(JSBool)
|
||||
JSJ_InitJSContext(JSContext *cx, JSObject *global_obj,
|
||||
JavaPackageDef *predefined_packages);
|
||||
|
||||
/* This function returns a structure that encapsulates the Java and JavaScript
|
||||
execution environment for the current native thread. It is intended to
|
||||
be called from the embedder's implementation of JSJCallback's
|
||||
map_js_context_to_jsj_thread() function. The thread_name argument is only
|
||||
used for debugging purposes and can be set to NULL. The Java JNI
|
||||
environment associated with this thread is returned through the java_envp
|
||||
argument if java_envp is non-NULL. */
|
||||
PR_IMPLEMENT(JSJavaThreadState *)
|
||||
JSJ_AttachCurrentThreadToJava(JSJavaVM *jsjava_vm, const char *thread_name,
|
||||
JNIEnv **java_envp);
|
||||
|
||||
/* Destructor routine for per-thread JSJavaThreadState structure */
|
||||
PR_IMPLEMENT(JSBool)
|
||||
JSJ_DetachCurrentThreadFromJava(JSJavaThreadState *jsj_env);
|
||||
|
||||
/* This function is used to specify a particular JSContext as *the* JavaScript
|
||||
execution environment to be used when LiveConnect is accessed from the given
|
||||
Java thread, i.e. when one of the methods of netscape.javascript.JSObject
|
||||
has been called. There can only be one such JS context for any given Java
|
||||
thread at a time. (To multiplex JSContexts among a single thread, this
|
||||
function could be called before Java is invoked on that thread.) The return
|
||||
value is the previous JSContext associated with the given Java thread.
|
||||
|
||||
If this function has not been called for a thread and a crossing is made
|
||||
into JavaScript from Java, the map_jsj_thread_to_js_context() callback will
|
||||
be invoked to determine the JSContext for the thread. The purpose of the
|
||||
function is to improve performance by avoiding the expense of the callback.
|
||||
*/
|
||||
PR_IMPLEMENT(JSContext *)
|
||||
JSJ_SetDefaultJSContextForJavaThread(JSContext *cx, JSJavaThreadState *jsj_env);
|
||||
|
||||
/* This routine severs the connection to a Java VM, freeing all related resources.
|
||||
It shouldn't be called until the global scope has been cleared in all related
|
||||
JSContexts (so that all LiveConnect objects are finalized) and a JavaScript
|
||||
GC is performed. Otherwise, accessed to free'ed memory could result. */
|
||||
PR_IMPLEMENT(void)
|
||||
JSJ_DisconnectFromJavaVM(JSJavaVM *);
|
||||
|
||||
/*
|
||||
* Reflect a Java object into a JS value. The source object, java_obj, must
|
||||
* be of type java.lang.Object or a subclass and may, therefore, be an array.
|
||||
*/
|
||||
PR_IMPLEMENT(JSBool)
|
||||
JSJ_ConvertJavaObjectToJSValue(JSContext *cx, jobject java_obj, jsval *vp);
|
||||
|
||||
PR_END_EXTERN_C
|
||||
#endif /* _JSJAVA_H */
|
||||
182
mozilla/js/src/liveconnect/makefile.win
Normal file
182
mozilla/js/src/liveconnect/makefile.win
Normal file
@@ -0,0 +1,182 @@
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "NPL"); you may not use this file except in
|
||||
# compliance with the NPL. You may obtain a copy of the NPL at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
# for the specific language governing rights and limitations under the
|
||||
# NPL.
|
||||
#
|
||||
# The Initial Developer of this code under the NPL is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
# Reserved.
|
||||
|
||||
IGNORE_MANIFEST=1
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Makefile to build the Java reflections of JavaScript objects
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Specify the depth of the current directory relative to the
|
||||
#// root of NS
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
DEPTH= ..\..\..
|
||||
|
||||
include <$(DEPTH)/config/config.mak>
|
||||
|
||||
!ifdef NSJVM
|
||||
DIRS = classes
|
||||
!endif
|
||||
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Define any Public Make Variables here: (ie. PDFFILE, MAPFILE, ...)
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
DLLNAME=jsj$(MOZ_BITS)$(VERSION_NUMBER)
|
||||
PDBFILE=$(DLLNAME).pdb
|
||||
MAPFILE = $(DLLNAME).map
|
||||
RESFILE = jsj1640.res
|
||||
DLL=.\$(OBJDIR)\$(DLLNAME).dll
|
||||
MAKE_OBJ_TYPE = DLL
|
||||
|
||||
!if "$(MOZ_BITS)" == "16"
|
||||
DEFFILE = $(DLLNAME).def
|
||||
!endif
|
||||
|
||||
LLIBS=$(LIBNSPR) $(DIST)\lib\js$(MOZ_BITS)$(VERSION_NUMBER).lib \
|
||||
$(DIST)\lib\xpcom32.lib
|
||||
|
||||
!if "$(MOZ_BITS)"=="32" && defined(MOZ_DEBUG) && defined(GLOWCODE)
|
||||
LLIBS=$(LLIBS) $(GLOWDIR)\glowcode.lib
|
||||
!endif
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Define the files necessary to build the target (ie. OBJS)
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
OBJS= \
|
||||
.\$(OBJDIR)\jsj.obj \
|
||||
.\$(OBJDIR)\jsj_JSObject.obj \
|
||||
.\$(OBJDIR)\jsj_JavaArray.obj \
|
||||
.\$(OBJDIR)\jsj_JavaClass.obj \
|
||||
.\$(OBJDIR)\jsj_JavaMember.obj \
|
||||
.\$(OBJDIR)\jsj_JavaObject.obj \
|
||||
.\$(OBJDIR)\jsj_JavaPackage.obj \
|
||||
.\$(OBJDIR)\jsj_array.obj \
|
||||
.\$(OBJDIR)\jsj_class.obj \
|
||||
.\$(OBJDIR)\jsj_convert.obj \
|
||||
.\$(OBJDIR)\jsj_field.obj \
|
||||
.\$(OBJDIR)\jsj_hash.obj \
|
||||
.\$(OBJDIR)\jsj_method.obj \
|
||||
.\$(OBJDIR)\jsj_utils.obj \
|
||||
.\$(OBJDIR)\nsCLiveconnect.obj \
|
||||
.\$(OBJDIR)\nsCLiveconnectFactory.obj \
|
||||
!if "$(MOZ_BITS)" == "16"
|
||||
.\$(OBJDIR)\jsj_nodl.obj \
|
||||
!endif
|
||||
$(NULL)
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// install headers
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
INSTALL_DIR=$(PUBLIC)\js
|
||||
INSTALL_FILE_LIST= \
|
||||
jsjava.h nsILiveconnect.h
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Define any Public Targets here (ie. PROGRAM, LIBRARY, DLL, ...)
|
||||
#// (these must be defined before the common makefiles are included)
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
|
||||
!ifdef NSJVM
|
||||
JNI_GEN= \
|
||||
netscape.javascript.JSObject \
|
||||
netscape.javascript.JSException \
|
||||
$(NULL)
|
||||
|
||||
!endif
|
||||
|
||||
MODULE = java
|
||||
EXPORTS = \
|
||||
$(JNI_GEN_DIR)\netscape_javascript_JSObject.h \
|
||||
$(JNI_GEN_DIR)\netscape_javascript_JSException.h \
|
||||
$(NULL)
|
||||
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Define any local options for the make tools
|
||||
#// (ie. LCFLAGS, LLFLAGS, LLIBS, LINCS)
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
|
||||
LINCS=$(LINCS) -I$(JNI_GEN_DIR) \
|
||||
-I$(PUBLIC)\js \
|
||||
-I$(PUBLIC)\java \
|
||||
-I$(PUBLIC)\xpcom \
|
||||
$(NULL)
|
||||
|
||||
|
||||
#!ifdef SERVER_BUILD
|
||||
#LLIBS=$(DIST)/lib/httpdlw.lib $(DIST)/lib/libsjboot.lib
|
||||
#!endif
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Include the common makefile rules
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
include <$(DEPTH)/config/rules.mak>
|
||||
|
||||
export:: INSTALL_FILES
|
||||
|
||||
libs:: $(DLL)
|
||||
$(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).dll $(DIST)\bin
|
||||
$(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).lib $(DIST)\lib
|
||||
|
||||
|
||||
####
|
||||
# this bit of extreme scariness came from the js/src makefile
|
||||
# reproduced here since that's where jsjava.c lives now...
|
||||
|
||||
!if ("$(MOZ_BITS)" == "16")
|
||||
#//
|
||||
#// Win16 Hoovers SO BAD!!!
|
||||
#//
|
||||
|
||||
!if !defined(MOZ_DEBUG)
|
||||
#//
|
||||
#// We must turn off codeview debug info so jni.c can build.
|
||||
#// Otherwise the linker gives errors about data in the $SYMBOLS
|
||||
#// segment being beyond a segment boundary.
|
||||
#//
|
||||
$(OBJDIR)\jsjava.obj: jsjava.c
|
||||
@$(CC) @<<$(CFGFILE)
|
||||
-c
|
||||
-Od
|
||||
$(CFLAGS)
|
||||
$(LCFLAGS)
|
||||
$(LINCS)
|
||||
$(LINCS_1)
|
||||
$(INCS)
|
||||
-Fd$(PDBFILE)
|
||||
-Fo.\$(OBJDIR)\
|
||||
$(*B).c
|
||||
<<KEEP
|
||||
!endif
|
||||
!endif
|
||||
111
mozilla/js/src/liveconnect/netscape_javascript_JSObject.h
Normal file
111
mozilla/js/src/liveconnect/netscape_javascript_JSObject.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/* -*- Mode: C; tab-width: 8 -*-
|
||||
* Copyright (C) 1998 Netscape Communications Corporation, All Rights Reserved.
|
||||
*/
|
||||
#include <jni.h>
|
||||
/* Header for class netscape_javascript_JSObject */
|
||||
|
||||
#ifndef _Included_netscape_javascript_JSObject
|
||||
#define _Included_netscape_javascript_JSObject
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: initClass
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_initClass
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: getMember
|
||||
* Signature: (Ljava/lang/String;)Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_getMember
|
||||
(JNIEnv *, jobject, jstring);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: getSlot
|
||||
* Signature: (I)Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_getSlot
|
||||
(JNIEnv *, jobject, jint);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: setMember
|
||||
* Signature: (Ljava/lang/String;Ljava/lang/Object;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_setMember
|
||||
(JNIEnv *, jobject, jstring, jobject);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: setSlot
|
||||
* Signature: (ILjava/lang/Object;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_setSlot
|
||||
(JNIEnv *, jobject, jint, jobject);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: removeMember
|
||||
* Signature: (Ljava/lang/String;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_removeMember
|
||||
(JNIEnv *, jobject, jstring);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: call
|
||||
* Signature: (Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_call
|
||||
(JNIEnv *, jobject, jstring, jobjectArray);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: eval
|
||||
* Signature: (Ljava/lang/String;)Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_eval
|
||||
(JNIEnv *, jobject, jstring);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: toString
|
||||
* Signature: ()Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_netscape_javascript_JSObject_toString
|
||||
(JNIEnv *, jobject);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: getWindow
|
||||
* Signature: (Ljava/applet/Applet;)Lnetscape/javascript/JSObject;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_getWindow
|
||||
(JNIEnv *, jclass, jobject);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: finalize
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_finalize
|
||||
(JNIEnv *, jobject);
|
||||
|
||||
/*
|
||||
* Class: netscape_javascript_JSObject
|
||||
* Method: equals
|
||||
* Signature: (Ljava/lang/Object;)Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_netscape_javascript_JSObject_equals
|
||||
(JNIEnv *, jobject, jobject);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
567
mozilla/js/src/liveconnect/nsCLiveconnect.cpp
Normal file
567
mozilla/js/src/liveconnect/nsCLiveconnect.cpp
Normal file
@@ -0,0 +1,567 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the implementation providing nsIFactory XP-COM interface.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "prtypes.h"
|
||||
#include "prprf.h"
|
||||
#include "prlog.h"
|
||||
PR_BEGIN_EXTERN_C
|
||||
|
||||
#ifdef XP_MAC
|
||||
#include "prosdep.h"
|
||||
#endif
|
||||
|
||||
#include "jsj_private.h"
|
||||
#include "jsjava.h"
|
||||
|
||||
#include "jscntxt.h" /* For js_ReportErrorAgain().
|
||||
TODO - get rid of private header */
|
||||
|
||||
#include "netscape_javascript_JSObject.h" /* javah-generated headers */
|
||||
|
||||
|
||||
/* A captured JavaScript error, created when JS_ReportError() is called while
|
||||
running JavaScript code that is itself called from Java. */
|
||||
struct CapturedJSError {
|
||||
char * message;
|
||||
JSErrorReport report; /* Line # of error, etc. */
|
||||
jthrowable java_exception; /* Java exception, error, or null */
|
||||
CapturedJSError * next; /* Next oldest captured JS error */
|
||||
};
|
||||
PR_END_EXTERN_C
|
||||
|
||||
#include "nsCLiveconnect.h"
|
||||
|
||||
static NS_DEFINE_IID(kILiveconnectIID, NS_ILIVECONNECT_IID);
|
||||
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsISupports and AggregatedQueryInterface:
|
||||
|
||||
// Thes macro expands to the aggregated query interface scheme.
|
||||
|
||||
NS_IMPL_AGGREGATED(nsCLiveconnect);
|
||||
|
||||
NS_METHOD
|
||||
nsCLiveconnect::AggregatedQueryInterface(const nsIID& aIID, void** aInstancePtr)
|
||||
{
|
||||
if (aIID.Equals(kISupportsIID)) {
|
||||
*aInstancePtr = GetInner();
|
||||
AddRef();
|
||||
return NS_OK;
|
||||
}
|
||||
if (aIID.Equals(kILiveconnectIID)) {
|
||||
*aInstancePtr = this;
|
||||
AddRef();
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsILiveconnect:
|
||||
|
||||
/**
|
||||
* get member of a Native JSObject for a given name.
|
||||
*
|
||||
* @param jEnv - JNIEnv on which the call is being made.
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a member.
|
||||
* @param pjobj - return parameter as a java object representing
|
||||
* the member. If it is a basic data type it is converted to
|
||||
* a corresponding java type. If it is a NJSObject, then it is
|
||||
* wrapped up as java wrapper netscape.javascript.JSObject.
|
||||
*/
|
||||
NS_METHOD
|
||||
nsCLiveconnect::GetMember(JNIEnv *jEnv, jsobject obj, const char *name, jobject *pjobj)
|
||||
{
|
||||
JSContext *cx = NULL;
|
||||
JSJavaThreadState *jsj_env = NULL;
|
||||
JSObject *js_obj = (JSObject *)obj;
|
||||
nsresult err = NS_OK;
|
||||
jobject member = NULL;
|
||||
jsval js_val = NULL;
|
||||
int dummy_cost = 0;
|
||||
JSBool dummy_bool = PR_FALSE;
|
||||
JavaToJSSavedState saved_state = {NULL,NULL};
|
||||
|
||||
if(jEnv == NULL)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
|
||||
if (!jsj_env)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (!name) {
|
||||
JS_ReportError(cx, "illegal null member name");
|
||||
member = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
if (!JS_GetProperty(cx, js_obj, name, &js_val))
|
||||
goto done;
|
||||
|
||||
jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, jsj_get_jlObject_descriptor(cx, jEnv),
|
||||
&dummy_cost, &member, &dummy_bool);
|
||||
|
||||
done:
|
||||
if (!jsj_exit_js(cx, jsj_env, &saved_state))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
*pjobj = member;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get member of a Native JSObject for a given index.
|
||||
*
|
||||
* @param jEnv - JNIEnv on which the call is being made.
|
||||
* @param obj - A Native JS Object.
|
||||
* @param index - Index of a member.
|
||||
* @param pjobj - return parameter as a java object representing
|
||||
* the member.
|
||||
*/
|
||||
NS_METHOD
|
||||
nsCLiveconnect::GetSlot(JNIEnv *jEnv, jsobject obj, int slot, jobject *pjobj)
|
||||
{
|
||||
JSContext *cx = NULL;
|
||||
JSJavaThreadState *jsj_env = NULL;
|
||||
JSObject *js_obj = (JSObject *)obj;
|
||||
nsresult err = NS_OK;
|
||||
jobject member = NULL;
|
||||
jsval js_val = NULL;
|
||||
int dummy_cost = 0;
|
||||
JSBool dummy_bool = PR_FALSE;
|
||||
JavaToJSSavedState saved_state = {NULL,NULL};
|
||||
|
||||
if(jEnv == NULL)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
|
||||
if (!jsj_env)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// =-= sudu: check to see if slot can be passed in as is.
|
||||
// Should it be converted to a jsint?
|
||||
if (!JS_GetElement(cx, js_obj, slot, &js_val))
|
||||
goto done;
|
||||
if (!jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, jsj_get_jlObject_descriptor(cx, jEnv),
|
||||
&dummy_cost, &member, &dummy_bool))
|
||||
goto done;
|
||||
|
||||
done:
|
||||
if (!jsj_exit_js(cx, jsj_env, &saved_state))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
*pjobj = member;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* set member of a Native JSObject for a given name.
|
||||
*
|
||||
* @param jEnv - JNIEnv on which the call is being made.
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a member.
|
||||
* @param jobj - Value to set. If this is a basic data type, it is converted
|
||||
* using standard JNI calls but if it is a wrapper to a JSObject
|
||||
* then a internal mapping is consulted to convert to a NJSObject.
|
||||
*/
|
||||
NS_METHOD
|
||||
nsCLiveconnect::SetMember(JNIEnv *jEnv, jsobject obj, const char *name, jobject java_obj)
|
||||
{
|
||||
JSContext *cx = NULL;
|
||||
JSJavaThreadState *jsj_env = NULL;
|
||||
JSObject *js_obj = (JSObject *)obj;
|
||||
nsresult err = NS_OK;
|
||||
jobject member = NULL;
|
||||
jsval js_val = NULL;
|
||||
JavaToJSSavedState saved_state = {NULL,NULL};
|
||||
|
||||
if(jEnv == NULL)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
|
||||
if (!jsj_env)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (!name) {
|
||||
JS_ReportError(cx, "illegal null member name");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_obj, &js_val))
|
||||
goto done;
|
||||
|
||||
JS_SetProperty(cx, js_obj, name, &js_val);
|
||||
|
||||
done:
|
||||
jsj_exit_js(cx, jsj_env, &saved_state);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* set member of a Native JSObject for a given index.
|
||||
*
|
||||
* @param jEnv - JNIEnv on which the call is being made.
|
||||
* @param obj - A Native JS Object.
|
||||
* @param index - Index of a member.
|
||||
* @param jobj - Value to set. If this is a basic data type, it is converted
|
||||
* using standard JNI calls but if it is a wrapper to a JSObject
|
||||
* then a internal mapping is consulted to convert to a NJSObject.
|
||||
*/
|
||||
NS_METHOD
|
||||
nsCLiveconnect::SetSlot(JNIEnv *jEnv, jsobject obj, int slot, jobject java_obj)
|
||||
{
|
||||
JSContext *cx = NULL;
|
||||
JSJavaThreadState *jsj_env = NULL;
|
||||
JSObject *js_obj = (JSObject *)obj;
|
||||
nsresult err = NS_OK;
|
||||
jsval js_val = NULL;
|
||||
JavaToJSSavedState saved_state = {NULL,NULL};
|
||||
|
||||
if(jEnv == NULL)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
|
||||
if (!jsj_env)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (!jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_obj, &js_val))
|
||||
goto done;
|
||||
JS_SetElement(cx, js_obj, slot, &js_val);
|
||||
|
||||
done:
|
||||
jsj_exit_js(cx, jsj_env, &saved_state);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* remove member of a Native JSObject for a given name.
|
||||
*
|
||||
* @param jEnv - JNIEnv on which the call is being made.
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a member.
|
||||
*/
|
||||
NS_METHOD
|
||||
nsCLiveconnect::RemoveMember(JNIEnv *jEnv, jsobject obj, const char *name)
|
||||
{
|
||||
JSContext *cx = NULL;
|
||||
JSJavaThreadState *jsj_env = NULL;
|
||||
JSObject *js_obj = (JSObject *)obj;
|
||||
nsresult err = NS_OK;
|
||||
jsval js_val = NULL;
|
||||
JavaToJSSavedState saved_state = {NULL,NULL};
|
||||
|
||||
if(jEnv == NULL)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
|
||||
if (!jsj_env)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (!name) {
|
||||
JS_ReportError(cx, "illegal null member name");
|
||||
goto done;
|
||||
}
|
||||
JS_DeleteProperty2(cx, js_obj, name, &js_val);
|
||||
|
||||
done:
|
||||
jsj_exit_js(cx, jsj_env, &saved_state);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* call a method of Native JSObject.
|
||||
*
|
||||
* @param jEnv - JNIEnv on which the call is being made.
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a method.
|
||||
* @param jobjArr - Array of jobjects representing parameters of method being caled.
|
||||
* @param pjobj - return value.
|
||||
*/
|
||||
NS_METHOD
|
||||
nsCLiveconnect::Call(JNIEnv *jEnv, jsobject obj, const char *name, jobjectArray java_args, jobject *pjobj)
|
||||
{
|
||||
int i = 0;
|
||||
int argc = 0;
|
||||
int arg_num = 0;
|
||||
jsval *argv = 0;
|
||||
JSContext *cx = NULL;
|
||||
JSJavaThreadState *jsj_env = NULL;
|
||||
JSObject *js_obj = (JSObject *)obj;
|
||||
nsresult err = NS_OK;
|
||||
jobject member = NULL;
|
||||
jsval js_val = NULL;
|
||||
jsval function_val = NULL;
|
||||
int dummy_cost = 0;
|
||||
JSBool dummy_bool = PR_FALSE;
|
||||
JavaToJSSavedState saved_state = {NULL,NULL};
|
||||
jobject result = NULL;
|
||||
|
||||
if(jEnv == NULL)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
|
||||
if (!jsj_env)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
result = NULL;
|
||||
if (!name) {
|
||||
JS_ReportError(cx, "illegal null JavaScript function name");
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
/* FIXME: What about security stuff ? Don't principals need to be set here ? */
|
||||
|
||||
/* Allocate space for JS arguments */
|
||||
if (java_args) {
|
||||
argc = jEnv->GetArrayLength(java_args);
|
||||
argv = (jsval*)JS_malloc(cx, argc * sizeof(jsval));
|
||||
} else {
|
||||
argc = 0;
|
||||
argv = 0;
|
||||
}
|
||||
|
||||
/* Convert arguments from Java to JS values */
|
||||
for (arg_num = 0; arg_num < argc; arg_num++) {
|
||||
jobject arg = jEnv->GetObjectArrayElement(java_args, arg_num);
|
||||
|
||||
if (!jsj_ConvertJavaObjectToJSValue(cx, jEnv, arg, &argv[arg_num]))
|
||||
goto cleanup_argv;
|
||||
JS_AddRoot(cx, &argv[arg_num]);
|
||||
}
|
||||
|
||||
if (!JS_GetProperty(cx, js_obj, name, &function_val))
|
||||
goto cleanup_argv;
|
||||
|
||||
if (!JS_CallFunctionValue(cx, js_obj, function_val, argc, argv, &js_val))
|
||||
goto cleanup_argv;
|
||||
|
||||
jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, jsj_get_jlObject_descriptor(cx, jEnv),
|
||||
&dummy_cost, &result, &dummy_bool);
|
||||
|
||||
cleanup_argv:
|
||||
if (argv) {
|
||||
for (i = 0; i < arg_num; i++)
|
||||
JS_RemoveRoot(cx, &argv[i]);
|
||||
JS_free(cx, argv);
|
||||
}
|
||||
|
||||
done:
|
||||
if (!jsj_exit_js(cx, jsj_env, &saved_state))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
*pjobj = result;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Evaluate a script with a Native JS Object representing scope.
|
||||
*
|
||||
* @param jEnv - JNIEnv on which the call is being made.
|
||||
* @param obj - A Native JS Object.
|
||||
* @param pNSIPrincipaArray - Array of principals to be used to compare privileges.
|
||||
* @param numPrincipals - Number of principals being passed.
|
||||
* @param script - Script to be executed.
|
||||
* @param pjobj - return value.
|
||||
*/
|
||||
NS_METHOD
|
||||
nsCLiveconnect::Eval(JNIEnv *jEnv, jsobject obj, const char *script, jobject *pjobj)
|
||||
{
|
||||
JSContext *cx = NULL;
|
||||
JSJavaThreadState *jsj_env = NULL;
|
||||
JSObject *js_obj = (JSObject *)obj;
|
||||
nsresult err = NS_OK;
|
||||
jobject member = NULL;
|
||||
jsval js_val = NULL;
|
||||
jsval function_val = NULL;
|
||||
int dummy_cost = 0;
|
||||
JSBool dummy_bool = PR_FALSE;
|
||||
JavaToJSSavedState saved_state = {NULL,NULL};
|
||||
jobject result = NULL;
|
||||
const char *codebase = NULL;
|
||||
JSPrincipals *principals = NULL;
|
||||
JSBool eval_succeeded = PR_FALSE;
|
||||
|
||||
if(jEnv == NULL)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
|
||||
if (!jsj_env)
|
||||
return NULL;
|
||||
|
||||
result = NULL;
|
||||
if (!script) {
|
||||
JS_ReportError(cx, "illegal null string eval argument");
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
/* Set up security stuff */
|
||||
principals = NULL;
|
||||
if (JSJ_callbacks->get_JSPrincipals_from_java_caller)
|
||||
principals = JSJ_callbacks->get_JSPrincipals_from_java_caller(jEnv, cx);
|
||||
codebase = principals ? principals->codebase : NULL;
|
||||
|
||||
/* Have the JS engine evaluate the unicode string */
|
||||
eval_succeeded = JS_EvaluateScriptForPrincipals(cx, js_obj, principals,
|
||||
script, strlen(script),
|
||||
codebase, 0, &js_val);
|
||||
if (!eval_succeeded)
|
||||
goto done;
|
||||
|
||||
/* Convert result to a subclass of java.lang.Object */
|
||||
jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, jsj_get_jlObject_descriptor(cx, jEnv),
|
||||
&dummy_cost, &result, &dummy_bool);
|
||||
|
||||
done:
|
||||
if (!jsj_exit_js(cx, jsj_env, &saved_state))
|
||||
return NULL;
|
||||
|
||||
*pjobj = result;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the window object for a plugin instance.
|
||||
*
|
||||
* @param jEnv - JNIEnv on which the call is being made.
|
||||
* @param pJavaObject - Either a jobject or a pointer to a plugin instance
|
||||
* representing the java object.
|
||||
* @param pjobj - return value. This is a native js object
|
||||
* representing the window object of a frame
|
||||
* in which a applet/bean resides.
|
||||
*/
|
||||
NS_METHOD
|
||||
nsCLiveconnect::GetWindow(JNIEnv *jEnv, void *pJavaObject, jsobject *pobj)
|
||||
{
|
||||
char *err_msg = NULL;
|
||||
JSContext *cx = NULL;
|
||||
JSObject *js_obj = NULL;
|
||||
jsval js_val = NULL;
|
||||
int dummy_cost = 0;
|
||||
JSBool dummy_bool = PR_FALSE;
|
||||
JavaToJSSavedState saved_state = {NULL,NULL};
|
||||
jobject java_obj = NULL;
|
||||
JSJavaThreadState *jsj_env = NULL;
|
||||
|
||||
if(jEnv == NULL)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
|
||||
if (!jsj_env)
|
||||
return NULL;
|
||||
|
||||
err_msg = NULL;
|
||||
java_obj = NULL;
|
||||
js_obj = JSJ_callbacks->map_java_object_to_js_object(jEnv, pJavaObject, &err_msg);
|
||||
if (!js_obj) {
|
||||
if (err_msg) {
|
||||
JS_ReportError(cx, err_msg);
|
||||
free(err_msg);
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
#if 0
|
||||
js_val = OBJECT_TO_JSVAL(js_obj);
|
||||
jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, jsj_get_jlObject_descriptor(cx, jEnv),
|
||||
&dummy_cost, &java_obj, &dummy_bool);
|
||||
#endif
|
||||
done:
|
||||
if (!jsj_exit_js(cx, jsj_env, &saved_state))
|
||||
return NULL;
|
||||
|
||||
//*pjobj = java_obj;
|
||||
*pobj = (jint)js_obj;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the window object for a plugin instance.
|
||||
*
|
||||
* @param jEnv - JNIEnv on which the call is being made.
|
||||
* @param obj - A Native JS Object.
|
||||
*/
|
||||
NS_METHOD
|
||||
nsCLiveconnect::FinalizeJSObject(JNIEnv *jEnv, jsobject obj)
|
||||
{
|
||||
JSContext *cx = NULL;
|
||||
JavaToJSSavedState saved_state = {NULL,NULL};
|
||||
JSJavaThreadState *jsj_env = NULL;
|
||||
JSObject *js_obj = (JSObject *)obj;
|
||||
|
||||
if(jEnv == NULL)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
|
||||
if (!jsj_env) /* Note: memory leak if we exit here */
|
||||
return NS_ERROR_FAILURE;
|
||||
#ifdef PRESERVE_JSOBJECT_IDENTITY
|
||||
jsj_remove_js_obj_reflection_from_hashtable(cx, js_obj);
|
||||
#endif /* PRESERVE_JSOBJECT_IDENTITY */
|
||||
jsj_exit_js(cx, jsj_env, &saved_state);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsCLiveconnect:
|
||||
|
||||
nsCLiveconnect::nsCLiveconnect(nsISupports *aOuter)
|
||||
{
|
||||
NS_INIT_AGGREGATED(aOuter);
|
||||
jsj_init_js_obj_reflections_table();
|
||||
}
|
||||
|
||||
nsCLiveconnect::~nsCLiveconnect()
|
||||
{
|
||||
}
|
||||
|
||||
166
mozilla/js/src/liveconnect/nsCLiveconnect.h
Normal file
166
mozilla/js/src/liveconnect/nsCLiveconnect.h
Normal file
@@ -0,0 +1,166 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains class definition implementing the public interface.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the class definition to implement nsILiveconnect XP-COM interface.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef nsCLiveconnect_h___
|
||||
#define nsCLiveconnect_h___
|
||||
|
||||
#include "nsILiveconnect.h"
|
||||
#include "nsAgg.h"
|
||||
|
||||
|
||||
/**
|
||||
* nsCLiveconnect implements nsILiveconnect interface for navigator.
|
||||
* This is used by a JVM to implement netscape.javascript.JSObject functionality.
|
||||
*/
|
||||
class nsCLiveconnect :public nsILiveconnect {
|
||||
public:
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsISupports and AggregatedQueryInterface:
|
||||
|
||||
NS_DECL_AGGREGATED
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsILiveconnect:
|
||||
|
||||
/**
|
||||
* get member of a Native JSObject for a given name.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a member.
|
||||
* @param pjobj - return parameter as a java object representing
|
||||
* the member. If it is a basic data type it is converted to
|
||||
* a corresponding java type. If it is a NJSObject, then it is
|
||||
* wrapped up as java wrapper netscape.javascript.JSObject.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
GetMember(JNIEnv *jEnv, jsobject obj, const char *name, jobject *pjobj);
|
||||
|
||||
/**
|
||||
* get member of a Native JSObject for a given index.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param index - Index of a member.
|
||||
* @param pjobj - return parameter as a java object representing
|
||||
* the member.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
GetSlot(JNIEnv *jEnv, jsobject obj, int index, jobject *pjobj);
|
||||
|
||||
/**
|
||||
* set member of a Native JSObject for a given name.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a member.
|
||||
* @param jobj - Value to set. If this is a basic data type, it is converted
|
||||
* using standard JNI calls but if it is a wrapper to a JSObject
|
||||
* then a internal mapping is consulted to convert to a NJSObject.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
SetMember(JNIEnv *jEnv, jsobject obj, const char *name, jobject jobj);
|
||||
|
||||
/**
|
||||
* set member of a Native JSObject for a given index.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param index - Index of a member.
|
||||
* @param jobj - Value to set. If this is a basic data type, it is converted
|
||||
* using standard JNI calls but if it is a wrapper to a JSObject
|
||||
* then a internal mapping is consulted to convert to a NJSObject.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
SetSlot(JNIEnv *jEnv, jsobject obj, int slot, jobject jobj);
|
||||
|
||||
/**
|
||||
* remove member of a Native JSObject for a given name.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a member.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
RemoveMember(JNIEnv *jEnv, jsobject obj, const char *name);
|
||||
|
||||
/**
|
||||
* call a method of Native JSObject.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a method.
|
||||
* @param jobjArr - Array of jobjects representing parameters of method being caled.
|
||||
* @param pjobj - return value.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
Call(JNIEnv *jEnv, jsobject obj, const char *name, jobjectArray jobjArr, jobject *pjobj);
|
||||
|
||||
/**
|
||||
* Evaluate a script with a Native JS Object representing scope.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param pNSIPrincipaArray - Array of principals to be used to compare privileges.
|
||||
* @param numPrincipals - Number of principals being passed.
|
||||
* @param script - Script to be executed.
|
||||
* @param pjobj - return value.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
//Eval(JNIEnv *jEnv, jsobject obj, nsIPrincipal **pNSIPrincipaArray, PRInt32 numPrincipals, const char *script, jobject *pjobj);
|
||||
Eval(JNIEnv *jEnv, jsobject obj, const char *script, jobject *pjobj);
|
||||
|
||||
/**
|
||||
* Get the window object for a plugin instance.
|
||||
*
|
||||
* @param pJavaObject - Either a jobject or a pointer to a plugin instance
|
||||
* representing the java object.
|
||||
* @param pjobj - return value. This is a native js object
|
||||
* representing the window object of a frame
|
||||
* in which a applet/bean resides.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
GetWindow(JNIEnv *jEnv, void *pJavaObject, jsobject *pobj);
|
||||
|
||||
/**
|
||||
* Get the window object for a plugin instance.
|
||||
*
|
||||
* @param jEnv - JNIEnv on which the call is being made.
|
||||
* @param obj - A Native JS Object.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
FinalizeJSObject(JNIEnv *jEnv, jsobject obj);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsCLiveconnect:
|
||||
|
||||
nsCLiveconnect(nsISupports *aOuter);
|
||||
virtual ~nsCLiveconnect(void);
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
#endif // nsCLiveconnect_h___
|
||||
168
mozilla/js/src/liveconnect/nsCLiveconnectFactory.cpp
Normal file
168
mozilla/js/src/liveconnect/nsCLiveconnectFactory.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the implementation providing nsILiveconnect XP-COM interface.
|
||||
*
|
||||
*/
|
||||
#include "prtypes.h"
|
||||
#include "nspr.h"
|
||||
#include "prmem.h"
|
||||
#include "prmon.h"
|
||||
#include "prlog.h"
|
||||
|
||||
#include "nsCLiveconnect.h"
|
||||
#include "nsCLiveconnectFactory.h"
|
||||
#include "nsRepository.h"
|
||||
|
||||
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
||||
static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID);
|
||||
static NS_DEFINE_CID(kCLiveconnectCID, NS_CLIVECONNECT_CID);
|
||||
static NS_DEFINE_IID(kILiveconnectIID, NS_ILIVECONNECT_IID);
|
||||
|
||||
nsIFactory *nsCLiveconnectFactory::m_pNSIFactory = NULL;
|
||||
nsCLiveconnect *nsCLiveconnectFactory::m_pNSCLiveconnect = NULL;
|
||||
|
||||
|
||||
|
||||
/*+++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
* NSGetFactory:
|
||||
* Provides entry point to liveconnect dll.
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
|
||||
extern "C" NS_EXPORT nsresult
|
||||
NSGetFactory(const nsCID &aClass, nsIFactory **aFactory)
|
||||
{
|
||||
|
||||
if (!aClass.Equals(kCLiveconnectCID)) {
|
||||
return NS_ERROR_FACTORY_NOT_LOADED; // XXX right error?
|
||||
}
|
||||
nsCLiveconnectFactory* pCLiveConnectFactory = new nsCLiveconnectFactory();
|
||||
if (pCLiveConnectFactory == NULL)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
pCLiveConnectFactory->AddRef();
|
||||
*aFactory = pCLiveConnectFactory;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
extern "C" NS_EXPORT PRBool
|
||||
NSCanUnload(void)
|
||||
{
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsISupports
|
||||
|
||||
NS_METHOD
|
||||
nsCLiveconnectFactory::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
||||
{
|
||||
PR_ASSERT(NULL != aInstancePtr);
|
||||
if (NULL == aInstancePtr) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
if (aIID.Equals(kIFactoryIID) ||
|
||||
aIID.Equals(kISupportsIID)) {
|
||||
*aInstancePtr = (void*) this;
|
||||
AddRef();
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(nsCLiveconnectFactory)
|
||||
NS_IMPL_RELEASE(nsCLiveconnectFactory)
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsIFactory:
|
||||
|
||||
NS_METHOD
|
||||
nsCLiveconnectFactory::CreateInstance(nsISupports *aOuter, REFNSIID aIID, void **aResult)
|
||||
{
|
||||
nsCLiveconnect *pNSCLiveconnect = NULL;
|
||||
*aResult = NULL;
|
||||
|
||||
if (aOuter && !aIID.Equals(kISupportsIID))
|
||||
return NS_NOINTERFACE; // XXX right error?
|
||||
if (m_pNSCLiveconnect == NULL)
|
||||
{
|
||||
m_pNSCLiveconnect = new nsCLiveconnect(aOuter);
|
||||
}
|
||||
if (m_pNSCLiveconnect == NULL)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (m_pNSCLiveconnect->QueryInterface(aIID,
|
||||
(void**)aResult) != NS_OK) {
|
||||
// then we're trying get a interface other than nsISupports and
|
||||
// nsICapsManager
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
nsCLiveconnectFactory::LockFactory(PRBool aLock)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsCLiveconnectFactory:
|
||||
|
||||
nsCLiveconnectFactory::nsCLiveconnectFactory(void)
|
||||
{
|
||||
if( m_pNSIFactory != NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NS_INIT_REFCNT();
|
||||
nsresult err = NS_OK;
|
||||
NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID);
|
||||
|
||||
err = this->QueryInterface(kIFactoryIID, (void**)&m_pNSIFactory);
|
||||
if ( (err == NS_OK) && (m_pNSIFactory != NULL) )
|
||||
{
|
||||
NS_DEFINE_CID(kCLiveconnectCID, NS_CLIVECONNECT_CID);
|
||||
nsRepository::RegisterFactory(kCLiveconnectCID, m_pNSIFactory,
|
||||
PR_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
nsCLiveconnectFactory::~nsCLiveconnectFactory()
|
||||
{
|
||||
if(mRefCnt == 0)
|
||||
{
|
||||
NS_DEFINE_CID(kCLiveconnectCID, NS_CLIVECONNECT_CID);
|
||||
nsRepository::UnregisterFactory(kCLiveconnectCID, (nsIFactory *)m_pNSIFactory);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
59
mozilla/js/src/liveconnect/nsCLiveconnectFactory.h
Normal file
59
mozilla/js/src/liveconnect/nsCLiveconnectFactory.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the class definition to implement nsIFactory XP-COM interface.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef nsCLiveconnectFactory_h___
|
||||
#define nsCLiveconnectFactory_h___
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsIFactory.h"
|
||||
|
||||
class nsCLiveconnectFactory : public nsIFactory {
|
||||
public:
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsISupports and AggregatedQueryInterface:
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsIFactory:
|
||||
|
||||
NS_IMETHOD
|
||||
CreateInstance(nsISupports *aOuter, REFNSIID aIID, void **aResult);
|
||||
|
||||
NS_IMETHOD
|
||||
LockFactory(PRBool aLock);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// from nsCLiveconnectFactory:
|
||||
|
||||
nsCLiveconnectFactory(void);
|
||||
virtual ~nsCLiveconnectFactory(void);
|
||||
|
||||
protected:
|
||||
static nsIFactory *m_pNSIFactory;
|
||||
static nsCLiveconnect *m_pNSCLiveconnect;
|
||||
};
|
||||
|
||||
#endif // nsCLiveconnectFactory_h___
|
||||
157
mozilla/js/src/liveconnect/nsILiveconnect.h
Normal file
157
mozilla/js/src/liveconnect/nsILiveconnect.h
Normal file
@@ -0,0 +1,157 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
/*
|
||||
* This file is part of the Java-vendor-neutral implementation of LiveConnect
|
||||
*
|
||||
* It contains the public XP-COM based interface for java to javascript communication.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef nsILiveconnect_h___
|
||||
#define nsILiveconnect_h___
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsIFactory.h"
|
||||
#include "jni.h"
|
||||
|
||||
|
||||
typedef jint jsobject;
|
||||
|
||||
class nsILiveconnect : public nsISupports {
|
||||
public:
|
||||
/**
|
||||
* get member of a Native JSObject for a given name.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a member.
|
||||
* @param pjobj - return parameter as a java object representing
|
||||
* the member. If it is a basic data type it is converted to
|
||||
* a corresponding java type. If it is a NJSObject, then it is
|
||||
* wrapped up as java wrapper netscape.javascript.JSObject.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
GetMember(JNIEnv *jEnv, jsobject obj, const char *name, jobject *pjobj) = 0;
|
||||
|
||||
/**
|
||||
* get member of a Native JSObject for a given index.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param index - Index of a member.
|
||||
* @param pjobj - return parameter as a java object representing
|
||||
* the member.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
GetSlot(JNIEnv *jEnv, jsobject obj, int index, jobject *pjobj) = 0;
|
||||
|
||||
/**
|
||||
* set member of a Native JSObject for a given name.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a member.
|
||||
* @param jobj - Value to set. If this is a basic data type, it is converted
|
||||
* using standard JNI calls but if it is a wrapper to a JSObject
|
||||
* then a internal mapping is consulted to convert to a NJSObject.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
SetMember(JNIEnv *jEnv, jsobject obj, const char *name, jobject jobj) = 0;
|
||||
|
||||
/**
|
||||
* set member of a Native JSObject for a given index.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param index - Index of a member.
|
||||
* @param jobj - Value to set. If this is a basic data type, it is converted
|
||||
* using standard JNI calls but if it is a wrapper to a JSObject
|
||||
* then a internal mapping is consulted to convert to a NJSObject.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
SetSlot(JNIEnv *jEnv, jsobject obj, int slot, jobject jobj) = 0;
|
||||
|
||||
/**
|
||||
* remove member of a Native JSObject for a given name.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a member.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
RemoveMember(JNIEnv *jEnv, jsobject obj, const char *name) = 0;
|
||||
|
||||
/**
|
||||
* call a method of Native JSObject.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param name - Name of a method.
|
||||
* @param jobjArr - Array of jobjects representing parameters of method being caled.
|
||||
* @param pjobj - return value.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
Call(JNIEnv *jEnv, jsobject obj, const char *name, jobjectArray jobjArr, jobject *pjobj) = 0;
|
||||
|
||||
/**
|
||||
* Evaluate a script with a Native JS Object representing scope.
|
||||
*
|
||||
* @param obj - A Native JS Object.
|
||||
* @param pNSIPrincipaArray - Array of principals to be used to compare privileges.
|
||||
* @param numPrincipals - Number of principals being passed.
|
||||
* @param script - Script to be executed.
|
||||
* @param pjobj - return value.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
//Eval(jsobject obj, nsIPrincipal **pNSIPrincipaArray, PRInt32 numPrincipals, const char *script, jobject *pjobj) = 0;
|
||||
Eval(JNIEnv *jEnv, jsobject obj, const char *script, jobject *pjobj) = 0;
|
||||
|
||||
/**
|
||||
* Get the window object for a plugin instance.
|
||||
*
|
||||
* @param pJavaObject - Either a jobject or a pointer to a plugin instance
|
||||
* representing the java object.
|
||||
* @param pjobj - return value. This is a native js object
|
||||
* representing the window object of a frame
|
||||
* in which a applet/bean resides.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
GetWindow(JNIEnv *jEnv, void *pJavaObject, jsobject *pobj) = 0;
|
||||
|
||||
/**
|
||||
* Get the window object for a plugin instance.
|
||||
*
|
||||
* @param jEnv - JNIEnv on which the call is being made.
|
||||
* @param obj - A Native JS Object.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
FinalizeJSObject(JNIEnv *jEnv, jsobject obj) = 0;
|
||||
|
||||
};
|
||||
|
||||
#define NS_ILIVECONNECT_IID \
|
||||
{ /* 68190910-3318-11d2-97f0-00805f8a28d0 */ \
|
||||
0x68190910, \
|
||||
0x3318, \
|
||||
0x11d2, \
|
||||
{0x97, 0xf0, 0x00, 0x80, 0x5f, 0x8a, 0x28, 0xd0} \
|
||||
};
|
||||
|
||||
#define NS_CLIVECONNECT_CID \
|
||||
{ /* b8f0cef0-3931-11d2-97f0-00805f8a28d0 */ \
|
||||
0xb8f0cef0, \
|
||||
0x3931, \
|
||||
0x11d2, \
|
||||
{0x97, 0xf0, 0x00, 0x80, 0x5f, 0x8a, 0x28, 0xd0} \
|
||||
};
|
||||
|
||||
#endif // nsILiveconnect_h___
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 13 KiB |
@@ -1,216 +0,0 @@
|
||||
# Backwards.pm
|
||||
|
||||
# Copyright (C) 1999 Uri Guttman. All rights reserved.
|
||||
# mail bugs, comments and feedback to uri@sysarch.com
|
||||
|
||||
|
||||
use strict ;
|
||||
|
||||
package Backwards ;
|
||||
|
||||
use Symbol ;
|
||||
use Fcntl ;
|
||||
use Carp ;
|
||||
use integer ;
|
||||
|
||||
#my $max_read_size = 3 ;
|
||||
|
||||
my $max_read_size = 1 << 13 ;
|
||||
|
||||
# support tied handles. the tied calls map directly to the object methods
|
||||
|
||||
*TIEHANDLE = \&new ;
|
||||
*READLINE = \&readline ;
|
||||
|
||||
# create a new Backwards object
|
||||
|
||||
sub new {
|
||||
|
||||
my( $class, $filename ) = @_ ;
|
||||
|
||||
my( $handle, $seek_pos, $read_size, $self ) ;
|
||||
|
||||
# get a new handle symbol and the real file handle
|
||||
|
||||
$handle = gensym() ;
|
||||
|
||||
# open the file for reading
|
||||
|
||||
unless( sysopen( $handle, $filename, O_RDONLY ) ) {
|
||||
carp "Can't open $filename $!" ;
|
||||
return ;
|
||||
}
|
||||
|
||||
# seek to the end of the file
|
||||
|
||||
seek( $handle, 0, 2 ) ;
|
||||
$seek_pos = tell( $handle ) ;
|
||||
|
||||
# get the size of the first block to read,
|
||||
# either a trailing partial one (the % size) or full sized one (max read size)
|
||||
|
||||
$read_size = $seek_pos % $max_read_size || $max_read_size ;
|
||||
|
||||
# create the hash for the object, bless and return it
|
||||
|
||||
$self = {
|
||||
'file_name' => $filename,
|
||||
'handle' => $handle,
|
||||
'read_size' => $read_size,
|
||||
'seek_pos' => $seek_pos,
|
||||
'lines' => [],
|
||||
} ;
|
||||
|
||||
return( bless( $self, $class ) ) ;
|
||||
}
|
||||
|
||||
sub readline {
|
||||
|
||||
my( $self, $line_ref ) = @_ ;
|
||||
|
||||
my( $handle, $lines_ref, $seek_pos, $read_cnt, $read_buf,
|
||||
$file_size, $read_size, $text ) ;
|
||||
|
||||
# get the buffer of lines
|
||||
|
||||
$lines_ref = $self->{'lines'} ;
|
||||
|
||||
while( 1 ) {
|
||||
|
||||
# see if there is more than 1 line in the buffer
|
||||
|
||||
if ( @{$lines_ref} > 1 ) {
|
||||
|
||||
# we have a complete line so return it
|
||||
|
||||
return( pop @{$lines_ref} ) ;
|
||||
}
|
||||
|
||||
# we don't have a complete, so have to read blocks until we do
|
||||
|
||||
$seek_pos = $self->{'seek_pos'} ;
|
||||
|
||||
# see if we are at the beginning of the file
|
||||
|
||||
if ( $seek_pos == 0 ) {
|
||||
|
||||
# the last read never made more lines, so return the last line in the buffer
|
||||
# if no lines left then undef will be returned
|
||||
|
||||
return( pop @{$lines_ref} ) ;
|
||||
}
|
||||
|
||||
#print "c size $read_size\n" ;
|
||||
|
||||
# we have to read more text so get the handle and the current read size
|
||||
|
||||
$handle = $self->{'handle'} ;
|
||||
$read_size = $self->{'read_size'} ;
|
||||
|
||||
# after the first read, always read the maximum size
|
||||
|
||||
$self->{'read_size'} = $max_read_size ;
|
||||
|
||||
# seek to the beginning of this block and save the new seek position
|
||||
|
||||
$seek_pos -= $read_size ;
|
||||
$self->{'seek_pos'} = $seek_pos ;
|
||||
seek( $handle, $seek_pos, 0 ) ;
|
||||
|
||||
#print "seek $seek_pos\n" ;
|
||||
|
||||
# read in the next (previous) block of text
|
||||
|
||||
$read_cnt = sysread( $handle, $read_buf, $read_size ) ;
|
||||
|
||||
#print "Read <$read_buf>\n" ;
|
||||
|
||||
# if ( $read_cnt != $read_size ) {
|
||||
# print "bad read cnt $read_cnt != size $read_size\n" ;
|
||||
# return( undef ) ;
|
||||
# }
|
||||
|
||||
# prepend the read buffer to the leftover (possibly partial) line
|
||||
|
||||
$text = $read_buf . ( pop @{$lines_ref} || '' ) ;
|
||||
|
||||
# split the buffer into a list of lines
|
||||
# this may want to be $/ but reading files backwards assumes plain text and
|
||||
# newline separators
|
||||
|
||||
@{$lines_ref} = $text =~ m[(^.*\n|^.+)]mg ;
|
||||
|
||||
#print "Lines \n=>", join( "<=\n=>", @{$lines_ref} ), "<=\n" ;
|
||||
}
|
||||
}
|
||||
|
||||
__END__
|
||||
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Backwards.pm -- Read a file backwards by lines.
|
||||
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Backwards ;
|
||||
|
||||
# Object interface
|
||||
|
||||
$bw = Backwards->new( 'log_file' ) ;
|
||||
|
||||
while( $log_line = $bw->readline ) {
|
||||
print $log_line ;
|
||||
}
|
||||
|
||||
# Tied Handle Interface
|
||||
|
||||
tie *BW, 'log_file' ;
|
||||
|
||||
while( <BW> ) {
|
||||
print ;
|
||||
}
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
|
||||
This module reads a file backwards line by line. It is simple to use,
|
||||
memory efficient and fast. It supports both an object and a tied handle
|
||||
interface.
|
||||
|
||||
It is intended for processing log and other similar text files which
|
||||
typically have new entries appended. It uses newline as the separator
|
||||
and not $/ since it is only meant to be used for text.
|
||||
|
||||
It works by reading large (8kb) blocks of text from the end of the file,
|
||||
splits them on newlines and stores the other lines until the buffer runs
|
||||
out. Then it seeks to the previous block and splits it. When it reaches
|
||||
the beginning of the file, it stops reading more blocks. All boundary
|
||||
conditions are handled correctly. If there is a trailing partial line
|
||||
(no newline) it will be the first line returned. Lines larger than the
|
||||
read buffer size are ok.
|
||||
|
||||
=head2 Object Interface
|
||||
|
||||
|
||||
There are only 2 methods in Backwards' object interface, new and
|
||||
readline.
|
||||
|
||||
=head2 new
|
||||
|
||||
New takes just a filename for an argument and it either returns the
|
||||
object on a successful open on that file or undef.
|
||||
|
||||
=head2 readline
|
||||
|
||||
Readline takes no arguments and it returns the previous line in the file
|
||||
or undef when there are no more lines in the file.
|
||||
|
||||
|
||||
=head2 Tied Handle Interface
|
||||
|
||||
The only tied handle calls supported are TIEHANDLE and READLINE and they
|
||||
are typeglobbed to new and readline respectively. All other tied handle
|
||||
operations will generate an unknown method error. Do not seek, write or
|
||||
do any other operation other than <> on the handle.
|
||||
@@ -1 +0,0 @@
|
||||
<font size=+2>Click on the <b>filename and line number</b> in the log and the source will appear in this window.</font>
|
||||
@@ -1,77 +0,0 @@
|
||||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Tinderbox build tool.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
|
||||
# This Makefile helps you install Tinderbox. Define PERL and MYSQLTCL to
|
||||
# the full pathnames of where you have these utilities. Define PREFIX
|
||||
# to where you will install the running Tinderbox. Then "make install" should
|
||||
# copy things for you.
|
||||
|
||||
#BONSAI = /home/httpd/html/bonsai
|
||||
#CVSROOT = /cvsroot
|
||||
#GZIP = /usr/bin/gzip
|
||||
#PERL = /usr/bin/perl
|
||||
#PREFIX = /home/httpd/html/tinderbox
|
||||
#UUDECODE = /usr/bin/uudecode
|
||||
|
||||
FILES = addimage.cgi \
|
||||
addnote.cgi \
|
||||
admintree.cgi \
|
||||
buildwho.pl \
|
||||
clean.pl \
|
||||
copydata.pl \
|
||||
doadmin.cgi \
|
||||
ep_mac.pl \
|
||||
ep_unix.pl \
|
||||
ep_windows.pl \
|
||||
fixupimages.pl \
|
||||
globals.pl \
|
||||
handlemail.pl \
|
||||
imagelog.pl \
|
||||
processbuild.pl \
|
||||
showbuilds.cgi \
|
||||
showimages.cgi \
|
||||
showlog.cgi \
|
||||
Empty.html \
|
||||
faq.html \
|
||||
index.html \
|
||||
examples/mozilla-unix.pl \
|
||||
examples/mozilla-windows.pl
|
||||
|
||||
PICS = \
|
||||
1afi003r.gif \
|
||||
reledanim.gif \
|
||||
star.gif
|
||||
|
||||
install:
|
||||
mkdir -p $(PREFIX) && \
|
||||
for I in $(FILES); do \
|
||||
echo Installing $$I && \
|
||||
sed -e s#/usr/bonsaitools/bin/perl#$(PERL)#g \
|
||||
-e s#/tools/ns/bin/perl5#$(PERL)#g \
|
||||
-e s#/m/src#$(CVSROOT)#g \
|
||||
-e s#/usr/local/bin/gzip#$(GZIP)#g \
|
||||
-e s#/tools/ns/bin/uudecode#$(UUDECODE)#g \
|
||||
-e s#/d/webdocs/projects/bonsai#$(BONSAI)#g \
|
||||
$$I > $(PREFIX)/$$I && \
|
||||
chmod 755 $(PREFIX)/$$I; done && \
|
||||
for I in $(PICS); do \
|
||||
echo Installing $$I && \
|
||||
cp -f $$I $(PREFIX) && \
|
||||
chmod 755 $(PREFIX)/$$I; done
|
||||
|
||||
@@ -1,287 +0,0 @@
|
||||
This is Tinderbox. See <http://www.mozilla.org/tinderbox.html>.
|
||||
|
||||
|
||||
==========
|
||||
DISCLAIMER
|
||||
==========
|
||||
|
||||
This is not very well packaged code. It's not packaged at all. Don't
|
||||
come here expecting something you plop in a directory, twiddle a few
|
||||
things, and you're off and using it. Much work has to be done to get
|
||||
there. We'd like to get there, but it wasn't clear when that would be,
|
||||
and so we decided to let people see it first.
|
||||
|
||||
Don't believe for a minute that you can use this stuff without first
|
||||
understanding most of the code.
|
||||
|
||||
|
||||
============
|
||||
DEPENDENCIES
|
||||
============
|
||||
|
||||
To use tinderbox, you must first have bonsai up and running.
|
||||
See <http://www.mozilla.org/bonsai.html>.
|
||||
|
||||
Be warned now that bonsai is not easily installed.
|
||||
|
||||
|
||||
====================================
|
||||
What's What in the Tinderbox sources:
|
||||
====================================
|
||||
|
||||
This is a rough first pass at cataloging and documenting the Tinderbox
|
||||
sources. Many hands have been in this code over the years, and it has
|
||||
accreted wildly. There is probably quite a lot of dead code in here.
|
||||
|
||||
|
||||
PROGRAMS
|
||||
========
|
||||
|
||||
handlemail.pl This is the mail deliverty agent (MDA) for tinderbox,
|
||||
the local message transfer agent (MTA) calls this
|
||||
program to deliver the tinderbox mail into the system.
|
||||
It is a wrapper for processbuild.pl.
|
||||
|
||||
processbuild.pl Update the "$tbx{tree}/build.dat" database as new
|
||||
mail comes in then run "./buildwho.pl $tree" and
|
||||
"./showbuilds.cgi" (to build static versions of
|
||||
tinderbox data.
|
||||
|
||||
buildwho.pl Update the who.dat file with the list of authors who
|
||||
checked in in the last two days. This is run from
|
||||
processbuild.pl, always, and from showbuild.cgi when
|
||||
'rebuildguilty' is clicked
|
||||
|
||||
|
||||
Conceptually, the three programs, handlemail.pl, processbuild.pl, and
|
||||
buildwho.pl, make up the MDA for tinderbox.
|
||||
|
||||
|
||||
showbuilds.cgi Create the Tinderbox web page.
|
||||
|
||||
showlog.cgi Show a build log (brief and full) update the brief_log if
|
||||
necessary. Requires the ep_$form{errorparser}.pl error
|
||||
parser.
|
||||
|
||||
ep_unix.pl Knows how to parse Unix build error logs. Used by
|
||||
processbuild.pl There needs to be one ep_* file for
|
||||
each distinct parsing algorithm used, typically this
|
||||
is per platform. This file defines the regular
|
||||
expressions which locate error lines: has_error()
|
||||
has_warning() and the function has_errorline() which
|
||||
parses the line into the global variables:
|
||||
$error_file, $error_file_ref, $error_line, $error_guess,
|
||||
|
||||
admintree.cgi Displays the admin cgi which depends on:
|
||||
$message_of_day, $ignore_builds
|
||||
|
||||
doadmin.cgi Actually do the work to admin a tinderbox tree
|
||||
(change message of the day, turn off displays for a
|
||||
channel)
|
||||
|
||||
clean.pl Run `find . -name \"*.gz\" -mtime +7 -print ` and
|
||||
unlink those files. Does not appear to be run from
|
||||
other tools. It is a good candidate for a cron job.
|
||||
|
||||
|
||||
|
||||
OPTIONS to showbuilds.cgi
|
||||
=========================
|
||||
|
||||
Options to showbuilds are specified in the URL and are undocumented
|
||||
elsewhere.
|
||||
|
||||
If called with no 'tree' option display the possible build trees to
|
||||
pick from. The 'tree' picks the build to display. An additional tree
|
||||
can be specified with 'tree2'.
|
||||
|
||||
Interesting visual params are:
|
||||
|
||||
current state monitoring mode:
|
||||
express=1
|
||||
or
|
||||
panel=1
|
||||
text mode state monitoring:
|
||||
quickparse=1
|
||||
|
||||
These modes do not show on my browser:
|
||||
flash=1
|
||||
rdf=1
|
||||
static=1
|
||||
|
||||
These are self explanatory:
|
||||
nocrap=1;
|
||||
hours=n;
|
||||
|
||||
|
||||
EMAIL FORMAT
|
||||
============
|
||||
|
||||
Each tinderbox client mails status updates to the tinderbox server.
|
||||
These mails contain special tinderbox data lines describing the
|
||||
progress of the build it may also contain the log of the build process
|
||||
and could contain a uuencoded binary.
|
||||
|
||||
|
||||
The email to the tinderbox server looks like:
|
||||
|
||||
tinderbox: tree: Mozilla
|
||||
tinderbox: builddate: 900002087
|
||||
tinderbox: status: building
|
||||
tinderbox: build: IRIX 6.3 Depend
|
||||
tinderbox: errorparser: unix
|
||||
|
||||
If binaryname is set then the mail message is run through uudecode to
|
||||
create a file called "$binaryname" on the tinderbox server.
|
||||
|
||||
# NOT USED tinderbox: buildfamily: unix
|
||||
|
||||
|
||||
DATA STRUCTURES IN showbuilds.cgi
|
||||
=================================
|
||||
|
||||
load_buildlog() creates build_list a list of hash refernces of this
|
||||
type
|
||||
$buildrec = {
|
||||
mailtime => $mailtime,
|
||||
buildtime => $buildtime,
|
||||
buildname => ($tree2 ne '' ? $t->{name} . ' ' : '' ) . $buildname,
|
||||
errorparser => $errorparser,
|
||||
buildstatus => $buildstatus,
|
||||
logfile => $logfile,
|
||||
binaryname => $binaryname,
|
||||
td => $t
|
||||
};
|
||||
|
||||
the $buildrec->{rowspan} variable holds the number of rows that the build
|
||||
should occupy on the table and is not stored in the build.dat file.
|
||||
|
||||
These are other add ons to the data structure
|
||||
$buildrec->{hasnote}=1;
|
||||
$buildrec->{noteid} = (0+@note_array);
|
||||
|
||||
commonly buildrec's are accessed through:
|
||||
$build_table->[$build_time][$build_name] = $buildrec;
|
||||
|
||||
The list of users who updated this build is stored as:
|
||||
$who_list->[$checkin_time]->{$author} = 1;
|
||||
|
||||
There are numerous duplicate data structures which hold partial
|
||||
information:
|
||||
|
||||
hashes which hold all indices:
|
||||
$build_name_index->{$br->{buildname}} = 1;
|
||||
$build_time_index->{$br->{buildtime}} = 1;
|
||||
other access into $build_table:
|
||||
$build_name_names->[$i] = $n;
|
||||
$build_time_times->[$i] = $n;
|
||||
|
||||
|
||||
loadquickparseinfo creates these references
|
||||
$build->{$buildname} = $buildstatus;
|
||||
$times->{$buildname} = $buildtime;
|
||||
|
||||
|
||||
|
||||
DATA FILES
|
||||
==========
|
||||
|
||||
These files are used to store data structures. They are a persistent
|
||||
store of data between executions of the same program and they pass the
|
||||
data between cooperating program. This data is often databases with
|
||||
rows separated by "\n" and columns by '|'.
|
||||
|
||||
|
||||
$tree/${logfile}
|
||||
$tree/${logfile}.brief.html
|
||||
$tree/ignorebuilds.pl
|
||||
$tree/mod.pl
|
||||
$tree/notes.txt
|
||||
$tree/treedata.pl
|
||||
$tree/who.dat
|
||||
$treename/build.dat
|
||||
|
||||
The logfile that the tinderbox client sent stored in gziped format.
|
||||
The filename is ${tree}/$builddate.$$.gz so its quite random and does
|
||||
not depend on the clients$build string and multiple logs are kept for
|
||||
each build, one for each mail message sent.
|
||||
|
||||
The brief.html file is a cache of the error log summary for this log
|
||||
file and is recreated when the logfile gets updated.
|
||||
|
||||
ignorebuilds.pl is a file which specifies builds that should not be
|
||||
performed. It is valid perl code which sets the hash reference
|
||||
$ignore_builds, each key is a tree name.
|
||||
|
||||
mod.pl stores the tree specific message of the day. This is not to be
|
||||
confused with mod perl the CGI library. Its contents looks like:
|
||||
$message_of_day = 'message';
|
||||
|
||||
notes.txt store the database of notes:
|
||||
$buildtime|$buildname||$author|$time_now|$note
|
||||
|
||||
|
||||
treedata.pl stores the cvs information pertaining to this tree and
|
||||
looks like this:
|
||||
$cvs_module='$modulename';
|
||||
$cvs_branch='$branchname';
|
||||
$cvs_root='$repository';
|
||||
|
||||
who.dat file has lines like:
|
||||
$checkin_time|$author
|
||||
This gets stored in the data structure, where checkin_time
|
||||
gets fudged up so that is is a time already in the
|
||||
build_table:
|
||||
$who_list->[$checkin_time]->{$author} = 1;
|
||||
|
||||
build.dat stores the build results table. It is a flat file
|
||||
representation of $build_table
|
||||
|
||||
build.dat is a database file each row is a build and has pipe
|
||||
separated columns:
|
||||
|
||||
1) the time stamp of the tinderbox server
|
||||
2) time stamp of the build machine
|
||||
3) the official build name (should include build machine name)
|
||||
( note: that 2 & 3 together uniquely identify the build
|
||||
and all relevant build data)
|
||||
4) the architecture dependent error parser to use on the log files
|
||||
5) status of the build (success|busted|building|testfailed)
|
||||
6) The log file for this build (if completed)
|
||||
7) the name of the binary (if any) that came from the build
|
||||
|
||||
|
||||
Other Files
|
||||
====================
|
||||
1afi003r.gif The "flames" animation used by showbuilds.cgi
|
||||
|
||||
Empty.html Document used for an empty frame by ???
|
||||
|
||||
addimage.cgi The form that lets you add a new image to the list of
|
||||
images that Tinderbox picks from randomly.
|
||||
|
||||
addnote.cgi Add a note to a build log.
|
||||
|
||||
admintree.cgi Lets you perform various admin tasks on a Tinderbox tree.
|
||||
This just prompts for a password and posts to doadmin.cgi.
|
||||
|
||||
clean.pl ???
|
||||
copydata.pl ???
|
||||
|
||||
doadmin.cgi Actually do the work to admin a tinderbox tree
|
||||
|
||||
ep_mac.pl Knows how to parse Mac build error logs. Used by ???
|
||||
ep_unix.pl Knows how to parse Unix build error logs. Used by ???
|
||||
ep_windows.pl Knows how to parse Windows build error logs. Used by ???
|
||||
|
||||
faq.html Wildly out of date.
|
||||
|
||||
fixupimages.pl ???
|
||||
globals.pl ???
|
||||
imagelog.pl ???
|
||||
index.html ???
|
||||
reledanim.gif ???
|
||||
|
||||
showimages.cgi Show all the images in the Tinderbox list. Password-protected.
|
||||
|
||||
star.gif The "star" image used to annotate builds by ???
|
||||
@@ -1,404 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl --
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Tinderbox build tool.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
use Socket;
|
||||
|
||||
use lib "../bonsai";
|
||||
require 'header.pl';
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
EmitHtmlTitleAndHeader("tinderbox: add images", "add images");
|
||||
|
||||
$| = 1;
|
||||
|
||||
require "globals.pl";
|
||||
require "imagelog.pl";
|
||||
|
||||
&split_cgi_args;
|
||||
|
||||
|
||||
sub Error {
|
||||
my ($msg) = @_;
|
||||
print "<BR><BR><BR>";
|
||||
print "<UL><FONT SIZE='+1'><B>Something went wrong:</B><P>";
|
||||
print "<UL>";
|
||||
print $msg;
|
||||
print "</UL>";
|
||||
print "<P>";
|
||||
print "Hit <B>\`Back'</B> and try again.";
|
||||
print "</UL>";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
|
||||
if( $url = $form{"url"} ){
|
||||
$quote = $form{"quote"};
|
||||
|
||||
$quote =~ s/[\r\n]/ /g;
|
||||
$url =~ s/[\r\n]/ /g;
|
||||
|
||||
$width = "";
|
||||
$height = "";
|
||||
# I think we don't want to allow this --jwz
|
||||
# $width = $form{"width"};
|
||||
# $height = $form{"height"};
|
||||
|
||||
if ($width eq "" || $height eq "") {
|
||||
$size = &URLsize($url);
|
||||
if ($size =~ /WIDTH=([0-9]*)/) {
|
||||
$width = $1;
|
||||
}
|
||||
if ($size =~ /HEIGHT=([0-9]*)/) {
|
||||
$height = $1;
|
||||
}
|
||||
if ($width eq "" || $height eq "") {
|
||||
Error "Couldn't get image size for \"$url\".\n";
|
||||
}
|
||||
}
|
||||
|
||||
print "
|
||||
|
||||
<P><center><img border=2 src='$url' width=$width height=$height><br>
|
||||
<i>$quote</i><br><br>
|
||||
";
|
||||
|
||||
if( $form{"submit"} ne "Yes" ){
|
||||
my $u2 = $url;
|
||||
my $q2 = $quote;
|
||||
$u2 =~ s@&@&@g; $u2 =~ s@<@<@g; $u2 =~ s@\"@"@g;
|
||||
$q2 =~ s@&@&@g; $q2 =~ s@<@<@g; $q2 =~ s@\"@"@g;
|
||||
|
||||
print "
|
||||
<form action='addimage.cgi' METHOD='get'>
|
||||
<input type=hidden name=url value=\"$u2\">
|
||||
<input type=hidden name=quote value=\"$q2\">
|
||||
<HR>
|
||||
<TABLE>
|
||||
<TR>
|
||||
<TH ALIGN=RIGHT NOWRAP>Image URL:</TH>
|
||||
<TD><TT><B>$u2</B></TT></TD>
|
||||
</TR><TR>
|
||||
<TH ALIGN=RIGHT>Caption:</TH>
|
||||
<TD><TT><B>$q2</B></TT></TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD></TD>
|
||||
<TD>
|
||||
<FONT SIZE=+2><B>
|
||||
Does that look right?
|
||||
<SPACER SIZE=10>
|
||||
<INPUT Type='submit' name='submit' value='Yes'>
|
||||
</B><BR>(If not, hit \`Back' and fix it.)
|
||||
</FONT>
|
||||
</TD>
|
||||
</TABLE>
|
||||
</form>
|
||||
";
|
||||
}
|
||||
else {
|
||||
&add_imagelog( $url, $quote, $width, $height );
|
||||
print "<br><br>
|
||||
<font size=+2>Has been added</font><br><br>
|
||||
<a href=showbuilds.cgi>Return to Log</a>";
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
print "
|
||||
<h2>Add an image and a funny caption.</h2>
|
||||
|
||||
<ul>
|
||||
<p>This is about fun, and making your daily excursion to
|
||||
<A HREF=http://www.mozilla.org/tinderbox.html>Tinderbox</A> a
|
||||
novel experience. Engineers spend a lot of time here; it might as well
|
||||
have some entertainment value.
|
||||
|
||||
<p>Please play nice. We don't have the time or inclination to look at
|
||||
everything you people submit, but if we get nastygrams or legalgrams
|
||||
and have to take something down, we will curse your IP address, and you
|
||||
might even make it so the whole thing goes away forever. Please don't
|
||||
make us go there. You might also avoid links to big images or slow
|
||||
servers.
|
||||
|
||||
<p><ul><B>Thank you for playing nice.</B></UL>
|
||||
|
||||
<p>If you really find an image offensive, please
|
||||
<A HREF=mailto:terry\@netscape.com?Subject=offensive%20tinderbox%20image>tell us</A>
|
||||
nicely before someone causes a stink. Be sure to include the URL of
|
||||
the image. Remember, we don't screen these submissions and may not
|
||||
have even seen it.
|
||||
|
||||
<p><ul><B>P.S. Please, no more pictures of Bill Gates.</B></UL>
|
||||
</ul>
|
||||
|
||||
<p><form action='addimage.cgi' METHOD='get'>
|
||||
<TABLE>
|
||||
<TR>
|
||||
<TH ALIGN=RIGHT NOWRAP>Image URL:</TH>
|
||||
<TD><INPUT NAME='url' SIZE=60></TD>
|
||||
</TR><TR>
|
||||
<TH ALIGN=RIGHT>Caption:</TH>
|
||||
<TD><INPUT NAME='quote' SIZE=60></TD>
|
||||
</TR><TR>
|
||||
<TD></TD>
|
||||
<TD><B>
|
||||
<INPUT Type='submit' name='submit' value='Test'>
|
||||
<SPACER SIZE=25>
|
||||
<INPUT Type='reset' name='reset' value='Reset'>
|
||||
</B></TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
</form>
|
||||
<br><br>
|
||||
";
|
||||
}
|
||||
|
||||
sub split_cgi_args {
|
||||
local($i,$var,$value, $s);
|
||||
|
||||
$s = $ENV{"QUERY_STRING"};
|
||||
|
||||
@args= split(/\&/, $s );
|
||||
|
||||
for $i (@args) {
|
||||
($var, $value) = split(/=/, $i);
|
||||
$value =~ tr/+/ /;
|
||||
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
|
||||
$form{$var} = $value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#sub imgsize {
|
||||
# local($file)= @_;
|
||||
#
|
||||
# #first try to open the file
|
||||
# if( !open(STREAM, "<$file") ){
|
||||
# Error "Can't open IMG $file";
|
||||
## $size="";
|
||||
# } else {
|
||||
# if ($file =~ /.jpg/i || $file =~ /.jpeg/i) {
|
||||
# $size = &jpegsize(STREAM);
|
||||
# } elsif($file =~ /.gif/i) {
|
||||
# $size = &gifsize(STREAM);
|
||||
# } elsif($file =~ /.xbm/i) {
|
||||
# $size = &xbmsize(STREAM);
|
||||
# } else {
|
||||
# return "";
|
||||
# }
|
||||
# $_ = $size;
|
||||
# if( /\s*width\s*=\s*([0-9]*)\s*/i ){
|
||||
# ($newwidth)= /\s*width\s*=\s*(\d*)\s*/i;
|
||||
# }
|
||||
# if( /\s*height\s*=\s*([0-9]*)\s*/i ){
|
||||
# ($newheight)=/\s*height\s*=\s*(\d*)\s*/i;
|
||||
# }
|
||||
# close(STREAM);
|
||||
# }
|
||||
# return $size;
|
||||
#}
|
||||
|
||||
###########################################################################
|
||||
# Subroutine gets the size of the specified GIF
|
||||
###########################################################################
|
||||
|
||||
# bug: it thinks that
|
||||
# http://cvs1.mozilla.org/webtools/tinderbox/data/knotts.gif
|
||||
# is 640x400, but it's really 200x245.
|
||||
# giftrans says of that image:
|
||||
#
|
||||
# Header: "GIF87a"
|
||||
# Logical Screen Descriptor:
|
||||
# Logical Screen Width: 640 pixels
|
||||
# Logical Screen Height: 480 pixels
|
||||
# Image Descriptor:
|
||||
# Image Width: 200 pixels
|
||||
# Image Height: 245 pixels
|
||||
|
||||
|
||||
sub gifsize {
|
||||
local($GIF) = @_;
|
||||
read($GIF, $type, 6);
|
||||
if(!($type =~ /GIF8[7,9]a/) ||
|
||||
!(read($GIF, $s, 4) == 4) ){
|
||||
Error "Invalid or Corrupted GIF";
|
||||
$size="";
|
||||
} else {
|
||||
($a,$b,$c,$d)=unpack("C"x4,$s);
|
||||
$size=join ("", 'WIDTH=', $b<<8|$a, ' HEIGHT=', $d<<8|$c);
|
||||
}
|
||||
return $size;
|
||||
}
|
||||
|
||||
sub xbmsize {
|
||||
local($XBM) = @_;
|
||||
local($input)="";
|
||||
|
||||
$input .= <$XBM>;
|
||||
$input .= <$XBM>;
|
||||
$_ = $input;
|
||||
if( /#define\s*\S*\s*\d*\s*\n#define\s*\S*\s*\d*\s*\n/i ){
|
||||
($a,$b)=/#define\s*\S*\s*(\d*)\s*\n#define\s*\S*\s*(\d*)\s*\n/i;
|
||||
$size=join ("", 'WIDTH=', $a, ' HEIGHT=', $b );
|
||||
} else {
|
||||
Error "Doesn't look like an XBM file";
|
||||
}
|
||||
return $size;
|
||||
}
|
||||
|
||||
# jpegsize : gets the width and height (in pixels) of a jpeg file
|
||||
# Andrew Tong, werdna@ugcs.caltech.edu February 14, 1995
|
||||
# modified slightly by alex@ed.ac.uk
|
||||
sub jpegsize {
|
||||
local($JPEG) = @_;
|
||||
local($done)=0;
|
||||
$size="";
|
||||
|
||||
read($JPEG, $c1, 1); read($JPEG, $c2, 1);
|
||||
if( !((ord($c1) == 0xFF) && (ord($c2) == 0xD8))){
|
||||
my $s = sprintf "This is not a JPEG! (Codes %02X %02X)\n", ord($c1), ord($c2);
|
||||
Error $s;
|
||||
$done=1;
|
||||
}
|
||||
while (ord($ch) != 0xDA && !$done) {
|
||||
# Find next marker (JPEG markers begin with 0xFF)
|
||||
# This can hang the program!!
|
||||
while (ord($ch) != 0xFF) { read($JPEG, $ch, 1); }
|
||||
# JPEG markers can be padded with unlimited 0xFF's
|
||||
while (ord($ch) == 0xFF) { read($JPEG, $ch, 1); }
|
||||
# Now, $ch contains the value of the marker.
|
||||
$marker=ord($ch);
|
||||
|
||||
if (($marker >= 0xC0) && ($marker <= 0xCF) &&
|
||||
($marker != 0xC4) && ($marker != 0xCC)) { # it's a SOFn marker
|
||||
read ($JPEG, $junk, 3); read($JPEG, $s, 4);
|
||||
($a,$b,$c,$d)=unpack("C"x4,$s);
|
||||
$size=join("", 'HEIGHT=',$a<<8|$b,' WIDTH=',$c<<8|$d );
|
||||
$done=1;
|
||||
} else {
|
||||
# We **MUST** skip variables, since FF's within variable
|
||||
# names are NOT valid JPEG markers
|
||||
read ($JPEG, $s, 2);
|
||||
($c1, $c2) = unpack("C"x2,$s);
|
||||
$length = $c1<<8|$c2;
|
||||
if( ($length < 2) ){
|
||||
Error "Bad JPEG file: erroneous marker length";
|
||||
$done=1;
|
||||
} else {
|
||||
read($JPEG, $junk, $length-2);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $size;
|
||||
}
|
||||
|
||||
###########################################################################
|
||||
# Subroutine grabs a gif from another server and gets its size
|
||||
###########################################################################
|
||||
|
||||
|
||||
sub URLsize {
|
||||
my ($fullurl) = @_;
|
||||
|
||||
$_ = $fullurl;
|
||||
if ( ! m@^http://@ ) {
|
||||
Error "HTTP URLs only, please: \"$_\" is no good.";
|
||||
}
|
||||
|
||||
my($dummy, $dummy, $serverstring, $url) = split(/\//, $fullurl, 4);
|
||||
my($them,$port) = split(/:/, $serverstring);
|
||||
my $port = 80 unless $port;
|
||||
my $size="";
|
||||
|
||||
$_ = $them;
|
||||
if ( m@^[^.]*$@ ) {
|
||||
Error "Fully-qualified host names only, please: \"$_\" is no good.";
|
||||
}
|
||||
|
||||
$_=$url;
|
||||
my ($remote, $iaddr, $paddr, $proto, $line);
|
||||
$remote = $them;
|
||||
if ($port =~ /\D/) { $port = getservbyname($port, 'tcp') }
|
||||
die "No port" unless $port;
|
||||
$iaddr = inet_aton($remote) || die "no host: $remote";
|
||||
$paddr = sockaddr_in($port, $iaddr);
|
||||
|
||||
$proto = getprotobyname('tcp');
|
||||
socket(S, PF_INET, SOCK_STREAM, $proto) || die "socket: $!";
|
||||
connect(S, $paddr) || die "connect: $!";
|
||||
select(S); $| = 1; select(STDOUT);
|
||||
|
||||
print S "GET /$url HTTP/1.0\r\n";
|
||||
print S "Host: $them\r\n";
|
||||
print S "User-Agent: Tinderbox/0.0\r\n";
|
||||
print S "\r\n";
|
||||
|
||||
$_ = <S>;
|
||||
if (! m@^HTTP/[0-9.]+ 200@ ) {
|
||||
Error "$them responded:<BR> $_";
|
||||
}
|
||||
|
||||
my $ctype = "";
|
||||
while (<S>) {
|
||||
# print "read: $_<br>\n";
|
||||
if ( m@^Content-Type:[ \t]*([^ \t\r\n]+)@io ) {
|
||||
$ctype = $1;
|
||||
}
|
||||
last if (/^[\r\n]/);
|
||||
}
|
||||
|
||||
$_ = $ctype;
|
||||
if ( $_ eq "" ) {
|
||||
Error "Server returned no content-type for \"$fullurl\"?";
|
||||
} elsif ( m@image/jpeg@i || m@image/pjpeg@i ) {
|
||||
$size = &jpegsize(S);
|
||||
} elsif ( m@image/gif@i ) {
|
||||
$size = &gifsize(S);
|
||||
} elsif ( m@image/xbm@i || m@image/x-xbm@i || m@image/x-xbitmap@i ) {
|
||||
$size = &xbmsize(S);
|
||||
} else {
|
||||
Error "Not a GIF, JPEG, or XBM: that was of type \"$ctype\".";
|
||||
}
|
||||
|
||||
$_ = $size;
|
||||
if( /\s*width\s*=\s*([0-9]*)\s*/i ){
|
||||
($newwidth)= /\s*width\s*=\s*(\d*)\s*/i;
|
||||
}
|
||||
if( /\s*height\s*=\s*([0-9]*)\s*/i ){
|
||||
($newheight)=/\s*height\s*=\s*(\d*)\s*/i;
|
||||
}
|
||||
|
||||
if ( $newwidth eq "" || $newheight eq "" ) {
|
||||
return "";
|
||||
} else {
|
||||
if ( $newwidth <= 5 || $newheight <= 5 ) {
|
||||
Error "${newwidth}x${newheight} seems small, don't you think?";
|
||||
} elsif ( $newwidth >= 400 || $newheight >= 400 ) {
|
||||
Error "${newwidth}x${newheight} is too big; please" .
|
||||
" keep it under 400x400."
|
||||
}
|
||||
return $size;
|
||||
}
|
||||
}
|
||||
|
||||
sub dokill {
|
||||
kill 9,$child if $child;
|
||||
}
|
||||
@@ -1,206 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl --
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Tinderbox build tool.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
use lib "../bonsai";
|
||||
use Fcntl;
|
||||
|
||||
require "globals.pl";
|
||||
require 'lloydcgi.pl';
|
||||
|
||||
if (defined($args = $form{log})) {
|
||||
|
||||
($tree, $logfile) = split /\//, $args;
|
||||
|
||||
my $br = find_build_record($tree, $logfile);
|
||||
$errorparser = $br->{errorparser};
|
||||
$buildname = $br->{buildname};
|
||||
$buildtime = $br->{buildtime};
|
||||
} else {
|
||||
$tree = $form{'tree'};
|
||||
$logfile = $form{'logfile'};
|
||||
$errorparser = $form{'errorparser'};
|
||||
$buildname = $form{'buildname'};
|
||||
$buildtime = $form{'buildtime'};
|
||||
}
|
||||
|
||||
$enc_buildname = &url_encode($buildname);
|
||||
|
||||
$note = $form{'note'};
|
||||
$who = $form{'who'};
|
||||
|
||||
$now = time;
|
||||
$now_str = &print_time($now);
|
||||
|
||||
$|=1;
|
||||
|
||||
if( -r "$tree/ignorebuilds.pl" ){
|
||||
require "$tree/ignorebuilds.pl";
|
||||
}
|
||||
|
||||
print "Content-Type:text/html\n";
|
||||
if ($ENV{"REQUEST_METHOD"} eq 'POST' && defined($form{'note'})) {
|
||||
# Expire the cookie 5 months from now
|
||||
print "Set-Cookie: email=$form{who}; expires="
|
||||
. toGMTString(time + 86400 * 152) . "; path=/\n";
|
||||
}
|
||||
print "\n<HTML>\n";
|
||||
|
||||
if( $url = $form{"note"} ){
|
||||
|
||||
$note =~ s/\&/&/gi;
|
||||
$note =~ s/\</</gi;
|
||||
$note =~ s/\>/>/gi;
|
||||
$enc_note = url_encode( $note );
|
||||
|
||||
open( NOTES,">>$tree/notes.txt");
|
||||
flock(NOTES, LOCK_EX);
|
||||
print NOTES "$buildtime|$buildname|$who|$now|$enc_note\n";
|
||||
|
||||
&LoadBuildTable;
|
||||
|
||||
foreach $element (keys %form) {
|
||||
|
||||
if(exists ${$build_name_index}{$element}) {
|
||||
print NOTES "${$build_name_index}{$element}|$element|$who|$now|$enc_note\n";
|
||||
} #EndIf
|
||||
} #Endforeach
|
||||
close(NOTES);
|
||||
|
||||
print "<H1>The following comment has been added to the log</h1>\n";
|
||||
|
||||
#print "$buildname \n $buildtime \n $errorparser \n $logfile \n $tree \n $enc_buildname \n";
|
||||
print "<pre>\n[<b>$who - $now_str</b>]\n$note\n</pre>";
|
||||
|
||||
print"
|
||||
<p><a href=\"showlog.cgi?tree=$tree\&buildname=$enc_buildname\&buildtime=$buildtime\&logfile=$logfile\&errorparser=$errorparser\">
|
||||
Go back to the Error Log</a>
|
||||
<a href=\"showbuilds.cgi?tree=$tree\">
|
||||
<br>Go back to the build Page</a>";
|
||||
|
||||
# Build tinderbox static pages
|
||||
$ENV{QUERY_STRING}="tree=$tree&static=1";
|
||||
$ENV{REQUEST_METHOD}="GET";
|
||||
system './showbuilds.cgi >/dev/null';
|
||||
|
||||
} else {
|
||||
|
||||
&GetBuildNameIndex;
|
||||
|
||||
@names = sort (keys %$build_name_index);
|
||||
|
||||
if ($buildname eq '' || $buildtime == 0) {
|
||||
print "<h1>Invalid parameters</h1>\n";
|
||||
die "\n";
|
||||
}
|
||||
|
||||
#print "$buildname \n $buildtime \n $errorparser \n $logfile \n $tree \n $enc_buildname \n";
|
||||
|
||||
$emailvalue = '';
|
||||
$emailvalue = " value='$cookie_jar{email}'" if defined($cookie_jar{email});
|
||||
|
||||
print qq(
|
||||
<head><title>Add a Comment to $buildname log</title></head>
|
||||
<body BGCOLOR="#FFFFFF" TEXT="#000000"LINK="#0000EE" VLINK="#551A8B" ALINK="#FF0000">
|
||||
|
||||
<table><tr><td>
|
||||
<b><font size="+2">Add a Log Comment</font></b>
|
||||
</td></tr><tr><td>
|
||||
<b><code>$buildname</code></b>
|
||||
</td></tr></table>
|
||||
|
||||
<form action='addnote.cgi' METHOD='post'>
|
||||
|
||||
<INPUT Type='hidden' name='buildname' value='${buildname}'>
|
||||
<INPUT Type='hidden' name='buildtime' value='${buildtime}'>
|
||||
<INPUT Type='hidden' name='errorparser' value='$errorparser'>
|
||||
<INPUT Type='hidden' name='logfile' value='$logfile'>
|
||||
<INPUT Type='hidden' name='tree' value='$tree'>
|
||||
|
||||
<table border=0 cellpadding=4 cellspacing=1>
|
||||
<tr valign=top>
|
||||
<td align=right>
|
||||
<NOWRAP>Email address:</NOWRAP>
|
||||
</td><td>
|
||||
<INPUT Type='input' name='who' size=32$emailvalue><BR>
|
||||
</td>
|
||||
</tr><tr valign=top>
|
||||
<td align=right>
|
||||
Comment:
|
||||
</td><td>
|
||||
<TEXTAREA NAME=note ROWS=10 COLS=30 WRAP=HARD></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br><b><font size="+2">Addition Builds</font></b><br>
|
||||
(Comment will be added to the most recent cycle.)<br>
|
||||
);
|
||||
|
||||
for $other_build (@names){
|
||||
if( $other_build ne "" ){
|
||||
|
||||
if (not exists ${$ignore_builds}{$other_build}) {
|
||||
if( $other_build ne $buildname ){
|
||||
print "<INPUT TYPE=checkbox NAME=\"$other_build\">";
|
||||
print "$other_build<BR>\n";
|
||||
}
|
||||
} #EndIf
|
||||
}
|
||||
} #Endfor
|
||||
|
||||
print "<INPUT Type='submit' name='submit' value='Add Comment'><BR>
|
||||
</form>\n</body>\n</html>";
|
||||
}
|
||||
|
||||
sub GetBuildNameIndex {
|
||||
local($mailtime, $buildtime, $buildname, $errorparser, $buildstatus, $logfile, $binaryname);
|
||||
|
||||
open(BUILDLOG, "$tree/build.dat") or die "Couldn't open build.dat: $!\n";
|
||||
|
||||
while(<BUILDLOG>) {
|
||||
chomp;
|
||||
($mailtime, $buildtime, $buildname, $errorparser, $buildstatus, $logfile, $binaryname) =
|
||||
split( /\|/ );
|
||||
|
||||
$build_name_index->{$buildname} = 0;
|
||||
|
||||
} #EndWhile
|
||||
close(BUILDLOG);
|
||||
|
||||
}
|
||||
|
||||
|
||||
sub LoadBuildTable {
|
||||
local($mailtime, $buildtime, $buildname, $errorparser, $buildstatus, $logfile, $binaryname);
|
||||
|
||||
open(BUILDLOG, "$tree/build.dat") or die "Couldn't open build.dat: $!\n";
|
||||
|
||||
while(<BUILDLOG>) {
|
||||
chomp;
|
||||
($mailtime, $buildtime, $buildname, $errorparser, $buildstatus, $logfile, $binaryname) =
|
||||
split( /\|/ );
|
||||
|
||||
if ($buildtime > $build_name_index->{$buildname} ) {
|
||||
$build_name_index->{$buildname} = $buildtime;
|
||||
}
|
||||
|
||||
} #EndWhile
|
||||
close(BUILDLOG);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl --
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Tinderbox build tool.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
use lib "../bonsai";
|
||||
|
||||
require 'lloydcgi.pl';
|
||||
require 'globals.pl';
|
||||
require 'header.pl';
|
||||
|
||||
$|=1;
|
||||
|
||||
print "Content-type: text/html\n\n<HTML>\n";
|
||||
|
||||
EmitHtmlHeader("administer tinderbox", "tree: $tree");
|
||||
|
||||
$form{noignore} = 1; # Force us to load all build info, not
|
||||
# paying any attention to ignore_builds stuff.
|
||||
$maxdate = time();
|
||||
$mindate = $maxdate - 24*60*60;
|
||||
&load_data;
|
||||
|
||||
if (defined($tree)) {
|
||||
if( -r "$tree/mod.pl" ){
|
||||
require "$tree/mod.pl";
|
||||
}
|
||||
else {
|
||||
$message_of_day = "";
|
||||
}
|
||||
|
||||
print "
|
||||
<FORM method=post action=doadmin.cgi>
|
||||
<B>Password:</B> <INPUT NAME=password TYPE=password>
|
||||
<INPUT TYPE=HIDDEN NAME=tree VALUE=$tree>
|
||||
<INPUT TYPE=HIDDEN NAME=command VALUE=set_message>
|
||||
<br><b>Message of the Day
|
||||
<br><TEXTAREA NAME=message ROWS=10 COLS=70 WRAP=SOFT>$message_of_day
|
||||
</TEXTAREA>
|
||||
<br><INPUT TYPE=SUBMIT VALUE='Set Message of the Day'>
|
||||
</FORM>
|
||||
<hr>
|
||||
";
|
||||
|
||||
|
||||
print "
|
||||
<FORM method=post action=doadmin.cgi>
|
||||
<B>Password:</B> <INPUT NAME=password TYPE=password>
|
||||
<INPUT TYPE=HIDDEN NAME=tree VALUE=$tree>
|
||||
<INPUT TYPE=HIDDEN NAME=command VALUE=trim_logs>
|
||||
<br><b>Trim Logs to <INPUT NAME=days size=5 VALUE='7'> days.</b> (Tinderbox
|
||||
shows 2 days history by default. You can see more by clicking show all).
|
||||
<br><INPUT TYPE=SUBMIT VALUE='Trim Logs'>
|
||||
</FORM>
|
||||
<FORM method=post action=doadmin.cgi>
|
||||
<hr>
|
||||
" ;
|
||||
}
|
||||
|
||||
print "
|
||||
<FORM method=post action=doadmin.cgi>
|
||||
<B>Password:</B> <INPUT NAME=password TYPE=password> <BR>
|
||||
<INPUT TYPE=HIDDEN NAME=tree VALUE=$tree>
|
||||
<INPUT TYPE=HIDDEN NAME=command VALUE=create_tree>
|
||||
<TABLE>
|
||||
<TR>
|
||||
<TD><B>tinderbox tree name:</B></TD>
|
||||
<TD><INPUT NAME=treename VALUE=''></TD>
|
||||
</TR><TR>
|
||||
<TD><B>cvs repository:</B></TD>
|
||||
<TD><INPUT NAME=repository VALUE=''></TD>
|
||||
</TR><TR>
|
||||
<TD><B>cvs module name:</B></TD>
|
||||
<TD><INPUT NAME=modulename VALUE=''></TD>
|
||||
</TR><TR>
|
||||
<TD><B>cvs branch:</B></TD>
|
||||
<TD><INPUT NAME=branchname VALUE='HEAD'></TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
<INPUT TYPE=SUBMIT VALUE='Create a new Tinderbox page'>
|
||||
</FORM>
|
||||
<FORM method=post action=doadmin.cgi>
|
||||
<hr>
|
||||
";
|
||||
|
||||
if (defined($tree)) {
|
||||
print "
|
||||
<B><font size=+1>If builds are behaving badly you can turn them off.</font></b><br> Uncheck
|
||||
the build that is misbehaving and click the button. You can still see all the
|
||||
builds even if some are disabled by adding the parameter <b><tt>&noignore=1</tt></b> to
|
||||
the tinderbox URL.<br>
|
||||
<B>Password:</B> <INPUT NAME=password TYPE=password> <BR>
|
||||
<INPUT TYPE=HIDDEN NAME=tree VALUE=$tree>
|
||||
<INPUT TYPE=HIDDEN NAME=command VALUE=disable_builds>
|
||||
";
|
||||
|
||||
@names = sort (@$build_name_names) ;
|
||||
|
||||
for $i (@names){
|
||||
if( $i ne "" ){
|
||||
$checked = ($ignore_builds->{$i} != 0 ? "": "CHECKED" );
|
||||
print "<INPUT TYPE=checkbox NAME='build_$i' $checked >";
|
||||
print "$i<br>\n";
|
||||
}
|
||||
}
|
||||
|
||||
print "
|
||||
<INPUT TYPE=SUBMIT VALUE='Show only checked builds'>
|
||||
</FORM>
|
||||
<hr>
|
||||
";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl --
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Tinderbox build tool.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
use lib "../bonsai";
|
||||
|
||||
require 'globals.pl';
|
||||
|
||||
$F_DEBUG=1;
|
||||
|
||||
|
||||
$days = 2;
|
||||
|
||||
if ($ARGV[0] eq "-days") {
|
||||
shift @ARGV;
|
||||
$days = shift @ARGV;
|
||||
}
|
||||
|
||||
$tree = $ARGV[0];
|
||||
|
||||
open(SEMFILE, ">>$tree/buildwho.sem") || die "Couldn't open semaphore file!";
|
||||
if (!flock(SEMFILE, 2 + 4)) { # 2 means "lock"; 4 means "fail immediately if
|
||||
# lock already taken".
|
||||
print "buildwho.pl: Another process is currently building the database.\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
require "$tree/treedata.pl";
|
||||
|
||||
if( $cvs_root eq '' ){
|
||||
$CVS_ROOT = '/m/src';
|
||||
}
|
||||
else {
|
||||
$CVS_ROOT = $cvs_root;
|
||||
}
|
||||
|
||||
$CVS_REPOS_SUFIX = $CVS_ROOT;
|
||||
$CVS_REPOS_SUFIX =~ s/\//_/g;
|
||||
|
||||
$CHECKIN_DATA_FILE = "/d/webdocs/projects/bonsai/data/checkinlog${CVS_REPOS_SUFIX}";
|
||||
$CHECKIN_INDEX_FILE = "/d/webdocs/projects/bonsai/data/index${CVS_REPOS_SUFIX}";
|
||||
|
||||
require 'cvsquery.pl';
|
||||
|
||||
print "cvsroot='$CVS_ROOT'\n";
|
||||
|
||||
&build_who;
|
||||
|
||||
flock(SEMFILE, 8); # '8' is magic 'unlock' const.
|
||||
close SEMFILE;
|
||||
|
||||
|
||||
sub build_who {
|
||||
open(BUILDLOG, "<$tree/build.dat" );
|
||||
$line = <BUILDLOG>;
|
||||
close(BUILDLOG);
|
||||
|
||||
#($j,$query_date_min) = split(/\|/, $line);
|
||||
$query_date_min = time - (60 * 60 * 24 * $days);
|
||||
|
||||
if( $F_DEBUG ){
|
||||
print "Minimum date: $query_date_min\n";
|
||||
}
|
||||
|
||||
$query_module=$cvs_module;
|
||||
$query_branch=$cvs_branch;
|
||||
|
||||
$result = &query_checkins;
|
||||
|
||||
|
||||
$last_who='';
|
||||
$last_date=0;
|
||||
open(WHOLOG, ">$tree/who.dat" );
|
||||
for $ci (@$result) {
|
||||
if( $ci->[$CI_DATE] != $last_date || $ci->[$CI_WHO] != $last_who ){
|
||||
print WHOLOG "$ci->[$CI_DATE]|$ci->[$CI_WHO]\n";
|
||||
}
|
||||
$last_who=$ci->[$CI_WHO];
|
||||
$last_date=$ci->[$CI_DATE];
|
||||
}
|
||||
close( WHOLOG );
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl --
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Tinderbox build tool.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
use lib "../bonsai";
|
||||
|
||||
require 'lloydcgi.pl';
|
||||
require 'globals.pl';
|
||||
require 'header.pl';
|
||||
|
||||
use Date::Parse;
|
||||
use Date::Format;
|
||||
|
||||
my $TIMEFORMAT = "%D %T";
|
||||
|
||||
$|=1;
|
||||
|
||||
print "Content-type: text/html\n\n<HTML>\n";
|
||||
|
||||
# &load_data;
|
||||
|
||||
EmitHtmlHeader("Statistics");
|
||||
|
||||
my $tree = $form{'tree'};
|
||||
my $start = $form{'start'};
|
||||
my $end = $form{'end'};
|
||||
|
||||
sub str2timeAndCheck {
|
||||
my ($str) = (@_);
|
||||
my $result = str2time($str);
|
||||
if (defined $result && $result > 7000000) {
|
||||
return $result;
|
||||
}
|
||||
print "<p><font color=red>Can't parse as a date: $str</font><p>\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (defined $tree && defined $start && defined $end) {
|
||||
my $first = str2timeAndCheck($start);
|
||||
my $last = str2timeAndCheck($end);
|
||||
if ($first > 0 && $last > 0) {
|
||||
if (open(IN, "<$tree/build.dat")) {
|
||||
print "<hr><center><h1>Bustage stats for $tree</H1><H3>from " .
|
||||
time2str($TIMEFORMAT, $first) . " to " .
|
||||
time2str($TIMEFORMAT, $last) . "</H3></center>\n";
|
||||
my %stats;
|
||||
while (<IN>) {
|
||||
chomp;
|
||||
my ($mailtime, $buildtime, $buildname, $errorparser,
|
||||
$buildstatus, $logfile, $binaryname) =
|
||||
split( /\|/ );
|
||||
if ($buildtime >= $first && $buildtime <= $last) {
|
||||
if (!defined $stats{$buildname}) {
|
||||
$stats{$buildname} = 0;
|
||||
}
|
||||
if ($buildstatus eq "busted") {
|
||||
$stats{$buildname}++;
|
||||
}
|
||||
}
|
||||
}
|
||||
print "<table>\n";
|
||||
print "<tr><th>Build name</th><th>Number of bustages</th></tr>\n";
|
||||
foreach my $key (sort (keys %stats)) {
|
||||
print "<tr><td>$key</td><td>$stats{$key}</td></tr>\n";
|
||||
}
|
||||
print "</table>\n";
|
||||
} else {
|
||||
print "<p><font color=red>There does not appear to be a tree " .
|
||||
"named '$tree'.</font><p>";
|
||||
}
|
||||
|
||||
}
|
||||
print "<hr>\n";
|
||||
}
|
||||
|
||||
if (!defined $tree) {
|
||||
$tree = "";
|
||||
}
|
||||
|
||||
if (!defined $start) {
|
||||
$start = time2str($TIMEFORMAT, time() - 7*24*60*60); # One week ago.
|
||||
}
|
||||
|
||||
if (!defined $end) {
|
||||
$end = time2str($TIMEFORMAT, time()); # #now
|
||||
}
|
||||
|
||||
|
||||
print qq|
|
||||
<form>
|
||||
<table>
|
||||
<tr>
|
||||
<th align=right>Tree:</th>
|
||||
<td><input name=tree size=30 value="$tree"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th align=right>Start time:</th>
|
||||
<td><input name=start size=30 value="$start"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th align=right>End time:</th>
|
||||
<td><input name=end size=30 value="$end"></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<INPUT TYPE=\"submit\" VALUE=\"Generate stats \">
|
||||
|
||||
</form>
|
||||
|;
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 295 B |
@@ -1,42 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl --
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Tinderbox build tool.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
# Figure out which directory tinderbox is in by looking at argv[0]
|
||||
|
||||
$tinderboxdir = $0;
|
||||
$tinderboxdir =~ s:/[^/]*$::; # Remove last word, and slash before it.
|
||||
if ($tinderboxdir eq "") {
|
||||
$tinderboxdir = ".";
|
||||
}
|
||||
|
||||
#print "tinderbox = $tinderboxdir\n";
|
||||
|
||||
chdir $tinderboxdir || die "Couldn't chdir to $tinderboxdir";
|
||||
|
||||
#print "cd ok\n";
|
||||
|
||||
open FL, "find . -name \"*.gz\" -mtime +7 -print |";
|
||||
|
||||
#print "find ok\n";
|
||||
|
||||
while( <FL> ){
|
||||
chop();
|
||||
#print "unlink $_\n";
|
||||
unlink $_;
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 69 B |
@@ -1,91 +0,0 @@
|
||||
#!/tools/ns/bin/perl5
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Tinderbox build tool.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
#
|
||||
# to run this script execute 'nohup copydata.pl &' from the tinderbox directory
|
||||
#
|
||||
|
||||
$start_dir = `pwd`;
|
||||
chop($start_dir);
|
||||
$scp_cmd = "scp -o 'User snapshot' -o'Port 22' -o 'UserKnownHostsFile /u/shaver/snapshot/known_hosts' -o 'IdentityFile /u/shaver/snapshot/identity'";
|
||||
|
||||
|
||||
$last_time = 0;
|
||||
|
||||
$min_cycle_time = 3 * 60; # 3 minutes
|
||||
|
||||
print "starting dir is :$start_dir\n";
|
||||
|
||||
while( 1 ){
|
||||
chdir("$start_dir");
|
||||
if( time - $last_time < $min_cycle_time ){
|
||||
$sleep_time = $min_cycle_time - (time - $last_time);
|
||||
print "\n\nSleeping $sleep_time seconds ...\n";
|
||||
sleep( $sleep_time );
|
||||
}
|
||||
|
||||
©_data("Mozilla");
|
||||
©_data("raptor");
|
||||
|
||||
chdir( "$start_dir");
|
||||
print "$scp_cmd * cvs1.mozilla.org:/e/webtools/tinderbox\n";
|
||||
system "$scp_cmd * cvs1.mozilla.org:/e/webtools/tinderbox";
|
||||
|
||||
chdir( "$start_dir/../bonsai");
|
||||
print "$scp_cmd * cvs1.mozilla.org:/e/webtools/bonsai\n";
|
||||
system "$scp_cmd * cvs1.mozilla.org:/e/webtools/bonsai";
|
||||
|
||||
|
||||
$last_time = time;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
|
||||
sub copy_data {
|
||||
local($data_dir) = @_;
|
||||
local($zips,$qry);
|
||||
|
||||
chdir $data_dir || die "couldn't chdir to $data_dir";
|
||||
|
||||
system "echo hello >lastup.new";
|
||||
|
||||
if( -r 'lastup' ) {
|
||||
$qry = '-newer lastup.old';
|
||||
rename 'lastup', 'lastup.old'
|
||||
}
|
||||
rename 'lastup.new', 'lastup';
|
||||
|
||||
|
||||
open( FINDER, "find . $qry -name \"*.gz\" -print|" );
|
||||
while(<FINDER>){
|
||||
print;
|
||||
chop;
|
||||
$zips .= "$_ ";
|
||||
}
|
||||
close( FINDER );
|
||||
|
||||
unlink 'lastup.old';
|
||||
|
||||
print "$scp_cmd *.txt $zips *.dat cvs1.mozilla.org:/e/webtools/tinderbox/$data_dir\n";
|
||||
system "$scp_cmd *.txt $zips *.dat cvs1.mozilla.org:/e/webtools/tinderbox/$data_dir";
|
||||
|
||||
|
||||
chdir $start_dir || die "couldn't chdir to $start_dir";
|
||||
}
|
||||
@@ -1,217 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl --
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Tinderbox build tool.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
|
||||
use lib "../bonsai";
|
||||
require 'lloydcgi.pl';
|
||||
require 'globals.pl';
|
||||
|
||||
umask O666;
|
||||
|
||||
|
||||
$|=1;
|
||||
|
||||
check_password();
|
||||
|
||||
print "Content-type: text/html\n\n<HTML>\n";
|
||||
|
||||
$command = $form{'command'};
|
||||
$tree= $form{'tree'};
|
||||
|
||||
if( $command eq 'create_tree' ){
|
||||
&create_tree;
|
||||
}
|
||||
elsif( $command eq 'remove_build' ){
|
||||
&remove_build;
|
||||
}
|
||||
elsif( $command eq 'trim_logs' ){
|
||||
&trim_logs;
|
||||
}
|
||||
elsif( $command eq 'set_message' ){
|
||||
&set_message;
|
||||
}
|
||||
elsif( $command eq 'disable_builds' ){
|
||||
&disable_builds;
|
||||
} else {
|
||||
print "Unknown command: \"$command\".";
|
||||
}
|
||||
|
||||
sub trim_logs {
|
||||
$days = $form{'days'};
|
||||
$tree = $form{'tree'};
|
||||
|
||||
print "<h2>Trimming Log files for $tree...</h2>\n<p>";
|
||||
|
||||
$min_date = time - (60*60*24 * $days);
|
||||
|
||||
#
|
||||
# Nuke the old log files
|
||||
#
|
||||
$i = 0;
|
||||
opendir( D, 'DogbertTip' );
|
||||
while( $fn = readdir( D ) ){
|
||||
if( $fn =~ /\.gz$/ ){
|
||||
($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,
|
||||
$ctime,$blksize,$blocks) = stat("$tree/$fn");
|
||||
if( $mtime && ($mtime < $min_date) ){
|
||||
print "$fn\n";
|
||||
$tblocks += $blocks;
|
||||
unlink( "$tree/$fn" );
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir( D );
|
||||
$k = $tblocks*512/1024;
|
||||
print "<br><b>$i Logfiles ( $k K bytes ) removed</b><br>\n";
|
||||
|
||||
#
|
||||
# Trim build.dat
|
||||
#
|
||||
$builds_removed = 0;
|
||||
open(BD, "<$tree/build.dat");
|
||||
open(NBD, ">$tree/build.dat.new");
|
||||
while( <BD> ){
|
||||
($mailtime,$buildtime,$buildname) = split( /\|/ );
|
||||
if( $buildtime >= $min_date ){
|
||||
print NBD $_;
|
||||
}
|
||||
else {
|
||||
$builds_removed++;
|
||||
}
|
||||
}
|
||||
close( BD );
|
||||
close( NBD );
|
||||
|
||||
rename( "$tree/build.dat", "$tree/build.dat.old" );
|
||||
rename( "$tree/build.dat.new", "$tree/build.dat" );
|
||||
|
||||
print "<h2>$builds_removed Builds removed from build.dat</h2>\n";
|
||||
}
|
||||
|
||||
sub create_tree {
|
||||
$treename = $form{'treename'};
|
||||
my $repository = $form{'repository'};
|
||||
$modulename = $form{'modulename'};
|
||||
$branchname = $form{'branchname'};
|
||||
|
||||
if( -r $treename ){
|
||||
chmod 0777, $treename;
|
||||
}
|
||||
else {
|
||||
mkdir( $treename, 0777 ) || die "<h1> Cannot mkdir $treename</h1>";
|
||||
}
|
||||
open( F, ">$treename/treedata.pl" );
|
||||
print F "\$cvs_module='$modulename';\n";
|
||||
print F "\$cvs_branch='$branchname';\n";
|
||||
if ($repository ne "") {
|
||||
print F "\$cvs_root='$repository';\n";
|
||||
}
|
||||
close( F );
|
||||
|
||||
open( F, ">$treename/build.dat" );
|
||||
close( F );
|
||||
|
||||
open( F, ">$treename/who.dat" );
|
||||
close( F );
|
||||
|
||||
open( F, ">$treename/notes.txt" );
|
||||
close( F );
|
||||
|
||||
chmod 0777, "$treename/build.dat", "$treename/who.dat", "$treename/notes.txt",
|
||||
"$treename/treedata.pl";
|
||||
|
||||
print "<h2><a href=showbuilds.cgi?tree=$treename>Tree created or modified</a></h2>\n";
|
||||
}
|
||||
|
||||
sub remove_build {
|
||||
$build_name = $form{'build'};
|
||||
|
||||
#
|
||||
# Trim build.dat
|
||||
#
|
||||
$builds_removed = 0;
|
||||
open(BD, "<$tree/build.dat");
|
||||
open(NBD, ">$tree/build.dat.new");
|
||||
while( <BD> ){
|
||||
($mailtime,$buildtime,$bname) = split( /\|/ );
|
||||
if( $bname ne $build_name ){
|
||||
print NBD $_;
|
||||
}
|
||||
else {
|
||||
$builds_removed++;
|
||||
}
|
||||
}
|
||||
close( BD );
|
||||
close( NBD );
|
||||
chmod( 0777, "$tree/build.dat.new");
|
||||
|
||||
rename( "$tree/build.dat", "$tree/build.dat.old" );
|
||||
rename( "$tree/build.dat.new", "$tree/build.dat" );
|
||||
|
||||
print "<h2><a href=showbuilds.cgi?tree=$tree>
|
||||
$builds_removed Builds removed from build.dat</a></h2>\n";
|
||||
}
|
||||
|
||||
sub disable_builds {
|
||||
my $i,%buildnames;
|
||||
$build_name = $form{'build'};
|
||||
|
||||
#
|
||||
# Trim build.dat
|
||||
#
|
||||
open(BD, "<$tree/build.dat");
|
||||
while( <BD> ){
|
||||
($mailtime,$buildtime,$bname) = split( /\|/ );
|
||||
$buildnames{$bname} = 0;
|
||||
}
|
||||
close( BD );
|
||||
|
||||
for $i (keys %form) {
|
||||
if ($i =~ /^build_/ ){
|
||||
$i =~ s/^build_//;
|
||||
$buildnames{$i} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
open(IGNORE, ">$tree/ignorebuilds.pl");
|
||||
print IGNORE '$ignore_builds = {' . "\n";
|
||||
for $i ( sort keys %buildnames ){
|
||||
if( $buildnames{$i} == 0 ){
|
||||
print IGNORE "\t\t'$i' => 1,\n";
|
||||
}
|
||||
}
|
||||
print IGNORE "\t};\n";
|
||||
|
||||
chmod( 0777, "$tree/ignorebuilds.pl");
|
||||
print "<h2><a href=showbuilds.cgi?tree=$treename>Build state Changed</a></h2>\n";
|
||||
}
|
||||
|
||||
|
||||
sub set_message {
|
||||
$m = $form{'message'};
|
||||
$m =~ s/\'/\\'/g;
|
||||
open(MOD, ">$tree/mod.pl");
|
||||
print MOD "\$message_of_day = \'$m\'\;\n1;";
|
||||
close(MOD);
|
||||
chmod( 0777, "$tree/mod.pl");
|
||||
print "<h2><a href=showbuilds.cgi?tree=$tree>
|
||||
Message Changed</a></h2>\n";
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Tinderbox build tool.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
1;
|
||||
#
|
||||
# Scan a line and see if it has an error
|
||||
#
|
||||
sub has_error {
|
||||
$line =~ /fatal error/ # link error
|
||||
|| $line =~ /Error / # C error
|
||||
|| $line =~ /\[checkout aborted\]/ #cvs error
|
||||
|| $line =~ /Couldn\'t find project file / # CW project error
|
||||
;
|
||||
}
|
||||
|
||||
sub has_warning {
|
||||
$line =~ /^[A-Za-z0-9_]+\.[A-Za-z0-9]+\ line [0-9]+/ ;
|
||||
}
|
||||
|
||||
sub has_errorline {
|
||||
local( $line ) = @_;
|
||||
if( $line =~ /^(([A-Za-z0-9_]+\.[A-Za-z0-9]+) line ([0-9]+))/ ){
|
||||
$error_file = $1;
|
||||
$error_file_ref = $2;
|
||||
$error_line = $3;
|
||||
$error_guess = 1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Tinderbox build tool.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
1;
|
||||
#
|
||||
# Scan a line and see if it has an error
|
||||
#
|
||||
sub has_error {
|
||||
$line =~ /fatal error/ # link error
|
||||
|| $line =~ /^C / # cvs merge conflict
|
||||
|| $line =~ / Error: / # C error
|
||||
|| $line =~ / error\([0-9]*\)\:/ # C error
|
||||
|| ($line =~ /gmake/ && $line =~ / Error /)
|
||||
|| $line =~ /\[checkout aborted\]/ #cvs error
|
||||
|| $line =~ /\: cannot find module/ #cvs error
|
||||
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
sub has_warning {
|
||||
$line =~ /^[A-Za-z0-9_]+\.[A-Za-z0-9]+\:[0-9]+\:/
|
||||
|| $line =~ /^\"[A-Za-z0-9_]+\.[A-Za-z0-9]+\"\, line [0-9]+\:/
|
||||
;
|
||||
}
|
||||
|
||||
sub has_errorline {
|
||||
local( $line ) = @_;
|
||||
if( $line =~ /^(([A-Za-z0-9_]+\.[A-Za-z0-9]+)\:([0-9]+)\:)/ ){
|
||||
$error_file = $1;
|
||||
$error_file_ref = $2;
|
||||
$error_line = $3;
|
||||
$error_guess = 1;
|
||||
return 1;
|
||||
}
|
||||
if ( $line =~ /^(\"([A-Za-z0-9_]+\.[A-Za-z0-9]+)\"\, line ([0-9]+)\:)/ ){
|
||||
$error_file = $1;
|
||||
$error_file_ref = $2;
|
||||
$error_line = $3;
|
||||
$error_guess = 1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Tinderbox build tool.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
1;
|
||||
#
|
||||
# Scan a line and see if it has an error
|
||||
#
|
||||
sub has_error {
|
||||
$line =~ /fatal error/ # link error
|
||||
|| $line =~ / error / # C error
|
||||
|| $line =~ /^C / # cvs merge conflict
|
||||
|| $line =~ /error C/ # C error
|
||||
|| $line =~ /Creating new precompiled header/ # Wastes time.
|
||||
|| $line =~ /error:/ # java error
|
||||
|| $line =~ /jmake.MakerFailedException:/ # java error
|
||||
|| $line =~ /Unknown host / # cvs error
|
||||
|| $line =~ /: build failed\;/ # nmake error
|
||||
|| ($line =~ /gmake/ && $line =~ / Error /)
|
||||
|| $line =~ /\[checkout aborted\]/ #cvs error
|
||||
|| $line =~ /\: cannot find module/ #cvs error
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
sub has_warning {
|
||||
$line =~ /: warning/ # link error
|
||||
|| $line =~ / error / # C error
|
||||
;
|
||||
}
|
||||
|
||||
sub has_errorline {
|
||||
local( $line ) = @_;
|
||||
$error_file = ''; #'NS\CMD\WINFE\CXICON.cpp';
|
||||
$error_line = 0;
|
||||
|
||||
if( $line =~ m@(ns([\\/][a-z0-9\._]+)*)@i ){
|
||||
$error_file = $1;
|
||||
$error_file_ref = lc $error_file;
|
||||
$error_file_ref =~ s@\\@/@g;
|
||||
|
||||
$line =~ m/\(([0-9]+)\)/;
|
||||
$error_line = $1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if( $line =~ m@(^([A-Za-z0-9_]+\.[A-Za-z])+\(([0-9]+)\))@ ){
|
||||
$error_file = $1;
|
||||
$error_file_ref = lc $2;
|
||||
$error_line = $3;
|
||||
$error_guess=1;
|
||||
$error_file_ref =~ s@\\@/@g;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
This directory contains example Tinderbox client scripts. These scripts are
|
||||
for illustration/documentation purposes only and are not maintained
|
||||
regularly. Current scripts to build mozilla will live in an another spot
|
||||
in the mozilla tree.
|
||||
|
||||
Three examples have been provided:
|
||||
|
||||
mozilla-windows.pl: perl script that drives mozilla tinderbox builds for Win32
|
||||
mozilla-unix.pl : perl script that drives mozilla tinderbox builds for UNIX
|
||||
build-moz-smoke.pl: perl script that drives mozilla tinderbox builds for UNIX,
|
||||
and subsequently runs the executable returning a green tree only if
|
||||
it does not crash.
|
||||
|
||||
These scripts show the basic elements of a Tinderbox client script. These
|
||||
elements are:
|
||||
|
||||
1) Sending a start e-mail to the Tinderbox server, in the form of a formatted
|
||||
mail message. Example:
|
||||
|
||||
tinderbox: tree: Mozilla
|
||||
tinderbox: builddate: 900002087
|
||||
tinderbox: status: building
|
||||
tinderbox: build: IRIX 6.3 Depend
|
||||
tinderbox: errorparser: unix
|
||||
tinderbox: buildfamily: unix
|
||||
|
||||
2) Obtain a source tree by performing a cvs checkout.
|
||||
|
||||
3) Perform the build, saving the output to a log file.
|
||||
|
||||
4) Determine if the build was successful or failed. This could be done either
|
||||
by checking for the presence of a binary, or being using error codes returned
|
||||
from the compile command.
|
||||
|
||||
5) Send a completion message to Tinderbox, identifying build success or
|
||||
failure. Example:
|
||||
|
||||
tinderbox: tree: Mozilla
|
||||
tinderbox: builddate: 900002087
|
||||
tinderbox: status: success
|
||||
tinderbox: build: IRIX 6.3 Depend
|
||||
tinderbox: errorparser: unix
|
||||
tinderbox: buildfamily: unix
|
||||
|
||||
@@ -1,594 +0,0 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
require 5.000;
|
||||
|
||||
use Sys::Hostname;
|
||||
use POSIX "sys_wait_h";
|
||||
use Cwd;
|
||||
|
||||
$Version = "1.000";
|
||||
|
||||
sub InitVars {
|
||||
|
||||
# PLEASE FILL THIS IN WITH YOUR PROPER EMAIL ADDRESS
|
||||
$BuildAdministrator = "$ENV{'USER'}\@$ENV{'HOST'}";
|
||||
|
||||
#Default values of cmdline opts
|
||||
$BuildDepend = 1; #depend or clobber
|
||||
$ReportStatus = 1; # Send results to server or not
|
||||
$BuildOnce = 0; # Build once, don't send results to server
|
||||
$BuildClassic = 0; # Build classic source
|
||||
|
||||
#relative path to binary
|
||||
$BinaryName{'x'} = 'mozilla-export';
|
||||
$BinaryName{'qt'} = 'qtmozilla-export';
|
||||
$BinaryName{'gnome'} = 'gnuzilla-export';
|
||||
$BinaryName{'webshell'} = '/webshell/tests/viewer/viewer';
|
||||
|
||||
# Set these to what makes sense for your system
|
||||
$cpus = 1;
|
||||
$Make = 'gmake'; # Must be gnu make
|
||||
$mail = '/bin/mail';
|
||||
$Autoconf = 'autoconf -l build/autoconf';
|
||||
$CVS = 'cvs -z3';
|
||||
$CVSCO = 'co -P';
|
||||
|
||||
# Set these proper values for your tinderbox server
|
||||
$Tinderbox_server = 'tinderbox-daemon\@cvs-mirror.mozilla.org';
|
||||
#$Tinderbox_server = 'external-tinderbox-incoming\@tinderbox.seawood.org';
|
||||
|
||||
# These shouldn't really need to be changed
|
||||
$BuildSleep = 10; # Minimum wait period from start of build to start
|
||||
# of next build in minutes
|
||||
$BuildTree = 'SeaMonkey';
|
||||
$BuildTag = '';
|
||||
$BuildName = '';
|
||||
$TopLevel = '.';
|
||||
$Topsrcdir = 'mozilla';
|
||||
$BuildObjName = '';
|
||||
$BuildConfigDir = 'mozilla/config';
|
||||
$ClobberStr = 'realclean';
|
||||
$ConfigureEnvArgs = 'CFLAGS=-pipe CXXFLAGS=-pipe';
|
||||
#$ConfigureEnvArgs = '';
|
||||
$ConfigureArgs = "--with-nspr=/usr/local/nspr --cache-file=/dev/null --with-static-gtk --enable-editor";
|
||||
$ConfigGuess = './build/autoconf/config.guess';
|
||||
$Logfile = '${BuildDir}.log';
|
||||
} #EndSub-InitVars
|
||||
|
||||
sub ConditionalArgs {
|
||||
if ( $BuildClassic ) {
|
||||
$FE = 'x';
|
||||
$ConfigureArgs .= " --enable-fe=$FE";
|
||||
# $BuildTree = 'raptor';
|
||||
$BuildModule = 'Raptor';
|
||||
$BuildTag = ''
|
||||
if ($BuildTag eq '');
|
||||
$TopLevel = "mozilla-classic";
|
||||
} else {
|
||||
# $BuildTree = 'raptor';
|
||||
# $Toolkit = 'gtk';
|
||||
$FE = 'webshell';
|
||||
# $BuildModule = 'Raptor';
|
||||
$BuildModule = 'SeaMonkeyAll';
|
||||
# $ConfigureArgs .= " --enable-toolkit=$Toolkit";
|
||||
}
|
||||
$CVSCO .= " -r $BuildTag" if ( $BuildTag ne '');
|
||||
}
|
||||
sub SetupEnv {
|
||||
umask(0);
|
||||
$ENV{"CVSROOT"} = ':pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot';
|
||||
$ENV{"LD_LIBRARY_PATH"} = '/usr/local/nspr:/builds/tinderbox/SeaMonkey/Linux_2.0.34_clobber/mozilla/obj-i586-pc-linux-gnu/dist/bin:/usr/lib/png:/usr/local/lib';
|
||||
$ENV{"DISPLAY"} = 'crucible.mcom.com:0.0';
|
||||
} #EndSub-SetupEnv
|
||||
|
||||
sub SetupPath {
|
||||
my($Path);
|
||||
$Path = $ENV{PATH};
|
||||
print "Path before: $Path\n";
|
||||
|
||||
if ( $OS eq 'SunOS' ) {
|
||||
$ENV{'PATH'} = '/usr/ccs/bin:' . $ENV{'PATH'};
|
||||
}
|
||||
|
||||
$Path = $ENV{PATH};
|
||||
print "Path After: $Path\n";
|
||||
} #EndSub-SetupPath
|
||||
|
||||
##########################################################################
|
||||
# NO USER CONFIGURABLE PIECES BEYOND THIS POINT #
|
||||
##########################################################################
|
||||
|
||||
sub GetSystemInfo {
|
||||
|
||||
$OS = `uname -s`;
|
||||
$OSVer = `uname -r`;
|
||||
|
||||
chop($OS, $OSVer);
|
||||
|
||||
if ( $OS eq 'AIX' ) {
|
||||
$OSVer = `uname -v`;
|
||||
chop($OSVer);
|
||||
$OSVer = $OSVer . "." . `uname -r`;
|
||||
chop($OSVer);
|
||||
}
|
||||
|
||||
if ( $OS eq 'IRIX64' ) {
|
||||
$OS = 'IRIX';
|
||||
}
|
||||
|
||||
if ( $OS eq 'SCO_SV' ) {
|
||||
$OS = 'SCOOS';
|
||||
$OSVer = '5.0';
|
||||
}
|
||||
|
||||
my $host, $myhost = hostname;
|
||||
chomp($myhost);
|
||||
($host, $junk) = split(/\./, $myhost);
|
||||
|
||||
$BuildName = "";
|
||||
|
||||
if ( "$host" ne "" ) {
|
||||
$BuildName = $host . ' ';
|
||||
}
|
||||
$BuildName .= $OS . ' ' . $OSVer . ' ' . ($BuildDepend?'Depend':'Clobber');
|
||||
$DirName = $OS . '_' . $OSVer . '_' . ($BuildDepend?'depend':'clobber');
|
||||
|
||||
$RealOS = $OS;
|
||||
$RealOSVer = $OSVer;
|
||||
|
||||
if ( $OS eq 'HP-UX' ) {
|
||||
$RealOSVer = substr($OSVer,0,4);
|
||||
}
|
||||
|
||||
if ( $OS eq 'Linux' ) {
|
||||
$RealOSVer = substr($OSVer,0,3);
|
||||
}
|
||||
|
||||
if ($BuildClassic) {
|
||||
$logfile = "${DirName}-classic.log";
|
||||
} else {
|
||||
$logfile = "${DirName}.log";
|
||||
}
|
||||
} #EndSub-GetSystemInfo
|
||||
|
||||
sub BuildIt {
|
||||
my ($fe, @felist, $EarlyExit, $LastTime, $StartTimeStr);
|
||||
|
||||
mkdir("$DirName", 0777);
|
||||
chdir("$DirName") || die "Couldn't enter $DirName";
|
||||
|
||||
$StartDir = getcwd();
|
||||
$LastTime = 0;
|
||||
|
||||
print "Starting dir is : $StartDir\n";
|
||||
|
||||
$EarlyExit = 0;
|
||||
|
||||
while ( ! $EarlyExit ) {
|
||||
chdir("$StartDir");
|
||||
if ( time - $LastTime < (60 * $BuildSleep) ) {
|
||||
$SleepTime = (60 * $BuildSleep) - (time - $LastTime);
|
||||
print "\n\nSleeping $SleepTime seconds ...\n";
|
||||
sleep($SleepTime);
|
||||
}
|
||||
|
||||
$LastTime = time;
|
||||
|
||||
$StartTime = time - 60 * 10;
|
||||
$StartTimeStr = &CVSTime($StartTime);
|
||||
|
||||
&StartBuild if ($ReportStatus);
|
||||
$CurrentDir = getcwd();
|
||||
if ( $CurrentDir ne $StartDir ) {
|
||||
print "startdir: $StartDir, curdir $CurrentDir\n";
|
||||
die "curdir != startdir";
|
||||
}
|
||||
|
||||
$BuildDir = $CurrentDir;
|
||||
|
||||
unlink( "$logfile" );
|
||||
|
||||
print "opening $logfile\n";
|
||||
open( LOG, ">$logfile" ) || print "can't open $?\n";
|
||||
print LOG "current dir is -- $hostname:$CurrentDir\n";
|
||||
print LOG "Build Administrator is $BuildAdministrator\n";
|
||||
&PrintEnv;
|
||||
|
||||
$BuildStatus = 0;
|
||||
|
||||
mkdir($TopLevel, 0777);
|
||||
chdir($TopLevel) || die "chdir($TopLevel): $!\n";
|
||||
|
||||
if ( $BuildClassic ) {
|
||||
print"$CVS $CVSCO $BuildModule\n";
|
||||
print LOG "$CVS $CVSCO $BuildModule\n";
|
||||
open (PULL, "$CVS $CVSCO $BuildModule 2>&1 |") || die "open: $!\n";
|
||||
} else {
|
||||
# print "$CVS $CVSCO mozilla/nglayout.mk\n";
|
||||
# print LOG "$CVS $CVSCO mozilla/nglayout.mk\n";
|
||||
# open (PULL, "$CVS $CVSCO mozilla/nglayout.mk 2>&1 |") || die "open: $!\n";
|
||||
print "$CVS $CVSCO mozilla/client.mk\n";
|
||||
print LOG "$CVS $CVSCO mozilla/client.mk\n";
|
||||
open (PULL, "$CVS $CVSCO mozilla/client.mk 2>&1 |") || die "open: $!\n";
|
||||
}
|
||||
while (<PULL>) {
|
||||
print $_;
|
||||
print LOG $_;
|
||||
}
|
||||
close(PULL);
|
||||
|
||||
# Move to topsrcdir
|
||||
#chdir($Topsrcdir) || die "chdir($Topsrcdir): $!\n";
|
||||
|
||||
|
||||
# Do a separate checkout with toplevel makefile
|
||||
if (! $BuildClassic) {
|
||||
# print LOG "$Make -f nglayout.mk pull_all CVSCO='$CVS $CVSCO'|\n";
|
||||
# open (PULLALL, "$Make -f nglayout.mk pull_all CVSCO='$CVS $CVSCO' |\n");
|
||||
print LOG "$Make -f mozilla/client.mk checkout CVSCO='$CVS $CVSCO'|\n";
|
||||
open (PULLALL, "$Make -f mozilla/client.mk checkout CVSCO='$CVS $CVSCO' |\n");
|
||||
while (<PULLALL>) {
|
||||
print LOG $_;
|
||||
print $_;
|
||||
}
|
||||
close(PULLALL);
|
||||
}
|
||||
|
||||
chdir($Topsrcdir) || die "chdir($Topsrcdir): $!\n";
|
||||
|
||||
print LOG "$Autoconf\n";
|
||||
open (AUTOCONF, "$Autoconf 2>&1 | ") || die "$Autoconf: $!\n";
|
||||
while (<AUTOCONF>) {
|
||||
print LOG $_;
|
||||
print $_;
|
||||
}
|
||||
close(AUTOCONF);
|
||||
|
||||
print LOG "$ConfigGuess\n";
|
||||
$BuildObjName = "obj-";
|
||||
open (GETOBJ, "$ConfigGuess 2>&1 |") || die "$ConfigGuess: $!\n";
|
||||
while (<GETOBJ>) {
|
||||
print $_;
|
||||
print LOG $_;
|
||||
chomp($BuildObjName .= $_);
|
||||
}
|
||||
close (GETOBJ);
|
||||
|
||||
mkdir($BuildObjName, 0777);
|
||||
chdir($BuildObjName) || die "chdir($BuildObjName): $!\n";
|
||||
|
||||
print LOG "$ConfigureEnvArgs ../configure $ConfigureArgs\n";
|
||||
open (CONFIGURE, "$ConfigureEnvArgs ../configure $ConfigureArgs 2>&1 |") || die "../configure: $!\n";
|
||||
while (<CONFIGURE>) {
|
||||
print $_;
|
||||
print LOG $_;
|
||||
}
|
||||
close(CONFIGURE);
|
||||
|
||||
# if we are building depend, rebuild dependencies
|
||||
|
||||
if ($BuildDepend) {
|
||||
print LOG "$Make MAKE='$Make -j $cpus' depend 2>&1 |\n";
|
||||
open ( MAKEDEPEND, "$Make MAKE='$Make -j $cpus' depend 2>&1 |\n");
|
||||
while ( <MAKEDEPEND> ) {
|
||||
print $_;
|
||||
print LOG $_;
|
||||
}
|
||||
close (MAKEDEPEND);
|
||||
system("rm -rf dist");
|
||||
|
||||
} else {
|
||||
# Building clobber
|
||||
print LOG "$Make MAKE='$Make -j $cpus' $ClobberStr 2>&1 |\n";
|
||||
open( MAKECLOBBER, "$Make MAKE='$Make -j $cpus' $ClobberStr 2>&1 |");
|
||||
while ( <MAKECLOBBER> ) {
|
||||
print $_;
|
||||
print LOG $_;
|
||||
}
|
||||
close( MAKECLOBBER );
|
||||
}
|
||||
|
||||
@felist = split(/,/, $FE);
|
||||
|
||||
foreach $fe ( @felist ) {
|
||||
if (&BinaryExists($fe)) {
|
||||
print LOG "deleting existing binary\n";
|
||||
&DeleteBinary($fe);
|
||||
}
|
||||
}
|
||||
|
||||
if ($BuildClassic) {
|
||||
# Build the BE only
|
||||
print LOG "$Make MAKE='$Make -j $cpus' MOZ_FE= 2>&1 |\n";
|
||||
open( BEBUILD, "$Make MAKE='$Make -j $cpus' MOZ_FE= 2>&1 |");
|
||||
|
||||
while ( <BEBUILD> ) {
|
||||
print $_;
|
||||
print LOG $_;
|
||||
}
|
||||
close( BEBUILD );
|
||||
|
||||
foreach $fe ( @felist ) {
|
||||
# Now build each front end
|
||||
print LOG "$Make MAKE='$Make -j $cpus' -C cmd/${fe}fe 2>&1 |\n";
|
||||
open(FEBUILD, "$Make MAKE='$Make -j $cpus' -C cmd/${fe}fe 2>&1 |\n");
|
||||
while (<FEBUILD>) {
|
||||
print $_;
|
||||
print LOG $_;
|
||||
}
|
||||
close(FEBUILD);
|
||||
}
|
||||
} else {
|
||||
print LOG "$Make MAKE='$Make -j $cpus' 2>&1 |\n";
|
||||
open(BUILD, "$Make MAKE='$Make -j $cpus' 2>&1 |\n");
|
||||
while (<BUILD>) {
|
||||
print $_;
|
||||
print LOG $_;
|
||||
}
|
||||
close(BUILD);
|
||||
}
|
||||
|
||||
foreach $fe (@felist) {
|
||||
if (&BinaryExists($fe)) {
|
||||
print LOG "export binary exists, build successful. Testing...\n";
|
||||
#return 0 if no problem, else 333 for a runtime error
|
||||
$BuildStatus = &RunSmokeTest($fe);
|
||||
}
|
||||
else {
|
||||
print LOG "export binary missing, build FAILED\n";
|
||||
$BuildStatus = 666;
|
||||
}
|
||||
|
||||
if ( $BuildStatus == 0 ) {
|
||||
$BuildStatusStr = 'success';
|
||||
}
|
||||
elsif ( $BuildStatus == 333 ) {
|
||||
$BuildStatusStr = 'testfailed';
|
||||
}
|
||||
else {
|
||||
$BuildStatusStr = 'busted';
|
||||
}
|
||||
# replaced by above lines
|
||||
# $BuildStatusStr = ( $BuildStatus ? 'busted' : 'success' );
|
||||
|
||||
print LOG "tinderbox: tree: $BuildTree\n";
|
||||
print LOG "tinderbox: builddate: $StartTime\n";
|
||||
print LOG "tinderbox: status: $BuildStatusStr\n";
|
||||
print LOG "tinderbox: build: $BuildName $fe\n";
|
||||
print LOG "tinderbox: errorparser: unix\n";
|
||||
print LOG "tinderbox: buildfamily: unix\n";
|
||||
print LOG "tinderbox: END\n";
|
||||
}
|
||||
close(LOG);
|
||||
chdir("$StartDir");
|
||||
|
||||
# this fun line added on 2/5/98. do not remove. Translated to english,
|
||||
# that's "take any line longer than 1000 characters, and split it into less
|
||||
# than 1000 char lines. If any of the resulting lines is
|
||||
# a dot on a line by itself, replace that with a blank line."
|
||||
# This is to prevent cases where a <cr>.<cr> occurs in the log file. Sendmail
|
||||
# interprets that as the end of the mail, and truncates the log before
|
||||
# it gets to Tinderbox. (terry weismann, chris yeh)
|
||||
#
|
||||
# This was replaced by a perl 'port' of the above, writen by
|
||||
# preed@netscape.com; good things: no need for system() call, and now it's
|
||||
# all in perl, so we don't have to do OS checking like before.
|
||||
|
||||
open(LOG, "$logfile") || die "Couldn't open logfile: $!\n";
|
||||
open(OUTLOG, ">${logfile}.last") || die "Couldn't open logfile: $!\n";
|
||||
|
||||
while (<LOG>) {
|
||||
$q = 0;
|
||||
|
||||
for (;;) {
|
||||
$val = $q * 1000;
|
||||
$Output = substr($_, $val, 1000);
|
||||
|
||||
last if $Output eq undef;
|
||||
|
||||
$Output =~ s/^\.$//g;
|
||||
$Output =~ s/\n//g;
|
||||
print OUTLOG "$Output\n";
|
||||
$q++;
|
||||
} #EndFor
|
||||
|
||||
} #EndWhile
|
||||
|
||||
close(LOG);
|
||||
close(OUTLOG);
|
||||
|
||||
system( "$mail $Tinderbox_server < ${logfile}.last" )
|
||||
if ($ReportStatus );
|
||||
unlink("$logfile");
|
||||
|
||||
# if this is a test run, set early_exit to 0.
|
||||
#This mean one loop of execution
|
||||
$EarlyExit++ if ($BuildOnce);
|
||||
}
|
||||
|
||||
} #EndSub-BuildIt
|
||||
|
||||
sub CVSTime {
|
||||
my($StartTimeArg) = @_;
|
||||
my($RetTime, $StartTimeArg, $sec, $minute, $hour, $mday, $mon, $year);
|
||||
|
||||
($sec,$minute,$hour,$mday,$mon,$year) = localtime($StartTimeArg);
|
||||
$mon++; # month is 0 based.
|
||||
|
||||
sprintf("%02d/%02d/%02d %02d:%02d:00", $mon,$mday,$year,$hour,$minute );
|
||||
}
|
||||
|
||||
sub StartBuild {
|
||||
|
||||
my($fe, @felist);
|
||||
|
||||
@felist = split(/,/, $FE);
|
||||
|
||||
# die "SERVER: " . $Tinderbox_server . "\n";
|
||||
open( LOG, "|$mail $Tinderbox_server" );
|
||||
foreach $fe ( @felist ) {
|
||||
print LOG "\n";
|
||||
print LOG "tinderbox: tree: $BuildTree\n";
|
||||
print LOG "tinderbox: builddate: $StartTime\n";
|
||||
print LOG "tinderbox: status: building\n";
|
||||
print LOG "tinderbox: build: $BuildName $fe\n";
|
||||
print LOG "tinderbox: errorparser: unix\n";
|
||||
print LOG "tinderbox: buildfamily: unix\n";
|
||||
print LOG "tinderbox: END\n";
|
||||
print LOG "\n";
|
||||
}
|
||||
close( LOG );
|
||||
}
|
||||
|
||||
# check for the existence of the binary
|
||||
sub BinaryExists {
|
||||
my($fe) = @_;
|
||||
my($Binname);
|
||||
$fe = 'x' if (!defined($fe));
|
||||
|
||||
if ($BuildClassic) {
|
||||
$BinName = $BuildDir . '/' . $TopLevel . '/' . $Topsrcdir . '/'. $BuildObjName . "/cmd/${fe}fe/" . $BinaryName{"$fe"};
|
||||
} else {
|
||||
$BinName = $BuildDir . '/' . $TopLevel . '/' . $Topsrcdir . '/' . $BuildObjName . $BinaryName{"$fe"};
|
||||
}
|
||||
print LOG $BinName . "\n";
|
||||
if ((-e $BinName) && (-x $BinName) && (-s $BinName)) {
|
||||
1;
|
||||
}
|
||||
else {
|
||||
0;
|
||||
}
|
||||
}
|
||||
|
||||
sub DeleteBinary {
|
||||
my($fe) = @_;
|
||||
my($BinName);
|
||||
$fe = 'x' if (!defined($fe));
|
||||
|
||||
if ($BuildClassic) {
|
||||
$BinName = $BuildDir . '/' . $TopLevel . '/' . $Topsrcdir . '/' . $BuildObjName . "/cmd/${fe}fe/" . $BinaryName{"$fe"};
|
||||
} else {
|
||||
$BinName = $BuildDir . '/' . $TopLevel . '/' . $Topsrcdir . '/' . $BuildObjName . $BinaryName{"$fe"};
|
||||
}
|
||||
print LOG "unlinking $BinName\n";
|
||||
unlink ($BinName) || print LOG "unlinking $BinName failed\n";
|
||||
}
|
||||
|
||||
sub ParseArgs {
|
||||
my($i, $manArg);
|
||||
|
||||
if( @ARGV == 0 ) {
|
||||
&PrintUsage;
|
||||
}
|
||||
$i = 0;
|
||||
$manArg = 0;
|
||||
while( $i < @ARGV ) {
|
||||
if ($ARGV[$i] eq '--depend') {
|
||||
$BuildDepend = 1;
|
||||
$manArg++;
|
||||
}
|
||||
elsif ($ARGV[$i] eq '--clobber') {
|
||||
$BuildDepend = 0;
|
||||
$manArg++;
|
||||
}
|
||||
elsif ( $ARGV[$i] eq '--once' ) {
|
||||
$BuildOnce = 1;
|
||||
#$ReportStatus = 0;
|
||||
}
|
||||
elsif ($ARGV[$i] eq '--classic') {
|
||||
$BuildClassic = 1;
|
||||
}
|
||||
elsif ($ARGV[$i] eq '--noreport') {
|
||||
$ReportStatus = 0;
|
||||
}
|
||||
elsif ($ARGV[$i] eq '--version' || $ARGV[$i] eq '-v') {
|
||||
die "$0: version $Version\n";
|
||||
}
|
||||
elsif ( $ARGV[$i] eq '-tag' ) {
|
||||
$i++;
|
||||
$BuildTag = $ARGV[$i];
|
||||
if ( $BuildTag eq '' || $BuildTag eq '-t') {
|
||||
&PrintUsage;
|
||||
}
|
||||
}
|
||||
elsif ( $ARGV[$i] eq '-t' ) {
|
||||
$i++;
|
||||
$BuildTree = $ARGV[$i];
|
||||
if ( $BuildTree eq '' ) {
|
||||
&PrintUsage;
|
||||
}
|
||||
} else {
|
||||
&PrintUsage;
|
||||
}
|
||||
|
||||
$i++;
|
||||
} #EndWhile
|
||||
|
||||
if ( $BuildTree =~ /^\s+$/i ) {
|
||||
&PrintUsage;
|
||||
}
|
||||
|
||||
if ($BuildDepend eq undef) {
|
||||
&PrintUsage;
|
||||
}
|
||||
|
||||
&PrintUsage if (! $manArg );
|
||||
|
||||
} #EndSub-ParseArgs
|
||||
|
||||
sub PrintUsage {
|
||||
die "usage: $0 [--depend | --clobber] [-v | --version ] [--once --classic --noreport -tag TREETAG -t TREENAME ]\n";
|
||||
}
|
||||
|
||||
sub PrintEnv {
|
||||
my ($key);
|
||||
foreach $key (keys %ENV) {
|
||||
print LOG "$key = $ENV{$key}\n";
|
||||
print "$key = $ENV{$key}\n";
|
||||
}
|
||||
} #EndSub-PrintEnv
|
||||
|
||||
sub RunSmokeTest {
|
||||
my($fe) = @_;
|
||||
my($Binary);
|
||||
$fe = 'x' if (!defined($fe));
|
||||
|
||||
$Binary = $BuildDir . '/' . $TopLevel . '/' . $Topsrcdir . '/' . $BuildObjName . $BinaryName{"$fe"};
|
||||
print LOG $BinName . "\n";
|
||||
|
||||
$waittime = 30;
|
||||
|
||||
$pid = fork;
|
||||
|
||||
exec $Binary if !$pid;
|
||||
|
||||
# parent - wait $waittime seconds then check on child
|
||||
sleep $waittime;
|
||||
$status = waitpid $pid, WNOHANG();
|
||||
if ($status != 0) {
|
||||
print LOG "$BinName has crashed or quit. Turn the tree orange now.\n";
|
||||
return 333;
|
||||
}
|
||||
|
||||
print LOG "Success! $BinName is still running. Killing..\n";
|
||||
# try to kill 3 times, then try a kill -9
|
||||
for ($i=0 ; $i<3 ; $i++) {
|
||||
kill 'TERM',$pid,;
|
||||
# give it 3 seconds to actually die
|
||||
sleep 3;
|
||||
$status = waitpid $pid, WNOHANG();
|
||||
last if ($status != 0);
|
||||
}
|
||||
return 0;
|
||||
} #EndSub-RunSmokeTest
|
||||
|
||||
# Main function
|
||||
&InitVars;
|
||||
&ParseArgs;
|
||||
&ConditionalArgs;
|
||||
&GetSystemInfo;
|
||||
&SetupEnv;
|
||||
&SetupPath;
|
||||
&BuildIt;
|
||||
|
||||
1;
|
||||
@@ -1,63 +0,0 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
sub InitVars {
|
||||
|
||||
#initialize variables
|
||||
#$binary_name = '/netscape-export';
|
||||
$BinaryName = '/mozilla-export';
|
||||
$BuildDepend = 1; #depend or clobber
|
||||
$BuildTree = '';
|
||||
$BuildTag = '';
|
||||
$BuildName = '';
|
||||
#$BuildContinue = 0;
|
||||
$TopLevel = 'mozilla/';
|
||||
$BuildObjName = '';
|
||||
$BuildSleep = 10;
|
||||
$BuildUnixclasses = 0;
|
||||
$EarlyExit = 1;
|
||||
$BuildStartDir = 'ns/';
|
||||
$BuildConfigDir = 'mozilla/config';
|
||||
|
||||
} #EndSub-InitVars
|
||||
|
||||
sub SetupEnv {
|
||||
|
||||
umask(0);
|
||||
$ENV{'MOZILLA_CLIENT'} = 1;
|
||||
$ENV{'NETSCAPE_HIERARCHY'} = 1;
|
||||
$ENV{'BUILD_OFFICIAL'} = 1;
|
||||
$ENV{'NSPR20'} = 1;
|
||||
$ENV{'AWT_11'} = 1;
|
||||
$ENV{'MOZ_SECURITY'} = 1;
|
||||
$ENV{"CVSROOT"} = '/m/src';
|
||||
$ENV{"MAKE"} = 'gmake -e';
|
||||
$ENV{'MOZ_MEDIUM'} = 1;
|
||||
$ENV{'NO_MDUPDATE'} = 1;
|
||||
$ENV{'EDITOR'} = 1;
|
||||
|
||||
} #EndSub-SetupEnv
|
||||
|
||||
sub SetupPath {
|
||||
|
||||
my($Path);
|
||||
$Path = $ENV{PATH};
|
||||
print "Path before: $Path\n";
|
||||
$ENV{'PATH'} = '/tools/ns/bin:/tools/contrib/bin:/usr/local/bin:/usr/sbin:/usr/bsd:/sbin:/usr/bin:/bin:/usr/bin/X11:/usr/etc:/usr/hosts:/usr/ucb:';
|
||||
|
||||
# This won't work on x86 or sunos4 systems....
|
||||
if ( $OS eq 'SunOS' ) {
|
||||
$ENV{'PATH'} = '/usr/ccs/bin:/tools/ns/soft/gcc-2.6.3/run/default/sparc_sun_solaris2.4/bin:' . $ENV{'PATH'};
|
||||
$ENV{'NO_MDUPDATE'} = 1;
|
||||
}
|
||||
|
||||
if ( $OS eq 'AIX' ) {
|
||||
$ENV{'PATH'} = $ENV{'PATH'} . '/usr/lpp/xlC/bin:/usr/local-aix/bin:';
|
||||
}
|
||||
|
||||
$Path = $ENV{PATH};
|
||||
print "Path After: $Path\n";
|
||||
|
||||
} #EndSub-SetupPath
|
||||
|
||||
|
||||
1;
|
||||
@@ -1,548 +0,0 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
require 5.000;
|
||||
|
||||
use Sys::Hostname;
|
||||
use Cwd;
|
||||
|
||||
$Version = "1.000";
|
||||
|
||||
sub InitVars {
|
||||
|
||||
# PLEASE FILL THIS IN WITH YOUR PROPER EMAIL ADDRESS
|
||||
$BuildAdministrator = "$ENV{'USER'}\@$ENV{'HOST'}";
|
||||
|
||||
#Default values of cmdline opts
|
||||
$BuildDepend = 1; #depend or clobber
|
||||
$ReportStatus = 1; # Send results to server or not
|
||||
$BuildOnce = 0; # Build once, don't send results to server
|
||||
$BuildClassic = 0; # Build classic source
|
||||
|
||||
#relative path to binary
|
||||
$BinaryName{'x'} = 'mozilla-export';
|
||||
$BinaryName{'qt'} = 'qtmozilla-export';
|
||||
$BinaryName{'gnome'} = 'gnuzilla-export';
|
||||
$BinaryName{'webshell'} = '/webshell/tests/viewer/viewer';
|
||||
$BinaryName{'xpfe'} = '/xpfe/xpviewer/src/xpviewer';
|
||||
|
||||
# Set these to what makes sense for your system
|
||||
$cpus = 1;
|
||||
$Make = 'gmake'; # Must be gnu make
|
||||
$mail = '/bin/mail';
|
||||
$Autoconf = 'autoconf -l build/autoconf';
|
||||
$CVS = 'cvs -z3';
|
||||
$CVSCO = 'co -P';
|
||||
|
||||
# Set these proper values for your tinderbox server
|
||||
$Tinderbox_server = 'tinderbox-daemon\@warp.mcom.com';
|
||||
#$Tinderbox_server = 'external-tinderbox-incoming\@tinderbox.seawood.org';
|
||||
|
||||
# These shouldn't really need to be changed
|
||||
$BuildSleep = 10; # Minimum wait period from start of build to start
|
||||
# of next build in minutes
|
||||
$BuildTree = 'raptor';
|
||||
$BuildTag = '';
|
||||
$BuildName = '';
|
||||
$TopLevel = '.';
|
||||
$Topsrcdir = 'mozilla';
|
||||
$BuildObjName = '';
|
||||
$BuildConfigDir = 'mozilla/config';
|
||||
$ClobberStr = 'realclean';
|
||||
$ConfigureEnvArgs = 'CFLAGS=-pipe CXXFLAGS=-pipe';
|
||||
#$ConfigureEnvArgs = '';
|
||||
$ConfigureArgs = "--cache-file=/dev/null";
|
||||
$ConfigGuess = './build/autoconf/config.guess';
|
||||
$Logfile = '${BuildDir}.log';
|
||||
} #EndSub-InitVars
|
||||
|
||||
sub ConditionalArgs {
|
||||
if ( $BuildClassic ) {
|
||||
$FE = 'x';
|
||||
$ConfigureArgs .= " --enable-fe=$FE";
|
||||
$BuildTree = 'raptor';
|
||||
$BuildModule = 'Raptor';
|
||||
$BuildTag = ''
|
||||
if ($BuildTag eq '');
|
||||
$TopLevel = "mozilla-classic";
|
||||
} else {
|
||||
$BuildTree = 'raptor';
|
||||
# $Toolkit = 'gtk';
|
||||
$FE = 'webshell,xpfe';
|
||||
$BuildModule = 'Raptor';
|
||||
# $ConfigureArgs .= " --enable-toolkit=$Toolkit";
|
||||
}
|
||||
$CVSCO .= " -r $BuildTag" if ( $BuildTag ne '');
|
||||
}
|
||||
sub SetupEnv {
|
||||
umask(0);
|
||||
$ENV{"CVSROOT"} = ':pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot';
|
||||
} #EndSub-SetupEnv
|
||||
|
||||
sub SetupPath {
|
||||
my($Path);
|
||||
$Path = $ENV{PATH};
|
||||
print "Path before: $Path\n";
|
||||
|
||||
if ( $OS eq 'SunOS' ) {
|
||||
$ENV{'PATH'} = '/usr/ccs/bin:' . $ENV{'PATH'};
|
||||
}
|
||||
|
||||
$Path = $ENV{PATH};
|
||||
print "Path After: $Path\n";
|
||||
} #EndSub-SetupPath
|
||||
|
||||
##########################################################################
|
||||
# NO USER CONFIGURABLE PIECES BEYOND THIS POINT #
|
||||
##########################################################################
|
||||
|
||||
sub GetSystemInfo {
|
||||
|
||||
$OS = `uname -s`;
|
||||
$OSVer = `uname -r`;
|
||||
|
||||
chop($OS, $OSVer);
|
||||
|
||||
if ( $OS eq 'AIX' ) {
|
||||
$OSVer = `uname -v`;
|
||||
chop($OSVer);
|
||||
$OSVer = $OSVer . "." . `uname -r`;
|
||||
chop($OSVer);
|
||||
}
|
||||
|
||||
if ( $OS eq 'IRIX64' ) {
|
||||
$OS = 'IRIX';
|
||||
}
|
||||
|
||||
if ( $OS eq 'SCO_SV' ) {
|
||||
$OS = 'SCOOS';
|
||||
$OSVer = '5.0';
|
||||
}
|
||||
|
||||
my $host, $myhost = hostname;
|
||||
chomp($myhost);
|
||||
($host, $junk) = split(/\./, $myhost);
|
||||
|
||||
$BuildName = "";
|
||||
|
||||
if ( "$host" ne "" ) {
|
||||
$BuildName = $host . ' ';
|
||||
}
|
||||
$BuildName .= $OS . ' ' . $OSVer . ' ' . ($BuildDepend?'Depend':'Clobber');
|
||||
$DirName = $OS . '_' . $OSVer . '_' . ($BuildDepend?'depend':'clobber');
|
||||
|
||||
$RealOS = $OS;
|
||||
$RealOSVer = $OSVer;
|
||||
|
||||
if ( $OS eq 'HP-UX' ) {
|
||||
$RealOSVer = substr($OSVer,0,4);
|
||||
}
|
||||
|
||||
if ( $OS eq 'Linux' ) {
|
||||
$RealOSVer = substr($OSVer,0,3);
|
||||
}
|
||||
|
||||
if ($BuildClassic) {
|
||||
$logfile = "${DirName}-classic.log";
|
||||
} else {
|
||||
$logfile = "${DirName}.log";
|
||||
}
|
||||
} #EndSub-GetSystemInfo
|
||||
|
||||
sub BuildIt {
|
||||
my ($fe, @felist, $EarlyExit, $LastTime, $StartTimeStr);
|
||||
|
||||
mkdir("$DirName", 0777);
|
||||
chdir("$DirName") || die "Couldn't enter $DirName";
|
||||
|
||||
$StartDir = getcwd();
|
||||
$LastTime = 0;
|
||||
|
||||
print "Starting dir is : $StartDir\n";
|
||||
|
||||
$EarlyExit = 0;
|
||||
|
||||
while ( ! $EarlyExit ) {
|
||||
chdir("$StartDir");
|
||||
if ( time - $LastTime < (60 * $BuildSleep) ) {
|
||||
$SleepTime = (60 * $BuildSleep) - (time - $LastTime);
|
||||
print "\n\nSleeping $SleepTime seconds ...\n";
|
||||
sleep($SleepTime);
|
||||
}
|
||||
|
||||
$LastTime = time;
|
||||
|
||||
$StartTime = time - 60 * 10;
|
||||
$StartTimeStr = &CVSTime($StartTime);
|
||||
|
||||
&StartBuild if ($ReportStatus);
|
||||
$CurrentDir = getcwd();
|
||||
if ( $CurrentDir ne $StartDir ) {
|
||||
print "startdir: $StartDir, curdir $CurrentDir\n";
|
||||
die "curdir != startdir";
|
||||
}
|
||||
|
||||
$BuildDir = $CurrentDir;
|
||||
|
||||
unlink( "$logfile" );
|
||||
|
||||
print "opening $logfile\n";
|
||||
open( LOG, ">$logfile" ) || print "can't open $?\n";
|
||||
print LOG "current dir is -- $hostname:$CurrentDir\n";
|
||||
print LOG "Build Administrator is $BuildAdministrator\n";
|
||||
&PrintEnv;
|
||||
|
||||
$BuildStatus = 0;
|
||||
|
||||
mkdir($TopLevel, 0777);
|
||||
chdir($TopLevel) || die "chdir($TopLevel): $!\n";
|
||||
|
||||
if ( $BuildClassic ) {
|
||||
print"$CVS $CVSCO $BuildModule\n";
|
||||
print LOG "$CVS $CVSCO $BuildModule\n";
|
||||
open (PULL, "$CVS $CVSCO $BuildModule 2>&1 |") || die "open: $!\n";
|
||||
} else {
|
||||
# print "$CVS $CVSCO mozilla/nglayout.mk\n";
|
||||
# print LOG "$CVS $CVSCO mozilla/nglayout.mk\n";
|
||||
# open (PULL, "$CVS $CVSCO mozilla/nglayout.mk 2>&1 |") || die "open: $!\n";
|
||||
print "$CVS $CVSCO mozilla/client.mk\n";
|
||||
print LOG "$CVS $CVSCO mozilla/client.mk\n";
|
||||
open (PULL, "$CVS $CVSCO mozilla/client.mk 2>&1 |") || die "open: $!\n";
|
||||
}
|
||||
while (<PULL>) {
|
||||
print $_;
|
||||
print LOG $_;
|
||||
}
|
||||
close(PULL);
|
||||
|
||||
# Move to topsrcdir
|
||||
#chdir($Topsrcdir) || die "chdir($Topsrcdir): $!\n";
|
||||
|
||||
|
||||
# Do a separate checkout with toplevel makefile
|
||||
if (! $BuildClassic) {
|
||||
# print LOG "$Make -f nglayout.mk pull_all CVSCO='$CVS $CVSCO'|\n";
|
||||
# open (PULLALL, "$Make -f nglayout.mk pull_all CVSCO='$CVS $CVSCO' |\n");
|
||||
print LOG "$Make -f mozilla/client.mk checkout CVSCO='$CVS $CVSCO'|\n";
|
||||
open (PULLALL, "$Make -f mozilla/client.mk checkout CVSCO='$CVS $CVSCO' |\n");
|
||||
while (<PULLALL>) {
|
||||
print LOG $_;
|
||||
print $_;
|
||||
}
|
||||
close(PULLALL);
|
||||
}
|
||||
|
||||
chdir($Topsrcdir) || die "chdir($Topsrcdir): $!\n";
|
||||
|
||||
print LOG "$Autoconf\n";
|
||||
open (AUTOCONF, "$Autoconf 2>&1 | ") || die "$Autoconf: $!\n";
|
||||
while (<AUTOCONF>) {
|
||||
print LOG $_;
|
||||
print $_;
|
||||
}
|
||||
close(AUTOCONF);
|
||||
|
||||
print LOG "$ConfigGuess\n";
|
||||
$BuildObjName = "obj-";
|
||||
open (GETOBJ, "$ConfigGuess 2>&1 |") || die "$ConfigGuess: $!\n";
|
||||
while (<GETOBJ>) {
|
||||
print $_;
|
||||
print LOG $_;
|
||||
chomp($BuildObjName .= $_);
|
||||
}
|
||||
close (GETOBJ);
|
||||
|
||||
mkdir($BuildObjName, 0777);
|
||||
chdir($BuildObjName) || die "chdir($BuildObjName): $!\n";
|
||||
|
||||
print LOG "$ConfigureEnvArgs ../configure $ConfigureArgs\n";
|
||||
open (CONFIGURE, "$ConfigureEnvArgs ../configure $ConfigureArgs 2>&1 |") || die "../configure: $!\n";
|
||||
while (<CONFIGURE>) {
|
||||
print $_;
|
||||
print LOG $_;
|
||||
}
|
||||
close(CONFIGURE);
|
||||
|
||||
# if we are building depend, rebuild dependencies
|
||||
|
||||
if ($BuildDepend) {
|
||||
print LOG "$Make MAKE='$Make -j $cpus' depend 2>&1 |\n";
|
||||
open ( MAKEDEPEND, "$Make MAKE='$Make -j $cpus' depend 2>&1 |\n");
|
||||
while ( <MAKEDEPEND> ) {
|
||||
print $_;
|
||||
print LOG $_;
|
||||
}
|
||||
close (MAKEDEPEND);
|
||||
system("rm -rf dist");
|
||||
|
||||
} else {
|
||||
# Building clobber
|
||||
print LOG "$Make MAKE='$Make -j $cpus' $ClobberStr 2>&1 |\n";
|
||||
open( MAKECLOBBER, "$Make MAKE='$Make -j $cpus' $ClobberStr 2>&1 |");
|
||||
while ( <MAKECLOBBER> ) {
|
||||
print $_;
|
||||
print LOG $_;
|
||||
}
|
||||
close( MAKECLOBBER );
|
||||
}
|
||||
|
||||
@felist = split(/,/, $FE);
|
||||
|
||||
foreach $fe ( @felist ) {
|
||||
if (&BinaryExists($fe)) {
|
||||
print LOG "deleting existing binary\n";
|
||||
&DeleteBinary($fe);
|
||||
}
|
||||
}
|
||||
|
||||
if ($BuildClassic) {
|
||||
# Build the BE only
|
||||
print LOG "$Make MAKE='$Make -j $cpus' MOZ_FE= 2>&1 |\n";
|
||||
open( BEBUILD, "$Make MAKE='$Make -j $cpus' MOZ_FE= 2>&1 |");
|
||||
|
||||
while ( <BEBUILD> ) {
|
||||
print $_;
|
||||
print LOG $_;
|
||||
}
|
||||
close( BEBUILD );
|
||||
|
||||
foreach $fe ( @felist ) {
|
||||
# Now build each front end
|
||||
print LOG "$Make MAKE='$Make -j $cpus' -C cmd/${fe}fe 2>&1 |\n";
|
||||
open(FEBUILD, "$Make MAKE='$Make -j $cpus' -C cmd/${fe}fe 2>&1 |\n");
|
||||
while (<FEBUILD>) {
|
||||
print $_;
|
||||
print LOG $_;
|
||||
}
|
||||
close(FEBUILD);
|
||||
}
|
||||
} else {
|
||||
print LOG "$Make MAKE='$Make -j $cpus' 2>&1 |\n";
|
||||
open(BUILD, "$Make MAKE='$Make -j $cpus' 2>&1 |\n");
|
||||
while (<BUILD>) {
|
||||
print $_;
|
||||
print LOG $_;
|
||||
}
|
||||
close(BUILD);
|
||||
}
|
||||
|
||||
foreach $fe (@felist) {
|
||||
if (&BinaryExists($fe)) {
|
||||
print LOG "export binary exists, build SUCCESSFUL!\n";
|
||||
$BuildStatus = 0;
|
||||
}
|
||||
else {
|
||||
print LOG "export binary missing, build FAILED\n";
|
||||
$BuildStatus = 666;
|
||||
}
|
||||
|
||||
print LOG "\nBuild Status = $BuildStatus\n";
|
||||
|
||||
$BuildStatusStr = ( $BuildStatus ? 'busted' : 'success' );
|
||||
|
||||
print LOG "tinderbox: tree: $BuildTree\n";
|
||||
print LOG "tinderbox: builddate: $StartTime\n";
|
||||
print LOG "tinderbox: status: $BuildStatusStr\n";
|
||||
print LOG "tinderbox: build: $BuildName $fe\n";
|
||||
print LOG "tinderbox: errorparser: unix\n";
|
||||
print LOG "tinderbox: buildfamily: unix\n";
|
||||
print LOG "tinderbox: END\n";
|
||||
}
|
||||
close(LOG);
|
||||
chdir("$StartDir");
|
||||
|
||||
# this fun line added on 2/5/98. do not remove. Translated to english,
|
||||
# that's "take any line longer than 1000 characters, and split it into less
|
||||
# than 1000 char lines. If any of the resulting lines is
|
||||
# a dot on a line by itself, replace that with a blank line."
|
||||
# This is to prevent cases where a <cr>.<cr> occurs in the log file. Sendmail
|
||||
# interprets that as the end of the mail, and truncates the log before
|
||||
# it gets to Tinderbox. (terry weismann, chris yeh)
|
||||
#
|
||||
# This was replaced by a perl 'port' of the above, writen by
|
||||
# preed@netscape.com; good things: no need for system() call, and now it's
|
||||
# all in perl, so we don't have to do OS checking like before.
|
||||
|
||||
open(LOG, "$logfile") || die "Couldn't open logfile: $!\n";
|
||||
open(OUTLOG, ">${logfile}.last") || die "Couldn't open logfile: $!\n";
|
||||
|
||||
while (<LOG>) {
|
||||
$q = 0;
|
||||
|
||||
for (;;) {
|
||||
$val = $q * 1000;
|
||||
$Output = substr($_, $val, 1000);
|
||||
|
||||
last if $Output eq undef;
|
||||
|
||||
$Output =~ s/^\.$//g;
|
||||
$Output =~ s/\n//g;
|
||||
print OUTLOG "$Output\n";
|
||||
$q++;
|
||||
} #EndFor
|
||||
|
||||
} #EndWhile
|
||||
|
||||
close(LOG);
|
||||
close(OUTLOG);
|
||||
|
||||
system( "$mail $Tinderbox_server < ${logfile}.last" )
|
||||
if ($ReportStatus );
|
||||
unlink("$logfile");
|
||||
|
||||
# if this is a test run, set early_exit to 0.
|
||||
#This mean one loop of execution
|
||||
$EarlyExit++ if ($BuildOnce);
|
||||
}
|
||||
|
||||
} #EndSub-BuildIt
|
||||
|
||||
sub CVSTime {
|
||||
my($StartTimeArg) = @_;
|
||||
my($RetTime, $StartTimeArg, $sec, $minute, $hour, $mday, $mon, $year);
|
||||
|
||||
($sec,$minute,$hour,$mday,$mon,$year) = localtime($StartTimeArg);
|
||||
$mon++; # month is 0 based.
|
||||
|
||||
sprintf("%02d/%02d/%02d %02d:%02d:00", $mon,$mday,$year,$hour,$minute );
|
||||
}
|
||||
|
||||
sub StartBuild {
|
||||
|
||||
my($fe, @felist);
|
||||
|
||||
@felist = split(/,/, $FE);
|
||||
|
||||
# die "SERVER: " . $Tinderbox_server . "\n";
|
||||
open( LOG, "|$mail $Tinderbox_server" );
|
||||
foreach $fe ( @felist ) {
|
||||
print LOG "\n";
|
||||
print LOG "tinderbox: tree: $BuildTree\n";
|
||||
print LOG "tinderbox: builddate: $StartTime\n";
|
||||
print LOG "tinderbox: status: building\n";
|
||||
print LOG "tinderbox: build: $BuildName $fe\n";
|
||||
print LOG "tinderbox: errorparser: unix\n";
|
||||
print LOG "tinderbox: buildfamily: unix\n";
|
||||
print LOG "tinderbox: END\n";
|
||||
print LOG "\n";
|
||||
}
|
||||
close( LOG );
|
||||
}
|
||||
|
||||
# check for the existence of the binary
|
||||
sub BinaryExists {
|
||||
my($fe) = @_;
|
||||
my($Binname);
|
||||
$fe = 'x' if (!defined($fe));
|
||||
|
||||
if ($BuildClassic) {
|
||||
$BinName = $BuildDir . '/' . $TopLevel . '/' . $Topsrcdir . '/'. $BuildObjName . "/cmd/${fe}fe/" . $BinaryName{"$fe"};
|
||||
} else {
|
||||
$BinName = $BuildDir . '/' . $TopLevel . '/' . $Topsrcdir . '/' . $BuildObjName . $BinaryName{"$fe"};
|
||||
}
|
||||
print LOG $BinName . "\n";
|
||||
if ((-e $BinName) && (-x $BinName) && (-s $BinName)) {
|
||||
1;
|
||||
}
|
||||
else {
|
||||
0;
|
||||
}
|
||||
}
|
||||
|
||||
sub DeleteBinary {
|
||||
my($fe) = @_;
|
||||
my($BinName);
|
||||
$fe = 'x' if (!defined($fe));
|
||||
|
||||
if ($BuildClassic) {
|
||||
$BinName = $BuildDir . '/' . $TopLevel . '/' . $Topsrcdir . '/' . $BuildObjName . "/cmd/${fe}fe/" . $BinaryName{"$fe"};
|
||||
} else {
|
||||
$BinName = $BuildDir . '/' . $TopLevel . '/' . $Topsrcdir . '/' . $BuildObjName . $BinaryName{"$fe"};
|
||||
}
|
||||
print LOG "unlinking $BinName\n";
|
||||
unlink ($BinName) || print LOG "unlinking $BinName failed\n";
|
||||
}
|
||||
|
||||
sub ParseArgs {
|
||||
my($i, $manArg);
|
||||
|
||||
if( @ARGV == 0 ) {
|
||||
&PrintUsage;
|
||||
}
|
||||
$i = 0;
|
||||
$manArg = 0;
|
||||
while( $i < @ARGV ) {
|
||||
if ($ARGV[$i] eq '--depend') {
|
||||
$BuildDepend = 1;
|
||||
$manArg++;
|
||||
}
|
||||
elsif ($ARGV[$i] eq '--clobber') {
|
||||
$BuildDepend = 0;
|
||||
$manArg++;
|
||||
}
|
||||
elsif ( $ARGV[$i] eq '--once' ) {
|
||||
$BuildOnce = 1;
|
||||
#$ReportStatus = 0;
|
||||
}
|
||||
elsif ($ARGV[$i] eq '--classic') {
|
||||
$BuildClassic = 1;
|
||||
}
|
||||
elsif ($ARGV[$i] eq '--noreport') {
|
||||
$ReportStatus = 0;
|
||||
}
|
||||
elsif ($ARGV[$i] eq '--version' || $ARGV[$i] eq '-v') {
|
||||
die "$0: version $Version\n";
|
||||
}
|
||||
elsif ( $ARGV[$i] eq '-tag' ) {
|
||||
$i++;
|
||||
$BuildTag = $ARGV[$i];
|
||||
if ( $BuildTag eq '' || $BuildTag eq '-t') {
|
||||
&PrintUsage;
|
||||
}
|
||||
}
|
||||
elsif ( $ARGV[$i] eq '-t' ) {
|
||||
$i++;
|
||||
$BuildTree = $ARGV[$i];
|
||||
if ( $BuildTree eq '' ) {
|
||||
&PrintUsage;
|
||||
}
|
||||
} else {
|
||||
&PrintUsage;
|
||||
}
|
||||
|
||||
$i++;
|
||||
} #EndWhile
|
||||
|
||||
if ( $BuildTree =~ /^\s+$/i ) {
|
||||
&PrintUsage;
|
||||
}
|
||||
|
||||
if ($BuildDepend eq undef) {
|
||||
&PrintUsage;
|
||||
}
|
||||
|
||||
&PrintUsage if (! $manArg );
|
||||
|
||||
} #EndSub-ParseArgs
|
||||
|
||||
sub PrintUsage {
|
||||
die "usage: $0 [--depend | --clobber] [-v | --version ] [--once --classic --noreport -tag TREETAG -t TREENAME ]\n";
|
||||
}
|
||||
|
||||
sub PrintEnv {
|
||||
my ($key);
|
||||
foreach $key (keys %ENV) {
|
||||
print LOG "$key = $ENV{$key}\n";
|
||||
print "$key = $ENV{$key}\n";
|
||||
}
|
||||
} #EndSub-PrintEnv
|
||||
|
||||
# Main function
|
||||
&InitVars;
|
||||
&ParseArgs;
|
||||
&ConditionalArgs;
|
||||
&GetSystemInfo;
|
||||
&SetupEnv;
|
||||
&SetupPath;
|
||||
&BuildIt;
|
||||
|
||||
1;
|
||||
@@ -1,416 +0,0 @@
|
||||
#!c:/nstools/bin/perl5
|
||||
|
||||
use Cwd;
|
||||
|
||||
$build_depend=1; #depend or clobber
|
||||
$build_tree = '';
|
||||
$build_tag = '';
|
||||
$build_name = '';
|
||||
$build_continue = 0;
|
||||
$build_sleep=10;
|
||||
$no32 = 0;
|
||||
$no16 = 0;
|
||||
$original_path = $ENV{'PATH'};
|
||||
$early_exit = 1;
|
||||
$doawt11 = 0;
|
||||
|
||||
$do_clobber = '';
|
||||
$client_param = 'pull_and_build_all';
|
||||
|
||||
&parse_args;
|
||||
|
||||
if( $build_test ){
|
||||
$build_sleep=1;
|
||||
}
|
||||
|
||||
$dirname = ($build_depend?'dep':'clob');
|
||||
|
||||
|
||||
$logfile = "${dirname}.log";
|
||||
|
||||
if( $build_depend ){
|
||||
$clobber_str = 'depend';
|
||||
}
|
||||
else {
|
||||
$clobber_str = 'clobber_all';
|
||||
}
|
||||
|
||||
|
||||
mkdir("$dirname", 0777);
|
||||
chdir("$dirname") || die "couldn't cd to $dirname";
|
||||
|
||||
$start_dir = cwd;
|
||||
$last_time = 0;
|
||||
|
||||
print "starting dir is :$start_dir\n";
|
||||
|
||||
|
||||
while( $early_exit ){
|
||||
chdir("$start_dir");
|
||||
if( time - $last_time < (60 * $build_sleep) ){
|
||||
$sleep_time = (60 * $build_sleep) - (time - $last_time);
|
||||
print "\n\nSleeping $sleep_time seconds ...\n";
|
||||
sleep( $sleep_time );
|
||||
}
|
||||
$last_time = time;
|
||||
|
||||
$start_time = time-60*10;
|
||||
$start_time_str = &cvs_time( $start_time );
|
||||
# call setup_env here in the loop, to update MOZ_DATE with each pass.
|
||||
# setup_env uses start_time_str for MOZ_DATE.
|
||||
&setup_env;
|
||||
|
||||
|
||||
$cur_dir = cwd;
|
||||
|
||||
if( $cur_dir ne $start_dir ){
|
||||
print "startdir: $start_dir, curdir $cur_dir\n";
|
||||
die "curdir != startdir";
|
||||
}
|
||||
|
||||
# build 32-bit with AWT_11=1
|
||||
&setup32("1");
|
||||
if( !$no32 ){
|
||||
if( !$noawt11 ){
|
||||
&do_build(1,$do_clobber);
|
||||
}
|
||||
}
|
||||
|
||||
if ($build_test) {
|
||||
$early_exit = 0; # stops this while loop after one pass.
|
||||
}
|
||||
if( !$no16 ){
|
||||
|
||||
# build 32-bit with AWT_11=0
|
||||
# necessary before building 16-bit because 16-bit cannot use AWT 1.1 classes
|
||||
&setup32("0");
|
||||
if( !$no32 ){
|
||||
if( !$noawt11 ){
|
||||
&do_build(0,'');
|
||||
} else {
|
||||
&do_build(1,$do_clobber);
|
||||
}
|
||||
}
|
||||
|
||||
&setup16;
|
||||
|
||||
# strip_conf fails to strip any variables from the real environemnt
|
||||
# &strip_config;
|
||||
&do_build(0,'');
|
||||
# &restore_config;
|
||||
}
|
||||
}
|
||||
|
||||
sub copy_win16_dist {
|
||||
|
||||
system 'xcopy w:\ y:\ns\dist /S /E /F';
|
||||
print "COPYCOPYCOPY\n";
|
||||
|
||||
}
|
||||
|
||||
sub build_NSPR20_Win16 {
|
||||
|
||||
&start_build;
|
||||
unlink( "${logname}.last" );
|
||||
rename( "${logname}","${logname}.last");
|
||||
|
||||
print "opening ${logname}\n";
|
||||
open( LOG, ">${logname}" ) || print "can't open $?\n";
|
||||
print LOG "current dir is :$cur_dir\n";
|
||||
|
||||
&print_env;
|
||||
|
||||
chdir("$moz_src/ns/nspr20") || die "couldn't chdir to '$moz_src/ns/nspr20'";
|
||||
print LOG "gmake |\n";
|
||||
open( BUILDNSPR, "gmake 2>&1 |") || print "couldn't execute gmake\n";;
|
||||
|
||||
while( <BUILDNSPR> ) {
|
||||
print $_;
|
||||
print LOG $_;
|
||||
}
|
||||
close ( BUILDNSPR );
|
||||
|
||||
close( LOG );
|
||||
}
|
||||
|
||||
sub setup32 {
|
||||
local ($awt) = @_;
|
||||
|
||||
$ENV{"MOZ_BITS"} = '32';
|
||||
$ENV{"AWT_11"} = $awt;
|
||||
$doawt11 = $awt;
|
||||
|
||||
$ENV{"INCLUDE"} = "$msdev\\include;$msdev\\mfc\\include";
|
||||
$ENV{"LIB"} = "$msdev\\lib;$msdev\\mfc\\lib";
|
||||
$ENV{"PATH"} = $original_path . ";$msdev\\bin";
|
||||
$ENV{"OS_TARGET"} = 'WIN95';
|
||||
$moz_src = $ENV{'MOZ_SRC'} = $start_dir;
|
||||
$build_name = 'Win32 ' . ($build_depend?'Depend':'Clobber');
|
||||
$do_clobber = $clobber_str;
|
||||
$logname = "win32.log";
|
||||
}
|
||||
|
||||
sub setup16 {
|
||||
$moz_src = $ENV{'MOZ_SRC'} = $start_dir;
|
||||
$ENV{"MOZ_BITS"} = '16';
|
||||
# perl 5 is fucked up. you MUST set AWT_11=0. deleting the environment
|
||||
# variable doesn't work. it's removed from the environment entry, but
|
||||
# is still defined as true for a build.
|
||||
$ENV{"AWT_11"} = '0';
|
||||
$moz_src = $ENV{'MOZ_SRC'} = "$src_16_drive";
|
||||
$ENV{"OS_TARGET"} = 'WIN16';
|
||||
|
||||
$msvc_inc = "$moz_src\\ns\\msvc15\\include;$moz_src\\ns\\msvc15\\mfc\\include";
|
||||
$msvc_lib = "$msvc\\lib;$msvc\\mfc\\lib";
|
||||
$msvcpath = "$msvc\\bin;c:\\nstools\\bin;c:\\WINNT40;c:\\WINNT40\\system32;c:\\utils";
|
||||
$ENV{"MSVC_INC"} = $msvc_inc;
|
||||
$ENV{"MSVC_LIB"} = $msvc_lib;
|
||||
$ENV{"MSVCPATH"} = $msvcpath;
|
||||
|
||||
$ENV{"INCLUDE"} = $msvc_inc;
|
||||
$ENV{"LIB"} = $msvc_lib;
|
||||
$ENV{"PATH"} = $msvcpath;
|
||||
|
||||
$watcom = $ENV{"WATCOM"} = "C:\\WATCOM";
|
||||
$ENV{"EDPATH"} = "$watcom\\EDDAT";
|
||||
$ENV{"WATC_INC"} = "$watcom\\h;$watcom\\h\win;$msvc_inc";
|
||||
$ENV{"WATC_LIB"} = $msvc_lib;
|
||||
$ENV{"WATCPATH"} = "$watcom\\BINNT;$watcom\\BINW;c:\\nstools\\bin";
|
||||
|
||||
$build_name = 'Win16 ' . ($build_depend?'Depend':'Clobber');
|
||||
$do_clobber = $clobber_str;
|
||||
$logname = "win16.log";
|
||||
|
||||
system "subst l: /d";
|
||||
system "subst r: /d";
|
||||
system "subst $src_16_drive /d";
|
||||
|
||||
system "subst $src_16_drive $start_dir";
|
||||
system "subst r: $src_16_drive\\ns\\netsite\\ldap\\libraries\\msdos\\winsock";
|
||||
system "subst l: $src_16_drive\\ns\\netsite";
|
||||
}
|
||||
|
||||
sub do_build {
|
||||
local ($pull, $do_clobber) = @_;
|
||||
|
||||
&start_build;
|
||||
|
||||
print "opening ${logname}\n";
|
||||
open( LOG, ">${logname}" ) || print "can't open $?\n";
|
||||
print LOG "current dir is :$cur_dir\n";
|
||||
|
||||
&print_env;
|
||||
$build_status = 0;
|
||||
if( $pull ){
|
||||
if ( $build_tag eq '' ){
|
||||
print LOG "cvs co -D\"$start_time_str\" mozilla/client.mak 2>&1 |\n";
|
||||
open( PULL, "cvs co -D\"$start_time_str\" mozilla/client.mak 2>&1 |") || print "couldn't execute cvs\n";;
|
||||
} else{
|
||||
print LOG "cvs co -r $build_tag mozilla/client.mak 2>&1 |\n";
|
||||
open( PULL, "cvs co -r $build_tag mozilla/client.mak 2>&1 |") || print "couldn't execute cvs\n";;
|
||||
}
|
||||
|
||||
# tee the output
|
||||
while( <PULL> ){
|
||||
print $_;
|
||||
print LOG $_;
|
||||
}
|
||||
close( PULL );
|
||||
|
||||
$build_status = $?;
|
||||
}
|
||||
|
||||
chdir("$moz_src/mozilla") || die "couldn't chdir to '$moz_src/mozilla'";
|
||||
|
||||
if( $do_clobber ne '' ){
|
||||
print LOG "nmake -f client.mak $do_clobber |\n";
|
||||
print "nmake -f client.mak $do_clobber |\n";
|
||||
open( PULL, "nmake -f client.mak $do_clobber 2>&1 |") || print "couldn't execute nmake\n";;
|
||||
|
||||
# tee the output
|
||||
while( <PULL> ){
|
||||
print $_;
|
||||
print LOG $_;
|
||||
}
|
||||
close( PULL );
|
||||
}
|
||||
|
||||
|
||||
if (!$pull) {
|
||||
$client_param = 'build_all';
|
||||
}
|
||||
else {
|
||||
$client_param = 'pull_and_build_all';
|
||||
}
|
||||
if (!$doawt11) {
|
||||
$client_param = 'build_dist';
|
||||
}
|
||||
|
||||
print LOG "nmake -f client.mak $client_param 2>&1 |\n";
|
||||
open( BUILD, "nmake -f client.mak $client_param 2>&1 |");
|
||||
|
||||
# tee the output
|
||||
while( <BUILD> ){
|
||||
print $_;
|
||||
print LOG $_;
|
||||
}
|
||||
close( BUILD );
|
||||
$build_status |= $?;
|
||||
|
||||
$build_status_str = ( $build_status ? 'busted' : 'success' );
|
||||
|
||||
print LOG "tinderbox: tree: $build_tree\n";
|
||||
print LOG "tinderbox: builddate: $start_time\n";
|
||||
print LOG "tinderbox: status: $build_status_str\n";
|
||||
print LOG "tinderbox: build: $build_name\n";
|
||||
print LOG "tinderbox: errorparser: windows\n";
|
||||
print LOG "tinderbox: buildfamily: windows\n";
|
||||
|
||||
close( LOG );
|
||||
chdir("$start_dir");
|
||||
system( "$nstools\\bin\\blat ${logname} -t tinderbox-daemon\@warp" );
|
||||
}
|
||||
|
||||
sub cvs_time {
|
||||
local( $ret_time );
|
||||
|
||||
($sec,$minute,$hour,$mday,$mon,$year) = localtime( $_[0] );
|
||||
$mon++; # month is 0 based.
|
||||
|
||||
sprintf("%02d/%02d/%02d %02d:%02d:00",
|
||||
$mon,$mday,$year,$hour,$minute );
|
||||
}
|
||||
|
||||
|
||||
sub start_build {
|
||||
open( LOG, ">>logfile" );
|
||||
print LOG "\n";
|
||||
print LOG "tinderbox: tree: $build_tree\n";
|
||||
print LOG "tinderbox: builddate: $start_time\n";
|
||||
print LOG "tinderbox: status: building\n";
|
||||
print LOG "tinderbox: build: $build_name\n";
|
||||
print LOG "tinderbox: errorparser: windows\n";
|
||||
print LOG "tinderbox: buildfamily: windows\n";
|
||||
print LOG "\n";
|
||||
close( LOG );
|
||||
system("$nstools\\bin\\blat logfile -t tinderbox-daemon\@warp" );
|
||||
}
|
||||
|
||||
sub parse_args {
|
||||
local($i);
|
||||
|
||||
if( @ARGV == 0 ){
|
||||
&usage;
|
||||
}
|
||||
$i = 0;
|
||||
while( $i < @ARGV ){
|
||||
if( $ARGV[$i] eq '--depend' ){
|
||||
$build_depend = 1;
|
||||
}
|
||||
elsif ( $ARGV[$i] eq '--clobber' ){
|
||||
$build_depend = 0;
|
||||
}
|
||||
elsif ( $ARGV[$i] eq '--continue' ){
|
||||
$build_continue = 1;
|
||||
}
|
||||
elsif ( $ARGV[$i] eq '--noawt11' ){
|
||||
$noawt11 = 1;
|
||||
}
|
||||
elsif ( $ARGV[$i] eq '--no32' ){
|
||||
$no32 = 1;
|
||||
}
|
||||
elsif ( $ARGV[$i] eq '--no16' ){
|
||||
$no16 = 1;
|
||||
}
|
||||
elsif ( $ARGV[$i] eq '--test' ){
|
||||
$build_test = 1;
|
||||
}
|
||||
elsif ( $ARGV[$i] eq '-tag' ){
|
||||
$i++;
|
||||
$build_tag = $ARGV[$i];
|
||||
if( $build_tag eq '' || $build_tag eq '-t'){
|
||||
&usage;
|
||||
}
|
||||
}
|
||||
elsif ( $ARGV[$i] eq '-t' ){
|
||||
$i++;
|
||||
$build_tree = $ARGV[$i];
|
||||
if( $build_tree eq '' ){
|
||||
&usage;
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
if( $build_tree eq '' ){
|
||||
&usage;
|
||||
}
|
||||
}
|
||||
|
||||
sub usage {
|
||||
die "usage: buildit.pl [--depend | --clobber] [--no16] [--continue] [--test] [-tag TAGNAME] -t TREENAME\n";
|
||||
}
|
||||
|
||||
sub setup_env {
|
||||
local($p);
|
||||
$ENV{"MOZ_DEBUG"} = '1';
|
||||
$ENV{"MOZ_GOLD"} = '1';
|
||||
$ENV{"NO_SECURITY"} = '1';
|
||||
$ENV{"MOZ_MEDIUM"} = '1';
|
||||
$ENV{"MOZ_CAFE"} = '1';
|
||||
$ENV{"NSPR20"} = '1';
|
||||
$ENV{"VERBOSE"} = '1';
|
||||
$nstools = $ENV{"MOZ_TOOLS"};
|
||||
if( $nstools eq '' ){
|
||||
die "error: environment variable MOZ_TOOLS not set\n";
|
||||
}
|
||||
$msdev = $ENV{"MOZ_MSDEV"} = 'c:\msdev';
|
||||
if( $msdev eq '' ){
|
||||
die "error: environment variable MOZ_MSDEV not set\n";
|
||||
}
|
||||
$msvc = $ENV{"MOZ_MSVC"} = 'c:\msvc';
|
||||
if( $msvc eq '' ){
|
||||
die "error: environment variable MOZ_VC not set\n";
|
||||
}
|
||||
if ( $build_tag ne '' ) {
|
||||
$ENV{"MOZ_BRANCH"} = $build_tag;
|
||||
}
|
||||
$moz_src = $ENV{"MOZ_SRC"} = $start_dir;
|
||||
$ENV{"MOZ_DATE"} = $start_time_str;
|
||||
$src_16_drive = 'y:';
|
||||
}
|
||||
|
||||
sub print_env {
|
||||
local( $k, $v);
|
||||
print LOG "\nEnvironment\n";
|
||||
print "\nEnvironment\n";
|
||||
for $k (sort keys %ENV){
|
||||
$v = $ENV{$k};
|
||||
print LOG " $k=$v\n";
|
||||
print " $k=$v\n";
|
||||
}
|
||||
print LOG "\n";
|
||||
print "\n";
|
||||
system 'set';
|
||||
}
|
||||
|
||||
sub strip_config {
|
||||
$save_compname=$ENV{"COMPUTERNAME"};
|
||||
$save_userdomain=$ENV{"USERDOMAIN"};
|
||||
$save_username=$ENV{"USERNAME"};
|
||||
$save_userprofile=$ENV{"USERPROFILE"};
|
||||
# most of these deletes have no effect.
|
||||
delete($ENV{"COMPUTERNAME"});
|
||||
delete($ENV{"USERDOMAIN"});
|
||||
delete($ENV{"USERNAME"});
|
||||
delete($ENV{"USERPROFILE"});
|
||||
# delete($ENV{"WATCOM"});
|
||||
|
||||
}
|
||||
|
||||
sub restore_config {
|
||||
$ENV{"COMPUTERNAME"}=$save_compname;
|
||||
$ENV{"USERDOMAIN"}=$save_userdomain;
|
||||
$ENV{"USERNAME"}=$save_username;
|
||||
$ENV{"MSDevDir"}=$save_userprofile;
|
||||
&print_env;
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||
<META NAME="GENERATOR" CONTENT="Mozilla/4.0b2 (WinNT; I) [Netscape]">
|
||||
</HEAD>
|
||||
<BODY>
|
||||
|
||||
<H1>
|
||||
FAQ on Tinderbox </H1>
|
||||
<B><FONT SIZE=+2>Q. What is Tinderbox.</FONT></B>
|
||||
<BR><FONT SIZE=+2>A. Your very own automated build page. It shows you how builds
|
||||
are going on various platforms. fs</FONT>
|
||||
<BR><FONT SIZE=+2></FONT>
|
||||
<BR><B><FONT SIZE=+2>Q. I just checked in some code. How can I tell when
|
||||
I'm OK.</FONT></B>
|
||||
<BR><FONT SIZE=+2>A. You name will appear in the <I>guilty </I>column.
|
||||
When there are successful (<FONT COLOR="#00FF00">green</FONT>) builds in
|
||||
all the columns in a row <B>above</B> your name, you know you are ok.</FONT>
|
||||
<BR>
|
||||
<BR><B><FONT SIZE=+2>Q. The tree is broken, how do I find out what is busted
|
||||
(or who busted it).</FONT></B>
|
||||
<BR><FONT SIZE=+2>A. Clicking 'L' in the first red box (first build to break)
|
||||
above a green will show you a build log for the broken build. You
|
||||
can also click 'C' in this box and see what code was checked in.</FONT>
|
||||
<BR>
|
||||
<BR><B><FONT SIZE=+2>More Questions? Mail me <A HREF="mailto:ltabb@netscape.com">ltabb@netscape.com</A></FONT></B>
|
||||
<BR>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
@@ -1,217 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl --
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Tinderbox build tool.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
use Socket;
|
||||
|
||||
require 'globals.pl';
|
||||
require 'imagelog.pl';
|
||||
|
||||
# Port an old-style imagelog thing to a newstyle one
|
||||
|
||||
open( IMAGELOG, "<$data_dir/imagelog.txt" ) || die "can't open file";
|
||||
open (OUT, ">$data_dir/newimagelog.txt") || die "can't open output file";
|
||||
select(OUT); $| = 1; select(STDOUT);
|
||||
|
||||
while( <IMAGELOG> ){
|
||||
chop;
|
||||
($url,$quote) = split(/\`/);
|
||||
print "$url\n";
|
||||
$size = &URLsize($url);
|
||||
$width = "";
|
||||
$height = "";
|
||||
if ($size =~ /WIDTH=([0-9]*)/) {
|
||||
$width = $1;
|
||||
}
|
||||
if ($size =~ /HEIGHT=([0-9]*)/) {
|
||||
$height = $1;
|
||||
}
|
||||
if ($width eq "" || $height eq "") {
|
||||
print "Couldn't get image size; skipping.\n";
|
||||
} else {
|
||||
print OUT "$url`$width`$height`$quote\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
sub imgsize {
|
||||
local($file)= @_;
|
||||
|
||||
#first try to open the file
|
||||
if( !open(STREAM, "<$file") ){
|
||||
print "Can't open IMG $file";
|
||||
$size="";
|
||||
} else {
|
||||
if ($file =~ /.jpg/i || $file =~ /.jpeg/i) {
|
||||
$size = &jpegsize(STREAM);
|
||||
} elsif($file =~ /.gif/i) {
|
||||
$size = &gifsize(STREAM);
|
||||
} elsif($file =~ /.xbm/i) {
|
||||
$size = &xbmsize(STREAM);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
$_ = $size;
|
||||
if( /\s*width\s*=\s*([0-9]*)\s*/i ){
|
||||
($newwidth)= /\s*width\s*=\s*(\d*)\s*/i;
|
||||
}
|
||||
if( /\s*height\s*=\s*([0-9]*)\s*/i ){
|
||||
($newheight)=/\s*height\s*=\s*(\d*)\s*/i;
|
||||
}
|
||||
close(STREAM);
|
||||
}
|
||||
return $size;
|
||||
}
|
||||
|
||||
###########################################################################
|
||||
# Subroutine gets the size of the specified GIF
|
||||
###########################################################################
|
||||
sub gifsize {
|
||||
local($GIF) = @_;
|
||||
read($GIF, $type, 6);
|
||||
if(!($type =~ /GIF8[7,9]a/) ||
|
||||
!(read($GIF, $s, 4) == 4) ){
|
||||
print "Invalid or Corrupted GIF";
|
||||
$size="";
|
||||
} else {
|
||||
($a,$b,$c,$d)=unpack("C"x4,$s);
|
||||
$size=join ("", 'WIDTH=', $b<<8|$a, ' HEIGHT=', $d<<8|$c);
|
||||
}
|
||||
return $size;
|
||||
}
|
||||
|
||||
sub xbmsize {
|
||||
local($XBM) = @_;
|
||||
local($input)="";
|
||||
|
||||
$input .= <$XBM>;
|
||||
$input .= <$XBM>;
|
||||
$_ = $input;
|
||||
if( /#define\s*\S*\s*\d*\s*\n#define\s*\S*\s*\d*\s*\n/i ){
|
||||
($a,$b)=/#define\s*\S*\s*(\d*)\s*\n#define\s*\S*\s*(\d*)\s*\n/i;
|
||||
$size=join ("", 'WIDTH=', $a, ' HEIGHT=', $b );
|
||||
} else {
|
||||
print "Hmmm... Doesn't look like an XBM file";
|
||||
}
|
||||
return $size;
|
||||
}
|
||||
|
||||
# jpegsize : gets the width and height (in pixels) of a jpeg file
|
||||
# Andrew Tong, werdna@ugcs.caltech.edu February 14, 1995
|
||||
# modified slightly by alex@ed.ac.uk
|
||||
sub jpegsize {
|
||||
local($JPEG) = @_;
|
||||
local($done)=0;
|
||||
$size="";
|
||||
|
||||
read($JPEG, $c1, 1); read($JPEG, $c2, 1);
|
||||
if( !((ord($c1) == 0xFF) && (ord($c2) == 0xD8))){
|
||||
printf "This is not a JPEG! (Codes %02X %02X)\n", ord($c1), ord($c2);
|
||||
$done=1;
|
||||
}
|
||||
while (ord($ch) != 0xDA && !$done) {
|
||||
# Find next marker (JPEG markers begin with 0xFF)
|
||||
# This can hang the program!!
|
||||
while (ord($ch) != 0xFF) { read($JPEG, $ch, 1); }
|
||||
# JPEG markers can be padded with unlimited 0xFF's
|
||||
while (ord($ch) == 0xFF) { read($JPEG, $ch, 1); }
|
||||
# Now, $ch contains the value of the marker.
|
||||
$marker=ord($ch);
|
||||
|
||||
if (($marker >= 0xC0) && ($marker <= 0xCF) &&
|
||||
($marker != 0xC4) && ($marker != 0xCC)) { # it's a SOFn marker
|
||||
read ($JPEG, $junk, 3); read($JPEG, $s, 4);
|
||||
($a,$b,$c,$d)=unpack("C"x4,$s);
|
||||
$size=join("", 'HEIGHT=',$a<<8|$b,' WIDTH=',$c<<8|$d );
|
||||
$done=1;
|
||||
} else {
|
||||
# We **MUST** skip variables, since FF's within variable
|
||||
# names are NOT valid JPEG markers
|
||||
read ($JPEG, $s, 2);
|
||||
($c1, $c2) = unpack("C"x2,$s);
|
||||
$length = $c1<<8|$c2;
|
||||
if( ($length < 2) ){
|
||||
print "Erroneous JPEG marker length";
|
||||
$done=1;
|
||||
} else {
|
||||
read($JPEG, $junk, $length-2);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $size;
|
||||
}
|
||||
|
||||
###########################################################################
|
||||
# Subroutine grabs a gif from another server and gets its size
|
||||
###########################################################################
|
||||
|
||||
|
||||
sub URLsize {
|
||||
my ($fullurl) = @_;
|
||||
my($dummy, $dummy, $serverstring, $url) = split(/\//, $fullurl, 4);
|
||||
my($them,$port) = split(/:/, $serverstring);
|
||||
my $port = 80 unless $port;
|
||||
$them = 'localhost' unless $them;
|
||||
my $size="";
|
||||
|
||||
$_=$url;
|
||||
if( /gif/i || /jpeg/i || /jpg/i || /xbm/i ) {
|
||||
my ($remote, $iaddr, $paddr, $proto, $line);
|
||||
$remote = $them;
|
||||
if ($port =~ /\D/) { $port = getservbyname($port, 'tcp') }
|
||||
die "No port" unless $port;
|
||||
$iaddr = inet_aton($remote) || die "no host: $remote";
|
||||
$paddr = sockaddr_in($port, $iaddr);
|
||||
|
||||
$proto = getprotobyname('tcp');
|
||||
socket(S, PF_INET, SOCK_STREAM, $proto) || return "socket: $!";
|
||||
connect(S, $paddr) || return "connect: $!";
|
||||
select(S); $| = 1; select(STDOUT);
|
||||
|
||||
|
||||
|
||||
print S "GET /$url\n";
|
||||
if ($url =~ /.jpg/i || $url =~ /.jpeg/i) {
|
||||
$size = &jpegsize(S);
|
||||
} elsif($url =~ /.gif/i) {
|
||||
$size = &gifsize(S);
|
||||
} elsif($url =~ /.xbm/i) {
|
||||
$size = &xbmsize(S);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
$_ = $size;
|
||||
if( /\s*width\s*=\s*([0-9]*)\s*/i ){
|
||||
($newwidth)= /\s*width\s*=\s*(\d*)\s*/i;
|
||||
}
|
||||
if( /\s*height\s*=\s*([0-9]*)\s*/i ){
|
||||
($newheight)=/\s*height\s*=\s*(\d*)\s*/i;
|
||||
}
|
||||
} else {
|
||||
$size="";
|
||||
}
|
||||
return $size;
|
||||
}
|
||||
|
||||
sub dokill {
|
||||
kill 9,$child if $child;
|
||||
}
|
||||
@@ -1,556 +0,0 @@
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Tinderbox build tool.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
#
|
||||
# Global variabls and functions for tinderbox
|
||||
#
|
||||
|
||||
#
|
||||
# Global variables
|
||||
#
|
||||
|
||||
$td1 = {};
|
||||
$td2 = {};
|
||||
|
||||
$build_list = []; # array of all build records
|
||||
$build_name_index = {};
|
||||
$ignore_builds = {};
|
||||
$build_name_names = [];
|
||||
$name_count = 0;
|
||||
|
||||
$build_time_index = {};
|
||||
$build_time_times = [];
|
||||
$time_count = 0;
|
||||
$mindate_time_count = 0; # time_count that corresponds to the mindate
|
||||
|
||||
$build_table = [];
|
||||
$who_list = [];
|
||||
$who_list2 = [];
|
||||
@note_array = ();
|
||||
|
||||
|
||||
#$body_tag = "<BODY TEXT=#000000 BGCOLOR=#8080C0 LINK=#FFFFFF VLINK=#800080 ALINK=#FFFF00>";
|
||||
#$body_tag = "<BODY TEXT=#000000 BGCOLOR=#FFFFC0 LINK=#0000FF VLINK=#800080 ALINK=#FF00FF>";
|
||||
if( $ENV{'USERNAME'} eq 'ltabb' ){
|
||||
$gzip = 'gzip';
|
||||
}
|
||||
else {
|
||||
$gzip = '/usr/local/bin/gzip';
|
||||
}
|
||||
|
||||
$data_dir='data';
|
||||
|
||||
$lock_count = 0;
|
||||
|
||||
1;
|
||||
|
||||
sub lock{
|
||||
#if( $lock_count == 0 ){
|
||||
# print "locking $tree/LOCKFILE.lck\n";
|
||||
# open( LOCKFILE_LOCK, ">$tree/LOCKFILE.lck" );
|
||||
# flock( LOCKFILE_LOCK, 2 );
|
||||
#}
|
||||
#$lock_count++;
|
||||
|
||||
}
|
||||
|
||||
sub unlock{
|
||||
#$lock_count--;
|
||||
#if( $lock_count == 0 ){
|
||||
# flock( LOCKFILE_LOCK, 8 );
|
||||
# close( LOCKFILE_LOCK );
|
||||
#}
|
||||
}
|
||||
|
||||
sub print_time {
|
||||
my ($t) = @_;
|
||||
my ($minute,$hour,$mday,$mon);
|
||||
(undef,$minute,$hour,$mday,$mon,undef) = localtime($t);
|
||||
sprintf("%02d/%02d %02d:%02d",$mon+1,$mday,$hour,$minute);
|
||||
}
|
||||
|
||||
sub url_encode {
|
||||
my ($s) = @_;
|
||||
|
||||
$s =~ s/\%/\%25/g;
|
||||
$s =~ s/\=/\%3d/g;
|
||||
$s =~ s/\?/\%3f/g;
|
||||
$s =~ s/ /\%20/g;
|
||||
$s =~ s/\n/\%0a/g;
|
||||
$s =~ s/\r//g;
|
||||
$s =~ s/\"/\%22/g;
|
||||
$s =~ s/\'/\%27/g;
|
||||
$s =~ s/\|/\%7c/g;
|
||||
$s =~ s/\&/\%26/g;
|
||||
return $s;
|
||||
}
|
||||
|
||||
sub url_decode {
|
||||
my ($value) = @_;
|
||||
$value =~ tr/+/ /;
|
||||
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
sub value_encode {
|
||||
my ($s) = @_;
|
||||
$s =~ s@&@&@g;
|
||||
$s =~ s@<@<@g;
|
||||
$s =~ s@>@>@g;
|
||||
$s =~ s@\"@"@g;
|
||||
return $s;
|
||||
}
|
||||
|
||||
|
||||
sub load_data {
|
||||
$tree2 = $form{'tree2'};
|
||||
if( $tree2 ne '' ){
|
||||
require "$tree2/treedata.pl";
|
||||
if( -r "$tree2/ignorebuilds.pl" ){
|
||||
require "$tree2/ignorebuilds.pl";
|
||||
}
|
||||
|
||||
$td2 = {};
|
||||
$td2->{name} = $tree2;
|
||||
$td2->{cvs_module} = $cvs_module;
|
||||
$td2->{cvs_branch} = $cvs_branch;
|
||||
$td2->{num} = 1;
|
||||
$td2->{ignore_builds} = $ignore_builds;
|
||||
if( $cvs_root eq '' ){
|
||||
$cvs_root = '/m/src';
|
||||
}
|
||||
$td2->{cvs_root} = $cvs_root;
|
||||
|
||||
$tree = $form{'tree'};
|
||||
require "$tree/treedata.pl";
|
||||
if( $cvs_root eq '' ){
|
||||
$cvs_root = '/m/src';
|
||||
}
|
||||
}
|
||||
|
||||
$tree = $form{'tree'};
|
||||
|
||||
return unless $tree;
|
||||
#die "the 'tree' parameter must be provided\n" unless $tree;
|
||||
|
||||
if ( -r "$tree/treedata.pl" ) {
|
||||
require "$tree/treedata.pl";
|
||||
}
|
||||
|
||||
$ignore_builds = {};
|
||||
if( -r "$tree/ignorebuilds.pl" ){
|
||||
require "$tree/ignorebuilds.pl";
|
||||
}
|
||||
|
||||
$td1 = {};
|
||||
$td1->{name} = $tree;
|
||||
$td1->{num} = 0;
|
||||
$td1->{cvs_module} = $cvs_module;
|
||||
$td1->{cvs_branch} = $cvs_branch;
|
||||
$td1->{ignore_builds} = $ignore_builds;
|
||||
if( $cvs_root eq '' ){
|
||||
$cvs_root = '/m/src';
|
||||
}
|
||||
$td1->{cvs_root} = $cvs_root;
|
||||
|
||||
&lock;
|
||||
&load_buildlog;
|
||||
&unlock;
|
||||
|
||||
&get_build_name_index;
|
||||
&get_build_time_index;
|
||||
|
||||
&load_who($who_list, $td1);
|
||||
if( $tree2 ne '' ){
|
||||
&load_who($who_list2, $td2);
|
||||
}
|
||||
|
||||
&make_build_table;
|
||||
}
|
||||
|
||||
sub load_buildlog {
|
||||
my $mailtime, $buildtime, $buildname, $errorparser;
|
||||
my $buildstatus, $logfile,$binaryname;
|
||||
my $buildrec, @treelist, $t;
|
||||
|
||||
if (not defined $maxdate) {
|
||||
$maxdate = time();
|
||||
}
|
||||
if (not defined $mindate) {
|
||||
$mindate = $maxdate - 24*60*60;
|
||||
}
|
||||
|
||||
if ($tree2 ne '') {
|
||||
@treelist = ($td1, $td2);
|
||||
}
|
||||
else {
|
||||
@treelist = ($td1);
|
||||
}
|
||||
|
||||
for $t (@treelist) {
|
||||
use Backwards;
|
||||
my ($bw) = Backwards->new("$t->{name}/build.dat") or die;
|
||||
|
||||
my $tooearly = 0;
|
||||
while( $_ = $bw->readline ) {
|
||||
chomp;
|
||||
($mailtime, $buildtime, $buildname,
|
||||
$errorparser, $buildstatus, $logfile, $binaryname) = split /\|/;
|
||||
|
||||
# Ignore stuff in the future.
|
||||
next if $buildtime > $maxdate;
|
||||
|
||||
# Ignore stuff in the past (but get a 2 hours of extra data)
|
||||
if ($buildtime < $mindate - 2*60*60) {
|
||||
# Occasionally, a build might show up with a bogus time. So,
|
||||
# we won't judge ourselves as having hit the end until we
|
||||
# hit a full 20 lines in a row that are too early.
|
||||
last if $tooearly++ > 20;
|
||||
|
||||
next;
|
||||
}
|
||||
$tooearly = 0;
|
||||
$buildrec = {
|
||||
mailtime => $mailtime,
|
||||
buildtime => $buildtime,
|
||||
buildname => ($tree2 ne '' ? $t->{name} . ' ' : '' ) . $buildname,
|
||||
errorparser => $errorparser,
|
||||
buildstatus => $buildstatus,
|
||||
logfile => $logfile,
|
||||
binaryname => $binaryname,
|
||||
td => $t
|
||||
};
|
||||
if ($form{noignore} or not $t->{ignore_builds}->{$buildname}) {
|
||||
push @{$build_list}, $buildrec;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub loadquickparseinfo {
|
||||
my ($tree, $build, $times) = (@_);
|
||||
|
||||
do "$tree/ignorebuilds.pl";
|
||||
|
||||
use Backwards;
|
||||
|
||||
my ($bw) = Backwards->new("$form{tree}/build.dat") or die;
|
||||
|
||||
my $latest_time = 0;
|
||||
my $tooearly = 0;
|
||||
while( $_ = $bw->readline ) {
|
||||
chop;
|
||||
my ($buildtime, $buildname, $buildstatus) = (split /\|/)[1,2,4];
|
||||
|
||||
if ($buildstatus =~ /^success|busted|testfailed$/) {
|
||||
|
||||
# Ignore stuff in the future.
|
||||
next if $buildtime > $maxdate;
|
||||
|
||||
$latest_time = $buildtime if $buildtime > $latest_time;
|
||||
|
||||
# Ignore stuff more than 12 hours old
|
||||
if ($buildtime < $latest_time - 12*60*60) {
|
||||
# Hack: A build may give a bogus time. To compensate, we will
|
||||
# not stop until we hit 20 consecutive lines that are too early.
|
||||
|
||||
last if $tooearly++ > 20;
|
||||
next;
|
||||
}
|
||||
$tooearly = 0;
|
||||
|
||||
next if exists $ignore_builds->{$buildname};
|
||||
next if exists $build->{$buildname}
|
||||
and $times->{$buildname} >= $buildtime;
|
||||
|
||||
$build->{$buildname} = $buildstatus;
|
||||
$times->{$buildname} = $buildtime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub load_who {
|
||||
my ($who_list, $td) = @_;
|
||||
my $d, $w, $i, $bfound;
|
||||
|
||||
open(WHOLOG, "<$td->{name}/who.dat");
|
||||
while (<WHOLOG>) {
|
||||
$i = $time_count;
|
||||
chop;
|
||||
($d,$w) = split /\|/;
|
||||
$bfound = 0;
|
||||
while ($i > 0 and not $bfound) {
|
||||
if ($d <= $build_time_times->[$i]) {
|
||||
$who_list->[$i+1]->{$w} = 1;
|
||||
$bfound = 1;
|
||||
}
|
||||
else {
|
||||
$i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Ignore the last one
|
||||
#
|
||||
if ($time_count > 0) {
|
||||
$who_list->[$time_count] = {};
|
||||
}
|
||||
}
|
||||
|
||||
sub get_build_name_index {
|
||||
my $i,$br;
|
||||
|
||||
# Get all the unique build names.
|
||||
#
|
||||
foreach $br (@{$build_list}) {
|
||||
$build_name_index->{$br->{buildname}} = 1;
|
||||
}
|
||||
|
||||
$i = 1;
|
||||
foreach $n (sort keys (%{$build_name_index})) {
|
||||
$build_name_names->[$i] = $n;
|
||||
$i++;
|
||||
}
|
||||
|
||||
$name_count = @{$build_name_names}-1;
|
||||
|
||||
# Update the map so it points to the right index
|
||||
#
|
||||
for ($i=1; $i < $name_count+1; $i++) {
|
||||
$build_name_index->{$build_name_names->[$i]} = $i;
|
||||
}
|
||||
}
|
||||
|
||||
sub get_build_time_index {
|
||||
my $i,$br;
|
||||
|
||||
# Get all the unique build names.
|
||||
#
|
||||
foreach $br (@{$build_list}) {
|
||||
$build_time_index->{$br->{buildtime}} = 1;
|
||||
}
|
||||
|
||||
$i = 1;
|
||||
foreach $n (sort {$b <=> $a} keys (%{$build_time_index})) {
|
||||
$build_time_times->[$i] = $n;
|
||||
$mindate_time_count = $i if $n >= $mindate;
|
||||
$i++;
|
||||
}
|
||||
|
||||
$time_count = @{$build_time_times}-1;
|
||||
|
||||
# Update the map so it points to the right index
|
||||
#
|
||||
for ($i=1; $i < $time_count+1; $i++) {
|
||||
$build_time_index->{$build_time_times->[$i]} = $i;
|
||||
}
|
||||
|
||||
#for $i (@{$build_time_times}) {
|
||||
# print $i . "\n";
|
||||
#}
|
||||
|
||||
#while( ($k,$v) = each(%{$build_time_index})) {
|
||||
# print "$k=$v\n";
|
||||
#}
|
||||
}
|
||||
|
||||
sub make_build_table {
|
||||
my $i,$ti,$bi,$ti1,$br;
|
||||
|
||||
# Create the build table
|
||||
#
|
||||
for ($i=1; $i <= $time_count; $i++){
|
||||
$build_table->[$i] = [];
|
||||
}
|
||||
|
||||
# Populate the build table with build data
|
||||
#
|
||||
foreach $br (reverse @{$build_list}) {
|
||||
$ti = $build_time_index->{$br->{buildtime}};
|
||||
$bi = $build_name_index->{$br->{buildname}};
|
||||
$build_table->[$ti][$bi] = $br;
|
||||
}
|
||||
|
||||
&load_notes;
|
||||
|
||||
for ($bi = $name_count; $bi > 0; $bi--) {
|
||||
for ($ti = $time_count; $ti > 0; $ti--) {
|
||||
if (defined($br = $build_table->[$ti][$bi])
|
||||
and not defined($br->{rowspan})) {
|
||||
|
||||
# If the cell immediately after us is defined, then we
|
||||
# can have a previousbuildtime.
|
||||
if (defined($br1 = $build_table->[$ti+1][$bi])) {
|
||||
$br->{previousbuildtime} = $br1->{buildtime};
|
||||
}
|
||||
|
||||
$ti1 = $ti-1;
|
||||
while ($ti1 > 0 and not defined($build_table->[$ti1][$bi])) {
|
||||
$build_table->[$ti1][$bi] = -1;
|
||||
$ti1--;
|
||||
}
|
||||
$br->{rowspan} = $ti - $ti1;
|
||||
if ($br->{rowspan} != 1) {
|
||||
$build_table->[$ti1+1][$bi] = $br;
|
||||
$build_table->[$ti][$bi] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub load_notes {
|
||||
if ($tree2 ne '') {
|
||||
@treelist = ($td1, $td2);
|
||||
}
|
||||
else {
|
||||
@treelist = ($td1);
|
||||
}
|
||||
|
||||
foreach $t (@treelist) {
|
||||
open(NOTES,"<$t->{name}/notes.txt")
|
||||
or print "<h2>warning: Couldn't open $t->{name}/notes.txt </h2>\n";
|
||||
while (<NOTES>) {
|
||||
chop;
|
||||
($nbuildtime,$nbuildname,$nwho,$nnow,$nenc_note) = split /\|/;
|
||||
$nbuildname = "$t->{name} $nbuildname" if $tree2 ne '';
|
||||
$ti = $build_time_index->{$nbuildtime};
|
||||
$bi = $build_name_index->{$nbuildname};
|
||||
#print "[ti = $ti][bi=$bi][buildname='$nbuildname' $_<br>";
|
||||
if ($ti != 0 and $bi != 0) {
|
||||
$build_table->[$ti][$bi]->{hasnote} = 1;
|
||||
if (not defined($build_table->[$ti][$bi]->{noteid})) {
|
||||
$build_table->[$ti][$bi]->{noteid} = (0+@note_array);
|
||||
}
|
||||
$noteid = $build_table->[$ti][$bi]->{noteid};
|
||||
$now_str = &print_time($nnow);
|
||||
$note = &url_decode($nenc_note);
|
||||
$note_array[$noteid] = "<pre>\n[<b><a href=mailto:$nwho>"
|
||||
."$nwho</a> - $now_str</b>]\n$note\n</pre>"
|
||||
.$note_array[$noteid];
|
||||
}
|
||||
}
|
||||
close(NOTES);
|
||||
}
|
||||
}
|
||||
|
||||
sub last_success_time {
|
||||
my ($row) = @_;
|
||||
|
||||
for (my $tt=1; $tt <= $time_count; $tt++) {
|
||||
my $br = $build_table->[$tt][$row];
|
||||
next unless defined $br;
|
||||
next unless $br->{buildstatus} eq 'success';
|
||||
return $build_time_times->[$tt + $br->{rowspan} ];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub last_status {
|
||||
my ($row) = @_;
|
||||
|
||||
for (my $tt=1; $tt <= $time_count; $tt++) {
|
||||
my $br = $build_table->[$tt][$row];
|
||||
next unless defined $br;
|
||||
next unless $br->{buildstatus} =~ /^(success|busted|testfailed)$/;
|
||||
return $br->{buildstatus};
|
||||
}
|
||||
return 'building';
|
||||
}
|
||||
|
||||
sub check_password {
|
||||
if ($form{password} eq '') {
|
||||
if (defined $cookie_jar{tinderbox_password}) {
|
||||
$form{password} = $cookie_jar{tinderbox_password};
|
||||
}
|
||||
}
|
||||
my $correct = '';
|
||||
if (open(REAL, '<data/passwd')) {
|
||||
$correct = <REAL>;
|
||||
close REAL;
|
||||
$correct =~ s/\s+$//; # Strip trailing whitespace.
|
||||
}
|
||||
$form{password} =~ s/\s+$//; # Strip trailing whitespace.
|
||||
if ($form{password} ne '') {
|
||||
open(TRAPDOOR, "../bonsai/data/trapdoor $form{'password'} |")
|
||||
or die "Can't run trapdoor func!";
|
||||
my $encoded = <TRAPDOOR>;
|
||||
close TRAPDOOR;
|
||||
$encoded =~ s/\s+$//; # Strip trailing whitespace.
|
||||
if ($encoded eq $correct) {
|
||||
if ($form{rememberpassword} ne '') {
|
||||
print "Set-Cookie: tinderbox_password=$form{'password'} ;"
|
||||
." path=/ ; expires = Sun, 1-Mar-2020 00:00:00 GMT\n";
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
require 'header.pl';
|
||||
|
||||
print "Content-type: text/html\n";
|
||||
print "Set-Cookie: tinderbox_password= ; path=/ ; "
|
||||
." expires = Sun, 1-Mar-2020 00:00:00 GMT\n";
|
||||
print "\n";
|
||||
|
||||
EmitHtmlHeader("What's the magic word?",
|
||||
"You need to know the magic word to use this page.");
|
||||
|
||||
if ($form{password} ne '') {
|
||||
print "<B>Invalid password; try again.<BR></B>";
|
||||
}
|
||||
print q(
|
||||
<FORM method=post>
|
||||
<B>Password:</B>
|
||||
<INPUT NAME=password TYPE=password><BR>
|
||||
<INPUT NAME=rememberpassword TYPE=checkbox>
|
||||
If correct, remember password as a cookie<BR>
|
||||
);
|
||||
|
||||
while (my ($key,$value) = each %form) {
|
||||
next if $key eq "password" or $key eq "rememberpassword";
|
||||
|
||||
my $enc = value_encode($value);
|
||||
print "<INPUT TYPE=HIDDEN NAME=$key VALUE='$enc'>\n";
|
||||
}
|
||||
print "<INPUT TYPE=SUBMIT value=Submit></FORM>\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
sub find_build_record {
|
||||
my ($tree, $logfile) = @_;
|
||||
|
||||
my $log_entry = `grep $logfile $tree/build.dat`;
|
||||
|
||||
chomp($log_entry);
|
||||
my ($mailtime, $buildtime, $buildname, $errorparser,
|
||||
$buildstatus, $logfile, $binaryname) = split /\|/, $log_entry;
|
||||
|
||||
$buildrec = {
|
||||
mailtime => $mailtime,
|
||||
buildtime => $buildtime,
|
||||
buildname => $buildname,
|
||||
errorparser => $errorparser,
|
||||
buildstatus => $buildstatus,
|
||||
logfile => $logfile,
|
||||
binaryname => $binaryname,
|
||||
td => undef
|
||||
};
|
||||
return $buildrec;
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl --
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Tinderbox build tool.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
# Figure out which directory tinderbox is in by looking at argv[0]. Unless
|
||||
# there is a command line argument; if there is, just use that.
|
||||
|
||||
$tinderboxdir = $0;
|
||||
$tinderboxdir =~ s:/[^/]*$::; # Remove last word, and slash before it.
|
||||
if ($tinderboxdir eq "") {
|
||||
$tinderboxdir = ".";
|
||||
}
|
||||
|
||||
if (@ARGV > 0) {
|
||||
$tinderboxdir = $ARGV[0];
|
||||
}
|
||||
|
||||
print "tinderbox = $tinderboxdir\n";
|
||||
|
||||
chdir $tinderboxdir || die "Couldn't chdir to $tinderboxdir";
|
||||
|
||||
|
||||
open(DF, ">data/tbx.$$") || die "could not open data/tbx.$$";
|
||||
while(<STDIN>){
|
||||
print DF $_;
|
||||
}
|
||||
close(DF);
|
||||
|
||||
$err = system("./processbuild.pl data/tbx.$$");
|
||||
|
||||
if( $err ) {
|
||||
die "processbuild.pl returned an error\n";
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl --
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Tinderbox build tool.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
1;
|
||||
|
||||
sub add_imagelog {
|
||||
local($url,$quote,$width,$height) = @_;
|
||||
open( IMAGELOG, ">>$data_dir/imagelog.txt" ) || die "Oops; can't open imagelog.txt";
|
||||
print IMAGELOG "$url`$width`$height`$quote\n";
|
||||
close( IMAGELOG );
|
||||
}
|
||||
|
||||
sub get_image{
|
||||
local(@log,@ret,$i);
|
||||
|
||||
open( IMAGELOG, "<$data_dir/imagelog.txt" );
|
||||
@log = <IMAGELOG>;
|
||||
|
||||
# return a random line
|
||||
srand;
|
||||
@ret = split(/\`/,$log[rand @log]);
|
||||
|
||||
close( IMAGELOG );
|
||||
@ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<TITLE>tinderbox</TITLE>
|
||||
<META HTTP-EQUIV="Refresh" CONTENT="1; URL=showbuilds.cgi">
|
||||
<BODY BGCOLOR="#FFFFFF" TEXT="#000000"
|
||||
LINK="#0000EE" VLINK="#551A8B" ALINK="#FF0000">
|
||||
<CENTER>
|
||||
<TABLE BORDER=0 WIDTH="100%" HEIGHT="100%"><TR><TD ALIGN=CENTER VALIGN=CENTER>
|
||||
<FONT SIZE="+2">
|
||||
You're looking for
|
||||
<A HREF="showbuilds.cgi">showbuilds.cgi</A>.
|
||||
</FONT>
|
||||
</TD></TR></TABLE>
|
||||
</CENTER>
|
||||
@@ -1,241 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl --
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Tinderbox build tool.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
require 'globals.pl';
|
||||
require 'timelocal.pl';
|
||||
|
||||
umask 0;
|
||||
|
||||
#$logfile = '';
|
||||
|
||||
%MAIL_HEADER = ();
|
||||
$DONE = 0;
|
||||
$building = 0;
|
||||
$endsection = 0;
|
||||
|
||||
open( LOG, "<$ARGV[0]") || die "cant open $!";
|
||||
&parse_mail_header;
|
||||
while ($DONE == 0) {
|
||||
%tbx = ();
|
||||
&get_variables;
|
||||
|
||||
# run thru if EOF and we haven't hit our section end marker
|
||||
|
||||
if ( !$DONE || !$endsection) {
|
||||
&check_required_vars;
|
||||
$tree = $tbx{'tree'} if (!defined($tree));
|
||||
$logfile = "$builddate.$$.gz" if (!defined($logfile));
|
||||
$building++ if ($tbx{'status'} =~ m/building/);
|
||||
&lock;
|
||||
&write_build_data;
|
||||
&unlock;
|
||||
}
|
||||
}
|
||||
close(LOG);
|
||||
|
||||
&compress_log_file;
|
||||
&unlink_log_file;
|
||||
|
||||
system "./buildwho.pl $tree";
|
||||
|
||||
# Build static pages for Sidebar flash and tinderbox panels.
|
||||
$ENV{QUERY_STRING}="tree=$tree&static=1";
|
||||
system './showbuilds.cgi';
|
||||
|
||||
# end of main
|
||||
######################################################################
|
||||
|
||||
|
||||
# This routine will scan through log looking for 'tinderbox:' variables
|
||||
#
|
||||
sub get_variables{
|
||||
|
||||
#while( ($k,$v) = each( %MAIL_HEADER ) ){
|
||||
# print "$k='$v'\n";
|
||||
#}
|
||||
|
||||
&parse_log_variables;
|
||||
|
||||
#while( ($k,$v) = each( %tbx ) ){
|
||||
# print "$k='$v'\n";
|
||||
#}
|
||||
}
|
||||
|
||||
|
||||
sub parse_log_variables {
|
||||
my ($line, $stop);
|
||||
$stop = 0;
|
||||
while($stop == 0){
|
||||
$line = <LOG>;
|
||||
$DONE++, return if !defined($line);
|
||||
chomp($line);
|
||||
if( $line =~ /^tinderbox\:/ ){
|
||||
if( $line =~ /^tinderbox\:[ \t]*([^:]*)\:[ \t]*([^\n]*)/ ){
|
||||
$tbx{$1} = $2;
|
||||
} elsif ( $line =~ /^tinderbox: END/ ) {
|
||||
$stop++, $endsection++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub parse_mail_header {
|
||||
my $line;
|
||||
my $name = '';
|
||||
while($line = <LOG> ){
|
||||
chomp($line);
|
||||
|
||||
if( $line eq '' ){
|
||||
return;
|
||||
}
|
||||
|
||||
if( $line =~ /([^ :]*)\:[ \t]+([^\n]*)/ ){
|
||||
$name = $1;
|
||||
$name =~ tr/A-Z/a-z/;
|
||||
$MAIL_HEADER{$name} = $2;
|
||||
#print "$name $2\n";
|
||||
}
|
||||
elsif( $name ne '' ){
|
||||
$MAIL_HEADER{$name} .= $2;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sub check_required_vars {
|
||||
$err_string = '';
|
||||
if( $tbx{'tree'} eq ''){
|
||||
$err_string .= "Variable 'tinderbox:tree' not set.\n";
|
||||
}
|
||||
elsif( ! -r $tbx{'tree'} ){
|
||||
$err_string .= "Variable 'tinderbox:tree' not set to a valid tree.\n";
|
||||
}
|
||||
elsif(($MAIL_HEADER{'to'} =~ /external/i ||
|
||||
$MAIL_HEADER{'cc'} =~ /external/i) &&
|
||||
$tbx{'tree'} !~ /external/i) {
|
||||
$err_string .= "Data from an external source didn't specify an 'external' tree.";
|
||||
}
|
||||
if( $tbx{'build'} eq ''){
|
||||
$err_string .= "Variable 'tinderbox:build' not set.\n";
|
||||
}
|
||||
if( $tbx{'errorparser'} eq ''){
|
||||
$err_string .= "Variable 'tinderbox:errorparser' not set.\n";
|
||||
}
|
||||
|
||||
#
|
||||
# Grab the date in the form of mm/dd/yy hh:mm:ss
|
||||
#
|
||||
# Or a GMT unix date
|
||||
#
|
||||
if( $tbx{'builddate'} eq ''){
|
||||
$err_string .= "Variable 'tinderbox:builddate' not set.\n";
|
||||
}
|
||||
else {
|
||||
if( $tbx{'builddate'} =~
|
||||
/([0-9]*)\/([0-9]*)\/([0-9]*)[ \t]*([0-9]*)\:([0-9]*)\:([0-9]*)/ ){
|
||||
|
||||
$builddate = timelocal($6,$5,$4,$2,$1-1,$3);
|
||||
|
||||
}
|
||||
elsif( $tbx{'builddate'} > 7000000 ){
|
||||
$builddate = $tbx{'builddate'};
|
||||
}
|
||||
else {
|
||||
$err_string .= "Variable 'tinderbox:builddate' not of the form MM/DD/YY HH:MM:SS or unix date\n";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#
|
||||
# Build Status
|
||||
#
|
||||
if( $tbx{'status'} eq ''){
|
||||
$err_string .= "Variable 'tinderbox:status' not set.\n";
|
||||
}
|
||||
elsif( ! $tbx{'status'} =~ /success|busted|building|testfailed/ ){
|
||||
$err_string .= "Variable 'tinderbox:status' must be 'success', 'busted', 'testfailed', or 'building'\n";
|
||||
}
|
||||
|
||||
#
|
||||
# Report errors
|
||||
#
|
||||
if( $err_string ne '' ){
|
||||
die $err_string;
|
||||
}
|
||||
}
|
||||
|
||||
sub write_build_data {
|
||||
$t = time;
|
||||
open( BUILDDATA, ">>$tbx{'tree'}/build.dat" )|| die "can't open $! for writing";
|
||||
print BUILDDATA "$t|$builddate|$tbx{'build'}|$tbx{'errorparser'}|$tbx{'status'}|$logfile|$tbx{binaryname}\n";
|
||||
close( BUILDDATA );
|
||||
}
|
||||
|
||||
sub compress_log_file {
|
||||
local( $done, $line);
|
||||
|
||||
return if ( $building );
|
||||
|
||||
open( LOG2, "<$ARGV[0]") || die "cant open $!";
|
||||
|
||||
#
|
||||
# Skip past the the RFC822.HEADER
|
||||
#
|
||||
$done = 0;
|
||||
while( !$done && ($line = <LOG2>) ){
|
||||
chomp($line);
|
||||
$done = ($line eq '');
|
||||
}
|
||||
|
||||
open( ZIPLOG, "| $gzip -c > ${tree}/$logfile" ) || die "can't open $! for writing";
|
||||
$inBinary = 0;
|
||||
$hasBinary = ($tbx{'binaryname'} ne '');
|
||||
while( $line = <LOG2> ){
|
||||
if( !$inBinary ){
|
||||
print ZIPLOG $line;
|
||||
if( $hasBinary ){
|
||||
$inBinary = ($line =~ /^begin [0-7][0-7][0-7] /);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if( $line =~ /^end\n/ ){
|
||||
$inBinary = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
close( ZIPLOG );
|
||||
close( LOG2 );
|
||||
|
||||
#
|
||||
# If a uuencoded binary is part of the build, unpack it.
|
||||
#
|
||||
if( $hasBinary ){
|
||||
$bin_dir = "$tbx{'tree'}/bin/$builddate/$tbx{'build'}";
|
||||
$bin_dir =~ s/ //g;
|
||||
|
||||
system("mkdir -m 0777 -p $bin_dir");
|
||||
|
||||
# LTNOTE: I'm not sure this is cross platform.
|
||||
system("/tools/ns/bin/uudecode --output-file=$bin_dir/$tbx{binaryname} < $ARGV[0]");
|
||||
}
|
||||
}
|
||||
|
||||
sub unlink_log_file {
|
||||
unlink( $ARGV[0] );
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.6 KiB |
@@ -1,782 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl --
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Tinderbox build tool.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
use lib '../bonsai';
|
||||
require 'globals.pl';
|
||||
require 'lloydcgi.pl';
|
||||
require 'imagelog.pl';
|
||||
require 'header.pl';
|
||||
$|=1;
|
||||
|
||||
# Hack this until I can figure out how to do get default root. -slamm
|
||||
$default_root = '/cvsroot';
|
||||
|
||||
# Show 12 hours by default
|
||||
#
|
||||
$nowdate = time;
|
||||
if (not defined($maxdate = $form{maxdate})) {
|
||||
$maxdate = $nowdate;
|
||||
}
|
||||
if ($form{showall}) {
|
||||
$mindate = 0;
|
||||
}
|
||||
else {
|
||||
$default_hours = 12;
|
||||
$hours = $default_hours;
|
||||
$hours = $form{hours} if $form{hours};
|
||||
$mindate = $maxdate - ($hours*60*60);
|
||||
}
|
||||
|
||||
%colormap = (
|
||||
success => '00ff00',
|
||||
busted => 'red',
|
||||
building => 'yellow',
|
||||
testfailed => 'orange'
|
||||
);
|
||||
|
||||
%images = (
|
||||
flames => '1afi003r.gif',
|
||||
star => 'star.gif'
|
||||
);
|
||||
|
||||
$tree = $form{tree};
|
||||
|
||||
if (exists $form{rebuildguilty} or exists $form{showall}) {
|
||||
system ("./buildwho.pl -days 7 $tree > /dev/null");
|
||||
undef $form{rebuildguilty};
|
||||
}
|
||||
&show_tree_selector, exit if $form{tree} eq '';
|
||||
&do_quickparse, exit if $form{quickparse};
|
||||
&do_express, exit if $form{express};
|
||||
&do_rdf, exit if $form{rdf};
|
||||
&do_static, exit if $form{static};
|
||||
&do_flash, exit if $form{flash};
|
||||
&do_panel, exit if $form{panel};
|
||||
&do_tinderbox, exit;
|
||||
|
||||
# end of main
|
||||
#=====================================================================
|
||||
|
||||
sub make_tree_list {
|
||||
my @result;
|
||||
while(<*>) {
|
||||
if( -d $_ && $_ ne 'data' && $_ ne 'CVS' && -f "$_/treedata.pl") {
|
||||
push @result, $_;
|
||||
}
|
||||
}
|
||||
return @result;
|
||||
}
|
||||
|
||||
sub show_tree_selector {
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
EmitHtmlHeader("tinderbox");
|
||||
|
||||
print "<P><TABLE WIDTH=\"100%\">";
|
||||
print "<TR><TD ALIGN=CENTER>Select one of the following trees:</TD></TR>";
|
||||
print "<TR><TD ALIGN=CENTER>\n";
|
||||
print " <TABLE><TR><TD><UL>\n";
|
||||
|
||||
my @list = make_tree_list();
|
||||
|
||||
foreach (@list) {
|
||||
print "<LI><a href=showbuilds.cgi?tree=$_>$_</a>\n";
|
||||
}
|
||||
print "<//UL></TD></TR></TABLE></TD></TR></TABLE>";
|
||||
|
||||
print "<P><TABLE WIDTH=\"100%\">";
|
||||
print "<TR><TD ALIGN=CENTER><a href=admintree.cgi>";
|
||||
print "Administer</a> one of the following trees:</TD></TR>";
|
||||
print "<TR><TD ALIGN=CENTER>\n";
|
||||
print " <TABLE><TR><TD><UL>\n";
|
||||
|
||||
foreach (@list) {
|
||||
print "<LI><a href=admintree.cgi?tree=$_>$_</a>\n";
|
||||
}
|
||||
print "<//UL></TD></TR></TABLE></TD></TR></TABLE>";
|
||||
}
|
||||
|
||||
sub do_static {
|
||||
local *OUT;
|
||||
|
||||
$form{nocrap}=1;
|
||||
|
||||
my @pages = ( ['index.html', 'do_tinderbox'],
|
||||
['flash.rdf', 'do_flash'],
|
||||
['panel.html', 'do_panel'] );
|
||||
|
||||
$rel_path = '../';
|
||||
while (($key, $value) = each %images) {
|
||||
$images{$key} = "$rel_path$value";
|
||||
}
|
||||
|
||||
my $oldfh = select;
|
||||
|
||||
foreach $pair (@pages) {
|
||||
my ($page, $call) = @{$pair};
|
||||
my $outfile = "$form{tree}/$page";
|
||||
|
||||
open(OUT,">$outfile.$$");
|
||||
select OUT;
|
||||
|
||||
eval "$call";
|
||||
|
||||
close(OUT);
|
||||
system "mv $outfile.$$ $outfile";
|
||||
}
|
||||
select $oldfh;
|
||||
}
|
||||
|
||||
sub do_tinderbox {
|
||||
&load_data;
|
||||
&print_page_head;
|
||||
&print_table_header;
|
||||
&print_table_body;
|
||||
&print_table_footer;
|
||||
}
|
||||
|
||||
sub print_page_head {
|
||||
|
||||
print "Content-type: text/html",
|
||||
($nowdate eq $maxdate ? "\nRefresh: 900" : ''),
|
||||
"\n\n<HTML>\n" unless $form{static};
|
||||
|
||||
# Get the message of the day only on the first pageful
|
||||
do "$tree/mod.pl" if $nowdate eq $maxdate;
|
||||
|
||||
use POSIX qw(strftime);
|
||||
# Print time in format, "HH:MM timezone"
|
||||
my $now = strftime("%H:%M %Z", localtime);
|
||||
|
||||
EmitHtmlTitleAndHeader("tinderbox: $tree", "tinderbox",
|
||||
"tree: $tree ($now)");
|
||||
|
||||
&print_javascript;
|
||||
|
||||
print "$message_of_day\n";
|
||||
|
||||
# Quote and Lengend
|
||||
#
|
||||
unless ($form{nocrap}) {
|
||||
my ($imageurl,$imagewidth,$imageheight,$quote) = &get_image;
|
||||
print qq{
|
||||
<table width="100%" cellpadding=0 cellspacing=0>
|
||||
<tr>
|
||||
<td valign=bottom>
|
||||
<p><center><a href=addimage.cgi><img src="$rel_path$imageurl"
|
||||
width=$imagewidth height=$imageheight><br>
|
||||
$quote</a><br>
|
||||
</center>
|
||||
<p>
|
||||
<td align=right valign=bottom>
|
||||
<table cellspacing=0 cellpadding=1 border=0><tr><td align=center>
|
||||
<TT>L</TT></td><td>= Show Build Log
|
||||
</td></tr><tr><td align=center>
|
||||
<img src="$images{star}"></td><td>= Show Log comments
|
||||
</td></tr><tr><td colspan=2>
|
||||
<table cellspacing=1 cellpadding=1 border=1>
|
||||
<tr bgcolor="$colormap{success}"><td>Successful Build
|
||||
<tr bgcolor="$colormap{building}"><td>Build in Progress
|
||||
<tr bgcolor="$colormap{testfailed}"><td>Successful Build,
|
||||
but Tests Failed
|
||||
<tr bgcolor="$colormap{busted}"><td>Build Failed
|
||||
</table>
|
||||
</td></tr></table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
};
|
||||
}
|
||||
if ($bonsai_tree) {
|
||||
print "The tree is currently <font size=+2>";
|
||||
print (&tree_open ? 'OPEN' : 'CLOSED');
|
||||
print "</font>\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub print_table_body {
|
||||
for (my $tt=1; $tt <= $time_count; $tt++) {
|
||||
last if $build_time_times->[$tt] < $mindate;
|
||||
print_table_row($tt);
|
||||
}
|
||||
}
|
||||
|
||||
sub print_table_row {
|
||||
my ($tt) = @_;
|
||||
|
||||
# Time column
|
||||
#
|
||||
my $query_link = '';
|
||||
my $end_query = '';
|
||||
my $pretty_time = &print_time($build_time_times->[$tt]);
|
||||
|
||||
($hour) = $pretty_time =~ /(\d\d):/;
|
||||
|
||||
if ($lasthour != $hour or &has_who_list($tt)) {
|
||||
$query_link = &query_ref($td1, $build_time_times->[$tt]);
|
||||
$end_query = '</a>';
|
||||
}
|
||||
if ($lasthour == $hour) {
|
||||
$pretty_time =~ s/^.* //;
|
||||
} else {
|
||||
$lasthour = $hour;
|
||||
}
|
||||
|
||||
my $hour_color = '';
|
||||
$hour_color = ' bgcolor=#e7e7e7' if $build_time_times->[$tt] % 7200 <= 3600;
|
||||
print "<tr align=center><td align=right$hour_color>",
|
||||
"$query_link\n$pretty_time$end_query</td>\n";
|
||||
|
||||
# Guilty
|
||||
#
|
||||
print '<td>';
|
||||
for $who (sort keys %{$who_list->[$tt]} ){
|
||||
$qr = &who_menu($td1, $build_time_times->[$tt],
|
||||
$build_time_times->[$tt-1],$who);
|
||||
$who =~ s/%.*$//;
|
||||
print " ${qr}$who</a>\n";
|
||||
}
|
||||
print '</td>';
|
||||
|
||||
# Build Status
|
||||
#
|
||||
for ($bn=1; $bn <= $name_count; $bn++) {
|
||||
if (not defined($br = $build_table->[$tt][$bn])) {
|
||||
# No build data for this time
|
||||
print "<td></td>\n";
|
||||
next;
|
||||
}
|
||||
next if $br == -1; # rowspan has covered this row
|
||||
|
||||
$hasnote = $br->{hasnote};
|
||||
$noteid = $hasnote ? $br->{noteid} : 0;
|
||||
$rowspan = $br->{rowspan};
|
||||
$rowspan = $mindate_time_count - $tt + 1
|
||||
if $tt + $rowspan - 1 > $mindate_time_count;
|
||||
$color = $colormap{$br->{buildstatus}};
|
||||
$status = $br->{buildstatus};
|
||||
print "<td rowspan=$rowspan bgcolor=${color}>\n";
|
||||
|
||||
$logfile = $br->{logfile};
|
||||
$errorparser = $br->{errorparser};
|
||||
$buildname = $br->{buildname};
|
||||
$buildtime = $br->{buildtime};
|
||||
$buildtree = $br->{td}->{name};
|
||||
|
||||
print "<tt>\n";
|
||||
|
||||
# Build Note
|
||||
#
|
||||
$buildname = &url_encode($buildname);
|
||||
my $logurl = "${rel_path}showlog.cgi?log=$buildtree/$logfile";
|
||||
|
||||
if ($hasnote) {
|
||||
print "<a href='$logurl' onclick=\"return ",
|
||||
"note(event,$noteid,'$logfile');\">",
|
||||
"<img src='$images{star}' border=0></a>\n";
|
||||
}
|
||||
|
||||
# Build Log
|
||||
#
|
||||
print "<A HREF='$logurl' onclick=\"return log(event,$bn,'$logfile');\">";
|
||||
print "L</a>";
|
||||
|
||||
# What Changed
|
||||
#
|
||||
if( $br->{previousbuildtime} ){
|
||||
my $previous_br = $build_table->[$tt+$rowspan][$bn];
|
||||
my $previous_rowspan = $previous_br->{rowspan};
|
||||
if (&has_who_list($tt+$rowspan,
|
||||
$tt+$rowspan+$previous_rowspan-1)) {
|
||||
print "\n", &query_ref($br->{td},
|
||||
$br->{previousbuildtime},
|
||||
$br->{buildtime});
|
||||
print "C</a>";
|
||||
}
|
||||
}
|
||||
|
||||
if ($br->{binaryname} ne '') {
|
||||
$binfile = "$buildtree/bin/$buildtime/$br->{buildname}/"
|
||||
."$br->{binaryname}";
|
||||
$binfile =~ s/ //g;
|
||||
print " <a href=$rel_path$binfile>B</a>";
|
||||
}
|
||||
print "</tt>\n</td>";
|
||||
}
|
||||
print "</tr>\n";
|
||||
}
|
||||
|
||||
sub print_table_header {
|
||||
my $ii, $nspan;
|
||||
|
||||
print "<table border=1 bgcolor='#FFFFFF' cellspacing=1 cellpadding=1>\n";
|
||||
|
||||
print "<tr align=center>\n";
|
||||
print "<td rowspan=1><font size=-1>Click time to <br>see changes <br>",
|
||||
"since time</font></td>";
|
||||
print "<td><font size=-1>",
|
||||
"Click name to see what they did</font>";
|
||||
print "<br><font size=-2>",
|
||||
&open_showbuilds_href(rebuildguilty=>'1'),
|
||||
"Rebuild guilty list</a></td>";
|
||||
|
||||
for ($ii=1; $ii <= $name_count; $ii++) {
|
||||
|
||||
my $bn = $build_name_names->[$ii];
|
||||
$bn =~ s/Clobber/Clbr/g;
|
||||
$bn =~ s/Depend/Dep/g;
|
||||
$bn = "<font face='Helvetica,Arial' size=-1>$bn</font>";
|
||||
|
||||
my $last_status = &last_status($ii);
|
||||
if ($last_status eq 'busted') {
|
||||
if ($form{nocrap}) {
|
||||
print "<td rowspan=2 bgcolor=$colormap{busted}>$bn</td>";
|
||||
} else {
|
||||
print "<td rowspan=2 bgcolor=000000 background='$images{flames}'>";
|
||||
print "<font color=white>$bn</font></td>";
|
||||
}
|
||||
}
|
||||
else {
|
||||
print "<td rowspan=2 bgcolor=$colormap{$last_status}>$bn</td>";
|
||||
}
|
||||
}
|
||||
print "</tr><tr>\n";
|
||||
print "<TH>Build Time</TH>\n";
|
||||
print "<TH>Guilty</th>\n";
|
||||
print "</tr>\n";
|
||||
}
|
||||
|
||||
sub print_table_footer {
|
||||
print "</table>\n";
|
||||
|
||||
my $nextdate = $maxdate - $hours*60*60;
|
||||
print &open_showbuilds_href(maxdate=>"$nextdate", nocrap=>'1')
|
||||
."Show next $hours hours</a>";
|
||||
|
||||
print "<p><a href='${rel_path}admintree.cgi?tree=$tree'>",
|
||||
"Administrate Tinderbox Trees</a><br>\n";
|
||||
}
|
||||
|
||||
sub open_showbuilds_url {
|
||||
my %args = (
|
||||
nocrap => "$form{nocrap}",
|
||||
@_
|
||||
);
|
||||
|
||||
my $url = "${rel_path}showbuilds.cgi?tree=$form{tree}";
|
||||
$url .= "&hours=$hours" if $hours ne $default_hours;
|
||||
while (my ($key, $value) = each %args) {
|
||||
$url .= "&$key=$value" if $value ne '';
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
sub open_showbuilds_href {
|
||||
return "<a href=".open_showbuilds_url(@_).">";
|
||||
}
|
||||
|
||||
sub query_ref {
|
||||
my ($td, $mindate, $maxdate, $who) = @_;
|
||||
my $output = '';
|
||||
|
||||
$output = "<a href=${rel_path}../bonsai/cvsquery.cgi";
|
||||
$output .= "?module=$td->{cvs_module}";
|
||||
$output .= "&branch=$td->{cvs_branch}" if $td->{cvs_branch} ne 'HEAD';
|
||||
$output .= "&cvsroot=$td->{cvs_root}" if $td->{cvs_root} ne $default_root;
|
||||
$output .= "&date=explicit&mindate=$mindate";
|
||||
$output .= "&maxdate=$maxdate" if $maxdate ne '';
|
||||
$output .= "&who=$who" if $who ne '';
|
||||
$output .= ">";
|
||||
}
|
||||
|
||||
sub query_ref2 {
|
||||
my ($td, $mindate, $maxdate, $who) = @_;
|
||||
return "${rel_path}../bonsai/cvsquery.cgi?module=$td->{cvs_module}"
|
||||
."&branch=$td->{cvs_branch}&cvsroot=$td->{cvs_root}"
|
||||
."&date=explicit&mindate=$mindate&maxdate=$maxdate&who="
|
||||
. url_encode($who);
|
||||
}
|
||||
|
||||
sub who_menu {
|
||||
my ($td, $mindate, $maxdate, $who) = @_;
|
||||
my $treeflag;
|
||||
|
||||
$qr = "${rel_path}../registry/who.cgi?email=". url_encode($who)
|
||||
. "&d=$td->{cvs_module}|$td->{cvs_branch}|$td->{cvs_root}|$mindate|$maxdate";
|
||||
|
||||
return "<a href='$qr' onclick=\"return who(event);\">";
|
||||
}
|
||||
|
||||
# Check to see if anyone checked in during time slot.
|
||||
# ex. has_who_list(1); # Check for checkins in most recent time slot.
|
||||
# ex. has_who_list(1,5); # Check range of times.
|
||||
sub has_who_list {
|
||||
my ($time1, $time2) = @_;
|
||||
|
||||
if (not defined(@who_check_list)) {
|
||||
# Build a static array of true/false values for each time slot.
|
||||
$who_check_list[$time_count] = 0;
|
||||
my ($t) = 1;
|
||||
for (; $t<=$time_count; $t++) {
|
||||
$who_check_list[$t] = 1 if each %{$who_list->[$t]};
|
||||
}
|
||||
}
|
||||
if ($time2) {
|
||||
for ($ii=$time1; $ii<=$time2; $ii++) {
|
||||
return 1 if $who_check_list[$ii]
|
||||
}
|
||||
return 0
|
||||
} else {
|
||||
return $who_check_list[$time1];
|
||||
}
|
||||
}
|
||||
|
||||
sub tree_open {
|
||||
my $done, $line, $a, $b;
|
||||
open(BID, "<../bonsai/data/$bonsai_tree/batchid")
|
||||
or print "can't open batchid<br>";
|
||||
($a,$b,$bid) = split / /, <BID>;
|
||||
close(BID);
|
||||
open(BATCH, "<../bonsai/data/$bonsai_tree/batch-${bid}")
|
||||
or print "can't open batch-${bid}<br>";;
|
||||
$done = 0;
|
||||
while (($line = <BATCH>) and not $done){
|
||||
if ($line =~ /^set treeopen/) {
|
||||
chop $line;
|
||||
($a,$b,$treestate) = split / /, $line ;
|
||||
$done = 1;
|
||||
}
|
||||
}
|
||||
close(BATCH);
|
||||
return $treestate;
|
||||
}
|
||||
|
||||
sub print_javascript {
|
||||
my $script;
|
||||
($script = <<"__ENDJS") =~ s/^ //gm;
|
||||
<script>
|
||||
if (parseInt(navigator.appVersion) < 4) {
|
||||
window.event = 0;
|
||||
}
|
||||
|
||||
function who(d) {
|
||||
var version = parseInt(navigator.appVersion);
|
||||
if (version < 4 || version >= 5) {
|
||||
return true;
|
||||
}
|
||||
var l = document.layers['popup'];
|
||||
l.src = d.target.href;
|
||||
l.top = d.target.y - 6;
|
||||
l.left = d.target.x - 6;
|
||||
if (l.left + l.clipWidth > window.width) {
|
||||
l.left = window.width - l.clipWidth;
|
||||
}
|
||||
l.visibility="show";
|
||||
return false;
|
||||
}
|
||||
function log_url(logfile) {
|
||||
return "showlog.cgi?log=" + buildtree + "/" + logfile;
|
||||
}
|
||||
function note(d,noteid,logfile) {
|
||||
var version = parseInt(navigator.appVersion);
|
||||
if (version < 4 || version >= 5) {
|
||||
document.location = log_url(logfile);
|
||||
return false;
|
||||
}
|
||||
var l = document.layers['popup'];
|
||||
l.document.write("<table border=1 cellspacing=1><tr><td>"
|
||||
+ notes[noteid] + "</tr></table>");
|
||||
l.document.close();
|
||||
|
||||
l.top = d.y-10;
|
||||
var zz = d.x;
|
||||
if (zz + l.clip.right > window.innerWidth) {
|
||||
zz = (window.innerWidth-30) - l.clip.right;
|
||||
if (zz < 0) { zz = 0; }
|
||||
}
|
||||
l.left = zz;
|
||||
l.visibility="show";
|
||||
return false;
|
||||
}
|
||||
function log(e,buildindex,logfile)
|
||||
{
|
||||
var logurl = log_url(logfile);
|
||||
var commenturl = "addnote.cgi?log=" + buildtree + "/" + logfile;
|
||||
var version = parseInt(navigator.appVersion);
|
||||
|
||||
if (version < 4 || version >= 5) {
|
||||
document.location = logurl;
|
||||
return false;
|
||||
}
|
||||
var q = document.layers["logpopup"];
|
||||
q.top = e.target.y - 6;
|
||||
|
||||
var yy = e.target.x;
|
||||
if ( yy + q.clip.right > window.innerWidth) {
|
||||
yy = (window.innerWidth-30) - q.clip.right;
|
||||
if (yy < 0) { yy = 0; }
|
||||
}
|
||||
q.left = yy;
|
||||
q.visibility="show";
|
||||
q.document.write("<TABLE BORDER=1><TR><TD><B>"
|
||||
+ builds[buildindex] + "</B><BR>"
|
||||
+ "<A HREF=$rel_path" + logurl + ">View Brief Log</A><BR>"
|
||||
+ "<A HREF=$rel_path" + logurl + "&fulltext=1"+">View Full Log</A><BR>"
|
||||
+ "<A HREF=$rel_path" + commenturl + ">Add a Comment</A><BR>"
|
||||
+ "</TD></TR></TABLE>");
|
||||
q.document.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
notes = new Array();
|
||||
builds = new Array();
|
||||
|
||||
__ENDJS
|
||||
print $script;
|
||||
|
||||
$ii = 0;
|
||||
while ($ii < @note_array) {
|
||||
$ss = $note_array[$ii];
|
||||
while ($ii < @note_array && $note_array[$ii] eq $ss) {
|
||||
print "notes[$ii] = ";
|
||||
$ii++;
|
||||
}
|
||||
$ss =~ s/\\/\\\\/g;
|
||||
$ss =~ s/\"/\\\"/g;
|
||||
$ss =~ s/\n/\\n/g;
|
||||
print "\"$ss\";\n";
|
||||
}
|
||||
for ($ii=1; $ii <= $name_count; $ii++) {
|
||||
if (defined($br = $build_table->[1][$ii]) and $br != -1) {
|
||||
my $bn = $build_name_names->[$ii];
|
||||
print "builds[$ii]='$bn';\n";
|
||||
}
|
||||
}
|
||||
print "buildtree = '$form{tree}';\n";
|
||||
|
||||
($script = <<'__ENDJS') =~ s/^ //gm;
|
||||
</script>
|
||||
|
||||
<layer name="popup" onMouseOut="this.visibility='hide';"
|
||||
left=0 top=0 bgcolor="#ffffff" visibility="hide">
|
||||
</layer>
|
||||
|
||||
<layer name="logpopup" onMouseOut="this.visibility='hide';"
|
||||
left=0 top=0 bgcolor="#ffffff" visibility="hide">
|
||||
</layer>
|
||||
__ENDJS
|
||||
print $script;
|
||||
}
|
||||
|
||||
sub do_express {
|
||||
print "Content-type: text/html\nRefresh: 900\n\n<HTML>\n";
|
||||
|
||||
my %build, %times;
|
||||
loadquickparseinfo($form{tree}, \%build, \%times);
|
||||
|
||||
my @keys = sort keys %build;
|
||||
my $keycount = @keys;
|
||||
my $tm = &print_time(time);
|
||||
print "<table border=1 cellpadding=1 cellspacing=1><tr>";
|
||||
print "<th align=left colspan=$keycount>";
|
||||
print &open_showbuilds_href."$tree as of $tm</a></tr><tr>\n";
|
||||
foreach my $buildname (@keys) {
|
||||
print "<td bgcolor='$colormap{$build{$buildname}}'>$buildname</td>";
|
||||
}
|
||||
print "</tr></table>\n";
|
||||
}
|
||||
|
||||
# This is essentially do_express but it outputs a different format
|
||||
sub do_panel {
|
||||
print "Content-type: text/html\n\n<HTML>\n" unless $form{static};
|
||||
|
||||
my %build, %times;
|
||||
loadquickparseinfo($form{tree}, \%build, \%times);
|
||||
|
||||
print q(
|
||||
<head>
|
||||
<META HTTP-EQUIV="Refresh" CONTENT="300">
|
||||
<style>
|
||||
body, td {
|
||||
font-family: Verdana, Sans-Serif;
|
||||
font-size: 8pt;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body BGCOLOR="#FFFFFF" TEXT="#000000"
|
||||
LINK="#0000EE" VLINK="#551A8B" ALINK="#FF0000">
|
||||
);
|
||||
# Hack the panel link for now.
|
||||
print "<a target='_content' href='http://tinderbox.mozilla.org/seamonkey/'>$tree";
|
||||
|
||||
$bonsai_tree = '';
|
||||
require "$tree/treedata.pl";
|
||||
if ($bonsai_tree ne '') {
|
||||
print " is ", tree_open() ? "OPEN" : "CLOSED";
|
||||
}
|
||||
# Add the current time
|
||||
my ($minute,$hour,$mday,$mon) = (localtime)[1..4];
|
||||
my $tm = sprintf("%d/%d %d:%02d",$mon+1,$mday,$hour,$minute);
|
||||
print " as of $tm</a><br>";
|
||||
|
||||
print "<table border=0 cellpadding=1 cellspacing=1>";
|
||||
while (my ($name, $status) = each %build) {
|
||||
print "<tr><td bgcolor='$colormap{$status}'>$name</td></tr>";
|
||||
}
|
||||
print "</table></body>";
|
||||
}
|
||||
|
||||
sub do_flash {
|
||||
print "Content-type: text/rdf\n\n" unless $form{static};
|
||||
|
||||
my %build, %times;
|
||||
loadquickparseinfo($form{tree}, \%build, \%times);
|
||||
|
||||
my ($mac,$unix,$win) = (0,0,0);
|
||||
|
||||
while (my ($name, $status) = each %build) {
|
||||
next if $status eq 'success';
|
||||
$mac = 1, next if $name =~ /Mac/;
|
||||
$win = 1, next if $name =~ /Win/;
|
||||
$unix = 1;
|
||||
}
|
||||
|
||||
print q{
|
||||
<RDF:RDF xmlns:RDF='http://www.w3.org/1999/02/22-rdf-syntax-ns#'
|
||||
xmlns:NC='http://home.netscape.com/NC-rdf#'>
|
||||
<RDF:Description about='NC:FlashRoot'>
|
||||
};
|
||||
|
||||
my $busted = $mac + $unix + $win;
|
||||
if ($busted) {
|
||||
|
||||
# Construct a legible sentence; e.g., "Mac, Unix, and Windows
|
||||
# are busted", "Windows is busted", etc. This is hideous. If
|
||||
# you can think of something better, please fix it.
|
||||
|
||||
my $text;
|
||||
if ($mac) {
|
||||
$text .= 'Mac' . ($busted > 2 ? ', ' : ($busted > 1 ? ' and ' : ''));
|
||||
}
|
||||
if ($unix) {
|
||||
$text .= 'Unix' . ($busted > 2 ? ', and ' : ($win ? ' and ' : ''));
|
||||
}
|
||||
if ($win) {
|
||||
$text .= 'Windows';
|
||||
}
|
||||
$text .= ($busted > 1 ? ' are ' : ' is ') . 'busted';
|
||||
|
||||
# The Flash spec says we need to give ctime.
|
||||
use POSIX;
|
||||
my $tm = POSIX::ctime(time());
|
||||
$tm =~ s/^...\s//; # Strip day of week
|
||||
$tm =~ s/:\d\d\s/ /; # Strip seconds
|
||||
chop $tm;
|
||||
|
||||
print qq{
|
||||
<NC:child>
|
||||
<RDF:Description ID='flash'>
|
||||
<NC:type resource='http://www.mozilla.org/RDF#TinderboxFlash' />
|
||||
<NC:source>$tree</NC:source>
|
||||
<NC:description>$text</NC:description>
|
||||
<NC:timestamp>$tm</NC:timestamp>
|
||||
</RDF:Description>
|
||||
</NC:child>
|
||||
};
|
||||
}
|
||||
print q{
|
||||
</RDF:Description>
|
||||
</RDF:RDF>
|
||||
};
|
||||
}
|
||||
|
||||
sub do_quickparse {
|
||||
print "Content-type: text/plain\n\n";
|
||||
|
||||
my @treelist = split /,/, $tree;
|
||||
foreach my $t (@treelist) {
|
||||
$bonsai_tree = "";
|
||||
require "$t/treedata.pl";
|
||||
if ($bonsai_tree ne "") {
|
||||
my $state = tree_open() ? "Open" : "Close";
|
||||
print "State|$t|$bonsai_tree|$state\n";
|
||||
}
|
||||
my %build, %times;
|
||||
loadquickparseinfo($t, \%build, \%times);
|
||||
|
||||
foreach my $buildname (sort keys %build) {
|
||||
print "Build|$t|$buildname|$build{$buildname}\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub do_rdf {
|
||||
print "Content-type: text/plain\n\n";
|
||||
|
||||
my $mainurl = "http://$ENV{SERVER_NAME}$ENV{SCRIPT_NAME}?tree=$tree";
|
||||
my $dirurl = $mainurl;
|
||||
|
||||
$dirurl =~ s@/[^/]*$@@;
|
||||
|
||||
my %build, %times;
|
||||
loadquickparseinfo($tree, \%build, \%times);
|
||||
|
||||
my $image = "channelok.gif";
|
||||
my $imagetitle = "OK";
|
||||
foreach my $buildname (sort keys %build) {
|
||||
if ($build{$buildname} eq 'busted') {
|
||||
$image = "channelflames.gif";
|
||||
$imagetitle = "Bad";
|
||||
last;
|
||||
}
|
||||
}
|
||||
print qq{<?xml version="1.0"?>
|
||||
<rdf:RDF
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns="http://my.netscape.com/rdf/simple/0.9/">
|
||||
<channel>
|
||||
<title>Tinderbox - $tree</title>
|
||||
<description>Build bustages for $tree</description>
|
||||
<link>$mainurl</link>
|
||||
</channel>
|
||||
<image>
|
||||
<title>$imagetitle</title>
|
||||
<url>$dirurl/$image</url>
|
||||
<link>$mainurl</link>
|
||||
</image>
|
||||
};
|
||||
|
||||
$bonsai_tree = '';
|
||||
require "$tree/treedata.pl";
|
||||
if ($bonsai_tree ne '') {
|
||||
my $state = tree_open() ? "OPEN" : "CLOSED";
|
||||
print "<item><title>The tree is currently $state</title>",
|
||||
"<link>$mainurl</link></item>\n";
|
||||
}
|
||||
|
||||
foreach my $buildname (sort keys %build) {
|
||||
if ($build{$buildname} eq 'busted') {
|
||||
print "<item><title>$buildname is in flames</title>",
|
||||
"<link>$mainurl</link></item>\n";
|
||||
}
|
||||
}
|
||||
print "</rdf:RDF>\n";
|
||||
}
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl --
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Tinderbox build tool.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
|
||||
$| = 1;
|
||||
|
||||
use lib "../bonsai";
|
||||
|
||||
require 'globals.pl';
|
||||
require 'imagelog.pl';
|
||||
require 'lloydcgi.pl';
|
||||
require 'header.pl';
|
||||
|
||||
check_password();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
@url = ();
|
||||
@quote = ();
|
||||
@width = ();
|
||||
@height = ();
|
||||
$i = 0;
|
||||
|
||||
EmitHtmlHeader("tinderbox: all images");
|
||||
|
||||
print '<UL>
|
||||
<P>These are all of the images currently in
|
||||
<A HREF=http://www.mozilla.org/tinderbox.html>Tinderbox</A>.
|
||||
<P>Please don\'t give out this URL: this is only here for our debugging
|
||||
needs, and isn\'t linked to by the rest of Tinderbox: because looking at
|
||||
all the images at once would be be cheating! you\'re supposed to let them
|
||||
surprise you over time. What, do you read ahead in your desktop calendar,
|
||||
too? Where\'s your sense of mystery and anticipation?
|
||||
|
||||
<P>
|
||||
</UL>
|
||||
';
|
||||
|
||||
|
||||
|
||||
|
||||
if ($form{'url'} ne "") {
|
||||
$oldname = "$data_dir/imagelog.txt";
|
||||
open (OLD, "<$oldname") || die "Oops; can't open imagelog.txt";
|
||||
$newname = "$oldname-$$";
|
||||
open (NEW, ">$newname") || die "Can't open $newname";
|
||||
$foundit = 0;
|
||||
while (<OLD>) {
|
||||
chop;
|
||||
($url, $width, $height, $quote) = split(/\`/);
|
||||
if ($url eq $form{'url'} && $quote eq $form{'origquote'}) {
|
||||
$foundit = 1;
|
||||
if ($form{'nukeit'} ne "") {
|
||||
next;
|
||||
}
|
||||
$quote = $form{'quote'};
|
||||
}
|
||||
print NEW "$url`$width`$height`$quote\n";
|
||||
}
|
||||
close OLD;
|
||||
close NEW;
|
||||
if (!$foundit) {
|
||||
print "<font color=red>Hey, couldn't find it!</font> Did someone\n";
|
||||
print "else already edit it?<P>\n";
|
||||
unlink $newname;
|
||||
} else {
|
||||
print "Change made.<P>";
|
||||
rename ($newname, $oldname) || die "Couldn't rename $newname to $oldname";
|
||||
}
|
||||
$form{'doedit'} = "1";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
$doedit = ($form{'doedit'} ne "");
|
||||
|
||||
if (!$doedit) {
|
||||
print "
|
||||
<form method=post>
|
||||
<input type=hidden name=password value=\"$form{'password'}\">
|
||||
<input type=hidden name=doedit value=1>
|
||||
<input type=submit value='Let me edit text or remove pictures.'>
|
||||
</form><P>";
|
||||
}
|
||||
|
||||
|
||||
|
||||
open( IMAGELOG, "<$data_dir/imagelog.txt" ) || die "can't open file";
|
||||
while( <IMAGELOG> ){
|
||||
chop;
|
||||
($url[$i],$width[$i],$height[$i],$quote[$i]) = split(/\`/);
|
||||
$i++;
|
||||
}
|
||||
close( IMAGELOG );
|
||||
|
||||
$i--;
|
||||
print "<center>";
|
||||
while( $i >= 0 ){
|
||||
$qurl = value_encode($url[$i]);
|
||||
$qquote = value_encode($quote[$i]);
|
||||
print "
|
||||
<img border=2 src='$url[$i]' width='$width[$i]' height='$height[$i]'><br>
|
||||
<i>$quote[$i]</i>";
|
||||
if ($doedit) {
|
||||
print "
|
||||
<form method=post>
|
||||
<input type=submit name=nukeit value='Delete this image'><br>
|
||||
<input name=quote size=60 value=\"$qquote\"><br>
|
||||
<input type=submit name=edit value='Change text'><hr>
|
||||
<input type=hidden name=url value=\"$qurl\">
|
||||
<input type=hidden name=origquote value=\"$qquote\">
|
||||
<input type=hidden name=password value=\"$form{'password'}\">
|
||||
</form>";
|
||||
}
|
||||
print "<br><br>\n";
|
||||
$i--;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,375 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl --
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Tinderbox build tool.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
use lib '../bonsai';
|
||||
|
||||
require 'globals.pl';
|
||||
require 'lloydcgi.pl';
|
||||
require 'header.pl';
|
||||
|
||||
#############################################################
|
||||
# Global variables
|
||||
|
||||
$LINES_AFTER_ERROR = 5;
|
||||
$LINES_BEFORE_ERROR = 30;
|
||||
|
||||
# These variables are set by the error parser functions:
|
||||
# has_error(), has_warning(), and has_errorline().
|
||||
$error_file = '';
|
||||
$error_file_ref = '';
|
||||
$error_line = 0;
|
||||
$error_guess = 0;
|
||||
|
||||
$next_err = 0;
|
||||
@log_errors = ();
|
||||
$log_line = 0;
|
||||
|
||||
#############################################################
|
||||
# CGI inputs
|
||||
|
||||
if (defined($args = $form{log}) or defined($args = $form{exerpt})) {
|
||||
|
||||
($full_logfile, $linenum) = split /:/, $args;
|
||||
($tree, $logfile) = split /\//, $full_logfile;
|
||||
|
||||
my $br = find_build_record($tree, $logfile);
|
||||
$errorparser = $br->{errorparser};
|
||||
$buildname = $br->{buildname};
|
||||
$buildtime = $br->{buildtime};
|
||||
|
||||
$numlines = 50;
|
||||
$numlines = $form{numlines} if exists $form{numlines};
|
||||
} else {
|
||||
$tree = $form{tree};
|
||||
$errorparser = $form{errorparser};
|
||||
$logfile = $form{logfile};
|
||||
$buildname = $form{buildname};
|
||||
$buildtime = $form{buildtime};
|
||||
}
|
||||
$fulltext = $form{fulltext};
|
||||
|
||||
$enc_buildname = &url_encode($buildname);
|
||||
|
||||
die "the \"tree\" parameter must be provided\n" unless $tree;
|
||||
require "$tree/treedata.pl";
|
||||
|
||||
$time_str = print_time( $buildtime );
|
||||
|
||||
$|=1;
|
||||
|
||||
if ($linenum) {
|
||||
|
||||
&print_fragment;
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
&print_header;
|
||||
&print_notes;
|
||||
|
||||
# Dynamically load the error parser
|
||||
#
|
||||
die "the \"errorparser\" parameter must be provided\n" unless $errorparser;
|
||||
require "ep_${errorparser}.pl";
|
||||
|
||||
if ($fulltext)
|
||||
{
|
||||
&print_summary;
|
||||
&print_log;
|
||||
}
|
||||
else
|
||||
{
|
||||
$brief_filename = $logfile;
|
||||
$brief_filename =~ s/.gz$/.brief.html/;
|
||||
if (-T "$tree/$brief_filename" and -M _ > -M $tree/$logfile)
|
||||
{
|
||||
open (BRIEFFILE, "<$tree/$brief_filename");
|
||||
print while (<BRIEFFILE>)
|
||||
}
|
||||
else
|
||||
{
|
||||
open (BRIEFFILE, ">$tree/$brief_filename");
|
||||
|
||||
&print_summary;
|
||||
&print_log;
|
||||
}
|
||||
}
|
||||
|
||||
# end of main
|
||||
############################################################
|
||||
|
||||
sub print_fragment {
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
print "<META HTTP-EQUIV=\"EXPIRES\" CONTENT=\"1\">\n";
|
||||
|
||||
my $heading = "Build Log (Fragment)";
|
||||
my $subheading = "$buildname on $time_str";
|
||||
my $title = "$heading - $subheading";
|
||||
|
||||
EmitHtmlTitleAndHeader($title, $heading, $subheading);
|
||||
|
||||
print "<a href='showlog.cgi?tree=$tree&errorparser=$errorparser&logfile=$logfile&buildtime=$buildtime&buildname=$enc_buildname&fulltext=1'>Show Full Build Log</a>";
|
||||
|
||||
open(BUILD_IN, "$gzip -d -c $tree/$logfile|");
|
||||
|
||||
my $first_line = $linenum - ($numlines/2);
|
||||
my $last_line = $linenum + ($numlines/2);
|
||||
|
||||
print "<pre><b>.<br>.<br>.<br></b>";
|
||||
while(<BUILD_IN>) {
|
||||
next if $. < $first_line;
|
||||
last if $. > $last_line;
|
||||
print "<b><font color='red'>" if $. == $linenum;
|
||||
print;
|
||||
print "</font></b>" if $. == $linenum;
|
||||
}
|
||||
print "<b>.<br>.<br>.<br></b></pre>";
|
||||
|
||||
}
|
||||
|
||||
sub print_header {
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
if( $fulltext ){
|
||||
$s = 'Show <b>Brief</b> Log';
|
||||
$s1 = '';
|
||||
$s2 = 'Full';
|
||||
}
|
||||
else {
|
||||
$s = 'Show <b>Full</b> Log';
|
||||
$s1 = 1;
|
||||
$s2 = 'Brief';
|
||||
}
|
||||
|
||||
print "<META HTTP-EQUIV=\"EXPIRES\" CONTENT=\"1\">\n";
|
||||
|
||||
my $heading = "Build Log ($s2)";
|
||||
my $subheading = "$buildname on $time_str";
|
||||
my $title = "$heading - $subheading";
|
||||
|
||||
EmitHtmlTitleAndHeader($title, $heading, $subheading);
|
||||
|
||||
print "
|
||||
<font size=+1>
|
||||
<dt><a href='showlog.cgi?tree=$tree&errorparser=$errorparser&logfile=$logfile&buildtime=$buildtime&buildname=$enc_buildname&fulltext=$s1'>$s</a>
|
||||
<dt><a href=\"showbuilds.cgi?tree=$tree\">Return to the Build Page</a>
|
||||
<dt><a href=\"addnote.cgi?tree=$tree\&buildname=$enc_buildname\&buildtime=$buildtime\&logfile=$logfile\&errorparser=$errorparser\">
|
||||
Add a Comment to the Log</a>
|
||||
</font>
|
||||
";
|
||||
}
|
||||
|
||||
sub print_notes {
|
||||
#
|
||||
# Print notes
|
||||
#
|
||||
$found_note = 0;
|
||||
open(NOTES,"<$tree/notes.txt")
|
||||
or print "<h2>warning: Couldn't open $tree/notes.txt </h2>\n";
|
||||
print "$buildtime, $buildname<br>\n";
|
||||
while(<NOTES>){
|
||||
chop;
|
||||
($nbuildtime,$nbuildname,$nwho,$nnow,$nenc_note) = split(/\|/);
|
||||
#print "$_<br>\n";
|
||||
if( $nbuildtime == $buildtime && $nbuildname eq $buildname ){
|
||||
if( !$found_note ){
|
||||
print "<H2>Build Comments</H2>\n";
|
||||
$found_note = 1;
|
||||
}
|
||||
$now_str = &print_time($nnow);
|
||||
$note = &url_decode($nenc_note);
|
||||
print "<pre>\n[<b><a href=mailto:$nwho>$nwho</a> - $now_str</b>]\n$note\n</pre>";
|
||||
}
|
||||
}
|
||||
close(NOTES);
|
||||
}
|
||||
|
||||
sub print_summary {
|
||||
#
|
||||
# Print the summary first
|
||||
#
|
||||
logprint('<H2>Build Error Summary</H2><PRE>');
|
||||
|
||||
$log_line = 0;
|
||||
open( BUILD_IN, "$gzip -d -c $tree/$logfile|" );
|
||||
while( $line = <BUILD_IN> ){
|
||||
&output_summary_line( $line );
|
||||
}
|
||||
close( BUILD_IN );
|
||||
push @log_errors, 9999999;
|
||||
|
||||
logprint('</PRE>');
|
||||
}
|
||||
|
||||
sub print_log_section {
|
||||
my ($tree, $logfile, $line_of_interest, $num_lines) = shift;
|
||||
local $_;
|
||||
|
||||
my $first_line = $line_of_interest - $num_lines / 2;
|
||||
my $last_line = $first_line + $num_lines;
|
||||
|
||||
print "<a href='showlog.cgi?tree=$tree&logfile=$logfile&line="
|
||||
.($line_of_interest-$num_lines)."&numlines=$num_lines'>"
|
||||
."Previous $num_lines</a>";
|
||||
print "<font size='+1'><b>.<br>.<br>.<br></b></font>";
|
||||
print "<pre>";
|
||||
my $ii = 0;
|
||||
open BUILD_IN, "$gzip -d -c $tree/$logfile|";
|
||||
while (<BUILD_IN>) {
|
||||
$ii++;
|
||||
next if $ii < $first_line;
|
||||
last if $ii > $last_line;
|
||||
if ($ii == $line_of_intested) {
|
||||
print "<b>$_</b>";
|
||||
} else {
|
||||
print;
|
||||
}
|
||||
}
|
||||
close BUILD_IN;
|
||||
print "</pre>";
|
||||
print "<font size='+1'><b>.<br>.<br>.<br></b></font>";
|
||||
print "<a href='showlog.cgi?tree=$tree&logfile=$logfile&line="
|
||||
.($line_of_interest+$num_lines)."&numlines=$num_lines'>"
|
||||
."Next $num_lines</a>";
|
||||
}
|
||||
|
||||
sub print_log {
|
||||
#
|
||||
# reset the error counter
|
||||
#
|
||||
$next_err = 0;
|
||||
|
||||
logprint('<H2>Build Error Log</H2><pre>');
|
||||
|
||||
$log_line = 0;
|
||||
open( BUILD_IN, "$gzip -d -c $tree/$logfile|" );
|
||||
while( $line = <BUILD_IN> ){
|
||||
&output_log_line( $line );
|
||||
}
|
||||
close( BUILD_IN );
|
||||
|
||||
logprint('</PRE><p>'
|
||||
."<font size=+1><a name=\"err$next_err\">No More Errors</a></font>"
|
||||
.'<br><br><br>');
|
||||
}
|
||||
|
||||
sub output_summary_line {
|
||||
my( $line ) = $_[0];
|
||||
my( $has_error );
|
||||
|
||||
$has_error = &has_error( $line );
|
||||
|
||||
$line =~ s/&/&/g;
|
||||
$line =~ s/</</g;
|
||||
|
||||
if( $has_error ){
|
||||
push @log_errors, $log_line + $LINES_AFTER_ERROR;
|
||||
if( ! $last_was_error ) {
|
||||
logprint("<a href=\"#err$next_err\">$line</a>");
|
||||
$next_err++;
|
||||
}
|
||||
$last_was_error = 1;
|
||||
}
|
||||
else {
|
||||
$last_was_error = 0;
|
||||
}
|
||||
|
||||
$log_line++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub output_log_line {
|
||||
my( $line ) = $_[0];
|
||||
my( $has_error, $dur, $dur_min,$dur_sec, $dur_str, $logline );
|
||||
|
||||
$has_error = &has_error( $line );
|
||||
$has_warning = &has_warning( $line );
|
||||
|
||||
$line =~ s/&/&/g;
|
||||
$line =~ s/</</g;
|
||||
|
||||
$logline = '';
|
||||
|
||||
if( ($has_error || $has_warning) && &has_errorline( $line ) ) {
|
||||
$q = quotemeta( $error_file );
|
||||
#$goto_line = ($error_line ? 10 > $error_line - 10 : 1 );
|
||||
$goto_line = ($error_line > 10 ? $error_line - 10 : 1 );
|
||||
$cvsblame = ($error_guess ? "cvsguess.cgi" : "cvsblame.cgi");
|
||||
$line =~ s@$q@<a href=../bonsai/$cvsblame?file=$error_file_ref&rev=$cvs_branch&mark=$error_line#$goto_line $source_target>$error_file</a>@
|
||||
}
|
||||
|
||||
|
||||
if( $has_error ){
|
||||
if( ! $last_was_error ) {
|
||||
$logline .= "<a name=\"err$next_err\"></a>";
|
||||
$next_err++;
|
||||
$logline .= "<a href=\"#err$next_err\">NEXT</a> ";
|
||||
}
|
||||
else {
|
||||
$logline .= " ";
|
||||
}
|
||||
|
||||
$logline .= "<font color=\"000080\">$line</font>";
|
||||
|
||||
$last_was_error = 1;
|
||||
}
|
||||
elsif( $has_warning ){
|
||||
$logline .= " ";
|
||||
$logline .= "<font color=000080>$line</font>";
|
||||
}
|
||||
else {
|
||||
$logline .= " $line";
|
||||
$last_was_error = 0;
|
||||
}
|
||||
|
||||
&push_log_line( $logline );
|
||||
}
|
||||
|
||||
|
||||
sub push_log_line {
|
||||
my( $line ) = $_[0];
|
||||
if( $fulltext ){
|
||||
logprint($line);
|
||||
return;
|
||||
}
|
||||
|
||||
if( $log_line > $log_errors[$cur_error] ){
|
||||
$cur_error++;
|
||||
}
|
||||
|
||||
if( $log_line >= $log_errors[$cur_error] - $LINES_BEFORE_ERROR ){
|
||||
if( $log_skip != 0 ){
|
||||
logprint("\n<i><font size=+1> Skipping $log_skip Lines...</i></font>\n\n");
|
||||
$log_skip = 0;
|
||||
}
|
||||
logprint($line);
|
||||
}
|
||||
else {
|
||||
$log_skip++;
|
||||
}
|
||||
$log_line++;
|
||||
}
|
||||
|
||||
sub logprint {
|
||||
my $line = $_[0];
|
||||
print $line;
|
||||
print BRIEFFILE $line if not $fulltext;
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 227 B |
@@ -1,75 +0,0 @@
|
||||
# The contents of this file are subject to the Mozilla Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License
|
||||
# at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
# the License for the specific language governing rights and
|
||||
# limitations under the License.
|
||||
#
|
||||
# The Original Code is the Tinderbox CVS Tool rpm spec file.
|
||||
#
|
||||
# The Initial Developer of this code under the MPL is Christopher
|
||||
# Seawood, <cls@seawood.org>. Portions created by Christopher Seawood
|
||||
# are Copyright (C) 1998 Christopher Seawood. All Rights Reserved.
|
||||
|
||||
%define ver SNAP
|
||||
%define perl /usr/bin/perl
|
||||
%define cvsroot /cvsroot
|
||||
%define gzip /usr/bin/gzip
|
||||
%define uudecode /usr/bin/uudecode
|
||||
%define bonsai ../bonsai
|
||||
%define prefix /home/httpd/html/tinderbox
|
||||
# This rpm is not relocateable
|
||||
Summary: automated build tool
|
||||
Name: tinderbox
|
||||
Version: %{ver}
|
||||
Release: 1
|
||||
Copyright: NPL
|
||||
Group: Networking/Admin
|
||||
Source: %{name}-%{ver}.tar.gz
|
||||
BuildRoot: /var/tmp/build-%{name}
|
||||
Requires: bonsai
|
||||
Packager: Christopher Seawood <cls@seawood.org>
|
||||
|
||||
%changelog
|
||||
* Thu Nov 12 1998 Christopher Seawood <cls@seawood.org>
|
||||
- Replaced ver with SNAP
|
||||
|
||||
* Mon Oct 26 1998 Christopher Seawood <cls@seawood.org>
|
||||
- Added MPL header
|
||||
|
||||
* Sun Aug 31 1998 Christopher Seawood <cls@seawood.org>
|
||||
- Made rpm from cvs snapshot
|
||||
|
||||
%description
|
||||
Essentially, Tinderbox is a detective tool. It allows you to see what
|
||||
is happening in the source tree. It shows you who checked in what (by
|
||||
asking Bonsai); what platforms have built successfully; what platforms
|
||||
are broken and exactly how they are broken (the build logs); and the
|
||||
state of the files that made up the build (cvsblame) so you can figure
|
||||
out who broke the build, so you can do the most important thing, hold
|
||||
them accountable for their actions.
|
||||
|
||||
%prep
|
||||
%setup -n %{name}
|
||||
|
||||
%build
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
mkdir -p ${RPM_BUILD_ROOT}%{prefix}/{data,examples}
|
||||
make install PERL=%perl UUDECODE=%uudecode GZIP=%gzip BONSAI=%bonsai CVSROOT=%cvsroot PREFIX=${RPM_BUILD_ROOT}%prefix
|
||||
|
||||
%post
|
||||
echo "Remember to set the admin passwd via '%{bonsai}/data/trapdoor password > %{prefix}/data/passwd"
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%files
|
||||
%defattr (-, nobody, nobody)
|
||||
%doc README Makefile
|
||||
%{prefix}
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
#!/usr/bonsaitools/bin/perl --
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Tinderbox build tool.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
use lib '../bonsai';
|
||||
require "globals.pl";
|
||||
require 'lloydcgi.pl';
|
||||
require 'header.pl';
|
||||
|
||||
use Date::Parse;
|
||||
use Date::Format;
|
||||
|
||||
my $TIMEFORMAT = "%D %T";
|
||||
|
||||
$| = 1;
|
||||
|
||||
print "Content-type: text/html\n\n<HTML>\n";
|
||||
|
||||
my $tree = $form{'tree'};
|
||||
my $start = $form{'start'};
|
||||
my $end = $form{'end'};
|
||||
|
||||
sub str2timeAndCheck {
|
||||
my ($str) = (@_);
|
||||
my $result = str2time($str);
|
||||
if (defined $result && $result > 7000000) {
|
||||
return $result;
|
||||
}
|
||||
print "<p><font color=red>Can't parse as a date: $str</font><p>\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
my $header = "<table border=1><th>Build time</th><th>Build name</th><th>Who</th><th>Note time</th><th>Note</th>";
|
||||
|
||||
if (defined $tree && defined $start && defined $end) {
|
||||
my $first = str2timeAndCheck($start);
|
||||
my $last = str2timeAndCheck($end);
|
||||
if ($first > 0 && $last > 0) {
|
||||
if (open(IN, "<$tree/notes.txt")) {
|
||||
print "<hr><center><h1>Notes for $tree</H1><H3>from " .
|
||||
time2str($TIMEFORMAT, $first) . " to " .
|
||||
time2str($TIMEFORMAT, $last) . "</H3></center>\n";
|
||||
my %stats;
|
||||
print "$header\n";
|
||||
while (<IN>) {
|
||||
chop;
|
||||
my ($nbuildtime,$nbuildname,$nwho,$nnow,$nenc_note)
|
||||
= split /\|/;
|
||||
if ($nbuildtime >= $first && $nbuildtime <= $last) {
|
||||
my $note = &url_decode($nenc_note);
|
||||
$nbuildtime = print_time($nbuildtime);
|
||||
$nnow = print_time($nnow);
|
||||
print "<tr>";
|
||||
print "<td>$nbuildtime</td>";
|
||||
print "<td>$nbuildname</td>";
|
||||
print "<td>$nwho</td>";
|
||||
print "<td>$nnow</td>";
|
||||
print "<td>$note</td>";
|
||||
print "</tr>\n";
|
||||
if (++$count % 100 == 0) {
|
||||
print "</table>$header\n";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
print "<p><font color=red>There does not appear to be a tree " .
|
||||
"named '$tree'.</font><p>";
|
||||
}
|
||||
}
|
||||
print "</table>\n";
|
||||
}
|
||||
|
||||
if (!defined $tree) {
|
||||
$tree = "";
|
||||
}
|
||||
|
||||
if (!defined $start) {
|
||||
$start = time2str($TIMEFORMAT, time() - 7*24*60*60); # One week ago.
|
||||
}
|
||||
|
||||
|
||||
if (!defined $end) {
|
||||
$end = time2str($TIMEFORMAT, time()); # #now
|
||||
}
|
||||
|
||||
print qq|
|
||||
<form>
|
||||
<table>
|
||||
<tr>
|
||||
<th align=right>Tree:</th>
|
||||
<td><input name=tree size=30 value="$tree"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th align=right>Start time:</th>
|
||||
<td><input name=start size=30 value="$start"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th align=right>End time:</th>
|
||||
<td><input name=end size=30 value="$end"></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<INPUT TYPE=\"submit\" VALUE=\"View Notes \">
|
||||
|
||||
</form>
|
||||
|;
|
||||
@@ -1,437 +0,0 @@
|
||||
#! /usr/bonsaitools/bin/perl
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License
|
||||
# Version 1.1 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is Tinderbox
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1999
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Stephen Lamm <slamm@mozilla.org>
|
||||
|
||||
use FileHandle;
|
||||
|
||||
$tree = 'SeaMonkey';
|
||||
# tinderbox/globals.pl uses many shameful globals
|
||||
$form{tree} = $tree;
|
||||
require 'globals.pl';
|
||||
|
||||
$cvsroot = '/cvsroot/mozilla';
|
||||
$lxr_data_root = '/export2/lxr-data';
|
||||
@ignore = (
|
||||
'long long',
|
||||
'__cmsg_data',
|
||||
'location of the previous definition',
|
||||
'\' was hidden',
|
||||
'declaration of \`index\'',
|
||||
);
|
||||
$ignore_pat = "(?:".join('|',@ignore).")";
|
||||
|
||||
print STDERR "Building hash of file names...";
|
||||
($file_bases, $file_fullpaths) = build_file_hash($cvsroot, $tree);
|
||||
print STDERR "done.\n";
|
||||
|
||||
for $br (last_successful_builds($tree)) {
|
||||
next unless $br->{buildname} =~ /shrike.*\b(Clobber|Clbr)\b/;
|
||||
|
||||
my $log_file = "$br->{logfile}";
|
||||
|
||||
warn "Parsing build log, $log_file\n";
|
||||
|
||||
$fh = new FileHandle "gunzip -c $tree/$log_file |";
|
||||
&gcc_parser($fh, $cvsroot, $tree, $log_file, $file_bases, $file_fullpaths);
|
||||
$fh->close;
|
||||
|
||||
&build_blame;
|
||||
|
||||
my $warn_file = "$tree/warn$log_file";
|
||||
$warn_file =~ s/.gz$/.html/;
|
||||
|
||||
$fh->open(">$warn_file") or die "Unable to open $warn_file: $!\n";
|
||||
&print_warnings_as_html($fh, $br);
|
||||
$fh->close;
|
||||
warn "Wrote output to $warn_file\n";
|
||||
|
||||
last;
|
||||
}
|
||||
|
||||
# end of main
|
||||
# ===================================================================
|
||||
|
||||
sub build_file_hash {
|
||||
my ($cvsroot, $tree) = @_;
|
||||
|
||||
$lxr_data_root = "/export2/lxr-data/\L$tree";
|
||||
|
||||
$lxr_file_list = "\L$lxr_data_root/.glimpse_filenames";
|
||||
open(LXR_FILENAMES, "<$lxr_file_list")
|
||||
or die "Unable to open $lxr_file_list: $!\n";
|
||||
|
||||
use File::Basename;
|
||||
|
||||
while (<LXR_FILENAMES>) {
|
||||
my ($base, $dir, $ext) = fileparse($_,'\.[^/]*');
|
||||
|
||||
next unless $ext =~ /^\.(cpp|h|C|s|c|mk|in)$/;
|
||||
|
||||
$base = "$base$ext";
|
||||
$dir =~ s|$lxr_data_root/mozilla/||;
|
||||
$dir =~ s|/$||;
|
||||
|
||||
$fullpath{"$dir/$base"}=1;
|
||||
|
||||
unless (exists $bases{$base}) {
|
||||
$bases{$base} = $dir;
|
||||
} else {
|
||||
$bases{$base} = '[multiple]';
|
||||
}
|
||||
}
|
||||
return \%bases, \%fullpath;
|
||||
}
|
||||
|
||||
sub last_successful_builds {
|
||||
my $tree = shift;
|
||||
my @build_records = ();
|
||||
my $br;
|
||||
|
||||
|
||||
$maxdate = time;
|
||||
$mindate = $maxdate - 5*60*60; # Go back 5 hours
|
||||
|
||||
print STDERR "Loading build data...";
|
||||
&load_data;
|
||||
print STDERR "done\n";
|
||||
|
||||
for (my $ii=1; $ii <= $name_count; $ii++) {
|
||||
for (my $tt=1; $tt <= $time_count; $tt++) {
|
||||
if (defined($br = $build_table->[$tt][$ii])
|
||||
and $br->{buildstatus} eq 'success') {
|
||||
push @build_records, $br;
|
||||
last;
|
||||
} } }
|
||||
return @build_records;
|
||||
}
|
||||
|
||||
sub gcc_parser {
|
||||
my ($fh, $cvsroot, $tree, $log_file, $file_bases, $file_fullnames) = @_;
|
||||
my $dir = '';
|
||||
|
||||
while (<$fh>) {
|
||||
# Directory
|
||||
#
|
||||
if (/^gmake\[\d\]: Entering directory \`(.*)\'$/) {
|
||||
($build_dir = $1) =~ s|.*/mozilla/||;
|
||||
next;
|
||||
}
|
||||
|
||||
# Now only match lines with "warning:"
|
||||
next unless /warning:/;
|
||||
next if /$ignore_pat/o;
|
||||
|
||||
chomp; # Yum, yum
|
||||
|
||||
my ($filename, $line, $warning_text);
|
||||
($filename, $line, undef, $warning_text) = split /:\s*/, $_, 4;
|
||||
$filename =~ s/.*\///;
|
||||
|
||||
# Special case for Makefiles
|
||||
$filename =~ s/Makefile$/Makefile.in/;
|
||||
|
||||
my $dir = '';
|
||||
if ($file_fullnames->{"$build_dir/$filename"}) {
|
||||
$dir = $build_dir;
|
||||
} else {
|
||||
unless(defined($dir = $file_bases->{$filename})) {
|
||||
$dir = '[no_match]';
|
||||
}
|
||||
}
|
||||
my $file = "$dir/$filename";
|
||||
|
||||
unless (defined($warnings{$file}{$line})) {
|
||||
|
||||
# Special case for "`foo' was hidden\nby `foo2'"
|
||||
$warning_text = "...was hidden " . $warning_text
|
||||
if $warning_text =~ /^by \`/;
|
||||
|
||||
# Remember where in the build log the warning occured
|
||||
$warnings{$file}{$line} = {
|
||||
first_seen_line => $.,
|
||||
log_file => $log_file,
|
||||
warning_text => $warning_text,
|
||||
};
|
||||
}
|
||||
$warnings{$file}{$line}->{count}++;
|
||||
$total_warnings_count++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub dump_warning_data {
|
||||
while (my ($file, $lines_hash) = each %warnings) {
|
||||
while (my ($line, $record) = each %{$lines_hash}) {
|
||||
print join ':',
|
||||
$file,$line,
|
||||
$record->{first_seen_line},
|
||||
$record->{count},
|
||||
$record->{warning_text};
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub build_blame {
|
||||
use lib '../bonsai';
|
||||
require 'utils.pl';
|
||||
require 'cvsblame.pl';
|
||||
|
||||
while (($file, $lines_hash) = each %warnings) {
|
||||
|
||||
my $rcs_filename = "$cvsroot/$file,v";
|
||||
|
||||
unless (-e $rcs_filename) {
|
||||
warn "Unable to find $rcs_filename\n";
|
||||
$unblamed{$file} = 1;
|
||||
next;
|
||||
}
|
||||
|
||||
my $revision = &parse_cvs_file($rcs_filename);
|
||||
@text = &extract_revision($revision);
|
||||
while (my ($line, $warn_rec) = each %{$lines_hash}) {
|
||||
my $line_rev = $revision_map[$line-1];
|
||||
my $who = $revision_author{$line_rev};
|
||||
my $source_text = join '', @text[$line-3..$line+1];
|
||||
$source_text =~ s/\t/ /g;
|
||||
|
||||
$who = "$who%netscape.com" unless $who =~ /[%]/;
|
||||
|
||||
$warn_rec->{line_rev} = $line_rev;
|
||||
$warn_rec->{source} = $source_text;
|
||||
|
||||
$warnings_by_who{$who}{$file}{$line} = $warn_rec;
|
||||
|
||||
$total_who_count++ unless exists $who_count{$who};
|
||||
$who_count{$who} += $warn_rec->{count};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub print_warnings_as_html {
|
||||
my ($fh, $br) = @_;
|
||||
my ($buildname, $buildtime) = ($br->{buildname}, $br->{buildtime});
|
||||
|
||||
my $time_str = print_time( $buildtime );
|
||||
|
||||
# Change the default destination for print to $fh
|
||||
my $old_fh = select($fh);
|
||||
|
||||
print <<"__END_HEADER";
|
||||
<html>
|
||||
<head>
|
||||
<title>Blamed Build Warnings</title>
|
||||
</head>
|
||||
<body>
|
||||
<font size="+2" face="Helvetica,Arial"><b>
|
||||
Blamed Build Warnings
|
||||
</b></font><br>
|
||||
<font size="+1" face="Helvetica,Arial">
|
||||
$buildname on $time_str<br>
|
||||
$total_warnings_count total warnings
|
||||
</font><p>
|
||||
|
||||
__END_HEADER
|
||||
|
||||
for $who (sort { $who_count{$b} <=> $who_count{$a}
|
||||
|| $a cmp $b } keys %who_count) {
|
||||
push @who_list, $who;
|
||||
}
|
||||
|
||||
# Summary Table (name, count)
|
||||
#
|
||||
use POSIX;
|
||||
print "<table border=0 cellpadding=1 cellspacing=0 bgcolor=#ededed>\n";
|
||||
my $num_columns = 6;
|
||||
my $num_rows = ceil($#who_list / $num_columns);
|
||||
for (my $ii=0; $ii < $num_rows; $ii++) {
|
||||
print "<tr>";
|
||||
for (my $jj=0; $jj < $num_columns; $jj++) {
|
||||
my $index = $ii + $jj * $num_rows;
|
||||
next if $index > $#who_list;
|
||||
my $name = $who_list[$index];
|
||||
my $count = $who_count{$name};
|
||||
$name =~ s/%.*//;
|
||||
print " " x $jj;
|
||||
print "<td><a href='#$name'>$name</a>";
|
||||
print "</td><td>";
|
||||
print "$count";
|
||||
print "</td><td> </td>\n";
|
||||
}
|
||||
print "</tr>\n";
|
||||
}
|
||||
print "</table><p>\n";
|
||||
|
||||
# Count Unblamed warnings
|
||||
#
|
||||
my $total_unblamed_warnigns=0;
|
||||
for my $file (keys %unblamed) {
|
||||
for my $linenum (keys %{$warnings{$file}}) {
|
||||
$total_unblamed_warnings += $warnings{$file}{$linenum}{count};
|
||||
$warnings_by_who{Unblamed}{$file}{$linenum} = $warnings{$file}{$linenum};
|
||||
}
|
||||
}
|
||||
$who_count{Unblamed} = $total_unblamed_warnings;
|
||||
|
||||
# Print all the warnings
|
||||
#
|
||||
for $who (@who_list, "Unblamed") {
|
||||
my $total_count = $who_count{$who};
|
||||
my ($name, $email);
|
||||
($name = $who) =~ s/%.*//;
|
||||
($email = $who) =~ s/%/@/;
|
||||
|
||||
print "<h2>";
|
||||
print "<a name='$name' href='mailto:$email'>" unless $name eq 'Unblamed';
|
||||
print "$name";
|
||||
print "</a>" unless $name eq 'Unblamed';
|
||||
print " (1 warning)" if $total_count == 1;
|
||||
print " ($total_count warnings)" if $total_count > 1;
|
||||
print "</h2>";
|
||||
|
||||
print "\n<table>\n";
|
||||
my $count = 1;
|
||||
for $file (sort keys %{$warnings_by_who{$who}}) {
|
||||
for $linenum (sort keys %{$warnings_by_who{$who}{$file}}) {
|
||||
my $warn_rec = $warnings_by_who{$who}{$file}{$linenum};
|
||||
print_count($count, $warn_rec->{count});
|
||||
print_warning($tree, $br, $file, $linenum, $warn_rec);
|
||||
print_source_code($linenum, $warn_rec) unless $unblamed{$file};
|
||||
$count += $warn_rec->{count};
|
||||
}
|
||||
}
|
||||
print "</table>\n";
|
||||
}
|
||||
|
||||
print <<"__END_FOOTER";
|
||||
<p>
|
||||
<hr align=left>
|
||||
Send questions or comments to
|
||||
<<a href="mailto:slamm\@netscape.com?subject=About the Blamed Build Warnings">slamm\@netcape.com</a>>.
|
||||
</body></html>
|
||||
__END_FOOTER
|
||||
|
||||
# Change default destination back.
|
||||
select($old_fh);
|
||||
}
|
||||
|
||||
sub print_count {
|
||||
my ($start, $count) = @_;
|
||||
|
||||
print "<tr><td align=right>$start";
|
||||
print "-".($start+$count-1) if $count > 1;
|
||||
print ".</td>";
|
||||
}
|
||||
|
||||
sub print_warning {
|
||||
my ($tree, $br, $file, $linenum, $warn_rec) = @_;
|
||||
|
||||
my $warning = $warn_rec->{warning_text};
|
||||
|
||||
print "<td>";
|
||||
|
||||
# File link
|
||||
if ($file =~ /\[multiple\]/) {
|
||||
$file =~ s/\[multiple\]\///;
|
||||
print "<a href='http://lxr.mozilla.org/seamonkey/find?string=$file'>";
|
||||
print "$file:$linenum";
|
||||
print "</a> (multiple file matches)";
|
||||
} elsif ($file =~ /\[no_match\]/) {
|
||||
$file =~ s/\[no_match\]\///;
|
||||
print "<b>$file:$linenum</b> (no file match)";
|
||||
} else {
|
||||
print "<a href='"
|
||||
.file_url($file,$linenum)."'>";
|
||||
print "$file:$linenum";
|
||||
print "</a> ";
|
||||
}
|
||||
print "</td></tr><tr><td></td><td>";
|
||||
# Warning text
|
||||
print "\u$warning";
|
||||
# Build log link
|
||||
my $log_line = $warn_rec->{first_seen_line};
|
||||
print " (<a href='"
|
||||
.build_url($tree, $br, $log_line)
|
||||
."'>";
|
||||
if ($warn_rec->{count} == 1) {
|
||||
print "See build log excerpt";
|
||||
} else {
|
||||
print "See 1st of $warn_rec->{count} occurrences in build log";
|
||||
}
|
||||
print "</a>)</td></tr>";
|
||||
}
|
||||
|
||||
sub print_source_code {
|
||||
my ($linenum, $warn_rec) = @_;
|
||||
my $warning = $warn_rec->{warning_text};
|
||||
|
||||
# Source code fragment
|
||||
#
|
||||
my ($keyword) = $warning =~ /\`([^\']*)\'/;
|
||||
print "<tr><td></td><td bgcolor=#ededed>";
|
||||
print "<pre><font size='-1'>";
|
||||
|
||||
my $source_text = trim_common_leading_whitespace($warn_rec->{source});
|
||||
$source_text =~ s/&/&/gm;
|
||||
$source_text =~ s/</</gm;
|
||||
$source_text =~ s/>/>/gm;
|
||||
$source_text =~ s|\b\Q$keyword\E\b|<b>$keyword</b>|gm unless $keyword eq '';
|
||||
my $line_index = $linenum - 2;
|
||||
$source_text =~ s/^(.*)$/$line_index++." $1"/gme;
|
||||
$source_text =~ s|^($linenum.*)$|<font color='red'>\1</font>|gm;
|
||||
chomp $source_text;
|
||||
print $source_text;
|
||||
|
||||
print "</font>";
|
||||
#print "</pre>";
|
||||
print "</td></tr>\n";
|
||||
}
|
||||
|
||||
sub build_url {
|
||||
my ($tree, $br, $linenum) = @_;
|
||||
|
||||
my $name = $br->{buildname};
|
||||
$name =~ s/ /%20/g;
|
||||
|
||||
return "../showlog.cgi?log=$tree/$br->{logfile}:$linenum";
|
||||
}
|
||||
|
||||
sub file_url {
|
||||
my ($file, $linenum) = @_;
|
||||
|
||||
return "http://cvs-mirror.mozilla.org/webtools/bonsai/cvsblame.cgi"
|
||||
."?file=mozilla/$file&mark=$linenum#".($linenum-10);
|
||||
|
||||
}
|
||||
|
||||
sub trim_common_leading_whitespace {
|
||||
# Adapted from dequote() in Perl Cookbook by Christiansen and Torkington
|
||||
local $_ = shift;
|
||||
my $white; # common whitespace
|
||||
if (/(?:(\s*).*\n)(?:(?:\1.*\n)|(?:\s*\n))+$/) {
|
||||
$white = $1;
|
||||
} else {
|
||||
$white = /^(\s+)/;
|
||||
}
|
||||
s/^(?:$white)?//gm;
|
||||
s/^\s+$//gm;
|
||||
return $_;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user