source: main/trunk/search4j/libsearch4j.cpp

Last change on this file was 35700, checked in by davidb, 3 years ago

Some additional checking added in

File size: 14.9 KB
Line 
1/*
2* Library of functions for the Search4j utility
3*/
4
5#include "libsearch4j.h"
6
7#ifdef WINDOWS
8//minimal launch4j stuff
9#define NO_JAVA_FOUND 0
10#define FOUND_JRE 1
11#define FOUND_SDK 2
12
13//windows functions
14#define popen _popen
15#define pclose _pclose
16#define strcmp _stricmp
17
18#endif /* WINDOWS */
19
20void replace_all ( std::string & str, std::string const & pattern, std::string const & replacement ) {
21
22 std::string::size_type start = str.find( pattern, 0 );
23
24 while ( start != str.npos ) {
25 str.replace( start, pattern.size(), replacement );
26 start = str.find( pattern, start+replacement.size() );
27 }
28
29}
30
31
32int process( string command, bool render ) {
33
34 #ifdef WINDOWS
35
36 STARTUPINFO si;
37 PROCESS_INFORMATION pi;
38 memset(&pi, 0, sizeof(pi));
39 memset(&si, 0, sizeof(si));
40 si.cb = sizeof(si);
41
42 DWORD dwExitCode = -1;
43 char* cmd = (char*)command.c_str();
44
45 bool result;
46 if ( render ) {
47 result = CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
48 } else {
49 result = CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
50 }
51
52 if ( result ) {
53 WaitForSingleObject(pi.hProcess, INFINITE);
54 GetExitCodeProcess(pi.hProcess, &dwExitCode);
55 CloseHandle(pi.hThread);
56 CloseHandle(pi.hProcess);
57 }
58 return dwExitCode;
59
60 #else
61
62 return system( command.c_str() );
63
64 #endif
65}
66
67
68
69int process_and_catch_output( string command, string& output ) {
70
71 FILE *pPipe;
72
73 char cmd[1024];
74 strcpy(cmd, command.c_str());
75 strcat(cmd, " 2>&1" );
76
77 //if ( verbose ) cout << "process(): running '" << command << "'" << endl;
78#ifdef WINDOWS
79 if( (pPipe = _popen( cmd, "rt" )) == NULL ) {
80 _pclose( pPipe );
81#else
82 if( (pPipe = popen( cmd, "r" )) == NULL ) {
83 pclose( pPipe );
84#endif
85 return -1;
86 }
87 //if ( verbose ) cout << "started process" << endl;
88
89 /* Read pipe until end of file. */
90 while( !feof( pPipe ) ) {
91 char psBuffer[512];
92 //if ( verbose ) cout << "get some data" << endl;
93 if( fgets( psBuffer, sizeof(psBuffer), pPipe ) != NULL ) {
94
95 //if ( verbose ) cout << "got: " << psBuffer << endl;
96 output.append( psBuffer );
97
98 } else {
99 //if ( verbose ) cout << "none left" << endl;
100 }
101
102 }
103
104 /* Close pipe and return return value of pPipe. */
105#ifdef WINDOWS
106 int code = _pclose( pPipe );
107#else
108 int code = pclose( pPipe );
109#endif
110
111 return code;
112
113}
114
115//Jvm class methods
116
117Jvm::Jvm()
118 : era_(1), major_(0), minor_(0), update_(0),
119 javaHome_(),
120 isJdk_(false), healthy_(false)
121{}
122
123Jvm::~Jvm()
124{
125 // javaHome automatically destructed
126}
127
128
129void Jvm::setJavaHome( string jh ) {
130 healthy_ = true;
131 javaHome_ = jh;
132 setVersionFromExeOuput();
133 setIsJdkFromJavacPresence();
134}
135
136string Jvm::getJavaHome() {
137 return javaHome_;
138}
139
140string Jvm::getExecutable() {
141 string exec = "";
142 exec.append( javaHome_ );
143
144 #ifdef WINDOWS
145 exec.append( "\\bin\\java.exe" );
146 #endif
147
148 #ifndef WINDOWS
149 exec.append( "/bin/java" );
150 #endif
151
152 return exec;
153}
154
155#ifdef WINDOWS
156string Jvm::getWinExecutable() {
157 string exec = "";
158 exec.append( javaHome_ );
159 exec.append( "\\bin\\javaw.exe" );
160 return exec;
161}
162#endif
163
164
165string Jvm::getVersion() {
166 stringstream ss;
167 ss << era_ << "." << major_ << "." << minor_ << "_" << update_;
168 return ss.str();
169}
170
171bool Jvm::check() {
172 return healthy_;
173}
174
175bool Jvm::setVersionFromString( string version ) {
176 era_ = atoi( version.substr(0,1).c_str() );
177 if (version[3] == '.') {
178 // Parsing something like 1.8.0_24
179 major_ = atoi( version.substr(2,1).c_str() );
180 if(version.length() >= 5) {
181 minor_ = atoi( version.substr(4,1).c_str() );
182 } else {
183 minor_ = 0;
184 }
185 if(version.length() >= 7) {
186 update_ = atoi( version.substr(6,2).c_str() );
187 } else {
188 update_ = 0;
189 }
190 }
191 else {
192 // Parsing something like 1.8.0_242
193 major_ = atoi( version.substr(2,2).c_str() );
194 if(version.length() >= 6) {
195 minor_ = atoi( version.substr(5,1).c_str() );
196 } else {
197 minor_ = 0;
198 }
199 if(version.length() >= 8) {
200 update_ = atoi( version.substr(7,2).c_str() );
201 } else {
202 update_ = 0;
203 }
204
205 }
206
207 return true;
208}
209
210int Jvm::compare( Jvm otherJvm ) {
211 //era
212 if ( era_ > otherJvm.getEra() )
213 return 1;
214 else if ( era_ < otherJvm.getEra() )
215 return -1;
216
217 //major
218 if ( major_ > otherJvm.getMajor() )
219 return 1;
220 else if ( major_ < otherJvm.getMajor() )
221 return -1;
222
223 //minor
224 if ( minor_ > otherJvm.getMinor() )
225 return 1;
226 else if ( minor_ < otherJvm.getMinor() )
227 return -1;
228
229 //update
230 if ( update_ > otherJvm.getUpdate() )
231 return 1;
232 else if ( update_ < otherJvm.getUpdate() )
233 return -1;
234
235 //all the same so far, must be exactly the same
236 return 0;
237
238}
239
240int Jvm::getEra() { return era_; }
241int Jvm::getMajor() { return major_; }
242int Jvm::getMinor() { return minor_; }
243int Jvm::getUpdate() { return update_; }
244
245bool Jvm::getIsJdk() { return isJdk_; }
246bool Jvm::getIsJre() { return !isJdk_; }
247
248void Jvm::setVersionFromExeOuput() {
249 string command = "", output = "";
250 command.append( "\"" );
251 command.append( getExecutable() );
252 command.append( "\"" );
253 command.append(" -version");
254
255 //cerr << "command: " << command << endl;
256 int result = process_and_catch_output( command, output );
257 //cerr << "output: " << output << endl;
258
259 if ( result == 0 ) {
260 // 22 is the length of sentinel string plus typical version value
261 int max_search_length = output.length() - 22;
262 int caret = 0;
263 bool found = false;
264 while (caret < max_search_length && !found) {
265 const int to_match_len = 8;
266 if ( strcmp( output.substr( caret, to_match_len ).c_str() , " version" ) == 0 ) {
267 if (output[caret+to_match_len+3] == '.') {
268 // Version of the form 1.8.0_24
269 era_ = atoi( output.substr(caret + to_match_len + 2,1).c_str() );
270 major_ = atoi( output.substr(caret + to_match_len + 4,1).c_str() );
271 minor_ = atoi( output.substr(caret + to_match_len + 6,1).c_str() );
272 update_ = atoi( output.substr(caret + to_match_len + 8,2).c_str() );
273 }
274 else {
275 // Version of the form 11.0.6
276 era_ = 1;
277 major_ = atoi( output.substr(caret + to_match_len + 2,2).c_str() );
278 minor_ = atoi( output.substr(caret + to_match_len + 5,1).c_str() );
279 update_ = atoi( output.substr(caret + to_match_len + 7,2).c_str() );
280
281 }
282 found = true;
283 }
284 else {
285 caret++;
286 }
287 }
288 if (!found) {
289 healthy_ = false;
290 }
291 }
292 else {
293 healthy_ = false;
294 }
295}
296void Jvm::setIsJdkFromJavacPresence() {
297 string javacFile = "";
298 javacFile.append( javaHome_ );
299
300 #ifdef WINDOWS
301 javacFile.append( "\\bin\\javac.exe" );
302 #endif
303 #ifndef WINDOWS
304 javacFile.append( "/bin/javac" );
305 #endif
306 struct stat stFileInfo;
307 isJdk_ = ( stat(javacFile.c_str(),&stFileInfo) == 0 );
308}
309
310//end of Jvm class methods
311
312
313#ifdef WINDOWS
314int regSearch(HKEY hKey, const char* keyName, int searchType, char* foundJavaVer ) {
315 DWORD x = 0;
316 unsigned long size = 1024;
317 FILETIME time;
318 char buffer[1024] = {0};
319
320 int foundJava = NO_JAVA_FOUND;
321
322 while (RegEnumKeyEx(
323 hKey, // handle to key to enumerate
324 x++, // index of subkey to enumerate
325 buffer, // address of buffer for subkey name
326 &size, // address for size of subkey buffer
327 NULL, // reserved
328 NULL, // address of buffer for class string
329 NULL, // address for size of class buffer
330 &time) == ERROR_SUCCESS) {
331 strcpy(foundJavaVer, buffer);
332 foundJava = searchType;
333 size = 1024;
334 }
335
336 return foundJava;
337
338}
339#endif
340
341
342char* get_dirname (const char* full_file_path)
343{
344 char* parent_dir = NULL;
345
346 if (full_file_path != NULL) {
347
348 char* full_file_path_dup = strdup(full_file_path);
349#ifdef WINDOWS
350 char *p = strrchr(full_file_path_dup, '\\');
351#else
352 char *p = strrchr(full_file_path_dup, '/');
353#endif
354
355 if (p != NULL) {
356 // truncate the string at the point where the dir-separator was found
357 p[0] = 0;
358 parent_dir = full_file_path_dup;
359 }
360 else {
361 // no dir-separator found
362 free(full_file_path_dup);
363 full_file_path_dup = NULL;
364 }
365 }
366
367 return parent_dir;
368}
369
370/*
371* function to find java
372* implements the logic drawn on the dl lab whiteboard in feb 08
373* return a Jvm object which represents the jvm on disk
374*/
375bool find( Jvm &jvm, bool use_minimum, const Jvm& minimum, bool jreOnly, bool jdkOnly, string phint, string hint, bool verbose ) {
376
377 if ( verbose ) cout << "Searching for a JVM" << endl;
378
379 char *javaHomeEnv = NULL; // use below would benefit from more careful application of strdup()/free()
380 bool jvmFound = false;
381
382 if ( !jvmFound ) {
383
384 //try the priority hint
385 if ( verbose ) cout << " - trying priority hint: ";
386 if ( strcmp(phint.c_str(),"") != 0 ) {
387 if ( verbose ) cout << "(" << phint << ") ";
388 jvm.setJavaHome( phint );
389 if ( jvm.check() ) {
390 if ( use_minimum ) {
391 if ( jvm.compare( minimum ) >= 0 ) {
392 jvmFound = true;
393 }
394 } else {
395 jvmFound = true;
396 }
397 }
398 if ( (jreOnly && !jvm.getIsJre() ) || (jdkOnly && !jvm.getIsJdk()) ) {
399 jvmFound = false;
400 }
401
402 }
403 if ( verbose ) { if( jvmFound ) cout << "yes" << endl; else cout << "no" << endl; }
404 }
405
406 if ( !jvmFound ) {
407
408 //try JAVA_HOME
409 if ( verbose ) cout << " - trying JAVA_HOME: ";
410 javaHomeEnv = getenv( "JAVA_HOME" );
411 if ( javaHomeEnv != NULL ) {
412 if ( verbose ) cout << "(" << javaHomeEnv << ") ";
413 jvm.setJavaHome( javaHomeEnv );
414 if ( jvm.check() ) {
415 if ( use_minimum ) {
416 if ( jvm.compare( minimum ) >= 0 ) {
417 jvmFound = true;
418 }
419 } else {
420 jvmFound = true;
421 }
422 }
423 if ( (jreOnly && !jvm.getIsJre() ) || (jdkOnly && !jvm.getIsJdk()) ) {
424 jvmFound = false;
425 }
426
427 }
428 if ( verbose ) { if( jvmFound ) cout << "yes" << endl; else cout << "no" << endl; }
429 }
430
431 if ( !jvmFound ) {
432
433 //try JRE_HOME
434 if ( verbose ) cout << " - trying JRE_HOME: ";
435 javaHomeEnv = getenv( "JRE_HOME" );
436 if ( javaHomeEnv != NULL ) {
437 if ( verbose ) cout << "(" << javaHomeEnv << ") ";
438 jvm.setJavaHome( javaHomeEnv );
439 if ( jvm.check() ) {
440 if ( use_minimum ) {
441 if ( jvm.compare( minimum ) >= 0 ) {
442 jvmFound = true;
443 }
444 } else {
445 jvmFound = true;
446 }
447 }
448 if ( (jreOnly && !jvm.getIsJre() ) || (jdkOnly && !jvm.getIsJdk()) ) {
449 jvmFound = false;
450 }
451
452 }
453 if ( verbose ) { if( jvmFound ) cout << "yes" << endl; else cout << "no" << endl; }
454 }
455
456 #ifdef WINDOWS
457 if ( !jvmFound ) {
458
459 //try the registry - this code based on launch4j code
460 char foundJavaVer[8192] = {0};
461 int foundJava = NO_JAVA_FOUND;
462
463 if ( verbose ) cout << " - trying the registry: "; cout.flush();
464 HKEY hKey;
465 const char jre[] = "SOFTWARE\\JavaSoft\\Java Runtime Environment";
466 const char sdk[] = "SOFTWARE\\JavaSoft\\Java Development Kit";
467
468 if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(jre), 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hKey) == ERROR_SUCCESS ) {
469 foundJava = regSearch(hKey, jre, FOUND_JRE, foundJavaVer);
470 RegCloseKey(hKey);
471 }
472
473 if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(sdk), 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hKey) == ERROR_SUCCESS ) {
474 foundJava = regSearch(hKey, sdk, FOUND_SDK, foundJavaVer);
475 RegCloseKey(hKey);
476 }
477
478 if ( foundJava != NO_JAVA_FOUND ) {
479 char path[1024] = {0};
480 char keyBuffer[1024];
481 unsigned long datatype;
482 unsigned long bufferlength = 1024;
483 if (foundJava == FOUND_JRE) {
484 strcpy(keyBuffer, jre);
485 } else {
486 strcpy(keyBuffer, sdk);
487 }
488
489 strcat(keyBuffer, "\\");
490 strcat(keyBuffer, foundJavaVer);
491
492 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(keyBuffer), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
493 unsigned char buffer[1024] = {0};
494 if (RegQueryValueEx(hKey, "JavaHome", NULL, &datatype, buffer, &bufferlength) == ERROR_SUCCESS) {
495 int i = 0;
496 do {
497 path[i] = buffer[i];
498 } while (path[i++] != 0);
499 if (foundJava == FOUND_SDK) {
500 strcat(path, "\\jre");
501 }
502 if ( verbose ) cerr << "path: " << path << endl ;
503 jvm.setJavaHome( path );
504 if ( jvm.check() ) {
505 if ( use_minimum ) {
506 if ( jvm.compare( minimum ) >= 0 ) {
507 jvmFound = true;
508 }
509 } else {
510 jvmFound = true;
511 }
512 }
513 if ( (jreOnly && !jvm.getIsJre() ) || (jdkOnly && !jvm.getIsJdk()) ) {
514 jvmFound = false;
515 }
516 }
517 RegCloseKey(hKey);
518 }
519 }
520 if ( verbose ) { if( jvmFound ) cout << "yes" << endl; else cout << "no" << endl; }
521 }
522 #endif
523
524 if ( !jvmFound ) {
525
526 //try the hint
527 if ( verbose ) cout << " - trying hint: ";
528 if ( strcmp(hint.c_str(),"") != 0 ) {
529 if ( verbose ) cout << "(" << hint << ") ";
530 jvm.setJavaHome( hint );
531 if ( jvm.check() ) {
532 if ( use_minimum ) {
533 if ( jvm.compare( minimum ) >= 0 ) {
534 jvmFound = true;
535 }
536 } else {
537 jvmFound = true;
538 }
539 }
540 if ( (jreOnly && !jvm.getIsJre() ) || (jdkOnly && !jvm.getIsJdk()) ) {
541 jvmFound = false;
542 }
543
544 }
545 if ( verbose ) { if( jvmFound ) cout << "yes" << endl; else cout << "no" << endl; }
546 }
547
548
549
550 if ( !jvmFound ) {
551 //look for it on PATH
552 if ( verbose ) cout << " - Looking on PATH (possibly yielding a pseudo, but passable, JAVA_HOME such as /usr): ";
553
554#ifdef WINDOWS
555 // The following is the DOS equivalent to 'which java', however note that
556 // 'where' returns a list of all possible matches (one per line)
557 const char* cmd = "where java 2>nul";
558#else
559 const char* cmd = "which java 2>/dev/null";
560#endif
561 char full_path_java[512] = { '\0' }; // empty string
562
563 // ****
564 // Consider replacing the following code with a call to process_and_catch_output(command, output)
565 // but would need extending to have extra (optional) argument 'only_first_list' which defaults to 'false'
566
567 FILE* PIN = popen(cmd,"r");
568 if (PIN == NULL) {
569 cerr << "Failed to run the command to locate 'java' on PATH" << endl;
570 cerr << "Command run was: " << cmd << endl;
571 }
572 else {
573 // Only need the first line of output
574
575 // Returns number of chars returned. OK to ignore here
576 if (fgets(full_path_java, sizeof(full_path_java), PIN) == NULL) {
577 // Not strictly necessary (as already initialized to be the empty string when declared)
578 // but done to void the warning g++ gives about not checking the return value
579 full_path_java[0] = '\0';
580 }
581 }
582
583 // Not all implmentations of 'which' are coded to return 0 if a program match is found
584 // => safer just to look to see if a non-empty string is returned
585
586 int ignore_exit_val = pclose(PIN);
587
588 if ( strcmp(full_path_java,"") != 0) {
589 // go two directories up from where 'java' was found
590
591 char* parent_dir = get_dirname(full_path_java);
592 char* parent_parent_dir = get_dirname(parent_dir);
593
594 javaHomeEnv = parent_parent_dir;
595
596 if (parent_dir != NULL) {
597 free(parent_dir);
598 }
599
600 // Logic from here same as for other search4j java/javac testing
601 if (javaHomeEnv != NULL) {
602 if ( verbose ) cout << "(" << javaHomeEnv << ") ";
603 jvm.setJavaHome( javaHomeEnv );
604 if ( jvm.check() ) {
605 if ( use_minimum ) {
606 if ( jvm.compare( minimum ) >= 0 ) {
607 jvmFound = true;
608 }
609 } else {
610 jvmFound = true;
611 }
612 }
613 if ( (jreOnly && !jvm.getIsJre() ) || (jdkOnly && !jvm.getIsJdk()) ) {
614 jvmFound = false;
615 }
616 }
617 }
618 if ( verbose ) { if( jvmFound ) cout << "yes" << endl; else cout << "no" << endl; }
619 }
620
621
622 return jvmFound;
623}
Note: See TracBrowser for help on using the repository browser.