Index: /other-projects/trunk/search4j/compile.bat
===================================================================
--- /other-projects/trunk/search4j/compile.bat	(revision 17486)
+++ /other-projects/trunk/search4j/compile.bat	(revision 17486)
@@ -0,0 +1,3 @@
+cl /c -GX /DWINDOWS=yes libsearch4j.cpp
+cl /c -GX /DWINDOWS=yes search4j.cpp
+link advapi32.lib search4j.obj libsearch4j.obj /out:search4j.exe 
Index: /other-projects/trunk/search4j/compile.sh
===================================================================
--- /other-projects/trunk/search4j/compile.sh	(revision 17486)
+++ /other-projects/trunk/search4j/compile.sh	(revision 17486)
@@ -0,0 +1,4 @@
+g++ -c libsearch4j.cpp
+g++ -c search4j.cpp
+g++ search4j.o libsearch4j.o -o search4j
+
Index: /other-projects/trunk/search4j/libsearch4j.cpp
===================================================================
--- /other-projects/trunk/search4j/libsearch4j.cpp	(revision 17486)
+++ /other-projects/trunk/search4j/libsearch4j.cpp	(revision 17486)
@@ -0,0 +1,451 @@
+/*
+* Library of functions for the Search4j utility
+*/
+
+#include "libsearch4j.h"
+
+
+#ifdef WINDOWS
+//minimal launch4j stuff
+#define NO_JAVA_FOUND 0
+#define FOUND_JRE 1
+#define FOUND_SDK 2
+
+//windows functions
+#define popen _popen
+#define pclose _pclose
+#define strcmp _stricmp
+
+#endif /* WINDOWS */
+
+void replace_all ( std::string & str, std::string const & pattern, std::string const & replacement ) {
+
+	std::string::size_type start = str.find( pattern, 0 );
+
+	while ( start != str.npos ) {
+		str.replace( start, pattern.size(), replacement );
+		start = str.find( pattern, start+replacement.size() );
+	}
+
+}
+
+
+int process( string command, bool render ) {
+
+	#ifdef WINDOWS
+
+	STARTUPINFO si;
+	PROCESS_INFORMATION pi;
+	memset(&pi, 0, sizeof(pi));
+	memset(&si, 0, sizeof(si));
+	si.cb = sizeof(si);
+
+	DWORD dwExitCode = -1;
+	char* cmd = (char*)command.c_str();
+
+	bool result;
+	if ( render ) {
+		result = CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
+	} else {
+		result = CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
+	}
+
+	if ( result ) {
+		WaitForSingleObject(pi.hProcess, INFINITE);
+		GetExitCodeProcess(pi.hProcess, &dwExitCode);
+		CloseHandle(pi.hThread);
+		CloseHandle(pi.hProcess);
+	}
+	return dwExitCode;
+
+	#else
+
+	return system( command.c_str() );
+
+	#endif
+}
+
+
+
+int process_and_catch_output( string command, string &output ) {
+	
+	#ifdef WINDOWS
+
+	char cmd[1024] = "cmd.exe /c ";
+	strcat(cmd, command.c_str());
+	strcat(cmd, " > cmd_output.txt 2>&1");
+	//cerr << "command: " << cmd << endl;
+	int code = process( cmd, false );
+	if ( code!= 0 )
+		return code;
+	
+	string line;
+	ifstream myfile("cmd_output.txt");
+	if ( !myfile.is_open() ) {
+		return -1;
+	}
+
+	while ( !myfile.eof() ) {
+		getline(myfile,line);
+		output.append( line );
+	}
+
+	myfile.close();
+	
+	_unlink( "cmd_output.txt" );
+	
+	return code;
+
+	#else
+	
+	FILE *pPipe;
+
+	char cmd[1024];
+	strcpy(cmd, command.c_str());
+	strcat(cmd, " 2>&1" );
+
+	//if ( verbose ) cout << "process(): running '" << command << "'" << endl;
+	if( (pPipe = popen( cmd, "r" )) == NULL ) {
+		//if ( verbose ) cout << "could not start process" << endl;
+		pclose( pPipe );
+		return -1;
+	}
+
+	//if ( verbose ) cout << "started process" << endl;
+
+	/* Read pipe until end of file. */
+	while( !feof( pPipe ) ) {
+		char psBuffer[128];
+		//if ( verbose ) cout << "get some data" << endl;
+		if( fgets( psBuffer, 128, pPipe ) != NULL ) {
+			
+			//if ( verbose ) cout << "got: " << psBuffer << endl;
+			output.append( psBuffer );
+			
+		} else {
+			//if ( verbose ) cout << "none left" << endl;
+		}
+		
+	}
+
+	/* Close pipe and return return value of pPipe. */
+	int code = pclose( pPipe );
+
+	return code;
+
+	#endif
+
+}
+
+//Jvm class methods
+
+Jvm::Jvm() {
+	healthy = false;
+}
+
+void Jvm::setJavaHome( string jh ) {
+	healthy = true;
+	javaHome = jh;
+	setVersionFromExeOuput();
+}
+
+string Jvm::getJavaHome() {
+	return javaHome;
+}
+
+string Jvm::getExecutable() {
+	string exec = "";
+	exec.append( javaHome );
+	
+	#ifdef WINDOWS
+	exec.append( "\\bin\\java.exe" );
+	#endif
+
+	#ifndef WINDOWS
+	exec.append( "/bin/java" );
+	#endif
+	
+	return exec;
+}
+
+#ifdef WINDOWS
+string Jvm::getWinExecutable() {
+	string exec = "";
+	exec.append( javaHome );
+	exec.append( "\\bin\\javaw.exe" );
+	return exec;
+}
+#endif
+
+
+string Jvm::getVersion() {
+	stringstream ss;
+	ss << era << "." << major << "." << minor << "_" << update;
+	return ss.str();
+}
+
+bool Jvm::check() {
+	return healthy;
+}
+
+bool Jvm::setVersionFromString( string version ) {
+	era = atoi( version.substr(0,1).c_str() );
+	major = atoi( version.substr(2,1).c_str() );
+	minor = atoi( version.substr(4,1).c_str() );
+	update = atoi( version.substr(6,2).c_str() );
+	return true;
+}
+
+int Jvm::compare( Jvm otherJvm ) {
+	//era
+	if ( era > otherJvm.getEra() )
+		return 1;
+	else if ( era < otherJvm.getEra() )
+		return -1;
+	
+	//major
+	if ( major > otherJvm.getMajor() )
+		return 1;
+	else if ( major < otherJvm.getMajor() )
+		return -1;
+		
+	//minor
+	if ( minor > otherJvm.getMinor() )
+		return 1;
+	else if ( minor < otherJvm.getMinor() )
+		return -1;
+
+	//update
+	if ( update > otherJvm.getUpdate() )
+		return 1;
+	else if ( update < otherJvm.getUpdate() )
+		return -1;
+
+	//all the same so far, must be exactly the same
+	return 0;
+
+}
+
+int Jvm::getEra() { return era; }
+int Jvm::getMajor() { return major; }
+int Jvm::getMinor() { return minor; }
+int Jvm::getUpdate() { return update; }
+
+void Jvm::setVersionFromExeOuput() {
+	string command = "", output = "";
+	command.append( "\"" );
+	command.append( getExecutable() );
+	command.append( "\"" );
+	command.append(" -version");
+
+	//cerr << "command: " << command << endl;
+	int result = process_and_catch_output( command, output );
+	//cerr << "output: " << output << endl;
+	
+	if ( result == 0 ) {
+		if ( strcmp( output.substr( 0, 12 ).c_str() , "java version" ) == 0 || true ) {
+			era = atoi( output.substr(14,1).c_str() );
+			major = atoi( output.substr(16,1).c_str() );
+			minor = atoi( output.substr(18,1).c_str() );
+			update = atoi( output.substr(20,2).c_str() );
+		} else {
+			healthy=false;
+		}
+	} else {
+		healthy = false;
+	}
+}
+	
+//end of Jvm class methods
+
+
+#ifdef WINDOWS
+int regSearch(HKEY hKey, const char* keyName, int searchType, char* foundJavaVer ) {
+	DWORD x = 0;
+	unsigned long size = 1024;
+	FILETIME time;
+	char buffer[1024] = {0};
+
+	int foundJava = NO_JAVA_FOUND;
+
+	while (RegEnumKeyEx(
+				hKey,			// handle to key to enumerate
+				x++,			// index of subkey to enumerate
+				buffer,			// address of buffer for subkey name
+				&size,			// address for size of subkey buffer
+				NULL,			// reserved
+				NULL,			// address of buffer for class string
+				NULL,			// address for size of class buffer
+				&time) == ERROR_SUCCESS) {
+		strcpy(foundJavaVer, buffer);
+		foundJava = searchType;
+		size = 1024;
+	}
+	
+	return foundJava;
+	
+}
+#endif
+
+/*
+* function to find java
+* implements the logic drawn on the dl lab whiteboard in feb 08
+* return a Jvm object which represents the jvm on disk
+*/
+bool find( Jvm &jvm, bool use_minimum, Jvm minimum, string phint, string hint, bool verbose ) {
+	
+	if ( verbose ) cout << "Searching for a JVM" << endl;
+	
+	char *javaHome = "";
+	bool jvmFound = false;
+	
+	if ( !jvmFound ) {
+		
+		//try the priority hint
+		if ( verbose ) cout << " - trying priority hint: ";
+		if ( strcmp(phint.c_str(),"") != 0  ) {
+			if ( verbose ) cout << "(" << phint << ") ";
+			jvm.setJavaHome( phint );
+			if ( jvm.check() ) {
+				if ( use_minimum ) {
+					if ( jvm.compare( minimum ) >= 0 ) {
+						jvmFound = true;
+					}
+				} else {
+					jvmFound = true;
+				}
+			}
+		}
+		if ( verbose ) { if( jvmFound ) cout << "yes" << endl; else cout << "no" << endl; }
+	}
+
+	if ( !jvmFound ) {
+		
+		//try JAVA_HOME
+		if ( verbose ) cout << " - trying JAVA_HOME: ";
+		javaHome = getenv( "JAVA_HOME" );
+		if ( javaHome != NULL ) {
+			if ( verbose ) cout << "(" << javaHome << ") ";
+			jvm.setJavaHome( javaHome );
+			if ( jvm.check() ) {
+				if ( use_minimum ) {
+					if ( jvm.compare( minimum ) >= 0 ) {
+						jvmFound = true;
+					}
+				} else {
+					jvmFound = true;
+				}
+			}
+		}
+		if ( verbose ) { if( jvmFound ) cout << "yes" << endl; else cout << "no" << endl; }
+	}
+	
+	if ( !jvmFound ) {
+		
+		//try JRE_HOME
+		if ( verbose ) cout << " - trying JRE_HOME: ";
+		javaHome = getenv( "JRE_HOME" );
+		if ( javaHome != NULL ) {
+			if ( verbose ) cout << "(" << javaHome << ") ";
+			jvm.setJavaHome( javaHome );
+			if ( jvm.check() ) {
+				if ( use_minimum ) {
+					if ( jvm.compare( minimum ) >= 0 ) {
+						jvmFound = true;
+					}
+				} else {
+					jvmFound = true;
+				}
+			}
+		}
+		if ( verbose ) { if( jvmFound ) cout << "yes" << endl; else cout << "no" << endl; }
+	}
+
+	#ifdef WINDOWS
+	if ( !jvmFound ) {
+
+		//try the registry - this code based on launch4j code
+		char foundJavaVer[8192] = {0};
+		int foundJava = NO_JAVA_FOUND;
+		
+		if ( verbose ) cout << " - trying the registry: "; cout.flush();
+		HKEY hKey;
+		const char jre[] = "SOFTWARE\\JavaSoft\\Java Runtime Environment";
+		const char sdk[] = "SOFTWARE\\JavaSoft\\Java Development Kit";
+		
+		if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(jre), 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hKey) == ERROR_SUCCESS ) {
+			foundJava = regSearch(hKey, jre, FOUND_JRE, foundJavaVer);
+			RegCloseKey(hKey);
+		}
+		
+		if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(sdk), 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hKey) == ERROR_SUCCESS ) {
+			foundJava = regSearch(hKey, sdk, FOUND_SDK, foundJavaVer);
+			RegCloseKey(hKey);
+		}
+		
+		if ( foundJava != NO_JAVA_FOUND ) {
+			char path[1024] = {0};
+			char keyBuffer[1024];
+			unsigned long datatype;
+			unsigned long bufferlength = 1024;
+			if (foundJava == FOUND_JRE)	{
+				strcpy(keyBuffer, jre);
+			} else {
+				strcpy(keyBuffer, sdk);
+			}
+			
+			strcat(keyBuffer, "\\");
+			strcat(keyBuffer, foundJavaVer);
+			
+			if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(keyBuffer), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
+				unsigned char buffer[1024] = {0};
+				if (RegQueryValueEx(hKey, "JavaHome", NULL, &datatype, buffer, &bufferlength) == ERROR_SUCCESS) {
+					int i = 0;
+					do {
+						path[i] = buffer[i];
+					} while (path[i++] != 0);
+					if (foundJava == FOUND_SDK) {
+						strcat(path, "\\jre");
+					}
+					if ( verbose ) cerr << "path: " << path << endl ;
+					jvm.setJavaHome( path );
+					if ( jvm.check() ) {
+						if ( use_minimum ) {
+							if ( jvm.compare( minimum ) >= 0 ) {
+								jvmFound = true;
+							}
+						} else {
+							jvmFound = true;
+						}
+					}
+				}
+				RegCloseKey(hKey);
+			}
+		}
+		if ( verbose ) { if( jvmFound ) cout << "yes" << endl; else cout << "no" << endl; }
+	}
+	#endif
+
+	if ( !jvmFound ) {
+		
+		//try the hint
+		if ( verbose ) cout << " - trying hint: ";
+		if ( strcmp(hint.c_str(),"") != 0  ) {
+			if ( verbose ) cout << "(" << hint << ") ";
+			jvm.setJavaHome( hint );
+			if ( jvm.check() ) {
+				if ( use_minimum ) {
+					if ( jvm.compare( minimum ) >= 0 ) {
+						jvmFound = true;
+					}
+				} else {
+					jvmFound = true;
+				}
+			}
+		}
+		if ( verbose ) { if( jvmFound ) cout << "yes" << endl; else cout << "no" << endl; }
+	}
+
+
+	return jvmFound;
+}
Index: /other-projects/trunk/search4j/libsearch4j.h
===================================================================
--- /other-projects/trunk/search4j/libsearch4j.h	(revision 17486)
+++ /other-projects/trunk/search4j/libsearch4j.h	(revision 17486)
@@ -0,0 +1,55 @@
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <sstream>
+using namespace std;
+#ifdef WINDOWS
+#include <windows.h>
+#endif
+
+
+void replace_all( std::string & str, std::string const & pattern, std::string const & replacement );
+int process( string command, bool render );
+int process_and_catch_output( string command, string &output );
+#ifdef WINDOWS
+int regSearch(HKEY hKey, const char* keyName, int searchType, char* foundJavaVer );
+#endif
+
+
+class Jvm {
+
+	// version string. era.major.minor_update. eg: 1.4.2_02
+	int era;
+	int major;
+	int minor;
+	int update;
+
+	string javaHome;
+	bool isJdk;
+	bool healthy;	
+
+	public:
+	Jvm();
+	void setJavaHome( string jh );
+	string getJavaHome();
+	string getExecutable();
+	#ifdef WINDOWS
+	string getWinExecutable();
+	#endif
+	string getVersion();
+	bool check();
+	bool setVersionFromString( string version );
+	int compare( Jvm otherJvm );
+	int getEra();
+	int getMajor();
+	int getMinor();
+	int getUpdate();
+
+	private:
+	void setVersionFromExeOuput();
+
+};
+
+
+
+bool find( Jvm &jvm, bool use_minimum, Jvm minimum, string phint, string hint, bool verbose );
Index: /other-projects/trunk/search4j/search4j.cpp
===================================================================
--- /other-projects/trunk/search4j/search4j.cpp	(revision 17486)
+++ /other-projects/trunk/search4j/search4j.cpp	(revision 17486)
@@ -0,0 +1,255 @@
+/*
+* Search4j utility
+* Command Line utility to search a system for java, launch a jar, or compare java versions
+* base on launch4j
+*/
+
+#include "libsearch4j.h"
+
+void usage();
+
+enum Action {
+	Find,
+	Launch,
+	Compare
+};
+
+enum JvmProperty {
+	JavaHome,
+	Version,
+	Executable
+};
+
+string actionToString( Action a ) {
+	if ( a == Find ) 
+		return "Find";
+	else if ( a == Launch )
+		return "Launch";
+	else if ( a == Compare )
+		return "Compare";
+	return "Unknown";
+}
+
+string jvmPropertyToString( JvmProperty jp ) {
+	if ( jp == JavaHome ) 
+		return "JavaHome";
+	else if ( jp == Version )
+		return "Version";
+	else if ( jp == Executable )
+		return "Executable";
+	return "Unknown";
+}
+
+
+int main ( int argc, char** argv ) {
+
+	bool verbose = false;
+	string phint = "";
+	string hint = "";
+	bool use_minimum = false;
+	bool useJavaw = false;
+	Jvm minimum; 
+	JvmProperty jvmProperty = JavaHome;
+	Action action = Find;
+	string arg1 = "";
+	
+	//parse commandline arguments
+	for (int i=1; i<argc; i++) {
+		if ( strcmp(argv[i], "--verbose") == 0 ) {
+			verbose = true;
+		} else if ( strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "--usage") == 0 ) {
+			usage();
+			return 0;
+		} else if ( strcmp(argv[i], "-v") == 0 ) {
+			jvmProperty = Version;
+		} else if ( strcmp(argv[i], "-e") == 0 ) {
+			jvmProperty = Executable;
+		} else if ( strcmp(argv[i], "-c") == 0 ) {
+			action = Compare;
+			if ( i == argc-1 ) {
+				usage();
+				return -1;
+			} else {
+				arg1 = argv[++i];
+			}
+
+		} else if ( strcmp(argv[i], "-m") == 0 ) {
+			if ( i == argc-1 ) {
+				usage();
+				return -1;
+			} else {
+				if ( !minimum.setVersionFromString( argv[++i] ) ) {
+					usage();
+					return 0;
+				}
+				use_minimum = true;
+			}
+
+		} else if ( strcmp(argv[i], "-l") == 0 ) {
+			if ( i == argc-1 ) {
+				usage();
+				return -1;
+			} else {
+				action = Launch;
+				arg1 = argv[++i];
+			}
+
+		} else if ( strcmp(argv[i], "-p") == 0 ) {
+			if ( i == argc-1 ) {
+				usage();
+				return -1;
+			} else {
+				phint = argv[++i];
+			}
+
+		} else if ( strcmp(argv[i], "-h") == 0 ) {
+			if ( i == argc-1 ) {
+				usage();
+				return -1;
+			} else {
+				hint = argv[++i];
+			}
+			
+		#ifdef WINDOWS
+		} else if ( strcmp(argv[i], "-w") == 0 ) {
+			useJavaw = true;
+		#endif
+
+		} else {
+			cout << "unknown option: " << argv[i] << endl;
+			return -1;
+		}
+	}
+	
+	//summarise commandline arguments
+	if ( verbose ) {
+		cout << "Action: " << actionToString( action ) << endl;
+	}
+
+	//find java
+	Jvm foundJvm;
+	bool found = find( foundJvm, use_minimum, minimum, phint, hint, verbose );
+
+	//check if it was found
+	if ( found ) {
+		if ( verbose ) cout << "Found JVM at '" << foundJvm.getJavaHome() << "'" << endl;
+	} else {
+		//not found - exit with -1
+		if ( verbose ) cout << "JVM not found" << endl;
+		return -1;
+	}
+
+
+	//Find Action
+	//---------------
+	if ( action == Find ) {
+
+		if ( verbose ) cout << "Property to print: " << jvmPropertyToString( jvmProperty ) << endl;		
+
+		//found - print out info about it
+		if ( jvmProperty == JavaHome ) {
+			cout << foundJvm.getJavaHome() << endl;
+		} else if ( jvmProperty == Version ) {
+			cout << foundJvm.getVersion() << endl;
+		} else if ( jvmProperty == Executable ) {
+			#ifdef WINDOWS
+			if ( useJavaw ) {
+				cout << foundJvm.getWinExecutable() << endl;
+			} else {
+				cout << foundJvm.getExecutable() << endl;
+			}
+			#else
+			cout << foundJvm.getExecutable() << endl;
+			#endif
+		} else {
+			return -1; //should never happen
+		}
+			
+
+	//Compare Action
+	//---------------
+	} else if ( action == Compare ) {
+		
+		if ( verbose ) cout << "Compare to java at: " << arg1 << endl;
+
+		//load a dummy jvm for comparison
+		Jvm givenJvm;
+		if ( !givenJvm.setVersionFromString(arg1) ) {
+			if ( verbose ) cout << "Could not parse that version string" << endl;
+			return -1;
+		}
+		
+		//compare
+		cout << foundJvm.compare( givenJvm );
+		return 0;
+
+		
+	//Launch Action
+	//---------------
+	} else if ( action == Launch ) {
+
+		if ( verbose ) cout << "Jar to launch: " << arg1 << endl;
+		
+		string cmd = "\"", output = "";
+		#ifdef WINDOWS
+		if ( useJavaw ) {
+			cmd.append( foundJvm.getWinExecutable() );
+		} else {
+			cmd.append( foundJvm.getExecutable() );
+		}
+		#else
+		cmd.append( foundJvm.getExecutable() );
+		#endif
+		cmd.append( "\" -jar " );
+		cmd.append( arg1 );
+		
+		process( cmd, true );
+		
+	}
+	
+	return 0;
+}
+
+void usage() {
+	
+	cout
+		<< "-----------------" << endl
+		<< " search4j: usage" << endl
+		<< "-----------------" << endl
+		<< "Three usage methods: find, compare and launch" << endl
+		<< endl
+		<< "find:     find java and print out information about it" << endl
+		<< endl
+		<< "          search4j [-v|-e]" << endl
+		<< "          eg: search4j -e" << endl
+		<< endl
+		<< "          by default, print JAVA_HOME. E.g., C:\\Program Files\\jre1.5.0_15, or" << endl
+		<< "          if -v is specified, print the java version string. E.g. 1.5.0_15, or" << endl
+		<< "          if -e is specified, print the path the to the java executable. E.g. C:\\Program Files\\jre1.5.0_15\\bin\\java.exe" << endl
+		<< endl
+		<< "compare:  compare the found java with the given java version string" << endl
+		<< endl
+		<< "          search4j -c VERSION_STRING" << endl
+		<< "          eg: search4j -c VERSION_STRING" << endl
+		<< endl
+		<< "          print -1 if found java is older" << endl
+		<< "          print 0 if found java is same" << endl
+		<< "          print 1 if found java is newer" << endl
+		<< endl
+		<< "launch:   launch the given executable jar with the found java" << endl
+		<< endl
+		<< "          search4j -l EXECUTABLE_JAR [-m VERSION_STRING]" << endl
+		<< "          eg: search4j -l greenstone3.jar" << endl
+		<< endl
+		<< "          specify the location of the jar relative to the current directory" << endl
+		<< endl
+		<< "Global Options:" << endl
+		<< "          -m VERSION_STRING: (minimum) find a java of the given version or newer, or fail" << endl
+		<< "          -p LOCATION: (priority hint) first look for java in LOCATION (treated as a JAVA_HOME)" << endl
+		<< "          -h LOCATION: (hint) as a last resort look for java in LOCATION (treated as a JAVA_HOME)" << endl
+		<< "          -w: (windows) find and/or use the javaw.exe executable instead of java.exe (in windows only)" << endl
+		<< "          --verbose : have search4j print out information about what its doing" << endl
+		<< "          --help : display this usage screen" << endl
+		<< endl
+		;
+}
