diff --git a/SearchFramework1.0.1/.idea/.gitignore b/SearchFramework1.0.1/.idea/.gitignore new file mode 100644 index 0000000..5ade2d4 --- /dev/null +++ b/SearchFramework1.0.1/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/../../../../../../../:\Study\2021春\人工智能\SearchFramework1.0.2\SearchFramework1.0.1\.idea/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/SearchFramework1.0.1/.idea/misc.xml b/SearchFramework1.0.1/.idea/misc.xml new file mode 100644 index 0000000..c14dbda --- /dev/null +++ b/SearchFramework1.0.1/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/SearchFramework1.0.1/.idea/modules.xml b/SearchFramework1.0.1/.idea/modules.xml new file mode 100644 index 0000000..06a8e60 --- /dev/null +++ b/SearchFramework1.0.1/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/SearchFramework1.0.1/.idea/uiDesigner.xml b/SearchFramework1.0.1/.idea/uiDesigner.xml new file mode 100644 index 0000000..b93ac08 --- /dev/null +++ b/SearchFramework1.0.1/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SearchFramework1.0.1/SearchFramework1.0.1.iml b/SearchFramework1.0.1/SearchFramework1.0.1.iml new file mode 100644 index 0000000..5165f39 --- /dev/null +++ b/SearchFramework1.0.1/SearchFramework1.0.1.iml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/META-INF/MANIFEST.MF b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/META-INF/MANIFEST.MF new file mode 100644 index 0000000..8b6e977 --- /dev/null +++ b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: runner.SearchRunner + diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/algs4/util/In.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/algs4/util/In.class new file mode 100644 index 0000000..3363cd0 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/algs4/util/In.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/algs4/util/Out.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/algs4/util/Out.class new file mode 100644 index 0000000..6c1dda1 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/algs4/util/Out.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/algs4/util/StdIn.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/algs4/util/StdIn.class new file mode 100644 index 0000000..7dc8f8b Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/algs4/util/StdIn.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/algs4/util/StdOut.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/algs4/util/StdOut.class new file mode 100644 index 0000000..bd96400 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/algs4/util/StdOut.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/algs4/util/StdRandom.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/algs4/util/StdRandom.class new file mode 100644 index 0000000..feb9cc7 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/algs4/util/StdRandom.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/algs4/util/Stopwatch.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/algs4/util/Stopwatch.class new file mode 100644 index 0000000..5f90393 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/algs4/util/Stopwatch.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/algs4/util/StopwatchCPU.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/algs4/util/StopwatchCPU.class new file mode 100644 index 0000000..ae62001 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/algs4/util/StopwatchCPU.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/problem/Action.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/problem/Action.class new file mode 100644 index 0000000..7718a84 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/problem/Action.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/problem/Problem.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/problem/Problem.class new file mode 100644 index 0000000..b332891 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/problem/Problem.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/problem/State.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/problem/State.class new file mode 100644 index 0000000..7dc90c0 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/problem/State.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/runner/EngineFeeder.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/runner/EngineFeeder.class new file mode 100644 index 0000000..6f7e062 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/runner/EngineFeeder.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/runner/HeuristicType.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/runner/HeuristicType.class new file mode 100644 index 0000000..859113e Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/runner/HeuristicType.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/runner/ProblemType.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/runner/ProblemType.class new file mode 100644 index 0000000..bd903c6 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/runner/ProblemType.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/runner/SearchRunner.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/runner/SearchRunner.class new file mode 100644 index 0000000..33328fc Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/runner/SearchRunner.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/Node.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/Node.class new file mode 100644 index 0000000..b1ce871 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/Node.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/Searcher.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/Searcher.class new file mode 100644 index 0000000..9f448ae Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/Searcher.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/blinded/BreadthFirstSearch.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/blinded/BreadthFirstSearch.class new file mode 100644 index 0000000..97d3429 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/blinded/BreadthFirstSearch.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/blinded/DepthFirstSearch.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/blinded/DepthFirstSearch.class new file mode 100644 index 0000000..f4c80e8 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/blinded/DepthFirstSearch.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/heuristic/AbstractFrontier.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/heuristic/AbstractFrontier.class new file mode 100644 index 0000000..060dbbb Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/heuristic/AbstractFrontier.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/heuristic/BestFirstSearch.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/heuristic/BestFirstSearch.class new file mode 100644 index 0000000..e1d32b3 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/heuristic/BestFirstSearch.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/heuristic/EvaluationType.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/heuristic/EvaluationType.class new file mode 100644 index 0000000..36f1d17 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/heuristic/EvaluationType.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/heuristic/Predictor.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/heuristic/Predictor.class new file mode 100644 index 0000000..470e687 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/core/solver/heuristic/Predictor.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/problem/npuzzle/MyFeeder.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/problem/npuzzle/MyFeeder.class new file mode 100644 index 0000000..0b54c01 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/problem/npuzzle/MyFeeder.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/problem/npuzzle/Puzzle.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/problem/npuzzle/Puzzle.class new file mode 100644 index 0000000..6347981 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/problem/npuzzle/Puzzle.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/problem/npuzzle/PuzzleAction.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/problem/npuzzle/PuzzleAction.class new file mode 100644 index 0000000..af13ec3 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/problem/npuzzle/PuzzleAction.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/problem/npuzzle/PuzzleState.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/problem/npuzzle/PuzzleState.class new file mode 100644 index 0000000..1a08a93 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/problem/npuzzle/PuzzleState.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/solver/heuristic/IDAStarSearch.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/solver/heuristic/IDAStarSearch.class new file mode 100644 index 0000000..b5c28c7 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/solver/heuristic/IDAStarSearch.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/solver/heuristic/MyFrontier$1.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/solver/heuristic/MyFrontier$1.class new file mode 100644 index 0000000..06d52d8 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/solver/heuristic/MyFrontier$1.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/solver/heuristic/MyFrontier.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/solver/heuristic/MyFrontier.class new file mode 100644 index 0000000..3fd4366 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/solver/heuristic/MyFrontier.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/solver/heuristic/VeryEffecientFrontier.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/solver/heuristic/VeryEffecientFrontier.class new file mode 100644 index 0000000..b288938 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/g04/solver/heuristic/VeryEffecientFrontier.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/problem/pathfinding/Direction.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/problem/pathfinding/Direction.class new file mode 100644 index 0000000..5520ae9 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/problem/pathfinding/Direction.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/problem/pathfinding/FeederXu.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/problem/pathfinding/FeederXu.class new file mode 100644 index 0000000..233385a Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/problem/pathfinding/FeederXu.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/problem/pathfinding/GridType.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/problem/pathfinding/GridType.class new file mode 100644 index 0000000..44283d3 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/problem/pathfinding/GridType.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/problem/pathfinding/Move.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/problem/pathfinding/Move.class new file mode 100644 index 0000000..a40d2fe Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/problem/pathfinding/Move.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/problem/pathfinding/PathFinding.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/problem/pathfinding/PathFinding.class new file mode 100644 index 0000000..8ce6cc4 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/problem/pathfinding/PathFinding.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/problem/pathfinding/Point.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/problem/pathfinding/Point.class new file mode 100644 index 0000000..04f7727 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/problem/pathfinding/Point.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/problem/pathfinding/Position.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/problem/pathfinding/Position.class new file mode 100644 index 0000000..c1460d4 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/problem/pathfinding/Position.class differ diff --git a/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/solver/heuristic/LinkedFrontier.class b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/solver/heuristic/LinkedFrontier.class new file mode 100644 index 0000000..a696cd5 Binary files /dev/null and b/SearchFramework1.0.1/out/production/SearchFramework1.0.1/xu/solver/heuristic/LinkedFrontier.class differ diff --git a/SearchFramework1.0.1/out/production/jdk1.8.0_131/.idea/checkstyle-idea.xml b/SearchFramework1.0.1/out/production/jdk1.8.0_131/.idea/checkstyle-idea.xml new file mode 100644 index 0000000..cab6d1e --- /dev/null +++ b/SearchFramework1.0.1/out/production/jdk1.8.0_131/.idea/checkstyle-idea.xml @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/SearchFramework1.0.1/out/production/jdk1.8.0_131/.idea/dbnavigator.xml b/SearchFramework1.0.1/out/production/jdk1.8.0_131/.idea/dbnavigator.xml new file mode 100644 index 0000000..898600f --- /dev/null +++ b/SearchFramework1.0.1/out/production/jdk1.8.0_131/.idea/dbnavigator.xml @@ -0,0 +1,464 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SearchFramework1.0.1/out/production/jdk1.8.0_131/.idea/misc.xml b/SearchFramework1.0.1/out/production/jdk1.8.0_131/.idea/misc.xml new file mode 100644 index 0000000..3987345 --- /dev/null +++ b/SearchFramework1.0.1/out/production/jdk1.8.0_131/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/SearchFramework1.0.1/out/production/jdk1.8.0_131/.idea/modules.xml b/SearchFramework1.0.1/out/production/jdk1.8.0_131/.idea/modules.xml new file mode 100644 index 0000000..1a1891a --- /dev/null +++ b/SearchFramework1.0.1/out/production/jdk1.8.0_131/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/SearchFramework1.0.1/out/production/jdk1.8.0_131/.idea/workspace.xml b/SearchFramework1.0.1/out/production/jdk1.8.0_131/.idea/workspace.xml new file mode 100644 index 0000000..aa9e9be --- /dev/null +++ b/SearchFramework1.0.1/out/production/jdk1.8.0_131/.idea/workspace.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1617149915487 + + + + + + \ No newline at end of file diff --git a/SearchFramework1.0.1/out/production/jdk1.8.0_131/jdk1.8.0_131.iml b/SearchFramework1.0.1/out/production/jdk1.8.0_131/jdk1.8.0_131.iml new file mode 100644 index 0000000..e3c5754 --- /dev/null +++ b/SearchFramework1.0.1/out/production/jdk1.8.0_131/jdk1.8.0_131.iml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/defines.h b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/defines.h new file mode 100644 index 0000000..d9e9803 --- /dev/null +++ b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/defines.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +#ifndef _DEFINES_H +#define _DEFINES_H + +#include "java.h" + +/* + * This file contains commonly defined constants used only by main.c + * and should not be included by another file. + */ +#ifndef FULL_VERSION +/* make sure the compilation fails */ +#error "FULL_VERSION must be defined" +#endif + +#if defined(JDK_MAJOR_VERSION) && defined(JDK_MINOR_VERSION) +#define DOT_VERSION JDK_MAJOR_VERSION "." JDK_MINOR_VERSION +#else +/* make sure the compilation fails */ +#error "JDK_MAJOR_VERSION and JDK_MINOR_VERSION must be defined" +#endif + + +#ifdef JAVA_ARGS +static const char* const_progname = "java"; +static const char* const_jargs[] = JAVA_ARGS; +/* + * ApplicationHome is prepended to each of these entries; the resulting + * strings are concatenated (separated by PATH_SEPARATOR) and used as the + * value of -cp option to the launcher. + */ +#ifndef APP_CLASSPATH +#define APP_CLASSPATH { "/lib/tools.jar", "/classes" } +#endif /* APP_CLASSPATH */ +static const char* const_appclasspath[] = APP_CLASSPATH; +#else /* !JAVA_ARGS */ +#ifdef PROGNAME +static const char* const_progname = PROGNAME; +#else +static char* const_progname = NULL; +#endif +static const char** const_jargs = NULL; +static const char** const_appclasspath = NULL; +#endif /* JAVA_ARGS */ + +#ifdef LAUNCHER_NAME +static const char* const_launcher = LAUNCHER_NAME; +#else /* LAUNCHER_NAME */ +static char* const_launcher = NULL; +#endif /* LAUNCHER_NAME */ + +#ifdef EXPAND_CLASSPATH_WILDCARDS +static const jboolean const_cpwildcard = JNI_TRUE; +#else +static const jboolean const_cpwildcard = JNI_FALSE; +#endif /* EXPAND_CLASSPATH_WILDCARDS */ + +#if defined(NEVER_ACT_AS_SERVER_CLASS_MACHINE) +static const jint const_ergo_class = NEVER_SERVER_CLASS; +#elif defined(ALWAYS_ACT_AS_SERVER_CLASS_MACHINE) +static const jint const_ergo_class = ALWAYS_SERVER_CLASS; +#else +static const jint const_ergo_class = DEFAULT_POLICY; +#endif /* NEVER_ACT_AS_SERVER_CLASS_MACHINE */ + +#endif /*_DEFINES_H */ diff --git a/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/emessages.h b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/emessages.h new file mode 100644 index 0000000..caa5fa4 --- /dev/null +++ b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/emessages.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * This file primarily consists of all the error and warning messages, that + * are used in JLI_ReportErrorMessage. All message must be defined here, in + * order to help with localizing the messages. + */ + +#ifndef _EMESSAGES_H +#define _EMESSAGES_H + +#define GEN_ERROR "Error: A fatal exception has occurred. Program will exit." +#define JNI_ERROR "Error: A JNI error has occurred, please check your installation and try again" +#define JNI_ERROR1 "Error: can't find JNI interfaces in: %s" + +#define ARG_WARN "Warning: %s option is no longer supported." + +#define ARG_ERROR1 "Error: %s requires class path specification" +#define ARG_ERROR2 "Error: %s requires jar file specification" +#define ARG_ERROR3 "Error: The -J option should not be followed by a space." + +#define JVM_ERROR1 "Error: Could not create the Java Virtual Machine.\n" GEN_ERROR +#define JVM_ERROR2 "Error: Could not detach main thread.\n" JNI_ERROR +#define JVM_ERROR3 "Error: SPARC V8 processor detected; Required V9 processors or better.\nUse JDK5 client compiler for V8 processors.\n" JVM_ERROR1 + +#define JAR_ERROR1 "Error: Failed to load Main-Class manifest attribute from\n%s\n%s" +#define JAR_ERROR2 "Error: Unable to access jarfile %s" +#define JAR_ERROR3 "Error: Invalid or corrupt jarfile %s" + +#define CLS_ERROR1 "Error: Could not find the main class %s.\n" JNI_ERROR +#define CLS_ERROR2 "Error: Failed to load Main Class: %s\n%s" +#define CLS_ERROR3 "Error: No main method found in specified class.\n" GEN_ERROR +#define CLS_ERROR4 "Error: Main method not public\n" GEN_ERROR +#define CLS_ERROR5 "Error: main-class: attribute exceeds system limits of %d bytes\n" GEN_ERROR + +#define CFG_WARN1 "Warning: %s VM not supported; %s VM will be used" +#define CFG_WARN2 "Warning: No leading - on line %d of `%s'" +#define CFG_WARN3 "Warning: Missing VM type on line %d of `%s'" +#define CFG_WARN4 "Warning: Missing server class VM on line %d of `%s'" +#define CFG_WARN5 "Warning: Unknown VM type on line %d of `%s'" + +#define CFG_ERROR1 "Error: Corrupt jvm.cfg file; cycle in alias list." +#define CFG_ERROR2 "Error: Unable to resolve VM alias %s" +#define CFG_ERROR3 "Error: %s VM not supported" +#define CFG_ERROR4 "Error: Unable to locate JRE meeting specification \"%s\"" +#define CFG_ERROR5 "Error: Could not determine application home." +#define CFG_ERROR6 "Error: could not open `%s'" +#define CFG_ERROR7 "Error: no known VMs. (check for corrupt jvm.cfg file)" +#define CFG_ERROR8 "Error: missing `%s' JVM at `%s'.\nPlease install or use the JRE or JDK that contains these missing components." +#define CFG_ERROR9 "Error: could not determine JVM type." + + +#define SPC_ERROR1 "Error: Syntax error in version specification \"%s\"" + +#define JRE_ERROR1 "Error: Could not find Java SE Runtime Environment." +#define JRE_ERROR2 "Error: This Java instance does not support a %d-bit JVM.\nPlease install the desired version." +#define JRE_ERROR3 "Error: Improper value at line %d." +#define JRE_ERROR4 "Error: trying to exec %s.\nCheck if file exists and permissions are set correctly." +#define JRE_ERROR5 "Error: Failed to start a %d-bit JVM process from a %d-bit JVM." +#define JRE_ERROR6 "Error: Verify all necessary Java SE components have been installed.\n(Solaris SPARC 64-bit components must be installed after 32-bit components.)" +#define JRE_ERROR7 "Error: Either 64-bit processes are not supported by this platform\nor the 64-bit components have not been installed." +#define JRE_ERROR8 "Error: could not find " +#define JRE_ERROR9 "Error: Unable to resolve %s" +#define JRE_ERROR10 "Error: Unable to resolve current executable" +#define JRE_ERROR11 "Error: Path length exceeds maximum length (PATH_MAX)" +#define JRE_ERROR12 "Error: Exec of %s failed" +#define JRE_ERROR13 "Error: String processing operation failed" + +#define DLL_ERROR1 "Error: dl failure on line %d" +#define DLL_ERROR2 "Error: failed %s, because %s" +#define DLL_ERROR3 "Error: could not find executable %s" +#define DLL_ERROR4 "Error: loading: %s" + +#define REG_ERROR1 "Error: opening registry key '%s'" +#define REG_ERROR2 "Error: Failed reading value of registry key:\n\t%s\\CurrentVersion" +#define REG_ERROR3 "Error: Registry key '%s'\\CurrentVersion'\nhas value '%s', but '%s' is required." +#define REG_ERROR4 "Failed reading value of registry key:\n\t%s\\%s\\JavaHome" + +#define SYS_ERROR1 "Error: CreateProcess(%s, ...) failed:" +#define SYS_ERROR2 "Error: WaitForSingleObject() failed." + + + +#endif /* _EMESSAGES_H */ diff --git a/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/java.c b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/java.c new file mode 100644 index 0000000..3e3ed86 --- /dev/null +++ b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/java.c @@ -0,0 +1,2081 @@ +/* + * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * Shared source for 'java' command line tool. + * + * If JAVA_ARGS is defined, then acts as a launcher for applications. For + * instance, the JDK command line tools such as javac and javadoc (see + * makefiles for more details) are built with this program. Any arguments + * prefixed with '-J' will be passed directly to the 'java' command. + */ + +/* + * One job of the launcher is to remove command line options which the + * vm does not understand and will not process. These options include + * options which select which style of vm is run (e.g. -client and + * -server) as well as options which select the data model to use. + * Additionally, for tools which invoke an underlying vm "-J-foo" + * options are turned into "-foo" options to the vm. This option + * filtering is handled in a number of places in the launcher, some of + * it in machine-dependent code. In this file, the function + * CheckJvmType removes vm style options and TranslateApplicationArgs + * removes "-J" prefixes. The CreateExecutionEnvironment function processes + * and removes -d options. On unix, there is a possibility that the running + * data model may not match to the desired data model, in this case an exec is + * required to start the desired model. If the data models match, then + * ParseArguments will remove the -d flags. If the data models do not match + * the CreateExecutionEnviroment will remove the -d flags. + */ + + +#include "java.h" + +/* + * A NOTE TO DEVELOPERS: For performance reasons it is important that + * the program image remain relatively small until after SelectVersion + * CreateExecutionEnvironment have finished their possibly recursive + * processing. Watch everything, but resist all temptations to use Java + * interfaces. + */ + +/* we always print to stderr */ +#define USE_STDERR JNI_TRUE + +static jboolean printVersion = JNI_FALSE; /* print and exit */ +static jboolean showVersion = JNI_FALSE; /* print but continue */ +static jboolean printUsage = JNI_FALSE; /* print and exit*/ +static jboolean printXUsage = JNI_FALSE; /* print and exit*/ +static char *showSettings = NULL; /* print but continue */ + +static const char *_program_name; +static const char *_launcher_name; +static jboolean _is_java_args = JNI_FALSE; +static const char *_fVersion; +static const char *_dVersion; +static jboolean _wc_enabled = JNI_FALSE; +static jint _ergo_policy = DEFAULT_POLICY; + +/* + * Entries for splash screen environment variables. + * putenv is performed in SelectVersion. We need + * them in memory until UnsetEnv, so they are made static + * global instead of auto local. + */ +static char* splash_file_entry = NULL; +static char* splash_jar_entry = NULL; + +/* + * List of VM options to be specified when the VM is created. + */ +static JavaVMOption *options; +static int numOptions, maxOptions; + +/* + * Prototypes for functions internal to launcher. + */ +static void SetClassPath(const char *s); +static void SelectVersion(int argc, char **argv, char **main_class); +static void SetJvmEnvironment(int argc, char **argv); +static jboolean ParseArguments(int *pargc, char ***pargv, + int *pmode, char **pwhat, + int *pret, const char *jrepath); +static jboolean InitializeJVM(JavaVM **pvm, JNIEnv **penv, + InvocationFunctions *ifn); +static jstring NewPlatformString(JNIEnv *env, char *s); +static jclass LoadMainClass(JNIEnv *env, int mode, char *name); +static jclass GetApplicationClass(JNIEnv *env); + +static void TranslateApplicationArgs(int jargc, const char **jargv, int *pargc, char ***pargv); +static jboolean AddApplicationOptions(int cpathc, const char **cpathv); +static void SetApplicationClassPath(const char**); + +static void PrintJavaVersion(JNIEnv *env, jboolean extraLF); +static void PrintUsage(JNIEnv* env, jboolean doXUsage); +static void ShowSettings(JNIEnv* env, char *optString); + +static void SetPaths(int argc, char **argv); + +static void DumpState(); +static jboolean RemovableOption(char *option); + +/* Maximum supported entries from jvm.cfg. */ +#define INIT_MAX_KNOWN_VMS 10 + +/* Values for vmdesc.flag */ +enum vmdesc_flag { + VM_UNKNOWN = -1, + VM_KNOWN, + VM_ALIASED_TO, + VM_WARN, + VM_ERROR, + VM_IF_SERVER_CLASS, + VM_IGNORE +}; + +struct vmdesc { + char *name; + int flag; + char *alias; + char *server_class; +}; +static struct vmdesc *knownVMs = NULL; +static int knownVMsCount = 0; +static int knownVMsLimit = 0; + +static void GrowKnownVMs(); +static int KnownVMIndex(const char* name); +static void FreeKnownVMs(); +static jboolean IsWildCardEnabled(); + +#define ARG_CHECK(AC_arg_count, AC_failure_message, AC_questionable_arg) \ + do { \ + if (AC_arg_count < 1) { \ + JLI_ReportErrorMessage(AC_failure_message, AC_questionable_arg); \ + printUsage = JNI_TRUE; \ + *pret = 1; \ + return JNI_TRUE; \ + } \ + } while (JNI_FALSE) + +/* + * Running Java code in primordial thread caused many problems. We will + * create a new thread to invoke JVM. See 6316197 for more information. + */ +static jlong threadStackSize = 0; /* stack size of the new thread */ +static jlong maxHeapSize = 0; /* max heap size */ +static jlong initialHeapSize = 0; /* inital heap size */ + +/* + * Entry point. + */ +int +JLI_Launch(int argc, char ** argv, /* main argc, argc */ + int jargc, const char** jargv, /* java args */ + int appclassc, const char** appclassv, /* app classpath */ + const char* fullversion, /* full version defined */ + const char* dotversion, /* dot version defined */ + const char* pname, /* program name */ + const char* lname, /* launcher name */ + jboolean javaargs, /* JAVA_ARGS */ + jboolean cpwildcard, /* classpath wildcard*/ + jboolean javaw, /* windows-only javaw */ + jint ergo /* ergonomics class policy */ +) +{ + int mode = LM_UNKNOWN; + char *what = NULL; + char *cpath = 0; + char *main_class = NULL; + int ret; + InvocationFunctions ifn; + jlong start, end; + char jvmpath[MAXPATHLEN]; + char jrepath[MAXPATHLEN]; + char jvmcfg[MAXPATHLEN]; + + _fVersion = fullversion; + _dVersion = dotversion; + _launcher_name = lname; + _program_name = pname; + _is_java_args = javaargs; + _wc_enabled = cpwildcard; + _ergo_policy = ergo; + + InitLauncher(javaw); + DumpState(); + if (JLI_IsTraceLauncher()) { + int i; + printf("Command line args:\n"); + for (i = 0; i < argc ; i++) { + printf("argv[%d] = %s\n", i, argv[i]); + } + AddOption("-Dsun.java.launcher.diag=true", NULL); + } + + /* + * Make sure the specified version of the JRE is running. + * + * There are three things to note about the SelectVersion() routine: + * 1) If the version running isn't correct, this routine doesn't + * return (either the correct version has been exec'd or an error + * was issued). + * 2) Argc and Argv in this scope are *not* altered by this routine. + * It is the responsibility of subsequent code to ignore the + * arguments handled by this routine. + * 3) As a side-effect, the variable "main_class" is guaranteed to + * be set (if it should ever be set). This isn't exactly the + * poster child for structured programming, but it is a small + * price to pay for not processing a jar file operand twice. + * (Note: This side effect has been disabled. See comment on + * bugid 5030265 below.) + */ + SelectVersion(argc, argv, &main_class); + + CreateExecutionEnvironment(&argc, &argv, + jrepath, sizeof(jrepath), + jvmpath, sizeof(jvmpath), + jvmcfg, sizeof(jvmcfg)); + + if (!IsJavaArgs()) { + SetJvmEnvironment(argc,argv); + } + + ifn.CreateJavaVM = 0; + ifn.GetDefaultJavaVMInitArgs = 0; + + if (JLI_IsTraceLauncher()) { + start = CounterGet(); + } + + if (!LoadJavaVM(jvmpath, &ifn)) { + return(6); + } + + if (JLI_IsTraceLauncher()) { + end = CounterGet(); + } + + JLI_TraceLauncher("%ld micro seconds to LoadJavaVM\n", + (long)(jint)Counter2Micros(end-start)); + + ++argv; + --argc; + + if (IsJavaArgs()) { + /* Preprocess wrapper arguments */ + TranslateApplicationArgs(jargc, jargv, &argc, &argv); + if (!AddApplicationOptions(appclassc, appclassv)) { + return(1); + } + } else { + /* Set default CLASSPATH */ + cpath = getenv("CLASSPATH"); + if (cpath == NULL) { + cpath = "."; + } + SetClassPath(cpath); + } + + /* Parse command line options; if the return value of + * ParseArguments is false, the program should exit. + */ + if (!ParseArguments(&argc, &argv, &mode, &what, &ret, jrepath)) + { + return(ret); + } + + /* Override class path if -jar flag was specified */ + if (mode == LM_JAR) { + SetClassPath(what); /* Override class path */ + } + + /* set the -Dsun.java.command pseudo property */ + SetJavaCommandLineProp(what, argc, argv); + + /* Set the -Dsun.java.launcher pseudo property */ + SetJavaLauncherProp(); + + /* set the -Dsun.java.launcher.* platform properties */ + SetJavaLauncherPlatformProps(); + + return JVMInit(&ifn, threadStackSize, argc, argv, mode, what, ret); +} +/* + * Always detach the main thread so that it appears to have ended when + * the application's main method exits. This will invoke the + * uncaught exception handler machinery if main threw an + * exception. An uncaught exception handler cannot change the + * launcher's return code except by calling System.exit. + * + * Wait for all non-daemon threads to end, then destroy the VM. + * This will actually create a trivial new Java waiter thread + * named "DestroyJavaVM", but this will be seen as a different + * thread from the one that executed main, even though they are + * the same C thread. This allows mainThread.join() and + * mainThread.isAlive() to work as expected. + */ +#define LEAVE() \ + do { \ + if ((*vm)->DetachCurrentThread(vm) != JNI_OK) { \ + JLI_ReportErrorMessage(JVM_ERROR2); \ + ret = 1; \ + } \ + if (JNI_TRUE) { \ + (*vm)->DestroyJavaVM(vm); \ + return ret; \ + } \ + } while (JNI_FALSE) + +#define CHECK_EXCEPTION_NULL_LEAVE(CENL_exception) \ + do { \ + if ((*env)->ExceptionOccurred(env)) { \ + JLI_ReportExceptionDescription(env); \ + LEAVE(); \ + } \ + if ((CENL_exception) == NULL) { \ + JLI_ReportErrorMessage(JNI_ERROR); \ + LEAVE(); \ + } \ + } while (JNI_FALSE) + +#define CHECK_EXCEPTION_LEAVE(CEL_return_value) \ + do { \ + if ((*env)->ExceptionOccurred(env)) { \ + JLI_ReportExceptionDescription(env); \ + ret = (CEL_return_value); \ + LEAVE(); \ + } \ + } while (JNI_FALSE) + +int JNICALL +JavaMain(void * _args) +{ + JavaMainArgs *args = (JavaMainArgs *)_args; + int argc = args->argc; + char **argv = args->argv; + int mode = args->mode; + char *what = args->what; + InvocationFunctions ifn = args->ifn; + + JavaVM *vm = 0; + JNIEnv *env = 0; + jclass mainClass = NULL; + jclass appClass = NULL; // actual application class being launched + jmethodID mainID; + jobjectArray mainArgs; + int ret = 0; + jlong start, end; + + RegisterThread(); + + /* Initialize the virtual machine */ + start = CounterGet(); + if (!InitializeJVM(&vm, &env, &ifn)) { + JLI_ReportErrorMessage(JVM_ERROR1); + exit(1); + } + + if (showSettings != NULL) { + ShowSettings(env, showSettings); + CHECK_EXCEPTION_LEAVE(1); + } + + if (printVersion || showVersion) { + PrintJavaVersion(env, showVersion); + CHECK_EXCEPTION_LEAVE(0); + if (printVersion) { + LEAVE(); + } + } + + /* If the user specified neither a class name nor a JAR file */ + if (printXUsage || printUsage || what == 0 || mode == LM_UNKNOWN) { + PrintUsage(env, printXUsage); + CHECK_EXCEPTION_LEAVE(1); + LEAVE(); + } + + FreeKnownVMs(); /* after last possible PrintUsage() */ + + if (JLI_IsTraceLauncher()) { + end = CounterGet(); + JLI_TraceLauncher("%ld micro seconds to InitializeJVM\n", + (long)(jint)Counter2Micros(end-start)); + } + + /* At this stage, argc/argv have the application's arguments */ + if (JLI_IsTraceLauncher()){ + int i; + printf("%s is '%s'\n", launchModeNames[mode], what); + printf("App's argc is %d\n", argc); + for (i=0; i < argc; i++) { + printf(" argv[%2d] = '%s'\n", i, argv[i]); + } + } + + ret = 1; + + /* + * Get the application's main class. + * + * See bugid 5030265. The Main-Class name has already been parsed + * from the manifest, but not parsed properly for UTF-8 support. + * Hence the code here ignores the value previously extracted and + * uses the pre-existing code to reextract the value. This is + * possibly an end of release cycle expedient. However, it has + * also been discovered that passing some character sets through + * the environment has "strange" behavior on some variants of + * Windows. Hence, maybe the manifest parsing code local to the + * launcher should never be enhanced. + * + * Hence, future work should either: + * 1) Correct the local parsing code and verify that the + * Main-Class attribute gets properly passed through + * all environments, + * 2) Remove the vestages of maintaining main_class through + * the environment (and remove these comments). + * + * This method also correctly handles launching existing JavaFX + * applications that may or may not have a Main-Class manifest entry. + */ + mainClass = LoadMainClass(env, mode, what); + CHECK_EXCEPTION_NULL_LEAVE(mainClass); + /* + * In some cases when launching an application that needs a helper, e.g., a + * JavaFX application with no main method, the mainClass will not be the + * applications own main class but rather a helper class. To keep things + * consistent in the UI we need to track and report the application main class. + */ + appClass = GetApplicationClass(env); + NULL_CHECK_RETURN_VALUE(appClass, -1); + /* + * PostJVMInit uses the class name as the application name for GUI purposes, + * for example, on OSX this sets the application name in the menu bar for + * both SWT and JavaFX. So we'll pass the actual application class here + * instead of mainClass as that may be a launcher or helper class instead + * of the application class. + */ + PostJVMInit(env, appClass, vm); + CHECK_EXCEPTION_LEAVE(1); + /* + * The LoadMainClass not only loads the main class, it will also ensure + * that the main method's signature is correct, therefore further checking + * is not required. The main method is invoked here so that extraneous java + * stacks are not in the application stack trace. + */ + mainID = (*env)->GetStaticMethodID(env, mainClass, "main", + "([Ljava/lang/String;)V"); + CHECK_EXCEPTION_NULL_LEAVE(mainID); + + /* Build platform specific argument array */ + mainArgs = CreateApplicationArgs(env, argv, argc); + CHECK_EXCEPTION_NULL_LEAVE(mainArgs); + + /* Invoke main method. */ + (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs); + + /* + * The launcher's exit code (in the absence of calls to + * System.exit) will be non-zero if main threw an exception. + */ + ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1; + LEAVE(); +} + +/* + * Checks the command line options to find which JVM type was + * specified. If no command line option was given for the JVM type, + * the default type is used. The environment variable + * JDK_ALTERNATE_VM and the command line option -XXaltjvm= are also + * checked as ways of specifying which JVM type to invoke. + */ +char * +CheckJvmType(int *pargc, char ***argv, jboolean speculative) { + int i, argi; + int argc; + char **newArgv; + int newArgvIdx = 0; + int isVMType; + int jvmidx = -1; + char *jvmtype = getenv("JDK_ALTERNATE_VM"); + + argc = *pargc; + + /* To make things simpler we always copy the argv array */ + newArgv = JLI_MemAlloc((argc + 1) * sizeof(char *)); + + /* The program name is always present */ + newArgv[newArgvIdx++] = (*argv)[0]; + + for (argi = 1; argi < argc; argi++) { + char *arg = (*argv)[argi]; + isVMType = 0; + + if (IsJavaArgs()) { + if (arg[0] != '-') { + newArgv[newArgvIdx++] = arg; + continue; + } + } else { + if (JLI_StrCmp(arg, "-classpath") == 0 || + JLI_StrCmp(arg, "-cp") == 0) { + newArgv[newArgvIdx++] = arg; + argi++; + if (argi < argc) { + newArgv[newArgvIdx++] = (*argv)[argi]; + } + continue; + } + if (arg[0] != '-') break; + } + + /* Did the user pass an explicit VM type? */ + i = KnownVMIndex(arg); + if (i >= 0) { + jvmtype = knownVMs[jvmidx = i].name + 1; /* skip the - */ + isVMType = 1; + *pargc = *pargc - 1; + } + + /* Did the user specify an "alternate" VM? */ + else if (JLI_StrCCmp(arg, "-XXaltjvm=") == 0 || JLI_StrCCmp(arg, "-J-XXaltjvm=") == 0) { + isVMType = 1; + jvmtype = arg+((arg[1]=='X')? 10 : 12); + jvmidx = -1; + } + + if (!isVMType) { + newArgv[newArgvIdx++] = arg; + } + } + + /* + * Finish copying the arguments if we aborted the above loop. + * NOTE that if we aborted via "break" then we did NOT copy the + * last argument above, and in addition argi will be less than + * argc. + */ + while (argi < argc) { + newArgv[newArgvIdx++] = (*argv)[argi]; + argi++; + } + + /* argv is null-terminated */ + newArgv[newArgvIdx] = 0; + + /* Copy back argv */ + *argv = newArgv; + *pargc = newArgvIdx; + + /* use the default VM type if not specified (no alias processing) */ + if (jvmtype == NULL) { + char* result = knownVMs[0].name+1; + /* Use a different VM type if we are on a server class machine? */ + if ((knownVMs[0].flag == VM_IF_SERVER_CLASS) && + (ServerClassMachine() == JNI_TRUE)) { + result = knownVMs[0].server_class+1; + } + JLI_TraceLauncher("Default VM: %s\n", result); + return result; + } + + /* if using an alternate VM, no alias processing */ + if (jvmidx < 0) + return jvmtype; + + /* Resolve aliases first */ + { + int loopCount = 0; + while (knownVMs[jvmidx].flag == VM_ALIASED_TO) { + int nextIdx = KnownVMIndex(knownVMs[jvmidx].alias); + + if (loopCount > knownVMsCount) { + if (!speculative) { + JLI_ReportErrorMessage(CFG_ERROR1); + exit(1); + } else { + return "ERROR"; + /* break; */ + } + } + + if (nextIdx < 0) { + if (!speculative) { + JLI_ReportErrorMessage(CFG_ERROR2, knownVMs[jvmidx].alias); + exit(1); + } else { + return "ERROR"; + } + } + jvmidx = nextIdx; + jvmtype = knownVMs[jvmidx].name+1; + loopCount++; + } + } + + switch (knownVMs[jvmidx].flag) { + case VM_WARN: + if (!speculative) { + JLI_ReportErrorMessage(CFG_WARN1, jvmtype, knownVMs[0].name + 1); + } + /* fall through */ + case VM_IGNORE: + jvmtype = knownVMs[jvmidx=0].name + 1; + /* fall through */ + case VM_KNOWN: + break; + case VM_ERROR: + if (!speculative) { + JLI_ReportErrorMessage(CFG_ERROR3, jvmtype); + exit(1); + } else { + return "ERROR"; + } + } + + return jvmtype; +} + +/* + * static void SetJvmEnvironment(int argc, char **argv); + * Is called just before the JVM is loaded. We can set env variables + * that are consumed by the JVM. This function is non-destructive, + * leaving the arg list intact. The first use is for the JVM flag + * -XX:NativeMemoryTracking=value. + */ +static void +SetJvmEnvironment(int argc, char **argv) { + + static const char* NMT_Env_Name = "NMT_LEVEL_"; + + int i; + for (i = 0; i < argc; i++) { + /* + * The following case checks for "-XX:NativeMemoryTracking=value". + * If value is non null, an environmental variable set to this value + * will be created to be used by the JVM. + * The argument is passed to the JVM, which will check validity. + * The JVM is responsible for removing the env variable. + */ + char *arg = argv[i]; + if (JLI_StrCCmp(arg, "-XX:NativeMemoryTracking=") == 0) { + int retval; + // get what follows this parameter, include "=" + size_t pnlen = JLI_StrLen("-XX:NativeMemoryTracking="); + if (JLI_StrLen(arg) > pnlen) { + char* value = arg + pnlen; + size_t pbuflen = pnlen + JLI_StrLen(value) + 10; // 10 max pid digits + + /* + * ensures that malloc successful + * DONT JLI_MemFree() pbuf. JLI_PutEnv() uses system call + * that could store the address. + */ + char * pbuf = (char*)JLI_MemAlloc(pbuflen); + + JLI_Snprintf(pbuf, pbuflen, "%s%d=%s", NMT_Env_Name, JLI_GetPid(), value); + retval = JLI_PutEnv(pbuf); + if (JLI_IsTraceLauncher()) { + char* envName; + char* envBuf; + + // ensures that malloc successful + envName = (char*)JLI_MemAlloc(pbuflen); + JLI_Snprintf(envName, pbuflen, "%s%d", NMT_Env_Name, JLI_GetPid()); + + printf("TRACER_MARKER: NativeMemoryTracking: env var is %s\n",envName); + printf("TRACER_MARKER: NativeMemoryTracking: putenv arg %s\n",pbuf); + envBuf = getenv(envName); + printf("TRACER_MARKER: NativeMemoryTracking: got value %s\n",envBuf); + free(envName); + } + + } + + } + + } +} + +/* copied from HotSpot function "atomll()" */ +static int +parse_size(const char *s, jlong *result) { + jlong n = 0; + int args_read = sscanf(s, jlong_format_specifier(), &n); + if (args_read != 1) { + return 0; + } + while (*s != '\0' && *s >= '0' && *s <= '9') { + s++; + } + // 4705540: illegal if more characters are found after the first non-digit + if (JLI_StrLen(s) > 1) { + return 0; + } + switch (*s) { + case 'T': case 't': + *result = n * GB * KB; + return 1; + case 'G': case 'g': + *result = n * GB; + return 1; + case 'M': case 'm': + *result = n * MB; + return 1; + case 'K': case 'k': + *result = n * KB; + return 1; + case '\0': + *result = n; + return 1; + default: + /* Create JVM with default stack and let VM handle malformed -Xss string*/ + return 0; + } +} + +/* + * Adds a new VM option with the given given name and value. + */ +void +AddOption(char *str, void *info) +{ + /* + * Expand options array if needed to accommodate at least one more + * VM option. + */ + if (numOptions >= maxOptions) { + if (options == 0) { + maxOptions = 4; + options = JLI_MemAlloc(maxOptions * sizeof(JavaVMOption)); + } else { + JavaVMOption *tmp; + maxOptions *= 2; + tmp = JLI_MemAlloc(maxOptions * sizeof(JavaVMOption)); + memcpy(tmp, options, numOptions * sizeof(JavaVMOption)); + JLI_MemFree(options); + options = tmp; + } + } + options[numOptions].optionString = str; + options[numOptions++].extraInfo = info; + + if (JLI_StrCCmp(str, "-Xss") == 0) { + jlong tmp; + if (parse_size(str + 4, &tmp)) { + threadStackSize = tmp; + } + } + + if (JLI_StrCCmp(str, "-Xmx") == 0) { + jlong tmp; + if (parse_size(str + 4, &tmp)) { + maxHeapSize = tmp; + } + } + + if (JLI_StrCCmp(str, "-Xms") == 0) { + jlong tmp; + if (parse_size(str + 4, &tmp)) { + initialHeapSize = tmp; + } + } +} + +static void +SetClassPath(const char *s) +{ + char *def; + const char *orig = s; + static const char format[] = "-Djava.class.path=%s"; + /* + * usually we should not get a null pointer, but there are cases where + * we might just get one, in which case we simply ignore it, and let the + * caller deal with it + */ + if (s == NULL) + return; + s = JLI_WildcardExpandClasspath(s); + if (sizeof(format) - 2 + JLI_StrLen(s) < JLI_StrLen(s)) + // s is corrupted after wildcard expansion + return; + def = JLI_MemAlloc(sizeof(format) + - 2 /* strlen("%s") */ + + JLI_StrLen(s)); + sprintf(def, format, s); + AddOption(def, NULL); + if (s != orig) + JLI_MemFree((char *) s); +} + +/* + * The SelectVersion() routine ensures that an appropriate version of + * the JRE is running. The specification for the appropriate version + * is obtained from either the manifest of a jar file (preferred) or + * from command line options. + * The routine also parses splash screen command line options and + * passes on their values in private environment variables. + */ +static void +SelectVersion(int argc, char **argv, char **main_class) +{ + char *arg; + char **new_argv; + char **new_argp; + char *operand; + char *version = NULL; + char *jre = NULL; + int jarflag = 0; + int headlessflag = 0; + int restrict_search = -1; /* -1 implies not known */ + manifest_info info; + char env_entry[MAXNAMELEN + 24] = ENV_ENTRY "="; + char *splash_file_name = NULL; + char *splash_jar_name = NULL; + char *env_in; + int res; + + /* + * If the version has already been selected, set *main_class + * with the value passed through the environment (if any) and + * simply return. + */ + if ((env_in = getenv(ENV_ENTRY)) != NULL) { + if (*env_in != '\0') + *main_class = JLI_StringDup(env_in); + return; + } + + /* + * Scan through the arguments for options relevant to multiple JRE + * support. For reference, the command line syntax is defined as: + * + * SYNOPSIS + * java [options] class [argument...] + * + * java [options] -jar file.jar [argument...] + * + * As the scan is performed, make a copy of the argument list with + * the version specification options (new to 1.5) removed, so that + * a version less than 1.5 can be exec'd. + * + * Note that due to the syntax of the native Windows interface + * CreateProcess(), processing similar to the following exists in + * the Windows platform specific routine ExecJRE (in java_md.c). + * Changes here should be reproduced there. + */ + new_argv = JLI_MemAlloc((argc + 1) * sizeof(char*)); + new_argv[0] = argv[0]; + new_argp = &new_argv[1]; + argc--; + argv++; + while ((arg = *argv) != 0 && *arg == '-') { + if (JLI_StrCCmp(arg, "-version:") == 0) { + version = arg + 9; + } else if (JLI_StrCmp(arg, "-jre-restrict-search") == 0) { + restrict_search = 1; + } else if (JLI_StrCmp(arg, "-no-jre-restrict-search") == 0) { + restrict_search = 0; + } else { + if (JLI_StrCmp(arg, "-jar") == 0) + jarflag = 1; + /* deal with "unfortunate" classpath syntax */ + if ((JLI_StrCmp(arg, "-classpath") == 0 || JLI_StrCmp(arg, "-cp") == 0) && + (argc >= 2)) { + *new_argp++ = arg; + argc--; + argv++; + arg = *argv; + } + + /* + * Checking for headless toolkit option in the some way as AWT does: + * "true" means true and any other value means false + */ + if (JLI_StrCmp(arg, "-Djava.awt.headless=true") == 0) { + headlessflag = 1; + } else if (JLI_StrCCmp(arg, "-Djava.awt.headless=") == 0) { + headlessflag = 0; + } else if (JLI_StrCCmp(arg, "-splash:") == 0) { + splash_file_name = arg+8; + } + *new_argp++ = arg; + } + argc--; + argv++; + } + if (argc <= 0) { /* No operand? Possibly legit with -[full]version */ + operand = NULL; + } else { + argc--; + *new_argp++ = operand = *argv++; + } + while (argc-- > 0) /* Copy over [argument...] */ + *new_argp++ = *argv++; + *new_argp = NULL; + + /* + * If there is a jar file, read the manifest. If the jarfile can't be + * read, the manifest can't be read from the jar file, or the manifest + * is corrupt, issue the appropriate error messages and exit. + * + * Even if there isn't a jar file, construct a manifest_info structure + * containing the command line information. It's a convenient way to carry + * this data around. + */ + if (jarflag && operand) { + if ((res = JLI_ParseManifest(operand, &info)) != 0) { + if (res == -1) + JLI_ReportErrorMessage(JAR_ERROR2, operand); + else + JLI_ReportErrorMessage(JAR_ERROR3, operand); + exit(1); + } + + /* + * Command line splash screen option should have precedence + * over the manifest, so the manifest data is used only if + * splash_file_name has not been initialized above during command + * line parsing + */ + if (!headlessflag && !splash_file_name && info.splashscreen_image_file_name) { + splash_file_name = info.splashscreen_image_file_name; + splash_jar_name = operand; + } + } else { + info.manifest_version = NULL; + info.main_class = NULL; + info.jre_version = NULL; + info.jre_restrict_search = 0; + } + + /* + * Passing on splash screen info in environment variables + */ + if (splash_file_name && !headlessflag) { + char* splash_file_entry = JLI_MemAlloc(JLI_StrLen(SPLASH_FILE_ENV_ENTRY "=")+JLI_StrLen(splash_file_name)+1); + JLI_StrCpy(splash_file_entry, SPLASH_FILE_ENV_ENTRY "="); + JLI_StrCat(splash_file_entry, splash_file_name); + putenv(splash_file_entry); + } + if (splash_jar_name && !headlessflag) { + char* splash_jar_entry = JLI_MemAlloc(JLI_StrLen(SPLASH_JAR_ENV_ENTRY "=")+JLI_StrLen(splash_jar_name)+1); + JLI_StrCpy(splash_jar_entry, SPLASH_JAR_ENV_ENTRY "="); + JLI_StrCat(splash_jar_entry, splash_jar_name); + putenv(splash_jar_entry); + } + + /* + * The JRE-Version and JRE-Restrict-Search values (if any) from the + * manifest are overwritten by any specified on the command line. + */ + if (version != NULL) + info.jre_version = version; + if (restrict_search != -1) + info.jre_restrict_search = restrict_search; + + /* + * "Valid" returns (other than unrecoverable errors) follow. Set + * main_class as a side-effect of this routine. + */ + if (info.main_class != NULL) + *main_class = JLI_StringDup(info.main_class); + + /* + * If no version selection information is found either on the command + * line or in the manifest, simply return. + */ + if (info.jre_version == NULL) { + JLI_FreeManifest(); + JLI_MemFree(new_argv); + return; + } + + /* + * Check for correct syntax of the version specification (JSR 56). + */ + if (!JLI_ValidVersionString(info.jre_version)) { + JLI_ReportErrorMessage(SPC_ERROR1, info.jre_version); + exit(1); + } + + /* + * Find the appropriate JVM on the system. Just to be as forgiving as + * possible, if the standard algorithms don't locate an appropriate + * jre, check to see if the one running will satisfy the requirements. + * This can happen on systems which haven't been set-up for multiple + * JRE support. + */ + jre = LocateJRE(&info); + JLI_TraceLauncher("JRE-Version = %s, JRE-Restrict-Search = %s Selected = %s\n", + (info.jre_version?info.jre_version:"null"), + (info.jre_restrict_search?"true":"false"), (jre?jre:"null")); + + if (jre == NULL) { + if (JLI_AcceptableRelease(GetFullVersion(), info.jre_version)) { + JLI_FreeManifest(); + JLI_MemFree(new_argv); + return; + } else { + JLI_ReportErrorMessage(CFG_ERROR4, info.jre_version); + exit(1); + } + } + + /* + * If I'm not the chosen one, exec the chosen one. Returning from + * ExecJRE indicates that I am indeed the chosen one. + * + * The private environment variable _JAVA_VERSION_SET is used to + * prevent the chosen one from re-reading the manifest file and + * using the values found within to override the (potential) command + * line flags stripped from argv (because the target may not + * understand them). Passing the MainClass value is an optimization + * to avoid locating, expanding and parsing the manifest extra + * times. + */ + if (info.main_class != NULL) { + if (JLI_StrLen(info.main_class) <= MAXNAMELEN) { + (void)JLI_StrCat(env_entry, info.main_class); + } else { + JLI_ReportErrorMessage(CLS_ERROR5, MAXNAMELEN); + exit(1); + } + } + (void)putenv(env_entry); + ExecJRE(jre, new_argv); + JLI_FreeManifest(); + JLI_MemFree(new_argv); + return; +} + +/* + * Parses command line arguments. Returns JNI_FALSE if launcher + * should exit without starting vm, returns JNI_TRUE if vm needs + * to be started to process given options. *pret (the launcher + * process return value) is set to 0 for a normal exit. + */ +static jboolean +ParseArguments(int *pargc, char ***pargv, + int *pmode, char **pwhat, + int *pret, const char *jrepath) +{ + int argc = *pargc; + char **argv = *pargv; + int mode = LM_UNKNOWN; + char *arg; + + *pret = 0; + + while ((arg = *argv) != 0 && *arg == '-') { + argv++; --argc; + if (JLI_StrCmp(arg, "-classpath") == 0 || JLI_StrCmp(arg, "-cp") == 0) { + ARG_CHECK (argc, ARG_ERROR1, arg); + SetClassPath(*argv); + mode = LM_CLASS; + argv++; --argc; + } else if (JLI_StrCmp(arg, "-jar") == 0) { + ARG_CHECK (argc, ARG_ERROR2, arg); + mode = LM_JAR; + } else if (JLI_StrCmp(arg, "-help") == 0 || + JLI_StrCmp(arg, "-h") == 0 || + JLI_StrCmp(arg, "-?") == 0) { + printUsage = JNI_TRUE; + return JNI_TRUE; + } else if (JLI_StrCmp(arg, "-version") == 0) { + printVersion = JNI_TRUE; + return JNI_TRUE; + } else if (JLI_StrCmp(arg, "-showversion") == 0) { + showVersion = JNI_TRUE; + } else if (JLI_StrCmp(arg, "-X") == 0) { + printXUsage = JNI_TRUE; + return JNI_TRUE; +/* + * The following case checks for -XshowSettings OR -XshowSetting:SUBOPT. + * In the latter case, any SUBOPT value not recognized will default to "all" + */ + } else if (JLI_StrCmp(arg, "-XshowSettings") == 0 || + JLI_StrCCmp(arg, "-XshowSettings:") == 0) { + showSettings = arg; + } else if (JLI_StrCmp(arg, "-Xdiag") == 0) { + AddOption("-Dsun.java.launcher.diag=true", NULL); +/* + * The following case provide backward compatibility with old-style + * command line options. + */ + } else if (JLI_StrCmp(arg, "-fullversion") == 0) { + JLI_ReportMessage("%s full version \"%s\"", _launcher_name, GetFullVersion()); + return JNI_FALSE; + } else if (JLI_StrCmp(arg, "-verbosegc") == 0) { + AddOption("-verbose:gc", NULL); + } else if (JLI_StrCmp(arg, "-t") == 0) { + AddOption("-Xt", NULL); + } else if (JLI_StrCmp(arg, "-tm") == 0) { + AddOption("-Xtm", NULL); + } else if (JLI_StrCmp(arg, "-debug") == 0) { + AddOption("-Xdebug", NULL); + } else if (JLI_StrCmp(arg, "-noclassgc") == 0) { + AddOption("-Xnoclassgc", NULL); + } else if (JLI_StrCmp(arg, "-Xfuture") == 0) { + AddOption("-Xverify:all", NULL); + } else if (JLI_StrCmp(arg, "-verify") == 0) { + AddOption("-Xverify:all", NULL); + } else if (JLI_StrCmp(arg, "-verifyremote") == 0) { + AddOption("-Xverify:remote", NULL); + } else if (JLI_StrCmp(arg, "-noverify") == 0) { + AddOption("-Xverify:none", NULL); + } else if (JLI_StrCCmp(arg, "-prof") == 0) { + char *p = arg + 5; + char *tmp = JLI_MemAlloc(JLI_StrLen(arg) + 50); + if (*p) { + sprintf(tmp, "-Xrunhprof:cpu=old,file=%s", p + 1); + } else { + sprintf(tmp, "-Xrunhprof:cpu=old,file=java.prof"); + } + AddOption(tmp, NULL); + } else if (JLI_StrCCmp(arg, "-ss") == 0 || + JLI_StrCCmp(arg, "-oss") == 0 || + JLI_StrCCmp(arg, "-ms") == 0 || + JLI_StrCCmp(arg, "-mx") == 0) { + char *tmp = JLI_MemAlloc(JLI_StrLen(arg) + 6); + sprintf(tmp, "-X%s", arg + 1); /* skip '-' */ + AddOption(tmp, NULL); + } else if (JLI_StrCmp(arg, "-checksource") == 0 || + JLI_StrCmp(arg, "-cs") == 0 || + JLI_StrCmp(arg, "-noasyncgc") == 0) { + /* No longer supported */ + JLI_ReportErrorMessage(ARG_WARN, arg); + } else if (JLI_StrCCmp(arg, "-version:") == 0 || + JLI_StrCmp(arg, "-no-jre-restrict-search") == 0 || + JLI_StrCmp(arg, "-jre-restrict-search") == 0 || + JLI_StrCCmp(arg, "-splash:") == 0) { + ; /* Ignore machine independent options already handled */ + } else if (ProcessPlatformOption(arg)) { + ; /* Processing of platform dependent options */ + } else if (RemovableOption(arg)) { + ; /* Do not pass option to vm. */ + } else { + AddOption(arg, NULL); + } + } + + if (--argc >= 0) { + *pwhat = *argv++; + } + + if (*pwhat == NULL) { + *pret = 1; + } else if (mode == LM_UNKNOWN) { + /* default to LM_CLASS if -jar and -cp option are + * not specified */ + mode = LM_CLASS; + } + + if (argc >= 0) { + *pargc = argc; + *pargv = argv; + } + + *pmode = mode; + + return JNI_TRUE; +} + +/* + * Initializes the Java Virtual Machine. Also frees options array when + * finished. + */ +static jboolean +InitializeJVM(JavaVM **pvm, JNIEnv **penv, InvocationFunctions *ifn) +{ + JavaVMInitArgs args; + jint r; + + memset(&args, 0, sizeof(args)); + args.version = JNI_VERSION_1_2; + args.nOptions = numOptions; + args.options = options; + args.ignoreUnrecognized = JNI_FALSE; + + if (JLI_IsTraceLauncher()) { + int i = 0; + printf("JavaVM args:\n "); + printf("version 0x%08lx, ", (long)args.version); + printf("ignoreUnrecognized is %s, ", + args.ignoreUnrecognized ? "JNI_TRUE" : "JNI_FALSE"); + printf("nOptions is %ld\n", (long)args.nOptions); + for (i = 0; i < numOptions; i++) + printf(" option[%2d] = '%s'\n", + i, args.options[i].optionString); + } + + r = ifn->CreateJavaVM(pvm, (void **)penv, &args); + JLI_MemFree(options); + return r == JNI_OK; +} + +static jclass helperClass = NULL; + +jclass +GetLauncherHelperClass(JNIEnv *env) +{ + if (helperClass == NULL) { + NULL_CHECK0(helperClass = FindBootStrapClass(env, + "sun/launcher/LauncherHelper")); + } + return helperClass; +} + +static jmethodID makePlatformStringMID = NULL; +/* + * Returns a new Java string object for the specified platform string. + */ +static jstring +NewPlatformString(JNIEnv *env, char *s) +{ + int len = (int)JLI_StrLen(s); + jbyteArray ary; + jclass cls = GetLauncherHelperClass(env); + NULL_CHECK0(cls); + if (s == NULL) + return 0; + + ary = (*env)->NewByteArray(env, len); + if (ary != 0) { + jstring str = 0; + (*env)->SetByteArrayRegion(env, ary, 0, len, (jbyte *)s); + if (!(*env)->ExceptionOccurred(env)) { + if (makePlatformStringMID == NULL) { + CHECK_JNI_RETURN_0( + makePlatformStringMID = (*env)->GetStaticMethodID(env, + cls, "makePlatformString", "(Z[B)Ljava/lang/String;")); + } + CHECK_JNI_RETURN_0( + str = (*env)->CallStaticObjectMethod(env, cls, + makePlatformStringMID, USE_STDERR, ary)); + (*env)->DeleteLocalRef(env, ary); + return str; + } + } + return 0; +} + +/* + * Returns a new array of Java string objects for the specified + * array of platform strings. + */ +jobjectArray +NewPlatformStringArray(JNIEnv *env, char **strv, int strc) +{ + jarray cls; + jarray ary; + int i; + + NULL_CHECK0(cls = FindBootStrapClass(env, "java/lang/String")); + NULL_CHECK0(ary = (*env)->NewObjectArray(env, strc, cls, 0)); + for (i = 0; i < strc; i++) { + jstring str = NewPlatformString(env, *strv++); + NULL_CHECK0(str); + (*env)->SetObjectArrayElement(env, ary, i, str); + (*env)->DeleteLocalRef(env, str); + } + return ary; +} + +/* + * Loads a class and verifies that the main class is present and it is ok to + * call it for more details refer to the java implementation. + */ +static jclass +LoadMainClass(JNIEnv *env, int mode, char *name) +{ + jmethodID mid; + jstring str; + jobject result; + jlong start, end; + jclass cls = GetLauncherHelperClass(env); + NULL_CHECK0(cls); + if (JLI_IsTraceLauncher()) { + start = CounterGet(); + } + NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls, + "checkAndLoadMain", + "(ZILjava/lang/String;)Ljava/lang/Class;")); + + str = NewPlatformString(env, name); + CHECK_JNI_RETURN_0( + result = (*env)->CallStaticObjectMethod( + env, cls, mid, USE_STDERR, mode, str)); + + if (JLI_IsTraceLauncher()) { + end = CounterGet(); + printf("%ld micro seconds to load main class\n", + (long)(jint)Counter2Micros(end-start)); + printf("----%s----\n", JLDEBUG_ENV_ENTRY); + } + + return (jclass)result; +} + +static jclass +GetApplicationClass(JNIEnv *env) +{ + jmethodID mid; + jobject result; + jclass cls = GetLauncherHelperClass(env); + NULL_CHECK0(cls); + NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls, + "getApplicationClass", + "()Ljava/lang/Class;")); + + return (*env)->CallStaticObjectMethod(env, cls, mid); +} + +/* + * For tools, convert command line args thus: + * javac -cp foo:foo/"*" -J-ms32m ... + * java -ms32m -cp JLI_WildcardExpandClasspath(foo:foo/"*") ... + * + * Takes 4 parameters, and returns the populated arguments + */ +static void +TranslateApplicationArgs(int jargc, const char **jargv, int *pargc, char ***pargv) +{ + int argc = *pargc; + char **argv = *pargv; + int nargc = argc + jargc; + char **nargv = JLI_MemAlloc((nargc + 1) * sizeof(char *)); + int i; + + *pargc = nargc; + *pargv = nargv; + + /* Copy the VM arguments (i.e. prefixed with -J) */ + for (i = 0; i < jargc; i++) { + const char *arg = jargv[i]; + if (arg[0] == '-' && arg[1] == 'J') { + *nargv++ = ((arg + 2) == NULL) ? NULL : JLI_StringDup(arg + 2); + } + } + + for (i = 0; i < argc; i++) { + char *arg = argv[i]; + if (arg[0] == '-' && arg[1] == 'J') { + if (arg[2] == '\0') { + JLI_ReportErrorMessage(ARG_ERROR3); + exit(1); + } + *nargv++ = arg + 2; + } + } + + /* Copy the rest of the arguments */ + for (i = 0; i < jargc ; i++) { + const char *arg = jargv[i]; + if (arg[0] != '-' || arg[1] != 'J') { + *nargv++ = (arg == NULL) ? NULL : JLI_StringDup(arg); + } + } + for (i = 0; i < argc; i++) { + char *arg = argv[i]; + if (arg[0] == '-') { + if (arg[1] == 'J') + continue; + if (IsWildCardEnabled() && arg[1] == 'c' + && (JLI_StrCmp(arg, "-cp") == 0 || + JLI_StrCmp(arg, "-classpath") == 0) + && i < argc - 1) { + *nargv++ = arg; + *nargv++ = (char *) JLI_WildcardExpandClasspath(argv[i+1]); + i++; + continue; + } + } + *nargv++ = arg; + } + *nargv = 0; +} + +/* + * For our tools, we try to add 3 VM options: + * -Denv.class.path= + * -Dapplication.home= + * -Djava.class.path= + * is the user's setting of CLASSPATH -- for instance the user + * tells javac where to find binary classes through this environment + * variable. Notice that users will be able to compile against our + * tools classes (sun.tools.javac.Main) only if they explicitly add + * tools.jar to CLASSPATH. + * is the directory where the application is installed. + * is the classpath to where our apps' classfiles are. + */ +static jboolean +AddApplicationOptions(int cpathc, const char **cpathv) +{ + char *envcp, *appcp, *apphome; + char home[MAXPATHLEN]; /* application home */ + char separator[] = { PATH_SEPARATOR, '\0' }; + int size, i; + + { + const char *s = getenv("CLASSPATH"); + if (s) { + s = (char *) JLI_WildcardExpandClasspath(s); + /* 40 for -Denv.class.path= */ + if (JLI_StrLen(s) + 40 > JLI_StrLen(s)) { // Safeguard from overflow + envcp = (char *)JLI_MemAlloc(JLI_StrLen(s) + 40); + sprintf(envcp, "-Denv.class.path=%s", s); + AddOption(envcp, NULL); + } + } + } + + if (!GetApplicationHome(home, sizeof(home))) { + JLI_ReportErrorMessage(CFG_ERROR5); + return JNI_FALSE; + } + + /* 40 for '-Dapplication.home=' */ + apphome = (char *)JLI_MemAlloc(JLI_StrLen(home) + 40); + sprintf(apphome, "-Dapplication.home=%s", home); + AddOption(apphome, NULL); + + /* How big is the application's classpath? */ + size = 40; /* 40: "-Djava.class.path=" */ + for (i = 0; i < cpathc; i++) { + size += (int)JLI_StrLen(home) + (int)JLI_StrLen(cpathv[i]) + 1; /* 1: separator */ + } + appcp = (char *)JLI_MemAlloc(size + 1); + JLI_StrCpy(appcp, "-Djava.class.path="); + for (i = 0; i < cpathc; i++) { + JLI_StrCat(appcp, home); /* c:\program files\myapp */ + JLI_StrCat(appcp, cpathv[i]); /* \lib\myapp.jar */ + JLI_StrCat(appcp, separator); /* ; */ + } + appcp[JLI_StrLen(appcp)-1] = '\0'; /* remove trailing path separator */ + AddOption(appcp, NULL); + return JNI_TRUE; +} + +/* + * inject the -Dsun.java.command pseudo property into the args structure + * this pseudo property is used in the HotSpot VM to expose the + * Java class name and arguments to the main method to the VM. The + * HotSpot VM uses this pseudo property to store the Java class name + * (or jar file name) and the arguments to the class's main method + * to the instrumentation memory region. The sun.java.command pseudo + * property is not exported by HotSpot to the Java layer. + */ +void +SetJavaCommandLineProp(char *what, int argc, char **argv) +{ + + int i = 0; + size_t len = 0; + char* javaCommand = NULL; + char* dashDstr = "-Dsun.java.command="; + + if (what == NULL) { + /* unexpected, one of these should be set. just return without + * setting the property + */ + return; + } + + /* determine the amount of memory to allocate assuming + * the individual components will be space separated + */ + len = JLI_StrLen(what); + for (i = 0; i < argc; i++) { + len += JLI_StrLen(argv[i]) + 1; + } + + /* allocate the memory */ + javaCommand = (char*) JLI_MemAlloc(len + JLI_StrLen(dashDstr) + 1); + + /* build the -D string */ + *javaCommand = '\0'; + JLI_StrCat(javaCommand, dashDstr); + JLI_StrCat(javaCommand, what); + + for (i = 0; i < argc; i++) { + /* the components of the string are space separated. In + * the case of embedded white space, the relationship of + * the white space separated components to their true + * positional arguments will be ambiguous. This issue may + * be addressed in a future release. + */ + JLI_StrCat(javaCommand, " "); + JLI_StrCat(javaCommand, argv[i]); + } + + AddOption(javaCommand, NULL); +} + +/* + * JVM would like to know if it's created by a standard Sun launcher, or by + * user native application, the following property indicates the former. + */ +void +SetJavaLauncherProp() { + AddOption("-Dsun.java.launcher=SUN_STANDARD", NULL); +} + +/* + * Prints the version information from the java.version and other properties. + */ +static void +PrintJavaVersion(JNIEnv *env, jboolean extraLF) +{ + jclass ver; + jmethodID print; + + NULL_CHECK(ver = FindBootStrapClass(env, "sun/misc/Version")); + NULL_CHECK(print = (*env)->GetStaticMethodID(env, + ver, + (extraLF == JNI_TRUE) ? "println" : "print", + "()V" + ) + ); + + (*env)->CallStaticVoidMethod(env, ver, print); +} + +/* + * Prints all the Java settings, see the java implementation for more details. + */ +static void +ShowSettings(JNIEnv *env, char *optString) +{ + jmethodID showSettingsID; + jstring joptString; + jclass cls = GetLauncherHelperClass(env); + NULL_CHECK(cls); + NULL_CHECK(showSettingsID = (*env)->GetStaticMethodID(env, cls, + "showSettings", "(ZLjava/lang/String;JJJZ)V")); + joptString = (*env)->NewStringUTF(env, optString); + (*env)->CallStaticVoidMethod(env, cls, showSettingsID, + USE_STDERR, + joptString, + (jlong)initialHeapSize, + (jlong)maxHeapSize, + (jlong)threadStackSize, + ServerClassMachine()); +} + +/* + * Prints default usage or the Xusage message, see sun.launcher.LauncherHelper.java + */ +static void +PrintUsage(JNIEnv* env, jboolean doXUsage) +{ + jmethodID initHelp, vmSelect, vmSynonym, vmErgo, printHelp, printXUsageMessage; + jstring jprogname, vm1, vm2; + int i; + jclass cls = GetLauncherHelperClass(env); + NULL_CHECK(cls); + if (doXUsage) { + NULL_CHECK(printXUsageMessage = (*env)->GetStaticMethodID(env, cls, + "printXUsageMessage", "(Z)V")); + (*env)->CallStaticVoidMethod(env, cls, printXUsageMessage, USE_STDERR); + } else { + NULL_CHECK(initHelp = (*env)->GetStaticMethodID(env, cls, + "initHelpMessage", "(Ljava/lang/String;)V")); + + NULL_CHECK(vmSelect = (*env)->GetStaticMethodID(env, cls, "appendVmSelectMessage", + "(Ljava/lang/String;Ljava/lang/String;)V")); + + NULL_CHECK(vmSynonym = (*env)->GetStaticMethodID(env, cls, + "appendVmSynonymMessage", + "(Ljava/lang/String;Ljava/lang/String;)V")); + NULL_CHECK(vmErgo = (*env)->GetStaticMethodID(env, cls, + "appendVmErgoMessage", "(ZLjava/lang/String;)V")); + + NULL_CHECK(printHelp = (*env)->GetStaticMethodID(env, cls, + "printHelpMessage", "(Z)V")); + + jprogname = (*env)->NewStringUTF(env, _program_name); + + /* Initialize the usage message with the usual preamble */ + (*env)->CallStaticVoidMethod(env, cls, initHelp, jprogname); + + + /* Assemble the other variant part of the usage */ + if ((knownVMs[0].flag == VM_KNOWN) || + (knownVMs[0].flag == VM_IF_SERVER_CLASS)) { + vm1 = (*env)->NewStringUTF(env, knownVMs[0].name); + vm2 = (*env)->NewStringUTF(env, knownVMs[0].name+1); + (*env)->CallStaticVoidMethod(env, cls, vmSelect, vm1, vm2); + } + for (i=1; iNewStringUTF(env, knownVMs[i].name); + vm2 = (*env)->NewStringUTF(env, knownVMs[i].name+1); + (*env)->CallStaticVoidMethod(env, cls, vmSelect, vm1, vm2); + } + } + for (i=1; iNewStringUTF(env, knownVMs[i].name); + vm2 = (*env)->NewStringUTF(env, knownVMs[i].alias+1); + (*env)->CallStaticVoidMethod(env, cls, vmSynonym, vm1, vm2); + } + } + + /* The first known VM is the default */ + { + jboolean isServerClassMachine = ServerClassMachine(); + + const char* defaultVM = knownVMs[0].name+1; + if ((knownVMs[0].flag == VM_IF_SERVER_CLASS) && isServerClassMachine) { + defaultVM = knownVMs[0].server_class+1; + } + + vm1 = (*env)->NewStringUTF(env, defaultVM); + (*env)->CallStaticVoidMethod(env, cls, vmErgo, isServerClassMachine, vm1); + } + + /* Complete the usage message and print to stderr*/ + (*env)->CallStaticVoidMethod(env, cls, printHelp, USE_STDERR); + } + return; +} + +/* + * Read the jvm.cfg file and fill the knownJVMs[] array. + * + * The functionality of the jvm.cfg file is subject to change without + * notice and the mechanism will be removed in the future. + * + * The lexical structure of the jvm.cfg file is as follows: + * + * jvmcfg := { vmLine } + * vmLine := knownLine + * | aliasLine + * | warnLine + * | ignoreLine + * | errorLine + * | predicateLine + * | commentLine + * knownLine := flag "KNOWN" EOL + * warnLine := flag "WARN" EOL + * ignoreLine := flag "IGNORE" EOL + * errorLine := flag "ERROR" EOL + * aliasLine := flag "ALIASED_TO" flag EOL + * predicateLine := flag "IF_SERVER_CLASS" flag EOL + * commentLine := "#" text EOL + * flag := "-" identifier + * + * The semantics are that when someone specifies a flag on the command line: + * - if the flag appears on a knownLine, then the identifier is used as + * the name of the directory holding the JVM library (the name of the JVM). + * - if the flag appears as the first flag on an aliasLine, the identifier + * of the second flag is used as the name of the JVM. + * - if the flag appears on a warnLine, the identifier is used as the + * name of the JVM, but a warning is generated. + * - if the flag appears on an ignoreLine, the identifier is recognized as the + * name of a JVM, but the identifier is ignored and the default vm used + * - if the flag appears on an errorLine, an error is generated. + * - if the flag appears as the first flag on a predicateLine, and + * the machine on which you are running passes the predicate indicated, + * then the identifier of the second flag is used as the name of the JVM, + * otherwise the identifier of the first flag is used as the name of the JVM. + * If no flag is given on the command line, the first vmLine of the jvm.cfg + * file determines the name of the JVM. + * PredicateLines are only interpreted on first vmLine of a jvm.cfg file, + * since they only make sense if someone hasn't specified the name of the + * JVM on the command line. + * + * The intent of the jvm.cfg file is to allow several JVM libraries to + * be installed in different subdirectories of a single JRE installation, + * for space-savings and convenience in testing. + * The intent is explicitly not to provide a full aliasing or predicate + * mechanism. + */ +jint +ReadKnownVMs(const char *jvmCfgName, jboolean speculative) +{ + FILE *jvmCfg; + char line[MAXPATHLEN+20]; + int cnt = 0; + int lineno = 0; + jlong start, end; + int vmType; + char *tmpPtr; + char *altVMName = NULL; + char *serverClassVMName = NULL; + static char *whiteSpace = " \t"; + if (JLI_IsTraceLauncher()) { + start = CounterGet(); + } + + jvmCfg = fopen(jvmCfgName, "r"); + if (jvmCfg == NULL) { + if (!speculative) { + JLI_ReportErrorMessage(CFG_ERROR6, jvmCfgName); + exit(1); + } else { + return -1; + } + } + while (fgets(line, sizeof(line), jvmCfg) != NULL) { + vmType = VM_UNKNOWN; + lineno++; + if (line[0] == '#') + continue; + if (line[0] != '-') { + JLI_ReportErrorMessage(CFG_WARN2, lineno, jvmCfgName); + } + if (cnt >= knownVMsLimit) { + GrowKnownVMs(cnt); + } + line[JLI_StrLen(line)-1] = '\0'; /* remove trailing newline */ + tmpPtr = line + JLI_StrCSpn(line, whiteSpace); + if (*tmpPtr == 0) { + JLI_ReportErrorMessage(CFG_WARN3, lineno, jvmCfgName); + } else { + /* Null-terminate this string for JLI_StringDup below */ + *tmpPtr++ = 0; + tmpPtr += JLI_StrSpn(tmpPtr, whiteSpace); + if (*tmpPtr == 0) { + JLI_ReportErrorMessage(CFG_WARN3, lineno, jvmCfgName); + } else { + if (!JLI_StrCCmp(tmpPtr, "KNOWN")) { + vmType = VM_KNOWN; + } else if (!JLI_StrCCmp(tmpPtr, "ALIASED_TO")) { + tmpPtr += JLI_StrCSpn(tmpPtr, whiteSpace); + if (*tmpPtr != 0) { + tmpPtr += JLI_StrSpn(tmpPtr, whiteSpace); + } + if (*tmpPtr == 0) { + JLI_ReportErrorMessage(CFG_WARN3, lineno, jvmCfgName); + } else { + /* Null terminate altVMName */ + altVMName = tmpPtr; + tmpPtr += JLI_StrCSpn(tmpPtr, whiteSpace); + *tmpPtr = 0; + vmType = VM_ALIASED_TO; + } + } else if (!JLI_StrCCmp(tmpPtr, "WARN")) { + vmType = VM_WARN; + } else if (!JLI_StrCCmp(tmpPtr, "IGNORE")) { + vmType = VM_IGNORE; + } else if (!JLI_StrCCmp(tmpPtr, "ERROR")) { + vmType = VM_ERROR; + } else if (!JLI_StrCCmp(tmpPtr, "IF_SERVER_CLASS")) { + tmpPtr += JLI_StrCSpn(tmpPtr, whiteSpace); + if (*tmpPtr != 0) { + tmpPtr += JLI_StrSpn(tmpPtr, whiteSpace); + } + if (*tmpPtr == 0) { + JLI_ReportErrorMessage(CFG_WARN4, lineno, jvmCfgName); + } else { + /* Null terminate server class VM name */ + serverClassVMName = tmpPtr; + tmpPtr += JLI_StrCSpn(tmpPtr, whiteSpace); + *tmpPtr = 0; + vmType = VM_IF_SERVER_CLASS; + } + } else { + JLI_ReportErrorMessage(CFG_WARN5, lineno, &jvmCfgName[0]); + vmType = VM_KNOWN; + } + } + } + + JLI_TraceLauncher("jvm.cfg[%d] = ->%s<-\n", cnt, line); + if (vmType != VM_UNKNOWN) { + knownVMs[cnt].name = JLI_StringDup(line); + knownVMs[cnt].flag = vmType; + switch (vmType) { + default: + break; + case VM_ALIASED_TO: + knownVMs[cnt].alias = JLI_StringDup(altVMName); + JLI_TraceLauncher(" name: %s vmType: %s alias: %s\n", + knownVMs[cnt].name, "VM_ALIASED_TO", knownVMs[cnt].alias); + break; + case VM_IF_SERVER_CLASS: + knownVMs[cnt].server_class = JLI_StringDup(serverClassVMName); + JLI_TraceLauncher(" name: %s vmType: %s server_class: %s\n", + knownVMs[cnt].name, "VM_IF_SERVER_CLASS", knownVMs[cnt].server_class); + break; + } + cnt++; + } + } + fclose(jvmCfg); + knownVMsCount = cnt; + + if (JLI_IsTraceLauncher()) { + end = CounterGet(); + printf("%ld micro seconds to parse jvm.cfg\n", + (long)(jint)Counter2Micros(end-start)); + } + + return cnt; +} + + +static void +GrowKnownVMs(int minimum) +{ + struct vmdesc* newKnownVMs; + int newMax; + + newMax = (knownVMsLimit == 0 ? INIT_MAX_KNOWN_VMS : (2 * knownVMsLimit)); + if (newMax <= minimum) { + newMax = minimum; + } + newKnownVMs = (struct vmdesc*) JLI_MemAlloc(newMax * sizeof(struct vmdesc)); + if (knownVMs != NULL) { + memcpy(newKnownVMs, knownVMs, knownVMsLimit * sizeof(struct vmdesc)); + } + JLI_MemFree(knownVMs); + knownVMs = newKnownVMs; + knownVMsLimit = newMax; +} + + +/* Returns index of VM or -1 if not found */ +static int +KnownVMIndex(const char* name) +{ + int i; + if (JLI_StrCCmp(name, "-J") == 0) name += 2; + for (i = 0; i < knownVMsCount; i++) { + if (!JLI_StrCmp(name, knownVMs[i].name)) { + return i; + } + } + return -1; +} + +static void +FreeKnownVMs() +{ + int i; + for (i = 0; i < knownVMsCount; i++) { + JLI_MemFree(knownVMs[i].name); + knownVMs[i].name = NULL; + } + JLI_MemFree(knownVMs); +} + +/* + * Displays the splash screen according to the jar file name + * and image file names stored in environment variables + */ +void +ShowSplashScreen() +{ + const char *jar_name = getenv(SPLASH_JAR_ENV_ENTRY); + const char *file_name = getenv(SPLASH_FILE_ENV_ENTRY); + int data_size; + void *image_data = NULL; + float scale_factor = 1; + char *scaled_splash_name = NULL; + + if (file_name == NULL){ + return; + } + + scaled_splash_name = DoSplashGetScaledImageName( + jar_name, file_name, &scale_factor); + if (jar_name) { + + if (scaled_splash_name) { + image_data = JLI_JarUnpackFile( + jar_name, scaled_splash_name, &data_size); + } + + if (!image_data) { + scale_factor = 1; + image_data = JLI_JarUnpackFile( + jar_name, file_name, &data_size); + } + if (image_data) { + DoSplashInit(); + DoSplashSetScaleFactor(scale_factor); + DoSplashLoadMemory(image_data, data_size); + JLI_MemFree(image_data); + } + } else { + DoSplashInit(); + if (scaled_splash_name) { + DoSplashSetScaleFactor(scale_factor); + DoSplashLoadFile(scaled_splash_name); + } else { + DoSplashLoadFile(file_name); + } + } + + if (scaled_splash_name) { + JLI_MemFree(scaled_splash_name); + } + + DoSplashSetFileJarName(file_name, jar_name); + + /* + * Done with all command line processing and potential re-execs so + * clean up the environment. + */ + (void)UnsetEnv(ENV_ENTRY); + (void)UnsetEnv(SPLASH_FILE_ENV_ENTRY); + (void)UnsetEnv(SPLASH_JAR_ENV_ENTRY); + + JLI_MemFree(splash_jar_entry); + JLI_MemFree(splash_file_entry); + +} + +const char* +GetDotVersion() +{ + return _dVersion; +} + +const char* +GetFullVersion() +{ + return _fVersion; +} + +const char* +GetProgramName() +{ + return _program_name; +} + +const char* +GetLauncherName() +{ + return _launcher_name; +} + +jint +GetErgoPolicy() +{ + return _ergo_policy; +} + +jboolean +IsJavaArgs() +{ + return _is_java_args; +} + +static jboolean +IsWildCardEnabled() +{ + return _wc_enabled; +} + +int +ContinueInNewThread(InvocationFunctions* ifn, jlong threadStackSize, + int argc, char **argv, + int mode, char *what, int ret) +{ + + /* + * If user doesn't specify stack size, check if VM has a preference. + * Note that HotSpot no longer supports JNI_VERSION_1_1 but it will + * return its default stack size through the init args structure. + */ + if (threadStackSize == 0) { + struct JDK1_1InitArgs args1_1; + memset((void*)&args1_1, 0, sizeof(args1_1)); + args1_1.version = JNI_VERSION_1_1; + ifn->GetDefaultJavaVMInitArgs(&args1_1); /* ignore return value */ + if (args1_1.javaStackSize > 0) { + threadStackSize = args1_1.javaStackSize; + } + } + + { /* Create a new thread to create JVM and invoke main method */ + JavaMainArgs args; + int rslt; + + args.argc = argc; + args.argv = argv; + args.mode = mode; + args.what = what; + args.ifn = *ifn; + + rslt = ContinueInNewThread0(JavaMain, threadStackSize, (void*)&args); + /* If the caller has deemed there is an error we + * simply return that, otherwise we return the value of + * the callee + */ + return (ret != 0) ? ret : rslt; + } +} + +static void +DumpState() +{ + if (!JLI_IsTraceLauncher()) return ; + printf("Launcher state:\n"); + printf("\tdebug:%s\n", (JLI_IsTraceLauncher() == JNI_TRUE) ? "on" : "off"); + printf("\tjavargs:%s\n", (_is_java_args == JNI_TRUE) ? "on" : "off"); + printf("\tprogram name:%s\n", GetProgramName()); + printf("\tlauncher name:%s\n", GetLauncherName()); + printf("\tjavaw:%s\n", (IsJavaw() == JNI_TRUE) ? "on" : "off"); + printf("\tfullversion:%s\n", GetFullVersion()); + printf("\tdotversion:%s\n", GetDotVersion()); + printf("\tergo_policy:"); + switch(GetErgoPolicy()) { + case NEVER_SERVER_CLASS: + printf("NEVER_ACT_AS_A_SERVER_CLASS_MACHINE\n"); + break; + case ALWAYS_SERVER_CLASS: + printf("ALWAYS_ACT_AS_A_SERVER_CLASS_MACHINE\n"); + break; + default: + printf("DEFAULT_ERGONOMICS_POLICY\n"); + } +} + +/* + * Return JNI_TRUE for an option string that has no effect but should + * _not_ be passed on to the vm; return JNI_FALSE otherwise. On + * Solaris SPARC, this screening needs to be done if: + * -d32 or -d64 is passed to a binary with an unmatched data model + * (the exec in CreateExecutionEnvironment removes -d options and points the + * exec to the proper binary). In the case of when the data model and the + * requested version is matched, an exec would not occur, and these options + * were erroneously passed to the vm. + */ +jboolean +RemovableOption(char * option) +{ + /* + * Unconditionally remove both -d32 and -d64 options since only + * the last such options has an effect; e.g. + * java -d32 -d64 -d32 -version + * is equivalent to + * java -d32 -version + */ + + if( (JLI_StrCCmp(option, "-d32") == 0 ) || + (JLI_StrCCmp(option, "-d64") == 0 ) ) + return JNI_TRUE; + else + return JNI_FALSE; +} + +/* + * A utility procedure to always print to stderr + */ +void +JLI_ReportMessage(const char* fmt, ...) +{ + va_list vl; + va_start(vl, fmt); + vfprintf(stderr, fmt, vl); + fprintf(stderr, "\n"); + va_end(vl); +} diff --git a/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/java.h b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/java.h new file mode 100644 index 0000000..1f9f300 --- /dev/null +++ b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/java.h @@ -0,0 +1,309 @@ +/* + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +#ifndef _JAVA_H_ +#define _JAVA_H_ + +#include +#include +#include +#include + +#include +#include + +/* + * Get system specific defines. + */ +#include "emessages.h" +#include "java_md.h" +#include "jli_util.h" + +#include "manifest_info.h" +#include "version_comp.h" +#include "wildcard.h" +#include "splashscreen.h" + +# define KB (1024UL) +# define MB (1024UL * KB) +# define GB (1024UL * MB) + +#define CURRENT_DATA_MODEL (CHAR_BIT * sizeof(void*)) + +/* + * The following environment variable is used to influence the behavior + * of the jre exec'd through the SelectVersion routine. The command line + * options which specify the version are not passed to the exec'd version, + * because that jre may be an older version which wouldn't recognize them. + * This environment variable is known to this (and later) version and serves + * to suppress the version selection code. This is not only for efficiency, + * but also for correctness, since any command line options have been + * removed which would cause any value found in the manifest to be used. + * This would be incorrect because the command line options are defined + * to take precedence. + * + * The value associated with this environment variable is the MainClass + * name from within the executable jar file (if any). This is strictly a + * performance enhancement to avoid re-reading the jar file manifest. + * + */ +#define ENV_ENTRY "_JAVA_VERSION_SET" + +#define SPLASH_FILE_ENV_ENTRY "_JAVA_SPLASH_FILE" +#define SPLASH_JAR_ENV_ENTRY "_JAVA_SPLASH_JAR" + +/* + * Pointers to the needed JNI invocation API, initialized by LoadJavaVM. + */ +typedef jint (JNICALL *CreateJavaVM_t)(JavaVM **pvm, void **env, void *args); +typedef jint (JNICALL *GetDefaultJavaVMInitArgs_t)(void *args); +typedef jint (JNICALL *GetCreatedJavaVMs_t)(JavaVM **vmBuf, jsize bufLen, jsize *nVMs); + +typedef struct { + CreateJavaVM_t CreateJavaVM; + GetDefaultJavaVMInitArgs_t GetDefaultJavaVMInitArgs; + GetCreatedJavaVMs_t GetCreatedJavaVMs; +} InvocationFunctions; + +int +JLI_Launch(int argc, char ** argv, /* main argc, argc */ + int jargc, const char** jargv, /* java args */ + int appclassc, const char** appclassv, /* app classpath */ + const char* fullversion, /* full version defined */ + const char* dotversion, /* dot version defined */ + const char* pname, /* program name */ + const char* lname, /* launcher name */ + jboolean javaargs, /* JAVA_ARGS */ + jboolean cpwildcard, /* classpath wildcard */ + jboolean javaw, /* windows-only javaw */ + jint ergo_class /* ergnomics policy */ +); + +/* + * Prototypes for launcher functions in the system specific java_md.c. + */ + +jboolean +LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn); + +void +GetXUsagePath(char *buf, jint bufsize); + +jboolean +GetApplicationHome(char *buf, jint bufsize); + +#define GetArch() GetArchPath(CURRENT_DATA_MODEL) + +/* + * Different platforms will implement this, here + * pargc is a pointer to the original argc, + * pargv is a pointer to the original argv, + * jrepath is an accessible path to the jre as determined by the call + * so_jrepath is the length of the buffer jrepath + * jvmpath is an accessible path to the jvm as determined by the call + * so_jvmpath is the length of the buffer jvmpath + */ +void CreateExecutionEnvironment(int *argc, char ***argv, + char *jrepath, jint so_jrepath, + char *jvmpath, jint so_jvmpath, + char *jvmcfg, jint so_jvmcfg); + +/* Reports an error message to stderr or a window as appropriate. */ +void JLI_ReportErrorMessage(const char * message, ...); + +/* Reports a system error message to stderr or a window */ +void JLI_ReportErrorMessageSys(const char * message, ...); + +/* Reports an error message only to stderr. */ +void JLI_ReportMessage(const char * message, ...); + +/* + * Reports an exception which terminates the vm to stderr or a window + * as appropriate. + */ +void JLI_ReportExceptionDescription(JNIEnv * env); +void PrintMachineDependentOptions(); + +const char *jlong_format_specifier(); + +/* + * Block current thread and continue execution in new thread + */ +int ContinueInNewThread0(int (JNICALL *continuation)(void *), + jlong stack_size, void * args); + +/* sun.java.launcher.* platform properties. */ +void SetJavaLauncherPlatformProps(void); +void SetJavaCommandLineProp(char* what, int argc, char** argv); +void SetJavaLauncherProp(void); + +/* + * Functions defined in java.c and used in java_md.c. + */ +jint ReadKnownVMs(const char *jvmcfg, jboolean speculative); +char *CheckJvmType(int *argc, char ***argv, jboolean speculative); +void AddOption(char *str, void *info); + +enum ergo_policy { + DEFAULT_POLICY = 0, + NEVER_SERVER_CLASS, + ALWAYS_SERVER_CLASS +}; + +const char* GetProgramName(); +const char* GetDotVersion(); +const char* GetFullVersion(); +jboolean IsJavaArgs(); +jboolean IsJavaw(); +jint GetErgoPolicy(); + +jboolean ServerClassMachine(); + +int ContinueInNewThread(InvocationFunctions* ifn, jlong threadStackSize, + int argc, char** argv, + int mode, char *what, int ret); + +int JVMInit(InvocationFunctions* ifn, jlong threadStackSize, + int argc, char** argv, + int mode, char *what, int ret); + +/* + * Initialize platform specific settings + */ +void InitLauncher(jboolean javaw); + +/* + * For MacOSX and Windows/Unix compatibility we require these + * entry points, some of them may be stubbed out on Windows/Unixes. + */ +void PostJVMInit(JNIEnv *env, jstring mainClass, JavaVM *vm); +void ShowSplashScreen(); +void RegisterThread(); +/* + * this method performs additional platform specific processing and + * should return JNI_TRUE to indicate the argument has been consumed, + * otherwise returns JNI_FALSE to allow the calling logic to further + * process the option. + */ +jboolean ProcessPlatformOption(const char *arg); + +/* + * This allows for finding classes from the VM's bootstrap class loader directly, + * FindClass uses the application class loader internally, this will cause + * unnecessary searching of the classpath for the required classes. + * + */ +typedef jclass (JNICALL FindClassFromBootLoader_t(JNIEnv *env, + const char *name)); +jclass FindBootStrapClass(JNIEnv *env, const char *classname); + +jobjectArray CreateApplicationArgs(JNIEnv *env, char **strv, int argc); +jobjectArray NewPlatformStringArray(JNIEnv *env, char **strv, int strc); +jclass GetLauncherHelperClass(JNIEnv *env); + +int JNICALL JavaMain(void * args); /* entry point */ + +enum LaunchMode { // cf. sun.launcher.LauncherHelper + LM_UNKNOWN = 0, + LM_CLASS, + LM_JAR +}; + +static const char *launchModeNames[] + = { "Unknown", "Main class", "JAR file" }; + +typedef struct { + int argc; + char **argv; + int mode; + char *what; + InvocationFunctions ifn; +} JavaMainArgs; + +#define NULL_CHECK_RETURN_VALUE(NCRV_check_pointer, NCRV_return_value) \ + do { \ + if ((NCRV_check_pointer) == NULL) { \ + JLI_ReportErrorMessage(JNI_ERROR); \ + return NCRV_return_value; \ + } \ + } while (JNI_FALSE) + +#define NULL_CHECK0(NC0_check_pointer) \ + NULL_CHECK_RETURN_VALUE(NC0_check_pointer, 0) + +#define NULL_CHECK(NC_check_pointer) \ + NULL_CHECK_RETURN_VALUE(NC_check_pointer, ) + +#define CHECK_EXCEPTION_RETURN() \ + do { \ + if ((*env)->ExceptionOccurred(env)) { \ + return; \ + } \ + } while (JNI_FALSE) + +/* + * For JNI calls : + * - check for thrown exceptions + * - check for null return + * + * JNI calls can return null and/or throw an exception. Check for these. + * + * : CHECK_JNI_RETURN_EXCEPTION() + * return the specified RETURNVALUE if exception was generated + * : CHECK_JNI_RETURN_0(JNISTATEMENT) : check if JNISTATEMENT was successful, return 0 if not + * : CHECK_JNI_RETURN_VOID(JNISTATEMENT) : check if JNISTATEMENT was successful, return void if not + * : CHECK_JNI_RETURN_VALUE(JNISTATEMENT,n) : check if JNISTATEMENT was successful, return n if not + * + * These macros need at least one parameter, the JNI statement [ JNISTATEMENT ]. + * + * E.G.: check the JNI statement, and specify a value to return if a failure was detected. + * + * CHECK_JNI_RETURN_VALUE(str = (*env)->CallStaticObjectMethod(env, cls, + * makePlatformStringMID, USE_STDERR, ary), -1); + */ + +#define RETURNVOID return +#define RETURN0 return 0 +#define RETURN(N) return (N) + +#define CHECK_JNI_RETURN_EXCEPTION(RETURNVALUE) \ + if ((((*env)->ExceptionOccurred(env))!=NULL)) { \ + RETURNVALUE; \ + } + +#define CHECK_JNI_RETURN_0(JNISTATEMENT) \ + CHECK_JNI_RETURN_EXCEPTION(RETURN0); \ + NULL_CHECK0(JNISTATEMENT); + +#define CHECK_JNI_RETURN_VOID(JNISTATEMENT) \ + CHECK_JNI_RETURN_EXCEPTION(RETURNVOID); \ + NULL_CHECK(JNISTATEMENT); + +#define CHECK_JNI_RETURN_VALUE(JNISTATEMENT, NCRV_return_value) \ + CHECK_JNI_RETURN_EXCEPTION(RETURN(NCRV_return_value)); \ + NULL_CHECK_RETURN_VALUE(JNISTATEMENT, NCRV_return_value); + + +#endif /* _JAVA_H_ */ diff --git a/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/java_md.c b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/java_md.c new file mode 100644 index 0000000..2c8a4ac --- /dev/null +++ b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/java_md.c @@ -0,0 +1,1521 @@ +/* + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "java.h" +#include "version_comp.h" + +#define JVM_DLL "jvm.dll" +#define JAVA_DLL "java.dll" + +/* + * Prototypes. + */ +static jboolean GetPublicJREHome(char *path, jint pathsize); +static jboolean GetJVMPath(const char *jrepath, const char *jvmtype, + char *jvmpath, jint jvmpathsize); +static jboolean GetJREPath(char *path, jint pathsize); + +/* We supports warmup for UI stack that is performed in parallel + * to VM initialization. + * This helps to improve startup of UI application as warmup phase + * might be long due to initialization of OS or hardware resources. + * It is not CPU bound and therefore it does not interfere with VM init. + * Obviously such warmup only has sense for UI apps and therefore it needs + * to be explicitly requested by passing -Dsun.awt.warmup=true property + * (this is always the case for plugin/javaws). + * + * Implementation launches new thread after VM starts and use it to perform + * warmup code (platform dependent). + * This thread is later reused as AWT toolkit thread as graphics toolkit + * often assume that they are used from the same thread they were launched on. + * + * At the moment we only support warmup for D3D. It only possible on windows + * and only if other flags do not prohibit this (e.g. OpenGL support requested). + */ +#undef ENABLE_AWT_PRELOAD +#ifndef JAVA_ARGS /* turn off AWT preloading for javac, jar, etc */ + /* CR6999872: fastdebug crashes if awt library is loaded before JVM is + * initialized*/ + #if !defined(DEBUG) + #define ENABLE_AWT_PRELOAD + #endif +#endif + +#ifdef ENABLE_AWT_PRELOAD +/* "AWT was preloaded" flag; + * turned on by AWTPreload(). + */ +int awtPreloaded = 0; + +/* Calls a function with the name specified + * the function must be int(*fn)(void). + */ +int AWTPreload(const char *funcName); +/* stops AWT preloading */ +void AWTPreloadStop(); + +/* D3D preloading */ +/* -1: not initialized; 0: OFF, 1: ON */ +int awtPreloadD3D = -1; +/* command line parameter to swith D3D preloading on */ +#define PARAM_PRELOAD_D3D "-Dsun.awt.warmup" +/* D3D/OpenGL management parameters */ +#define PARAM_NODDRAW "-Dsun.java2d.noddraw" +#define PARAM_D3D "-Dsun.java2d.d3d" +#define PARAM_OPENGL "-Dsun.java2d.opengl" +/* funtion in awt.dll (src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp) */ +#define D3D_PRELOAD_FUNC "preloadD3D" + +/* Extracts value of a parameter with the specified name + * from command line argument (returns pointer in the argument). + * Returns NULL if the argument does not contains the parameter. + * e.g.: + * GetParamValue("theParam", "theParam=value") returns pointer to "value". + */ +const char * GetParamValue(const char *paramName, const char *arg) { + int nameLen = JLI_StrLen(paramName); + if (JLI_StrNCmp(paramName, arg, nameLen) == 0) { + /* arg[nameLen] is valid (may contain final NULL) */ + if (arg[nameLen] == '=') { + return arg + nameLen + 1; + } + } + return NULL; +} + +/* Checks if commandline argument contains property specified + * and analyze it as boolean property (true/false). + * Returns -1 if the argument does not contain the parameter; + * Returns 1 if the argument contains the parameter and its value is "true"; + * Returns 0 if the argument contains the parameter and its value is "false". + */ +int GetBoolParamValue(const char *paramName, const char *arg) { + const char * paramValue = GetParamValue(paramName, arg); + if (paramValue != NULL) { + if (JLI_StrCaseCmp(paramValue, "true") == 0) { + return 1; + } + if (JLI_StrCaseCmp(paramValue, "false") == 0) { + return 0; + } + } + return -1; +} +#endif /* ENABLE_AWT_PRELOAD */ + + +static jboolean _isjavaw = JNI_FALSE; + + +jboolean +IsJavaw() +{ + return _isjavaw; +} + +/* + * Returns the arch path, to get the current arch use the + * macro GetArch, nbits here is ignored for now. + */ +const char * +GetArchPath(int nbits) +{ +#ifdef _M_AMD64 + return "amd64"; +#elif defined(_M_IA64) + return "ia64"; +#else + return "i386"; +#endif +} + +/* + * + */ +void +CreateExecutionEnvironment(int *pargc, char ***pargv, + char *jrepath, jint so_jrepath, + char *jvmpath, jint so_jvmpath, + char *jvmcfg, jint so_jvmcfg) { + char * jvmtype; + int i = 0; + int running = CURRENT_DATA_MODEL; + + int wanted = running; + + char** argv = *pargv; + for (i = 1; i < *pargc ; i++) { + if (JLI_StrCmp(argv[i], "-J-d64") == 0 || JLI_StrCmp(argv[i], "-d64") == 0) { + wanted = 64; + continue; + } + if (JLI_StrCmp(argv[i], "-J-d32") == 0 || JLI_StrCmp(argv[i], "-d32") == 0) { + wanted = 32; + continue; + } + + if (IsJavaArgs() && argv[i][0] != '-') + continue; + if (argv[i][0] != '-') + break; + } + if (running != wanted) { + JLI_ReportErrorMessage(JRE_ERROR2, wanted); + exit(1); + } + + /* Find out where the JRE is that we will be using. */ + if (!GetJREPath(jrepath, so_jrepath)) { + JLI_ReportErrorMessage(JRE_ERROR1); + exit(2); + } + + JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%s%s%sjvm.cfg", + jrepath, FILESEP, FILESEP, (char*)GetArch(), FILESEP); + + /* Find the specified JVM type */ + if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) { + JLI_ReportErrorMessage(CFG_ERROR7); + exit(1); + } + + jvmtype = CheckJvmType(pargc, pargv, JNI_FALSE); + if (JLI_StrCmp(jvmtype, "ERROR") == 0) { + JLI_ReportErrorMessage(CFG_ERROR9); + exit(4); + } + + jvmpath[0] = '\0'; + if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath)) { + JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath); + exit(4); + } + /* If we got here, jvmpath has been correctly initialized. */ + + /* Check if we need preload AWT */ +#ifdef ENABLE_AWT_PRELOAD + argv = *pargv; + for (i = 0; i < *pargc ; i++) { + /* Tests the "turn on" parameter only if not set yet. */ + if (awtPreloadD3D < 0) { + if (GetBoolParamValue(PARAM_PRELOAD_D3D, argv[i]) == 1) { + awtPreloadD3D = 1; + } + } + /* Test parameters which can disable preloading if not already disabled. */ + if (awtPreloadD3D != 0) { + if (GetBoolParamValue(PARAM_NODDRAW, argv[i]) == 1 + || GetBoolParamValue(PARAM_D3D, argv[i]) == 0 + || GetBoolParamValue(PARAM_OPENGL, argv[i]) == 1) + { + awtPreloadD3D = 0; + /* no need to test the rest of the parameters */ + break; + } + } + } +#endif /* ENABLE_AWT_PRELOAD */ +} + + +static jboolean +LoadMSVCRT() +{ + // Only do this once + static int loaded = 0; + char crtpath[MAXPATHLEN]; + + if (!loaded) { + /* + * The Microsoft C Runtime Library needs to be loaded first. A copy is + * assumed to be present in the "JRE path" directory. If it is not found + * there (or "JRE path" fails to resolve), skip the explicit load and let + * nature take its course, which is likely to be a failure to execute. + * This is clearly completely specific to the exact compiler version + * which isn't very nice, but its hardly the only place. + * No attempt to look for compiler versions in between 2003 and 2010 + * as we aren't supporting building with those. + */ +#ifdef _MSC_VER +#if _MSC_VER < 1400 +#define CRT_DLL "msvcr71.dll" +#endif +#if _MSC_VER >= 1600 +#define CRT_DLL "msvcr100.dll" +#endif +#ifdef CRT_DLL + if (GetJREPath(crtpath, MAXPATHLEN)) { + if (JLI_StrLen(crtpath) + JLI_StrLen("\\bin\\") + + JLI_StrLen(CRT_DLL) >= MAXPATHLEN) { + JLI_ReportErrorMessage(JRE_ERROR11); + return JNI_FALSE; + } + (void)JLI_StrCat(crtpath, "\\bin\\" CRT_DLL); /* Add crt dll */ + JLI_TraceLauncher("CRT path is %s\n", crtpath); + if (_access(crtpath, 0) == 0) { + if (LoadLibrary(crtpath) == 0) { + JLI_ReportErrorMessage(DLL_ERROR4, crtpath); + return JNI_FALSE; + } + } + } +#endif /* CRT_DLL */ +#endif /* _MSC_VER */ + loaded = 1; + } + return JNI_TRUE; +} + + +/* + * Find path to JRE based on .exe's location or registry settings. + */ +jboolean +GetJREPath(char *path, jint pathsize) +{ + char javadll[MAXPATHLEN]; + struct stat s; + + if (GetApplicationHome(path, pathsize)) { + /* Is JRE co-located with the application? */ + JLI_Snprintf(javadll, sizeof(javadll), "%s\\bin\\" JAVA_DLL, path); + if (stat(javadll, &s) == 0) { + JLI_TraceLauncher("JRE path is %s\n", path); + return JNI_TRUE; + } + /* ensure storage for path + \jre + NULL */ + if ((JLI_StrLen(path) + 4 + 1) > pathsize) { + JLI_TraceLauncher("Insufficient space to store JRE path\n"); + return JNI_FALSE; + } + /* Does this app ship a private JRE in \jre directory? */ + JLI_Snprintf(javadll, sizeof (javadll), "%s\\jre\\bin\\" JAVA_DLL, path); + if (stat(javadll, &s) == 0) { + JLI_StrCat(path, "\\jre"); + JLI_TraceLauncher("JRE path is %s\n", path); + return JNI_TRUE; + } + } + + /* Look for a public JRE on this machine. */ + if (GetPublicJREHome(path, pathsize)) { + JLI_TraceLauncher("JRE path is %s\n", path); + return JNI_TRUE; + } + + JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL); + return JNI_FALSE; + +} + +/* + * Given a JRE location and a JVM type, construct what the name the + * JVM shared library will be. Return true, if such a library + * exists, false otherwise. + */ +static jboolean +GetJVMPath(const char *jrepath, const char *jvmtype, + char *jvmpath, jint jvmpathsize) +{ + struct stat s; + if (JLI_StrChr(jvmtype, '/') || JLI_StrChr(jvmtype, '\\')) { + JLI_Snprintf(jvmpath, jvmpathsize, "%s\\" JVM_DLL, jvmtype); + } else { + JLI_Snprintf(jvmpath, jvmpathsize, "%s\\bin\\%s\\" JVM_DLL, + jrepath, jvmtype); + } + if (stat(jvmpath, &s) == 0) { + return JNI_TRUE; + } else { + return JNI_FALSE; + } +} + +/* + * Load a jvm from "jvmpath" and initialize the invocation functions. + */ +jboolean +LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) +{ + HINSTANCE handle; + + JLI_TraceLauncher("JVM path is %s\n", jvmpath); + + /* + * The Microsoft C Runtime Library needs to be loaded first. A copy is + * assumed to be present in the "JRE path" directory. If it is not found + * there (or "JRE path" fails to resolve), skip the explicit load and let + * nature take its course, which is likely to be a failure to execute. + * + */ + LoadMSVCRT(); + + /* Load the Java VM DLL */ + if ((handle = LoadLibrary(jvmpath)) == 0) { + JLI_ReportErrorMessage(DLL_ERROR4, (char *)jvmpath); + return JNI_FALSE; + } + + /* Now get the function addresses */ + ifn->CreateJavaVM = + (void *)GetProcAddress(handle, "JNI_CreateJavaVM"); + ifn->GetDefaultJavaVMInitArgs = + (void *)GetProcAddress(handle, "JNI_GetDefaultJavaVMInitArgs"); + if (ifn->CreateJavaVM == 0 || ifn->GetDefaultJavaVMInitArgs == 0) { + JLI_ReportErrorMessage(JNI_ERROR1, (char *)jvmpath); + return JNI_FALSE; + } + + return JNI_TRUE; +} + +/* + * If app is "c:\foo\bin\javac", then put "c:\foo" into buf. + */ +jboolean +GetApplicationHome(char *buf, jint bufsize) +{ + char *cp; + GetModuleFileName(0, buf, bufsize); + *JLI_StrRChr(buf, '\\') = '\0'; /* remove .exe file name */ + if ((cp = JLI_StrRChr(buf, '\\')) == 0) { + /* This happens if the application is in a drive root, and + * there is no bin directory. */ + buf[0] = '\0'; + return JNI_FALSE; + } + *cp = '\0'; /* remove the bin\ part */ + return JNI_TRUE; +} + +/* + * Helpers to look in the registry for a public JRE. + */ + /* Same for 1.5.0, 1.5.1, 1.5.2 etc. */ +#define JRE_KEY "Software\\JavaSoft\\Java Runtime Environment" + +static jboolean +GetStringFromRegistry(HKEY key, const char *name, char *buf, jint bufsize) +{ + DWORD type, size; + + if (RegQueryValueEx(key, name, 0, &type, 0, &size) == 0 + && type == REG_SZ + && (size < (unsigned int)bufsize)) { + if (RegQueryValueEx(key, name, 0, 0, buf, &size) == 0) { + return JNI_TRUE; + } + } + return JNI_FALSE; +} + +static jboolean +GetPublicJREHome(char *buf, jint bufsize) +{ + HKEY key, subkey; + char version[MAXPATHLEN]; + + /* + * Note: There is a very similar implementation of the following + * registry reading code in the Windows java control panel (javacp.cpl). + * If there are bugs here, a similar bug probably exists there. Hence, + * changes here require inspection there. + */ + + /* Find the current version of the JRE */ + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, JRE_KEY, 0, KEY_READ, &key) != 0) { + JLI_ReportErrorMessage(REG_ERROR1, JRE_KEY); + return JNI_FALSE; + } + + if (!GetStringFromRegistry(key, "CurrentVersion", + version, sizeof(version))) { + JLI_ReportErrorMessage(REG_ERROR2, JRE_KEY); + RegCloseKey(key); + return JNI_FALSE; + } + + if (JLI_StrCmp(version, GetDotVersion()) != 0) { + JLI_ReportErrorMessage(REG_ERROR3, JRE_KEY, version, GetDotVersion() + ); + RegCloseKey(key); + return JNI_FALSE; + } + + /* Find directory where the current version is installed. */ + if (RegOpenKeyEx(key, version, 0, KEY_READ, &subkey) != 0) { + JLI_ReportErrorMessage(REG_ERROR1, JRE_KEY, version); + RegCloseKey(key); + return JNI_FALSE; + } + + if (!GetStringFromRegistry(subkey, "JavaHome", buf, bufsize)) { + JLI_ReportErrorMessage(REG_ERROR4, JRE_KEY, version); + RegCloseKey(key); + RegCloseKey(subkey); + return JNI_FALSE; + } + + if (JLI_IsTraceLauncher()) { + char micro[MAXPATHLEN]; + if (!GetStringFromRegistry(subkey, "MicroVersion", micro, + sizeof(micro))) { + printf("Warning: Can't read MicroVersion\n"); + micro[0] = '\0'; + } + printf("Version major.minor.micro = %s.%s\n", version, micro); + } + + RegCloseKey(key); + RegCloseKey(subkey); + return JNI_TRUE; +} + +/* + * Support for doing cheap, accurate interval timing. + */ +static jboolean counterAvailable = JNI_FALSE; +static jboolean counterInitialized = JNI_FALSE; +static LARGE_INTEGER counterFrequency; + +jlong CounterGet() +{ + LARGE_INTEGER count; + + if (!counterInitialized) { + counterAvailable = QueryPerformanceFrequency(&counterFrequency); + counterInitialized = JNI_TRUE; + } + if (!counterAvailable) { + return 0; + } + QueryPerformanceCounter(&count); + return (jlong)(count.QuadPart); +} + +jlong Counter2Micros(jlong counts) +{ + if (!counterAvailable || !counterInitialized) { + return 0; + } + return (counts * 1000 * 1000)/counterFrequency.QuadPart; +} +/* + * windows snprintf does not guarantee a null terminator in the buffer, + * if the computed size is equal to or greater than the buffer size, + * as well as error conditions. This function guarantees a null terminator + * under all these conditions. An unreasonable buffer or size will return + * an error value. Under all other conditions this function will return the + * size of the bytes actually written minus the null terminator, similar + * to ansi snprintf api. Thus when calling this function the caller must + * ensure storage for the null terminator. + */ +int +JLI_Snprintf(char* buffer, size_t size, const char* format, ...) { + int rc; + va_list vl; + if (size == 0 || buffer == NULL) + return -1; + buffer[0] = '\0'; + va_start(vl, format); + rc = vsnprintf(buffer, size, format, vl); + va_end(vl); + /* force a null terminator, if something is amiss */ + if (rc < 0) { + /* apply ansi semantics */ + buffer[size - 1] = '\0'; + return size; + } else if (rc == size) { + /* force a null terminator */ + buffer[size - 1] = '\0'; + } + return rc; +} + +void +JLI_ReportErrorMessage(const char* fmt, ...) { + va_list vl; + va_start(vl,fmt); + + if (IsJavaw()) { + char *message; + + /* get the length of the string we need */ + int n = _vscprintf(fmt, vl); + + message = (char *)JLI_MemAlloc(n + 1); + _vsnprintf(message, n, fmt, vl); + message[n]='\0'; + MessageBox(NULL, message, "Java Virtual Machine Launcher", + (MB_OK|MB_ICONSTOP|MB_APPLMODAL)); + JLI_MemFree(message); + } else { + vfprintf(stderr, fmt, vl); + fprintf(stderr, "\n"); + } + va_end(vl); +} + +/* + * Just like JLI_ReportErrorMessage, except that it concatenates the system + * error message if any, its upto the calling routine to correctly + * format the separation of the messages. + */ +void +JLI_ReportErrorMessageSys(const char *fmt, ...) +{ + va_list vl; + + int save_errno = errno; + DWORD errval; + jboolean freeit = JNI_FALSE; + char *errtext = NULL; + + va_start(vl, fmt); + + if ((errval = GetLastError()) != 0) { /* Platform SDK / DOS Error */ + int n = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM| + FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, errval, 0, (LPTSTR)&errtext, 0, NULL); + if (errtext == NULL || n == 0) { /* Paranoia check */ + errtext = ""; + n = 0; + } else { + freeit = JNI_TRUE; + if (n > 2) { /* Drop final CR, LF */ + if (errtext[n - 1] == '\n') n--; + if (errtext[n - 1] == '\r') n--; + errtext[n] = '\0'; + } + } + } else { /* C runtime error that has no corresponding DOS error code */ + errtext = strerror(save_errno); + } + + if (IsJavaw()) { + char *message; + int mlen; + /* get the length of the string we need */ + int len = mlen = _vscprintf(fmt, vl) + 1; + if (freeit) { + mlen += (int)JLI_StrLen(errtext); + } + + message = (char *)JLI_MemAlloc(mlen); + _vsnprintf(message, len, fmt, vl); + message[len]='\0'; + + if (freeit) { + JLI_StrCat(message, errtext); + } + + MessageBox(NULL, message, "Java Virtual Machine Launcher", + (MB_OK|MB_ICONSTOP|MB_APPLMODAL)); + + JLI_MemFree(message); + } else { + vfprintf(stderr, fmt, vl); + if (freeit) { + fprintf(stderr, "%s", errtext); + } + } + if (freeit) { + (void)LocalFree((HLOCAL)errtext); + } + va_end(vl); +} + +void JLI_ReportExceptionDescription(JNIEnv * env) { + if (IsJavaw()) { + /* + * This code should be replaced by code which opens a window with + * the exception detail message, for now atleast put a dialog up. + */ + MessageBox(NULL, "A Java Exception has occurred.", "Java Virtual Machine Launcher", + (MB_OK|MB_ICONSTOP|MB_APPLMODAL)); + } else { + (*env)->ExceptionDescribe(env); + } +} + +jboolean +ServerClassMachine() { + return (GetErgoPolicy() == ALWAYS_SERVER_CLASS) ? JNI_TRUE : JNI_FALSE; +} + +/* + * Determine if there is an acceptable JRE in the registry directory top_key. + * Upon locating the "best" one, return a fully qualified path to it. + * "Best" is defined as the most advanced JRE meeting the constraints + * contained in the manifest_info. If no JRE in this directory meets the + * constraints, return NULL. + * + * It doesn't matter if we get an error reading the registry, or we just + * don't find anything interesting in the directory. We just return NULL + * in either case. + */ +static char * +ProcessDir(manifest_info* info, HKEY top_key) { + DWORD index = 0; + HKEY ver_key; + char name[MAXNAMELEN]; + int len; + char *best = NULL; + + /* + * Enumerate "/SOFTWARE/JavaSoft/Java Runtime Environment" + * searching for the best available version. + */ + while (RegEnumKey(top_key, index, name, MAXNAMELEN) == ERROR_SUCCESS) { + index++; + if (JLI_AcceptableRelease(name, info->jre_version)) + if ((best == NULL) || (JLI_ExactVersionId(name, best) > 0)) { + if (best != NULL) + JLI_MemFree(best); + best = JLI_StringDup(name); + } + } + + /* + * Extract "JavaHome" from the "best" registry directory and return + * that path. If no appropriate version was located, or there is an + * error in extracting the "JavaHome" string, return null. + */ + if (best == NULL) + return (NULL); + else { + if (RegOpenKeyEx(top_key, best, 0, KEY_READ, &ver_key) + != ERROR_SUCCESS) { + JLI_MemFree(best); + if (ver_key != NULL) + RegCloseKey(ver_key); + return (NULL); + } + JLI_MemFree(best); + len = MAXNAMELEN; + if (RegQueryValueEx(ver_key, "JavaHome", NULL, NULL, (LPBYTE)name, &len) + != ERROR_SUCCESS) { + if (ver_key != NULL) + RegCloseKey(ver_key); + return (NULL); + } + if (ver_key != NULL) + RegCloseKey(ver_key); + return (JLI_StringDup(name)); + } +} + +/* + * This is the global entry point. It examines the host for the optimal + * JRE to be used by scanning a set of registry entries. This set of entries + * is hardwired on Windows as "Software\JavaSoft\Java Runtime Environment" + * under the set of roots "{ HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE }". + * + * This routine simply opens each of these registry directories before passing + * control onto ProcessDir(). + */ +char * +LocateJRE(manifest_info* info) { + HKEY key = NULL; + char *path; + int key_index; + HKEY root_keys[2] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE }; + + for (key_index = 0; key_index <= 1; key_index++) { + if (RegOpenKeyEx(root_keys[key_index], JRE_KEY, 0, KEY_READ, &key) + == ERROR_SUCCESS) + if ((path = ProcessDir(info, key)) != NULL) { + if (key != NULL) + RegCloseKey(key); + return (path); + } + if (key != NULL) + RegCloseKey(key); + } + return NULL; +} + +/* + * Local helper routine to isolate a single token (option or argument) + * from the command line. + * + * This routine accepts a pointer to a character pointer. The first + * token (as defined by MSDN command-line argument syntax) is isolated + * from that string. + * + * Upon return, the input character pointer pointed to by the parameter s + * is updated to point to the remainding, unscanned, portion of the string, + * or to a null character if the entire string has been consummed. + * + * This function returns a pointer to a null-terminated string which + * contains the isolated first token, or to the null character if no + * token could be isolated. + * + * Note the side effect of modifying the input string s by the insertion + * of a null character, making it two strings. + * + * See "Parsing C Command-Line Arguments" in the MSDN Library for the + * parsing rule details. The rule summary from that specification is: + * + * * Arguments are delimited by white space, which is either a space or a tab. + * + * * A string surrounded by double quotation marks is interpreted as a single + * argument, regardless of white space contained within. A quoted string can + * be embedded in an argument. Note that the caret (^) is not recognized as + * an escape character or delimiter. + * + * * A double quotation mark preceded by a backslash, \", is interpreted as a + * literal double quotation mark ("). + * + * * Backslashes are interpreted literally, unless they immediately precede a + * double quotation mark. + * + * * If an even number of backslashes is followed by a double quotation mark, + * then one backslash (\) is placed in the argv array for every pair of + * backslashes (\\), and the double quotation mark (") is interpreted as a + * string delimiter. + * + * * If an odd number of backslashes is followed by a double quotation mark, + * then one backslash (\) is placed in the argv array for every pair of + * backslashes (\\) and the double quotation mark is interpreted as an + * escape sequence by the remaining backslash, causing a literal double + * quotation mark (") to be placed in argv. + */ +static char* +nextarg(char** s) { + char *p = *s; + char *head; + int slashes = 0; + int inquote = 0; + + /* + * Strip leading whitespace, which MSDN defines as only space or tab. + * (Hence, no locale specific "isspace" here.) + */ + while (*p != (char)0 && (*p == ' ' || *p == '\t')) + p++; + head = p; /* Save the start of the token to return */ + + /* + * Isolate a token from the command line. + */ + while (*p != (char)0 && (inquote || !(*p == ' ' || *p == '\t'))) { + if (*p == '\\' && *(p+1) == '"' && slashes % 2 == 0) + p++; + else if (*p == '"') + inquote = !inquote; + slashes = (*p++ == '\\') ? slashes + 1 : 0; + } + + /* + * If the token isolated isn't already terminated in a "char zero", + * then replace the whitespace character with one and move to the + * next character. + */ + if (*p != (char)0) + *p++ = (char)0; + + /* + * Update the parameter to point to the head of the remaining string + * reflecting the command line and return a pointer to the leading + * token which was isolated from the command line. + */ + *s = p; + return (head); +} + +/* + * Local helper routine to return a string equivalent to the input string + * s, but with quotes removed so the result is a string as would be found + * in argv[]. The returned string should be freed by a call to JLI_MemFree(). + * + * The rules for quoting (and escaped quotes) are: + * + * 1 A double quotation mark preceded by a backslash, \", is interpreted as a + * literal double quotation mark ("). + * + * 2 Backslashes are interpreted literally, unless they immediately precede a + * double quotation mark. + * + * 3 If an even number of backslashes is followed by a double quotation mark, + * then one backslash (\) is placed in the argv array for every pair of + * backslashes (\\), and the double quotation mark (") is interpreted as a + * string delimiter. + * + * 4 If an odd number of backslashes is followed by a double quotation mark, + * then one backslash (\) is placed in the argv array for every pair of + * backslashes (\\) and the double quotation mark is interpreted as an + * escape sequence by the remaining backslash, causing a literal double + * quotation mark (") to be placed in argv. + */ +static char* +unquote(const char *s) { + const char *p = s; /* Pointer to the tail of the original string */ + char *un = (char*)JLI_MemAlloc(JLI_StrLen(s) + 1); /* Ptr to unquoted string */ + char *pun = un; /* Pointer to the tail of the unquoted string */ + + while (*p != '\0') { + if (*p == '"') { + p++; + } else if (*p == '\\') { + const char *q = p + JLI_StrSpn(p,"\\"); + if (*q == '"') + do { + *pun++ = '\\'; + p += 2; + } while (*p == '\\' && p < q); + else + while (p < q) + *pun++ = *p++; + } else { + *pun++ = *p++; + } + } + *pun = '\0'; + return un; +} + +/* + * Given a path to a jre to execute, this routine checks if this process + * is indeed that jre. If not, it exec's that jre. + * + * We want to actually check the paths rather than just the version string + * built into the executable, so that given version specification will yield + * the exact same Java environment, regardless of the version of the arbitrary + * launcher we start with. + */ +void +ExecJRE(char *jre, char **argv) { + jint len; + char path[MAXPATHLEN + 1]; + + const char *progname = GetProgramName(); + + /* + * Resolve the real path to the currently running launcher. + */ + len = GetModuleFileName(NULL, path, MAXPATHLEN + 1); + if (len == 0 || len > MAXPATHLEN) { + JLI_ReportErrorMessageSys(JRE_ERROR9, progname); + exit(1); + } + + JLI_TraceLauncher("ExecJRE: old: %s\n", path); + JLI_TraceLauncher("ExecJRE: new: %s\n", jre); + + /* + * If the path to the selected JRE directory is a match to the initial + * portion of the path to the currently executing JRE, we have a winner! + * If so, just return. + */ + if (JLI_StrNCaseCmp(jre, path, JLI_StrLen(jre)) == 0) + return; /* I am the droid you were looking for */ + + /* + * If this isn't the selected version, exec the selected version. + */ + JLI_Snprintf(path, sizeof(path), "%s\\bin\\%s.exe", jre, progname); + + /* + * Although Windows has an execv() entrypoint, it doesn't actually + * overlay a process: it can only create a new process and terminate + * the old process. Therefore, any processes waiting on the initial + * process wake up and they shouldn't. Hence, a chain of pseudo-zombie + * processes must be retained to maintain the proper wait semantics. + * Fortunately the image size of the launcher isn't too large at this + * time. + * + * If it weren't for this semantic flaw, the code below would be ... + * + * execv(path, argv); + * JLI_ReportErrorMessage("Error: Exec of %s failed\n", path); + * exit(1); + * + * The incorrect exec semantics could be addressed by: + * + * exit((int)spawnv(_P_WAIT, path, argv)); + * + * Unfortunately, a bug in Windows spawn/exec impementation prevents + * this from completely working. All the Windows POSIX process creation + * interfaces are implemented as wrappers around the native Windows + * function CreateProcess(). CreateProcess() takes a single string + * to specify command line options and arguments, so the POSIX routine + * wrappers build a single string from the argv[] array and in the + * process, any quoting information is lost. + * + * The solution to this to get the original command line, to process it + * to remove the new multiple JRE options (if any) as was done for argv + * in the common SelectVersion() routine and finally to pass it directly + * to the native CreateProcess() Windows process control interface. + */ + { + char *cmdline; + char *p; + char *np; + char *ocl; + char *ccl; + char *unquoted; + DWORD exitCode; + STARTUPINFO si; + PROCESS_INFORMATION pi; + + /* + * The following code block gets and processes the original command + * line, replacing the argv[0] equivalent in the command line with + * the path to the new executable and removing the appropriate + * Multiple JRE support options. Note that similar logic exists + * in the platform independent SelectVersion routine, but is + * replicated here due to the syntax of CreateProcess(). + * + * The magic "+ 4" characters added to the command line length are + * 2 possible quotes around the path (argv[0]), a space after the + * path and a terminating null character. + */ + ocl = GetCommandLine(); + np = ccl = JLI_StringDup(ocl); + p = nextarg(&np); /* Discard argv[0] */ + cmdline = (char *)JLI_MemAlloc(JLI_StrLen(path) + JLI_StrLen(np) + 4); + if (JLI_StrChr(path, (int)' ') == NULL && JLI_StrChr(path, (int)'\t') == NULL) + cmdline = JLI_StrCpy(cmdline, path); + else + cmdline = JLI_StrCat(JLI_StrCat(JLI_StrCpy(cmdline, "\""), path), "\""); + + while (*np != (char)0) { /* While more command-line */ + p = nextarg(&np); + if (*p != (char)0) { /* If a token was isolated */ + unquoted = unquote(p); + if (*unquoted == '-') { /* Looks like an option */ + if (JLI_StrCmp(unquoted, "-classpath") == 0 || + JLI_StrCmp(unquoted, "-cp") == 0) { /* Unique cp syntax */ + cmdline = JLI_StrCat(JLI_StrCat(cmdline, " "), p); + p = nextarg(&np); + if (*p != (char)0) /* If a token was isolated */ + cmdline = JLI_StrCat(JLI_StrCat(cmdline, " "), p); + } else if (JLI_StrNCmp(unquoted, "-version:", 9) != 0 && + JLI_StrCmp(unquoted, "-jre-restrict-search") != 0 && + JLI_StrCmp(unquoted, "-no-jre-restrict-search") != 0) { + cmdline = JLI_StrCat(JLI_StrCat(cmdline, " "), p); + } + } else { /* End of options */ + cmdline = JLI_StrCat(JLI_StrCat(cmdline, " "), p); + cmdline = JLI_StrCat(JLI_StrCat(cmdline, " "), np); + JLI_MemFree((void *)unquoted); + break; + } + JLI_MemFree((void *)unquoted); + } + } + JLI_MemFree((void *)ccl); + + if (JLI_IsTraceLauncher()) { + np = ccl = JLI_StringDup(cmdline); + p = nextarg(&np); + printf("ReExec Command: %s (%s)\n", path, p); + printf("ReExec Args: %s\n", np); + JLI_MemFree((void *)ccl); + } + (void)fflush(stdout); + (void)fflush(stderr); + + /* + * The following code is modeled after a model presented in the + * Microsoft Technical Article "Moving Unix Applications to + * Windows NT" (March 6, 1994) and "Creating Processes" on MSDN + * (Februrary 2005). It approximates UNIX spawn semantics with + * the parent waiting for termination of the child. + */ + memset(&si, 0, sizeof(si)); + si.cb =sizeof(STARTUPINFO); + memset(&pi, 0, sizeof(pi)); + + if (!CreateProcess((LPCTSTR)path, /* executable name */ + (LPTSTR)cmdline, /* command line */ + (LPSECURITY_ATTRIBUTES)NULL, /* process security attr. */ + (LPSECURITY_ATTRIBUTES)NULL, /* thread security attr. */ + (BOOL)TRUE, /* inherits system handles */ + (DWORD)0, /* creation flags */ + (LPVOID)NULL, /* environment block */ + (LPCTSTR)NULL, /* current directory */ + (LPSTARTUPINFO)&si, /* (in) startup information */ + (LPPROCESS_INFORMATION)&pi)) { /* (out) process information */ + JLI_ReportErrorMessageSys(SYS_ERROR1, path); + exit(1); + } + + if (WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_FAILED) { + if (GetExitCodeProcess(pi.hProcess, &exitCode) == FALSE) + exitCode = 1; + } else { + JLI_ReportErrorMessage(SYS_ERROR2); + exitCode = 1; + } + + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + + exit(exitCode); + } +} + +/* + * Wrapper for platform dependent unsetenv function. + */ +int +UnsetEnv(char *name) +{ + int ret; + char *buf = JLI_MemAlloc(JLI_StrLen(name) + 2); + buf = JLI_StrCat(JLI_StrCpy(buf, name), "="); + ret = _putenv(buf); + JLI_MemFree(buf); + return (ret); +} + +/* --- Splash Screen shared library support --- */ + +static const char* SPLASHSCREEN_SO = "\\bin\\splashscreen.dll"; + +static HMODULE hSplashLib = NULL; + +void* SplashProcAddress(const char* name) { + char libraryPath[MAXPATHLEN]; /* some extra space for JLI_StrCat'ing SPLASHSCREEN_SO */ + + if (!GetJREPath(libraryPath, MAXPATHLEN)) { + return NULL; + } + if (JLI_StrLen(libraryPath)+JLI_StrLen(SPLASHSCREEN_SO) >= MAXPATHLEN) { + return NULL; + } + JLI_StrCat(libraryPath, SPLASHSCREEN_SO); + + if (!hSplashLib) { + hSplashLib = LoadLibrary(libraryPath); + } + if (hSplashLib) { + return GetProcAddress(hSplashLib, name); + } else { + return NULL; + } +} + +void SplashFreeLibrary() { + if (hSplashLib) { + FreeLibrary(hSplashLib); + hSplashLib = NULL; + } +} + +const char * +jlong_format_specifier() { + return "%I64d"; +} + +/* + * Block current thread and continue execution in a new thread + */ +int +ContinueInNewThread0(int (JNICALL *continuation)(void *), jlong stack_size, void * args) { + int rslt = 0; + unsigned thread_id; + +#ifndef STACK_SIZE_PARAM_IS_A_RESERVATION +#define STACK_SIZE_PARAM_IS_A_RESERVATION (0x10000) +#endif + + /* + * STACK_SIZE_PARAM_IS_A_RESERVATION is what we want, but it's not + * supported on older version of Windows. Try first with the flag; and + * if that fails try again without the flag. See MSDN document or HotSpot + * source (os_win32.cpp) for details. + */ + HANDLE thread_handle = + (HANDLE)_beginthreadex(NULL, + (unsigned)stack_size, + continuation, + args, + STACK_SIZE_PARAM_IS_A_RESERVATION, + &thread_id); + if (thread_handle == NULL) { + thread_handle = + (HANDLE)_beginthreadex(NULL, + (unsigned)stack_size, + continuation, + args, + 0, + &thread_id); + } + + /* AWT preloading (AFTER main thread start) */ +#ifdef ENABLE_AWT_PRELOAD + /* D3D preloading */ + if (awtPreloadD3D != 0) { + char *envValue; + /* D3D routines checks env.var J2D_D3D if no appropriate + * command line params was specified + */ + envValue = getenv("J2D_D3D"); + if (envValue != NULL && JLI_StrCaseCmp(envValue, "false") == 0) { + awtPreloadD3D = 0; + } + /* Test that AWT preloading isn't disabled by J2D_D3D_PRELOAD env.var */ + envValue = getenv("J2D_D3D_PRELOAD"); + if (envValue != NULL && JLI_StrCaseCmp(envValue, "false") == 0) { + awtPreloadD3D = 0; + } + if (awtPreloadD3D < 0) { + /* If awtPreloadD3D is still undefined (-1), test + * if it is turned on by J2D_D3D_PRELOAD env.var. + * By default it's turned OFF. + */ + awtPreloadD3D = 0; + if (envValue != NULL && JLI_StrCaseCmp(envValue, "true") == 0) { + awtPreloadD3D = 1; + } + } + } + if (awtPreloadD3D) { + AWTPreload(D3D_PRELOAD_FUNC); + } +#endif /* ENABLE_AWT_PRELOAD */ + + if (thread_handle) { + WaitForSingleObject(thread_handle, INFINITE); + GetExitCodeThread(thread_handle, &rslt); + CloseHandle(thread_handle); + } else { + rslt = continuation(args); + } + +#ifdef ENABLE_AWT_PRELOAD + if (awtPreloaded) { + AWTPreloadStop(); + } +#endif /* ENABLE_AWT_PRELOAD */ + + return rslt; +} + +/* Unix only, empty on windows. */ +void SetJavaLauncherPlatformProps() {} + +/* + * The implementation for finding classes from the bootstrap + * class loader, refer to java.h + */ +static FindClassFromBootLoader_t *findBootClass = NULL; + +jclass FindBootStrapClass(JNIEnv *env, const char *classname) +{ + HMODULE hJvm; + + if (findBootClass == NULL) { + hJvm = GetModuleHandle(JVM_DLL); + if (hJvm == NULL) return NULL; + /* need to use the demangled entry point */ + findBootClass = (FindClassFromBootLoader_t *)GetProcAddress(hJvm, + "JVM_FindClassFromBootLoader"); + if (findBootClass == NULL) { + JLI_ReportErrorMessage(DLL_ERROR4, "JVM_FindClassFromBootLoader"); + return NULL; + } + } + return findBootClass(env, classname); +} + +void +InitLauncher(boolean javaw) +{ + INITCOMMONCONTROLSEX icx; + + /* + * Required for javaw mode MessageBox output as well as for + * HotSpot -XX:+ShowMessageBoxOnError in java mode, an empty + * flag field is sufficient to perform the basic UI initialization. + */ + memset(&icx, 0, sizeof(INITCOMMONCONTROLSEX)); + icx.dwSize = sizeof(INITCOMMONCONTROLSEX); + InitCommonControlsEx(&icx); + _isjavaw = javaw; + JLI_SetTraceLauncher(); +} + + +/* ============================== */ +/* AWT preloading */ +#ifdef ENABLE_AWT_PRELOAD + +typedef int FnPreloadStart(void); +typedef void FnPreloadStop(void); +static FnPreloadStop *fnPreloadStop = NULL; +static HMODULE hPreloadAwt = NULL; + +/* + * Starts AWT preloading + */ +int AWTPreload(const char *funcName) +{ + int result = -1; + /* load AWT library once (if several preload function should be called) */ + if (hPreloadAwt == NULL) { + /* awt.dll is not loaded yet */ + char libraryPath[MAXPATHLEN]; + int jrePathLen = 0; + HMODULE hJava = NULL; + HMODULE hVerify = NULL; + + while (1) { + /* awt.dll depends on jvm.dll & java.dll; + * jvm.dll is already loaded, so we need only java.dll; + * java.dll depends on MSVCRT lib & verify.dll. + */ + if (!GetJREPath(libraryPath, MAXPATHLEN)) { + break; + } + + /* save path length */ + jrePathLen = JLI_StrLen(libraryPath); + + if (jrePathLen + JLI_StrLen("\\bin\\verify.dll") >= MAXPATHLEN) { + /* jre path is too long, the library path will not fit there; + * report and abort preloading + */ + JLI_ReportErrorMessage(JRE_ERROR11); + break; + } + + /* load msvcrt 1st */ + LoadMSVCRT(); + + /* load verify.dll */ + JLI_StrCat(libraryPath, "\\bin\\verify.dll"); + hVerify = LoadLibrary(libraryPath); + if (hVerify == NULL) { + break; + } + + /* restore jrePath */ + libraryPath[jrePathLen] = 0; + /* load java.dll */ + JLI_StrCat(libraryPath, "\\bin\\" JAVA_DLL); + hJava = LoadLibrary(libraryPath); + if (hJava == NULL) { + break; + } + + /* restore jrePath */ + libraryPath[jrePathLen] = 0; + /* load awt.dll */ + JLI_StrCat(libraryPath, "\\bin\\awt.dll"); + hPreloadAwt = LoadLibrary(libraryPath); + if (hPreloadAwt == NULL) { + break; + } + + /* get "preloadStop" func ptr */ + fnPreloadStop = (FnPreloadStop *)GetProcAddress(hPreloadAwt, "preloadStop"); + + break; + } + } + + if (hPreloadAwt != NULL) { + FnPreloadStart *fnInit = (FnPreloadStart *)GetProcAddress(hPreloadAwt, funcName); + if (fnInit != NULL) { + /* don't forget to stop preloading */ + awtPreloaded = 1; + + result = fnInit(); + } + } + + return result; +} + +/* + * Terminates AWT preloading + */ +void AWTPreloadStop() { + if (fnPreloadStop != NULL) { + fnPreloadStop(); + } +} + +#endif /* ENABLE_AWT_PRELOAD */ + +int +JVMInit(InvocationFunctions* ifn, jlong threadStackSize, + int argc, char **argv, + int mode, char *what, int ret) +{ + ShowSplashScreen(); + return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret); +} + +void +PostJVMInit(JNIEnv *env, jstring mainClass, JavaVM *vm) +{ + // stubbed out for windows and *nixes. +} + +void +RegisterThread() +{ + // stubbed out for windows and *nixes. +} + +/* + * on windows, we return a false to indicate this option is not applicable + */ +jboolean +ProcessPlatformOption(const char *arg) +{ + return JNI_FALSE; +} + +int +filterArgs(StdArg *stdargs, const int nargc, StdArg **pargv) { + StdArg* argv = NULL; + int nargs = 0; + int i; + + /* Copy the non-vm args */ + for (i = 0; i < nargc ; i++) { + const char *arg = stdargs[i].arg; + if (arg[0] == '-' && arg[1] == 'J') + continue; + argv = (StdArg*) JLI_MemRealloc(argv, (nargs+1) * sizeof(StdArg)); + argv[nargs].arg = JLI_StringDup(arg); + argv[nargs].has_wildcard = stdargs[i].has_wildcard; + nargs++; + } + *pargv = argv; + return nargs; +} + +/* + * At this point we have the arguments to the application, and we need to + * check with original stdargs in order to compare which of these truly + * needs expansion. cmdtoargs will specify this if it finds a bare + * (unquoted) argument containing a glob character(s) ie. * or ? + */ +jobjectArray +CreateApplicationArgs(JNIEnv *env, char **strv, int argc) +{ + int i, j, idx, tlen; + jobjectArray outArray, inArray; + char *ostart, *astart, **nargv; + jboolean needs_expansion = JNI_FALSE; + jmethodID mid; + int filteredargc, stdargc; + StdArg *stdargs; + StdArg *filteredargs; + jclass cls = GetLauncherHelperClass(env); + NULL_CHECK0(cls); + + if (argc == 0) { + return NewPlatformStringArray(env, strv, argc); + } + // the holy grail we need to compare with. + stdargs = JLI_GetStdArgs(); + stdargc = JLI_GetStdArgc(); + + filteredargc = filterArgs(stdargs, stdargc, &filteredargs); + + // sanity check, this should never happen + if (argc > stdargc) { + JLI_TraceLauncher("Warning: app args is larger than the original, %d %d\n", argc, stdargc); + JLI_TraceLauncher("passing arguments as-is.\n"); + return NewPlatformStringArray(env, strv, argc); + } + + // sanity check, match the args we have, to the holy grail + idx = filteredargc - argc; + ostart = filteredargs[idx].arg; + astart = strv[0]; + // sanity check, ensure that the first argument of the arrays are the same + if (JLI_StrCmp(ostart, astart) != 0) { + // some thing is amiss the args don't match + JLI_TraceLauncher("Warning: app args parsing error\n"); + JLI_TraceLauncher("passing arguments as-is\n"); + return NewPlatformStringArray(env, strv, argc); + } + + // make a copy of the args which will be expanded in java if required. + nargv = (char **)JLI_MemAlloc(argc * sizeof(char*)); + for (i = 0, j = idx; i < argc; i++, j++) { + jboolean arg_expand = (JLI_StrCmp(filteredargs[j].arg, strv[i]) == 0) + ? filteredargs[j].has_wildcard + : JNI_FALSE; + if (needs_expansion == JNI_FALSE) + needs_expansion = arg_expand; + + // indicator char + String + NULL terminator, the java method will strip + // out the first character, the indicator character, so no matter what + // we add the indicator + tlen = 1 + JLI_StrLen(strv[i]) + 1; + nargv[i] = (char *) JLI_MemAlloc(tlen); + if (JLI_Snprintf(nargv[i], tlen, "%c%s", arg_expand ? 'T' : 'F', + strv[i]) < 0) { + return NULL; + } + JLI_TraceLauncher("%s\n", nargv[i]); + } + + if (!needs_expansion) { + // clean up any allocated memory and return back the old arguments + for (i = 0 ; i < argc ; i++) { + JLI_MemFree(nargv[i]); + } + JLI_MemFree(nargv); + return NewPlatformStringArray(env, strv, argc); + } + NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls, + "expandArgs", + "([Ljava/lang/String;)[Ljava/lang/String;")); + + // expand the arguments that require expansion, the java method will strip + // out the indicator character. + inArray = NewPlatformStringArray(env, nargv, argc); + outArray = (*env)->CallStaticObjectMethod(env, cls, mid, inArray); + for (i = 0; i < argc; i++) { + JLI_MemFree(nargv[i]); + } + JLI_MemFree(nargv); + JLI_MemFree(filteredargs); + return outArray; +} diff --git a/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/java_md.h b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/java_md.h new file mode 100644 index 0000000..bd3e9b9 --- /dev/null +++ b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/java_md.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +#ifndef JAVA_MD_H +#define JAVA_MD_H + +#include +#include +#include +#include "manifest_info.h" +#include "jli_util.h" + +#define PATH_SEPARATOR ';' +#define FILESEP "\\" +#define FILE_SEPARATOR '\\' +#define IS_FILE_SEPARATOR(c) ((c) == '\\' || (c) == '/') +#define MAXPATHLEN MAX_PATH +#define MAXNAMELEN MAX_PATH + + +/* + * Support for doing cheap, accurate interval timing. + */ +extern jlong CounterGet(void); +extern jlong Counter2Micros(jlong counts); + + +/* + * Function prototypes. + */ +char *LocateJRE(manifest_info *info); +void ExecJRE(char *jre, char **argv); +int UnsetEnv(char *name); + +#endif /* JAVA_MD_H */ diff --git a/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/jli_util.c b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/jli_util.c new file mode 100644 index 0000000..4f2bed8 --- /dev/null +++ b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/jli_util.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +#include +#include +#include + +#include "jli_util.h" + +/* + * Returns a pointer to a block of at least 'size' bytes of memory. + * Prints error message and exits if the memory could not be allocated. + */ +void * +JLI_MemAlloc(size_t size) +{ + void *p = malloc(size); + if (p == 0) { + perror("malloc"); + exit(1); + } + return p; +} + +/* + * Equivalent to realloc(size). + * Prints error message and exits if the memory could not be reallocated. + */ +void * +JLI_MemRealloc(void *ptr, size_t size) +{ + void *p = realloc(ptr, size); + if (p == 0) { + perror("realloc"); + exit(1); + } + return p; +} + +/* + * Wrapper over strdup(3C) which prints an error message and exits if memory + * could not be allocated. + */ +char * +JLI_StringDup(const char *s1) +{ + char *s = strdup(s1); + if (s == NULL) { + perror("strdup"); + exit(1); + } + return s; +} + +/* + * Very equivalent to free(ptr). + * Here to maintain pairing with the above routines. + */ +void +JLI_MemFree(void *ptr) +{ + free(ptr); +} + +/* + * debug helpers we use + */ +static jboolean _launcher_debug = JNI_FALSE; + +void +JLI_TraceLauncher(const char* fmt, ...) +{ + va_list vl; + if (_launcher_debug != JNI_TRUE) return; + va_start(vl, fmt); + vprintf(fmt,vl); + va_end(vl); +} + +void +JLI_SetTraceLauncher() +{ + if (getenv(JLDEBUG_ENV_ENTRY) != 0) { + _launcher_debug = JNI_TRUE; + JLI_TraceLauncher("----%s----\n", JLDEBUG_ENV_ENTRY); + } +} + +jboolean +JLI_IsTraceLauncher() +{ + return _launcher_debug; +} + +int +JLI_StrCCmp(const char *s1, const char* s2) +{ + return JLI_StrNCmp(s1, s2, JLI_StrLen(s2)); +} diff --git a/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/jli_util.h b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/jli_util.h new file mode 100644 index 0000000..4335ba3 --- /dev/null +++ b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/jli_util.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +#ifndef _JLI_UTIL_H +#define _JLI_UTIL_H + +#include +#include +#include +#include +#define JLDEBUG_ENV_ENTRY "_JAVA_LAUNCHER_DEBUG" + +void *JLI_MemAlloc(size_t size); +void *JLI_MemRealloc(void *ptr, size_t size); +char *JLI_StringDup(const char *s1); +void JLI_MemFree(void *ptr); +int JLI_StrCCmp(const char *s1, const char* s2); + +typedef struct { + char *arg; + jboolean has_wildcard; +} StdArg; + +StdArg *JLI_GetStdArgs(); +int JLI_GetStdArgc(); + +#define JLI_StrLen(p1) strlen((p1)) +#define JLI_StrChr(p1, p2) strchr((p1), (p2)) +#define JLI_StrRChr(p1, p2) strrchr((p1), (p2)) +#define JLI_StrCmp(p1, p2) strcmp((p1), (p2)) +#define JLI_StrNCmp(p1, p2, p3) strncmp((p1), (p2), (p3)) +#define JLI_StrCat(p1, p2) strcat((p1), (p2)) +#define JLI_StrCpy(p1, p2) strcpy((p1), (p2)) +#define JLI_StrNCpy(p1, p2, p3) strncpy((p1), (p2), (p3)) +#define JLI_StrStr(p1, p2) strstr((p1), (p2)) +#define JLI_StrSpn(p1, p2) strspn((p1), (p2)) +#define JLI_StrCSpn(p1, p2) strcspn((p1), (p2)) +#define JLI_StrPBrk(p1, p2) strpbrk((p1), (p2)) +#define JLI_StrTok(p1, p2) strtok((p1), (p2)) + +/* On Windows lseek() is in io.h rather than the location dictated by POSIX. */ +#ifdef _WIN32 +#include +#include +#include +#define JLI_StrCaseCmp(p1, p2) stricmp((p1), (p2)) +#define JLI_StrNCaseCmp(p1, p2, p3) strnicmp((p1), (p2), (p3)) +int JLI_Snprintf(char *buffer, size_t size, const char *format, ...); +void JLI_CmdToArgs(char *cmdline); +#define JLI_Lseek _lseeki64 +#define JLI_PutEnv _putenv +#define JLI_GetPid _getpid +#else /* NIXES */ +#include +#include +#define JLI_StrCaseCmp(p1, p2) strcasecmp((p1), (p2)) +#define JLI_StrNCaseCmp(p1, p2, p3) strncasecmp((p1), (p2), (p3)) +#define JLI_Snprintf snprintf +#define JLI_PutEnv putenv +#define JLI_GetPid getpid +#ifdef __solaris__ +#define JLI_Lseek llseek +#endif +#ifdef __linux__ +#define _LARGFILE64_SOURCE +#define JLI_Lseek lseek64 +#endif +#ifdef MACOSX +#define JLI_Lseek lseek +#endif +#ifdef _AIX +#define JLI_Lseek lseek +#endif +#endif /* _WIN32 */ + +/* + * Make launcher spit debug output. + */ +void JLI_TraceLauncher(const char* fmt, ...); +void JLI_SetTraceLauncher(); +jboolean JLI_IsTraceLauncher(); + +#endif /* _JLI_UTIL_H */ diff --git a/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/main.c b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/main.c new file mode 100644 index 0000000..d05fff9 --- /dev/null +++ b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/main.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + + +/* + * This file contains the main entry point into the launcher code + * this is the only file which will be repeatedly compiled by other + * tools. The rest of the files will be linked in. + */ + +#include "defines.h" + +#ifdef _MSC_VER +#if _MSC_VER > 1400 && _MSC_VER < 1600 + +/* + * When building for Microsoft Windows, main has a dependency on msvcr??.dll. + * + * When using Visual Studio 2005 or 2008, that must be recorded in + * the [java,javaw].exe.manifest file. + * + * As of VS2010 (ver=1600), the runtimes again no longer need manifests. + * + * Reference: + * C:/Program Files/Microsoft SDKs/Windows/v6.1/include/crtdefs.h + */ +#include +#ifdef _M_IX86 + +#pragma comment(linker,"/manifestdependency:\"type='win32' " \ + "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".CRT' " \ + "version='" _CRT_ASSEMBLY_VERSION "' " \ + "processorArchitecture='x86' " \ + "publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'\"") + +#endif /* _M_IX86 */ + +//This may not be necessary yet for the Windows 64-bit build, but it +//will be when that build environment is updated. Need to test to see +//if it is harmless: +#ifdef _M_AMD64 + +#pragma comment(linker,"/manifestdependency:\"type='win32' " \ + "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".CRT' " \ + "version='" _CRT_ASSEMBLY_VERSION "' " \ + "processorArchitecture='amd64' " \ + "publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'\"") + +#endif /* _M_AMD64 */ +#endif /* _MSC_VER > 1400 && _MSC_VER < 1600 */ +#endif /* _MSC_VER */ + +/* + * Entry point. + */ +#ifdef JAVAW + +char **__initenv; + +int WINAPI +WinMain(HINSTANCE inst, HINSTANCE previnst, LPSTR cmdline, int cmdshow) +{ + int margc; + char** margv; + const jboolean const_javaw = JNI_TRUE; + + __initenv = _environ; + +#else /* JAVAW */ +int +main(int argc, char **argv) +{ + int margc; + char** margv; + const jboolean const_javaw = JNI_FALSE; +#endif /* JAVAW */ +#ifdef _WIN32 + { + int i = 0; + if (getenv(JLDEBUG_ENV_ENTRY) != NULL) { + printf("Windows original main args:\n"); + for (i = 0 ; i < __argc ; i++) { + printf("wwwd_args[%d] = %s\n", i, __argv[i]); + } + } + } + JLI_CmdToArgs(GetCommandLine()); + margc = JLI_GetStdArgc(); + // add one more to mark the end + margv = (char **)JLI_MemAlloc((margc + 1) * (sizeof(char *))); + { + int i = 0; + StdArg *stdargs = JLI_GetStdArgs(); + for (i = 0 ; i < margc ; i++) { + margv[i] = stdargs[i].arg; + } + margv[i] = NULL; + } +#else /* *NIXES */ + margc = argc; + margv = argv; +#endif /* WIN32 */ + return JLI_Launch(margc, margv, + sizeof(const_jargs) / sizeof(char *), const_jargs, + sizeof(const_appclasspath) / sizeof(char *), const_appclasspath, + FULL_VERSION, + DOT_VERSION, + (const_progname != NULL) ? const_progname : *margv, + (const_launcher != NULL) ? const_launcher : *margv, + (const_jargs != NULL) ? JNI_TRUE : JNI_FALSE, + const_cpwildcard, const_javaw, const_ergo_class); +} diff --git a/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/manifest_info.h b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/manifest_info.h new file mode 100644 index 0000000..8a4e824 --- /dev/null +++ b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/manifest_info.h @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +#ifndef _MANIFEST_INFO_H +#define _MANIFEST_INFO_H + +#include + +/* + * Zip file header signatures + */ +#define SIGSIZ 4 /* size of all header signatures */ +#define LOCSIG 0x04034b50L /* "PK\003\004" */ +#define EXTSIG 0x08074b50L /* "PK\007\008" */ +#define CENSIG 0x02014b50L /* "PK\001\002" */ +#define ENDSIG 0x06054b50L /* "PK\005\006" */ + +#define ZIP64_ENDSIG 0x06064b50L /* "PK\006\006" */ +#define ZIP64_LOCSIG 0x07064b50L /* "PK\006\007" */ +/* + * Header sizes including signatures + */ +#define LOCHDR 30 +#define EXTHDR 16 +#define CENHDR 46 +#define ENDHDR 22 + +#define ZIP64_ENDHDR 56 // ZIP64 end header size +#define ZIP64_LOCHDR 20 // ZIP64 end loc header size +#define ZIP64_EXTHDR 24 // EXT header size +#define ZIP64_EXTID 1 // Extra field Zip64 header ID + +#define ZIP64_MAGICVAL 0xffffffffLL +#define ZIP64_MAGICCOUNT 0xffff + +/* + * Header field access macros + */ +#define CH(b, n) (((unsigned char *)(b))[n]) +#define SH(b, n) (CH(b, n) | (CH(b, n+1) << 8)) +#define LG(b, n) ((SH(b, n) | (SH(b, n+2) << 16)) &0xffffffffUL) +#define LL(b, n) (((jlong)LG(b, n)) | (((jlong)LG(b, n+4)) << 32)) +#define GETSIG(b) LG(b, 0) + +/* + * Macros for getting local file (LOC) header fields + */ +#define LOCVER(b) SH(b, 4) /* version needed to extract */ +#define LOCFLG(b) SH(b, 6) /* general purpose bit flags */ +#define LOCHOW(b) SH(b, 8) /* compression method */ +#define LOCTIM(b) LG(b, 10) /* modification time */ +#define LOCCRC(b) LG(b, 14) /* crc of uncompressed data */ +#define LOCSIZ(b) LG(b, 18) /* compressed data size */ +#define LOCLEN(b) LG(b, 22) /* uncompressed data size */ +#define LOCNAM(b) SH(b, 26) /* filename length */ +#define LOCEXT(b) SH(b, 28) /* extra field length */ + +/* + * Macros for getting extra local (EXT) header fields + */ +#define EXTCRC(b) LG(b, 4) /* crc of uncompressed data */ +#define EXTSIZ(b) LG(b, 8) /* compressed size */ +#define EXTLEN(b) LG(b, 12) /* uncompressed size */ + +/* + * Macros for getting central directory header (CEN) fields + */ +#define CENVEM(b) SH(b, 4) /* version made by */ +#define CENVER(b) SH(b, 6) /* version needed to extract */ +#define CENFLG(b) SH(b, 8) /* general purpose bit flags */ +#define CENHOW(b) SH(b, 10) /* compression method */ +#define CENTIM(b) LG(b, 12) /* modification time */ +#define CENCRC(b) LG(b, 16) /* crc of uncompressed data */ +#define CENSIZ(b) LG(b, 20) /* compressed size */ +#define CENLEN(b) LG(b, 24) /* uncompressed size */ +#define CENNAM(b) SH(b, 28) /* length of filename */ +#define CENEXT(b) SH(b, 30) /* length of extra field */ +#define CENCOM(b) SH(b, 32) /* file comment length */ +#define CENDSK(b) SH(b, 34) /* disk number start */ +#define CENATT(b) SH(b, 36) /* internal file attributes */ +#define CENATX(b) LG(b, 38) /* external file attributes */ +#define CENOFF(b) LG(b, 42) /* offset of local header */ + +/* + * Macros for getting end of central directory header (END) fields + */ +#define ENDSUB(b) SH(b, 8) /* number of entries on this disk */ +#define ENDTOT(b) SH(b, 10) /* total number of entries */ +#define ENDSIZ(b) LG(b, 12) /* central directory size */ +#define ENDOFF(b) LG(b, 16) /* central directory offset */ +#define ENDCOM(b) SH(b, 20) /* size of zip file comment */ + +/* + * Macros for getting Zip64 end of central directory header fields + */ +#define ZIP64_ENDLEN(b) LL(b, 4) /* size of zip64 end of central dir */ +#define ZIP64_ENDVEM(b) SH(b, 12) /* version made by */ +#define ZIP64_ENDVER(b) SH(b, 14) /* version needed to extract */ +#define ZIP64_ENDNMD(b) LG(b, 16) /* number of this disk */ +#define ZIP64_ENDDSK(b) LG(b, 20) /* disk number of start */ +#define ZIP64_ENDTOD(b) LL(b, 24) /* total number of entries on this disk */ +#define ZIP64_ENDTOT(b) LL(b, 32) /* total number of entries */ +#define ZIP64_ENDSIZ(b) LL(b, 40) /* central directory size in bytes */ +#define ZIP64_ENDOFF(b) LL(b, 48) /* offset of first CEN header */ + +/* + * Macros for getting Zip64 end of central directory locator fields + */ +#define ZIP64_LOCDSK(b) LG(b, 4) /* disk number start */ +#define ZIP64_LOCOFF(b) LL(b, 8) /* offset of zip64 end */ +#define ZIP64_LOCTOT(b) LG(b, 16) /* total number of disks */ + +/* + * A comment of maximum length of 64kb can follow the END record. This + * is the furthest the END record can be from the end of the file. + */ +#define END_MAXLEN (0xFFFF + ENDHDR) + +/* + * Supported compression methods. + */ +#define STORED 0 +#define DEFLATED 8 + +/* + * Information from the CEN entry to inflate a file. + */ +typedef struct zentry { /* Zip file entry */ + size_t isize; /* size of inflated data */ + size_t csize; /* size of compressed data (zero if uncompressed) */ + jlong offset; /* position of compressed data */ + int how; /* compression method (if any) */ +} zentry; + +/* + * Information returned from the Manifest file by the ParseManifest() routine. + * Certainly (much) more could be returned, but this is the information + * currently of interest to the C based Java utilities (particularly the + * Java launcher). + */ +typedef struct manifest_info { /* Interesting fields from the Manifest */ + char *manifest_version; /* Manifest-Version string */ + char *main_class; /* Main-Class entry */ + char *jre_version; /* Appropriate J2SE release spec */ + char jre_restrict_search; /* Restricted JRE search */ + char *splashscreen_image_file_name; /* splashscreen image file */ +} manifest_info; + +/* + * Attribute closure to provide to manifest_iterate. + */ +typedef void (*attribute_closure)(const char *name, const char *value, + void *user_data); + +/* + * Function prototypes. + */ +int JLI_ParseManifest(char *jarfile, manifest_info *info); +void *JLI_JarUnpackFile(const char *jarfile, const char *filename, + int *size); +void JLI_FreeManifest(void); +int JLI_ManifestIterate(const char *jarfile, attribute_closure ac, + void *user_data); + +#endif /* _MANIFEST_INFO_H */ diff --git a/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/parse_manifest.c b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/parse_manifest.c new file mode 100644 index 0000000..130c4c3 --- /dev/null +++ b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/parse_manifest.c @@ -0,0 +1,698 @@ +/* + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +#include +#include +#include +#include +#include +#include +#include "jli_util.h" + +#include +#include "manifest_info.h" + +static char *manifest; + +static const char *manifest_name = "META-INF/MANIFEST.MF"; + +/* + * Inflate the manifest file (or any file for that matter). + * + * fd: File descriptor of the jar file. + * entry: Contains the information necessary to perform the inflation + * (the compressed and uncompressed sizes and the offset in + * the file where the compressed data is located). + * size_out: Returns the size of the inflated file. + * + * Upon success, it returns a pointer to a NUL-terminated malloc'd buffer + * containing the inflated manifest file. When the caller is done with it, + * this buffer should be released by a call to free(). Upon failure, + * returns NULL. + */ +static char * +inflate_file(int fd, zentry *entry, int *size_out) +{ + char *in; + char *out; + z_stream zs; + + if (entry->csize == (size_t) -1 || entry->isize == (size_t) -1 ) + return (NULL); + if (JLI_Lseek(fd, entry->offset, SEEK_SET) < (jlong)0) + return (NULL); + if ((in = malloc(entry->csize + 1)) == NULL) + return (NULL); + if ((size_t)(read(fd, in, (unsigned int)entry->csize)) != entry->csize) { + free(in); + return (NULL); + } + if (entry->how == STORED) { + *(char *)((size_t)in + entry->csize) = '\0'; + if (size_out) { + *size_out = (int)entry->csize; + } + return (in); + } else if (entry->how == DEFLATED) { + zs.zalloc = (alloc_func)Z_NULL; + zs.zfree = (free_func)Z_NULL; + zs.opaque = (voidpf)Z_NULL; + zs.next_in = (Byte*)in; + zs.avail_in = (uInt)entry->csize; + if (inflateInit2(&zs, -MAX_WBITS) < 0) { + free(in); + return (NULL); + } + if ((out = malloc(entry->isize + 1)) == NULL) { + free(in); + return (NULL); + } + zs.next_out = (Byte*)out; + zs.avail_out = (uInt)entry->isize; + if (inflate(&zs, Z_PARTIAL_FLUSH) < 0) { + free(in); + free(out); + return (NULL); + } + *(char *)((size_t)out + entry->isize) = '\0'; + free(in); + if (inflateEnd(&zs) < 0) { + free(out); + return (NULL); + } + if (size_out) { + *size_out = (int)entry->isize; + } + return (out); + } + free(in); + return (NULL); +} + +static jboolean zip64_present = JNI_FALSE; + +/* + * Checks to see if we have ZIP64 archive, and save + * the check for later use + */ +static int +haveZIP64(Byte *p) { + jlong cenlen, cenoff, centot; + cenlen = ENDSIZ(p); + cenoff = ENDOFF(p); + centot = ENDTOT(p); + zip64_present = (cenlen == ZIP64_MAGICVAL || + cenoff == ZIP64_MAGICVAL || + centot == ZIP64_MAGICCOUNT); + return zip64_present; +} + +static jlong +find_end64(int fd, Byte *ep, jlong pos) +{ + jlong end64pos; + jlong bytes; + if ((end64pos = JLI_Lseek(fd, pos - ZIP64_LOCHDR, SEEK_SET)) < (jlong)0) + return -1; + if ((bytes = read(fd, ep, ZIP64_LOCHDR)) < 0) + return -1; + if (GETSIG(ep) == ZIP64_LOCSIG) + return end64pos; + return -1; +} + +/* + * A very little used routine to handle the case that zip file has + * a comment at the end. Believe it or not, the only way to find the + * END record is to walk backwards, byte by bloody byte looking for + * the END record signature. + * + * fd: File descriptor of the jar file. + * eb: Pointer to a buffer to receive a copy of the END header. + * + * Returns the offset of the END record in the file on success, + * -1 on failure. + */ +static jlong +find_end(int fd, Byte *eb) +{ + jlong len; + jlong pos; + jlong flen; + int bytes; + Byte *cp; + Byte *endpos; + Byte *buffer; + + /* + * 99.44% (or more) of the time, there will be no comment at the + * end of the zip file. Try reading just enough to read the END + * record from the end of the file, at this time we should also + * check to see if we have a ZIP64 archive. + */ + if ((pos = JLI_Lseek(fd, -ENDHDR, SEEK_END)) < (jlong)0) + return (-1); + if ((bytes = read(fd, eb, ENDHDR)) < 0) + return (-1); + if (GETSIG(eb) == ENDSIG) { + return haveZIP64(eb) ? find_end64(fd, eb, pos) : pos; + } + + /* + * Shucky-Darn,... There is a comment at the end of the zip file. + * + * Allocate and fill a buffer with enough of the zip file + * to meet the specification for a maximal comment length. + */ + if ((flen = JLI_Lseek(fd, 0, SEEK_END)) < (jlong)0) + return (-1); + len = (flen < END_MAXLEN) ? flen : END_MAXLEN; + if (JLI_Lseek(fd, -len, SEEK_END) < (jlong)0) + return (-1); + if ((buffer = malloc(END_MAXLEN)) == NULL) + return (-1); + if ((bytes = read(fd, buffer, len)) < 0) { + free(buffer); + return (-1); + } + + /* + * Search backwards from the end of file stopping when the END header + * signature is found. (The first condition of the "if" is just a + * fast fail, because the GETSIG macro isn't always cheap. The + * final condition protects against false positives.) + */ + endpos = &buffer[bytes]; + for (cp = &buffer[bytes - ENDHDR]; cp >= &buffer[0]; cp--) + if ((*cp == (ENDSIG & 0xFF)) && (GETSIG(cp) == ENDSIG) && + (cp + ENDHDR + ENDCOM(cp) == endpos)) { + (void) memcpy(eb, cp, ENDHDR); + free(buffer); + pos = flen - (endpos - cp); + return haveZIP64(eb) ? find_end64(fd, eb, pos) : pos; + } + free(buffer); + return (-1); +} + +#define BUFSIZE (3 * 65536 + CENHDR + SIGSIZ) +#define MINREAD 1024 + +/* + * Computes and positions at the start of the CEN header, ie. the central + * directory, this will also return the offset if there is a zip file comment + * at the end of the archive, for most cases this would be 0. + */ +static jlong +compute_cen(int fd, Byte *bp) +{ + int bytes; + Byte *p; + jlong base_offset; + jlong offset; + char buffer[MINREAD]; + p = buffer; + /* + * Read the END Header, which is the starting point for ZIP files. + * (Clearly designed to make writing a zip file easier than reading + * one. Now isn't that precious...) + */ + if ((base_offset = find_end(fd, bp)) == -1) { + return (-1); + } + p = bp; + /* + * There is a historical, but undocumented, ability to allow for + * additional "stuff" to be prepended to the zip/jar file. It seems + * that this has been used to prepend an actual java launcher + * executable to the jar on Windows. Although this is just another + * form of statically linking a small piece of the JVM to the + * application, we choose to continue to support it. Note that no + * guarantees have been made (or should be made) to the customer that + * this will continue to work. + * + * Therefore, calculate the base offset of the zip file (within the + * expanded file) by assuming that the central directory is followed + * immediately by the end record. + */ + if (zip64_present) { + if ((offset = ZIP64_LOCOFF(p)) < (jlong)0) { + return -1; + } + if (JLI_Lseek(fd, offset, SEEK_SET) < (jlong) 0) { + return (-1); + } + if ((bytes = read(fd, buffer, MINREAD)) < 0) { + return (-1); + } + if (GETSIG(buffer) != ZIP64_ENDSIG) { + return -1; + } + if ((offset = ZIP64_ENDOFF(buffer)) < (jlong)0) { + return -1; + } + if (JLI_Lseek(fd, offset, SEEK_SET) < (jlong)0) { + return (-1); + } + p = buffer; + base_offset = base_offset - ZIP64_ENDSIZ(p) - ZIP64_ENDOFF(p) - ZIP64_ENDHDR; + } else { + base_offset = base_offset - ENDSIZ(p) - ENDOFF(p); + /* + * The END Header indicates the start of the Central Directory + * Headers. Remember that the desired Central Directory Header (CEN) + * will almost always be the second one and the first one is a small + * directory entry ("META-INF/"). Keep the code optimized for + * that case. + * + * Seek to the beginning of the Central Directory. + */ + if (JLI_Lseek(fd, base_offset + ENDOFF(p), SEEK_SET) < (jlong) 0) { + return (-1); + } + } + return base_offset; +} + +/* + * Locate the manifest file with the zip/jar file. + * + * fd: File descriptor of the jar file. + * entry: To be populated with the information necessary to perform + * the inflation (the compressed and uncompressed sizes and + * the offset in the file where the compressed data is located). + * + * Returns zero upon success. Returns a negative value upon failure. + * + * The buffer for reading the Central Directory if the zip/jar file needs + * to be large enough to accommodate the largest possible single record + * and the signature of the next record which is: + * + * 3*2**16 + CENHDR + SIGSIZ + * + * Each of the three variable sized fields (name, comment and extension) + * has a maximum possible size of 64k. + * + * Typically, only a small bit of this buffer is used with bytes shuffled + * down to the beginning of the buffer. It is one thing to allocate such + * a large buffer and another thing to actually start faulting it in. + * + * In most cases, all that needs to be read are the first two entries in + * a typical jar file (META-INF and META-INF/MANIFEST.MF). Keep this factoid + * in mind when optimizing this code. + */ +static int +find_file(int fd, zentry *entry, const char *file_name) +{ + int bytes; + int res; + int entry_size; + int read_size; + jlong base_offset; + Byte *p; + Byte *bp; + Byte *buffer; + Byte locbuf[LOCHDR]; + + if ((buffer = (Byte*)malloc(BUFSIZE)) == NULL) { + return(-1); + } + + bp = buffer; + base_offset = compute_cen(fd, bp); + if (base_offset == -1) { + free(buffer); + return -1; + } + + if ((bytes = read(fd, bp, MINREAD)) < 0) { + free(buffer); + return (-1); + } + p = bp; + /* + * Loop through the Central Directory Headers. Note that a valid zip/jar + * must have an ENDHDR (with ENDSIG) after the Central Directory. + */ + while (GETSIG(p) == CENSIG) { + + /* + * If a complete header isn't in the buffer, shift the contents + * of the buffer down and refill the buffer. Note that the check + * for "bytes < CENHDR" must be made before the test for the entire + * size of the header, because if bytes is less than CENHDR, the + * actual size of the header can't be determined. The addition of + * SIGSIZ guarantees that the next signature is also in the buffer + * for proper loop termination. + */ + if (bytes < CENHDR) { + p = memmove(bp, p, bytes); + if ((res = read(fd, bp + bytes, MINREAD)) <= 0) { + free(buffer); + return (-1); + } + bytes += res; + } + entry_size = CENHDR + CENNAM(p) + CENEXT(p) + CENCOM(p); + if (bytes < entry_size + SIGSIZ) { + if (p != bp) + p = memmove(bp, p, bytes); + read_size = entry_size - bytes + SIGSIZ; + read_size = (read_size < MINREAD) ? MINREAD : read_size; + if ((res = read(fd, bp + bytes, read_size)) <= 0) { + free(buffer); + return (-1); + } + bytes += res; + } + + /* + * Check if the name is the droid we are looking for; the jar file + * manifest. If so, build the entry record from the data found in + * the header located and return success. + */ + if ((size_t)CENNAM(p) == JLI_StrLen(file_name) && + memcmp((p + CENHDR), file_name, JLI_StrLen(file_name)) == 0) { + if (JLI_Lseek(fd, base_offset + CENOFF(p), SEEK_SET) < (jlong)0) { + free(buffer); + return (-1); + } + if (read(fd, locbuf, LOCHDR) < 0) { + free(buffer); + return (-1); + } + if (GETSIG(locbuf) != LOCSIG) { + free(buffer); + return (-1); + } + entry->isize = CENLEN(p); + entry->csize = CENSIZ(p); + entry->offset = base_offset + CENOFF(p) + LOCHDR + + LOCNAM(locbuf) + LOCEXT(locbuf); + entry->how = CENHOW(p); + free(buffer); + return (0); + } + + /* + * Point to the next entry and decrement the count of valid remaining + * bytes. + */ + bytes -= entry_size; + p += entry_size; + } + free(buffer); + return (-1); /* Fell off the end the loop without a Manifest */ +} + +/* + * Parse a Manifest file header entry into a distinct "name" and "value". + * Continuation lines are joined into a single "value". The documented + * syntax for a header entry is: + * + * header: name ":" value + * + * name: alphanum *headerchar + * + * value: SPACE *otherchar newline *continuation + * + * continuation: SPACE *otherchar newline + * + * newline: CR LF | LF | CR (not followed by LF) + * + * alphanum: {"A"-"Z"} | {"a"-"z"} | {"0"-"9"} + * + * headerchar: alphanum | "-" | "_" + * + * otherchar: any UTF-8 character except NUL, CR and LF + * + * Note that a manifest file may be composed of multiple sections, + * each of which may contain multiple headers. + * + * section: *header +newline + * + * nonempty-section: +header +newline + * + * (Note that the point of "nonempty-section" is unclear, because it isn't + * referenced elsewhere in the full specification for the Manifest file.) + * + * Arguments: + * lp pointer to a character pointer which points to the start + * of a valid header. + * name pointer to a character pointer which will be set to point + * to the name portion of the header (nul terminated). + * value pointer to a character pointer which will be set to point + * to the value portion of the header (nul terminated). + * + * Returns: + * 1 Successful parsing of an NV pair. lp is updated to point to the + * next character after the terminating newline in the string + * representing the Manifest file. name and value are updated to + * point to the strings parsed. + * 0 A valid end of section indicator was encountered. lp, name, and + * value are not modified. + * -1 lp does not point to a valid header. Upon return, the values of + * lp, name, and value are undefined. + */ +static int +parse_nv_pair(char **lp, char **name, char **value) +{ + char *nl; + char *cp; + + /* + * End of the section - return 0. The end of section condition is + * indicated by either encountering a blank line or the end of the + * Manifest "string" (EOF). + */ + if (**lp == '\0' || **lp == '\n' || **lp == '\r') + return (0); + + /* + * Getting to here, indicates that *lp points to an "otherchar". + * Turn the "header" into a string on its own. + */ + nl = JLI_StrPBrk(*lp, "\n\r"); + if (nl == NULL) { + nl = JLI_StrChr(*lp, (int)'\0'); + } else { + cp = nl; /* For merging continuation lines */ + if (*nl == '\r' && *(nl+1) == '\n') + *nl++ = '\0'; + *nl++ = '\0'; + + /* + * Process any "continuation" line(s), by making them part of the + * "header" line. Yes, I know that we are "undoing" the NULs we + * just placed here, but continuation lines are the fairly rare + * case, so we shouldn't unnecessarily complicate the code above. + * + * Note that an entire continuation line is processed each iteration + * through the outer while loop. + */ + while (*nl == ' ') { + nl++; /* First character to be moved */ + while (*nl != '\n' && *nl != '\r' && *nl != '\0') + *cp++ = *nl++; /* Shift string */ + if (*nl == '\0') + return (-1); /* Error: newline required */ + *cp = '\0'; + if (*nl == '\r' && *(nl+1) == '\n') + *nl++ = '\0'; + *nl++ = '\0'; + } + } + + /* + * Separate the name from the value; + */ + cp = JLI_StrChr(*lp, (int)':'); + if (cp == NULL) + return (-1); + *cp++ = '\0'; /* The colon terminates the name */ + if (*cp != ' ') + return (-1); + *cp++ = '\0'; /* Eat the required space */ + *name = *lp; + *value = cp; + *lp = nl; + return (1); +} + +/* + * Read the manifest from the specified jar file and fill in the manifest_info + * structure with the information found within. + * + * Error returns are as follows: + * 0 Success + * -1 Unable to open jarfile + * -2 Error accessing the manifest from within the jarfile (most likely + * a manifest is not present, or this isn't a valid zip/jar file). + */ +int +JLI_ParseManifest(char *jarfile, manifest_info *info) +{ + int fd; + zentry entry; + char *lp; + char *name; + char *value; + int rc; + char *splashscreen_name = NULL; + + if ((fd = open(jarfile, O_RDONLY +#ifdef O_LARGEFILE + | O_LARGEFILE /* large file mode */ +#endif +#ifdef O_BINARY + | O_BINARY /* use binary mode on windows */ +#endif + )) == -1) { + return (-1); + } + info->manifest_version = NULL; + info->main_class = NULL; + info->jre_version = NULL; + info->jre_restrict_search = 0; + info->splashscreen_image_file_name = NULL; + if (rc = find_file(fd, &entry, manifest_name) != 0) { + close(fd); + return (-2); + } + manifest = inflate_file(fd, &entry, NULL); + if (manifest == NULL) { + close(fd); + return (-2); + } + lp = manifest; + while ((rc = parse_nv_pair(&lp, &name, &value)) > 0) { + if (JLI_StrCaseCmp(name, "Manifest-Version") == 0) + info->manifest_version = value; + else if (JLI_StrCaseCmp(name, "Main-Class") == 0) + info->main_class = value; + else if (JLI_StrCaseCmp(name, "JRE-Version") == 0) + info->jre_version = value; + else if (JLI_StrCaseCmp(name, "JRE-Restrict-Search") == 0) { + if (JLI_StrCaseCmp(value, "true") == 0) + info->jre_restrict_search = 1; + } else if (JLI_StrCaseCmp(name, "Splashscreen-Image") == 0) { + info->splashscreen_image_file_name = value; + } + } + close(fd); + if (rc == 0) + return (0); + else + return (-2); +} + +/* + * Opens the jar file and unpacks the specified file from its contents. + * Returns NULL on failure. + */ +void * +JLI_JarUnpackFile(const char *jarfile, const char *filename, int *size) { + int fd; + zentry entry; + void *data = NULL; + + if ((fd = open(jarfile, O_RDONLY +#ifdef O_LARGEFILE + | O_LARGEFILE /* large file mode */ +#endif +#ifdef O_BINARY + | O_BINARY /* use binary mode on windows */ +#endif + )) == -1) { + return NULL; + } + if (find_file(fd, &entry, filename) == 0) { + data = inflate_file(fd, &entry, size); + } + close(fd); + return (data); +} + +/* + * Specialized "free" function. + */ +void +JLI_FreeManifest() +{ + if (manifest) + free(manifest); +} + +/* + * Iterate over the manifest of the specified jar file and invoke the provided + * closure function for each attribute encountered. + * + * Error returns are as follows: + * 0 Success + * -1 Unable to open jarfile + * -2 Error accessing the manifest from within the jarfile (most likely + * this means a manifest is not present, or it isn't a valid zip/jar file). + */ +int +JLI_ManifestIterate(const char *jarfile, attribute_closure ac, void *user_data) +{ + int fd; + zentry entry; + char *mp; /* manifest pointer */ + char *lp; /* pointer into manifest, updated during iteration */ + char *name; + char *value; + int rc; + + if ((fd = open(jarfile, O_RDONLY +#ifdef O_LARGEFILE + | O_LARGEFILE /* large file mode */ +#endif +#ifdef O_BINARY + | O_BINARY /* use binary mode on windows */ +#endif + )) == -1) { + return (-1); + } + + if (rc = find_file(fd, &entry, manifest_name) != 0) { + close(fd); + return (-2); + } + + mp = inflate_file(fd, &entry, NULL); + if (mp == NULL) { + close(fd); + return (-2); + } + + lp = mp; + while ((rc = parse_nv_pair(&lp, &name, &value)) > 0) { + (*ac)(name, value, user_data); + } + free(mp); + close(fd); + return (rc == 0) ? 0 : -2; +} diff --git a/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/splashscreen.h b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/splashscreen.h new file mode 100644 index 0000000..ff3b402 --- /dev/null +++ b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/splashscreen.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + + +int DoSplashLoadMemory(void* pdata, int size); /* requires preloading the file */ +int DoSplashLoadFile(const char* filename); +void DoSplashInit(void); +void DoSplashClose(void); +void DoSplashSetFileJarName(const char* fileName, const char* jarName); +void DoSplashSetScaleFactor(float scaleFactor); +char* DoSplashGetScaledImageName(const char* jarName, const char* fileName, + float* scaleFactor); diff --git a/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/splashscreen_stubs.c b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/splashscreen_stubs.c new file mode 100644 index 0000000..15b2e62 --- /dev/null +++ b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/splashscreen_stubs.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +#include +#include "splashscreen.h" + +extern void* SplashProcAddress(const char* name); /* in java_md.c */ + +/* + * Prototypes of pointers to functions in splashscreen shared lib + */ +typedef int (*SplashLoadMemory_t)(void* pdata, int size); +typedef int (*SplashLoadFile_t)(const char* filename); +typedef void (*SplashInit_t)(void); +typedef void (*SplashClose_t)(void); +typedef void (*SplashSetFileJarName_t)(const char* fileName, + const char* jarName); +typedef void (*SplashSetScaleFactor_t)(float scaleFactor); +typedef char* (*SplashGetScaledImageName_t)(const char* fileName, + const char* jarName, float* scaleFactor); + +/* + * This macro invokes a function from the shared lib. + * it locates a function with SplashProcAddress on demand. + * if SplashProcAddress fails, def value is returned. + * + * it is further wrapped with INVOKEV (works with functions which return + * void and INVOKE (for all other functions). INVOKEV looks a bit ugly, + * that's due being unable to return a value of type void in C. INVOKEV + * works around this by using semicolon instead of return operator. + */ +#define _INVOKE(name,def,ret) \ + static void* proc = NULL; \ + if (!proc) { proc = SplashProcAddress(#name); } \ + if (!proc) { return def; } \ + ret ((name##_t)proc) + +#define INVOKE(name,def) _INVOKE(name,def,return) +#define INVOKEV(name) _INVOKE(name, ,;) + +int DoSplashLoadMemory(void* pdata, int size) { + INVOKE(SplashLoadMemory, NULL)(pdata, size); +} + +int DoSplashLoadFile(const char* filename) { + INVOKE(SplashLoadFile, NULL)(filename); +} + +void DoSplashInit(void) { + INVOKEV(SplashInit)(); +} + +void DoSplashClose(void) { + INVOKEV(SplashClose)(); +} + +void DoSplashSetFileJarName(const char* fileName, const char* jarName) { + INVOKEV(SplashSetFileJarName)(fileName, jarName); +} + +void DoSplashSetScaleFactor(float scaleFactor) { + INVOKEV(SplashSetScaleFactor)(scaleFactor); +} + +char* DoSplashGetScaledImageName(const char* fileName, const char* jarName, + float* scaleFactor) { + INVOKE(SplashGetScaledImageName, NULL)(fileName, jarName, scaleFactor); +} \ No newline at end of file diff --git a/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/version_comp.c b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/version_comp.c new file mode 100644 index 0000000..d688796 --- /dev/null +++ b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/version_comp.c @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +#include +#include +#include +#include +#include "jni.h" +#include "jli_util.h" +#include "version_comp.h" + +/* + * A collection of useful strings. One should think of these as #define + * entries, but actual strings can be more efficient (with many compilers). + */ +static const char *separators = ".-_"; +static const char *zero_string = "0"; + +/* + * Validate a string as parsable as a "Java int". If so parsable, + * return true (non-zero) and store the numeric value at the address + * passed in as "value"; otherwise return false (zero). + * + * Note that the maximum allowable value is 2147483647 as defined by + * the "Java Language Specification" which precludes the use of native + * conversion routines which may have other limits. + * + * Also note that we don't have to worry about the alternate maximum + * allowable value of 2147483648 because it is only allowed after + * the unary negation operator and this grammar doesn't have one + * of those. + * + * Finally, note that a value which exceeds the maximum jint value will + * return false (zero). This results in the otherwise purely numeric + * string being compared as a string of characters (as per the spec.) + */ +static int +isjavaint(const char *s, jint *value) +{ + jlong sum = 0; + jint digit; + while (*s != '\0') + if (isdigit(*s)) { + digit = (jint)((int)(*s++) - (int)('0')); + sum = (sum * 10) + digit; + if (sum > 2147483647) + return (0); /* Overflows jint (but not jlong) */ + } else + return (0); + *value = (jint)sum; + return (1); +} + +/* + * Modeled after strcmp(), compare two strings (as in the grammar defined + * in Appendix A of JSR 56). If both strings can be interpreted as + * Java ints, do a numeric comparison, else it is strcmp(). + */ +static int +comp_string(const char *s1, const char *s2) +{ + jint v1, v2; + if (isjavaint(s1, &v1) && isjavaint(s2, &v2)) + return ((int)(v1 - v2)); + else + return (JLI_StrCmp(s1, s2)); +} + +/* + * Modeled after strcmp(), compare two version-ids for a Prefix + * Match as defined in JSR 56. + */ +int +JLI_PrefixVersionId(const char *id1, char *id2) +{ + char *s1 = JLI_StringDup(id1); + char *s2 = JLI_StringDup(id2); + char *m1 = s1; + char *m2 = s2; + char *end1 = NULL; + char *end2 = NULL; + int res = 0; + + do { + + if ((s1 != NULL) && ((end1 = JLI_StrPBrk(s1, ".-_")) != NULL)) + *end1 = '\0'; + if ((s2 != NULL) && ((end2 = JLI_StrPBrk(s2, ".-_")) != NULL)) + *end2 = '\0'; + + res = comp_string(s1, s2); + + if (end1 != NULL) + s1 = end1 + 1; + else + s1 = NULL; + if (end2 != NULL) + s2 = end2 + 1; + else + s2 = NULL; + + } while (res == 0 && ((s1 != NULL) && (s2 != NULL))); + + JLI_MemFree(m1); + JLI_MemFree(m2); + return (res); +} + +/* + * Modeled after strcmp(), compare two version-ids for an Exact + * Match as defined in JSR 56. + */ +int +JLI_ExactVersionId(const char *id1, char *id2) +{ + char *s1 = JLI_StringDup(id1); + char *s2 = JLI_StringDup(id2); + char *m1 = s1; + char *m2 = s2; + char *end1 = NULL; + char *end2 = NULL; + int res = 0; + + do { + + if ((s1 != NULL) && ((end1 = JLI_StrPBrk(s1, separators)) != NULL)) + *end1 = '\0'; + if ((s2 != NULL) && ((end2 = JLI_StrPBrk(s2, separators)) != NULL)) + *end2 = '\0'; + + if ((s1 != NULL) && (s2 == NULL)) + res = comp_string(s1, zero_string); + else if ((s1 == NULL) && (s2 != NULL)) + res = comp_string(zero_string, s2); + else + res = comp_string(s1, s2); + + if (end1 != NULL) + s1 = end1 + 1; + else + s1 = NULL; + if (end2 != NULL) + s2 = end2 + 1; + else + s2 = NULL; + + } while (res == 0 && ((s1 != NULL) || (s2 != NULL))); + + JLI_MemFree(m1); + JLI_MemFree(m2); + return (res); +} + +/* + * Return true if this simple-element (as defined in JSR 56) forms + * an acceptable match. + * + * JSR 56 is modified by the Java Web Start Developer Guide + * where it is stated "... Java Web Start will not consider an installed + * non-FCS (i.e., milestone) JRE as a match. ... a JRE from Sun + * Microsystems, Inc., is by convention a non-FCS (milestone) JRE + * if there is a dash (-) in the version string." + * + * An undocumented caveat to the above is that an exact match with a + * hyphen is accepted as a development extension. + * + * These modifications are addressed by the specific comparisons + * for releases with hyphens. + */ +static int +acceptable_simple_element(const char *release, char *simple_element) +{ + char *modifier; + modifier = simple_element + JLI_StrLen(simple_element) - 1; + if (*modifier == '*') { + *modifier = '\0'; + if (JLI_StrChr(release, '-')) + return ((JLI_StrCmp(release, simple_element) == 0)?1:0); + return ((JLI_PrefixVersionId(release, simple_element) == 0)?1:0); + } else if (*modifier == '+') { + *modifier = '\0'; + if (JLI_StrChr(release, '-')) + return ((JLI_StrCmp(release, simple_element) == 0)?1:0); + return ((JLI_ExactVersionId(release, simple_element) >= 0)?1:0); + } else { + return ((JLI_ExactVersionId(release, simple_element) == 0)?1:0); + } +} + +/* + * Return true if this element (as defined in JSR 56) forms + * an acceptable match. An element is the intersection (and) + * of multiple simple-elements. + */ +static int +acceptable_element(const char *release, char *element) +{ + char *end; + do { + if ((end = JLI_StrChr(element, '&')) != NULL) + *end = '\0'; + if (!acceptable_simple_element(release, element)) + return (0); + if (end != NULL) + element = end + 1; + } while (end != NULL); + return (1); +} + +/* + * Checks if release is acceptable by the specification version-string. + * Return true if this version-string (as defined in JSR 56) forms + * an acceptable match. A version-string is the union (or) of multiple + * elements. + */ +int +JLI_AcceptableRelease(const char *release, char *version_string) +{ + char *vs; + char *m1; + char *end; + m1 = vs = JLI_StringDup(version_string); + do { + if ((end = JLI_StrChr(vs, ' ')) != NULL) + *end = '\0'; + if (acceptable_element(release, vs)) { + JLI_MemFree(m1); + return (1); + } + if (end != NULL) + vs = end + 1; + } while (end != NULL); + JLI_MemFree(m1); + return (0); +} + +/* + * Return true if this is a valid simple-element (as defined in JSR 56). + * + * The official grammar for a simple-element is: + * + * simple-element ::= version-id | version-id modifier + * modifier ::= '+' | '*' + * version-id ::= string ( separator string )* + * string ::= char ( char )* + * char ::= Any ASCII character except a space, an + * ampersand, a separator or a modifier + * separator ::= '.' | '-' | '_' + * + * However, for efficiency, it is time to abandon the top down parser + * implementation. After deleting the potential trailing modifier, we + * are left with a version-id. + * + * Note that a valid version-id has three simple properties: + * + * 1) Doesn't contain a space, an ampersand or a modifier. + * + * 2) Doesn't begin or end with a separator. + * + * 3) Doesn't contain two adjacent separators. + * + * Any other line noise constitutes a valid version-id. + */ +static int +valid_simple_element(char *simple_element) +{ + char *last; + size_t len; + + if ((simple_element == NULL) || ((len = JLI_StrLen(simple_element)) == 0)) + return (0); + last = simple_element + len - 1; + if (*last == '*' || *last == '+') { + if (--len == 0) + return (0); + *last-- = '\0'; + } + if (JLI_StrPBrk(simple_element, " &+*") != NULL) /* Property #1 */ + return (0); + if ((JLI_StrChr(".-_", *simple_element) != NULL) || /* Property #2 */ + (JLI_StrChr(".-_", *last) != NULL)) + return (0); + for (; simple_element != last; simple_element++) /* Property #3 */ + if ((JLI_StrChr(".-_", *simple_element) != NULL) && + (JLI_StrChr(".-_", *(simple_element + 1)) != NULL)) + return (0); + return (1); +} + +/* + * Return true if this is a valid element (as defined in JSR 56). + * An element is the intersection (and) of multiple simple-elements. + */ +static int +valid_element(char *element) +{ + char *end; + if ((element == NULL) || (JLI_StrLen(element) == 0)) + return (0); + do { + if ((end = JLI_StrChr(element, '&')) != NULL) + *end = '\0'; + if (!valid_simple_element(element)) + return (0); + if (end != NULL) + element = end + 1; + } while (end != NULL); + return (1); +} + +/* + * Validates a version string by the extended JSR 56 grammar. + */ +int +JLI_ValidVersionString(char *version_string) +{ + char *vs; + char *m1; + char *end; + if ((version_string == NULL) || (JLI_StrLen(version_string) == 0)) + return (0); + m1 = vs = JLI_StringDup(version_string); + do { + if ((end = JLI_StrChr(vs, ' ')) != NULL) + *end = '\0'; + if (!valid_element(vs)) { + JLI_MemFree(m1); + return (0); + } + if (end != NULL) + vs = end + 1; + } while (end != NULL); + JLI_MemFree(m1); + return (1); +} diff --git a/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/version_comp.h b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/version_comp.h new file mode 100644 index 0000000..f50ab34 --- /dev/null +++ b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/version_comp.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +#ifndef _VERSION_COMP_H +#define _VERSION_COMP_H + +/* + * Function prototypes. + */ +int JLI_ExactVersionId(const char *id1, char *id2); +int JLI_PrefixVersionId(const char *id1, char *id2); +int JLI_AcceptableRelease(const char *release, char *version_string); +int JLI_ValidVersionString(char *version_string); + +#endif /* _VERSION_COMP_H */ diff --git a/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/wildcard.c b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/wildcard.c new file mode 100644 index 0000000..c3dc646 --- /dev/null +++ b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/wildcard.c @@ -0,0 +1,501 @@ +/* + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * Class-Path Wildcards + * + * The syntax for wildcards is a single asterisk. The class path + * foo/"*", e.g., loads all jar files in the directory named foo. + * (This requires careful quotation when used in shell scripts.) + * + * Only files whose names end in .jar or .JAR are matched. + * Files whose names end in .zip, or which have a particular + * magic number, regardless of filename extension, are not + * matched. + * + * Files are considered regardless of whether or not they are + * "hidden" in the UNIX sense, i.e., have names beginning with '.'. + * + * A wildcard only matches jar files, not class files in the same + * directory. If you want to load both class files and jar files from + * a single directory foo then you can say foo:foo/"*", or foo/"*":foo + * if you want the jar files to take precedence. + * + * Subdirectories are not searched recursively, i.e., foo/"*" only + * looks for jar files in foo, not in foo/bar, foo/baz, etc. + * + * Expansion of wildcards is done early, prior to the invocation of a + * program's main method, rather than late, during the class-loading + * process itself. Each element of the input class path containing a + * wildcard is replaced by the (possibly empty) sequence of elements + * generated by enumerating the jar files in the named directory. If + * the directory foo contains a.jar, b.jar, and c.jar, + * e.g., then the class path foo/"*" is expanded into + * foo/a.jar:foo/b.jar:foo/c.jar, and that string would be the value + * of the system property java.class.path. + * + * The order in which the jar files in a directory are enumerated in + * the expanded class path is not specified and may vary from platform + * to platform and even from moment to moment on the same machine. A + * well-constructed application should not depend upon any particular + * order. If a specific order is required then the jar files can be + * enumerated explicitly in the class path. + * + * The CLASSPATH environment variable is not treated any differently + * from the -classpath (equiv. -cp) command-line option, + * i.e. wildcards are honored in all these cases. + * + * Class-path wildcards are not honored in the Class-Path jar-manifest + * header. + * + * Class-path wildcards are honored not only by the Java launcher but + * also by most other command-line tools that accept class paths, and + * in particular by javac and javadoc. + * + * Class-path wildcards are not honored in any other kind of path, and + * especially not in the bootstrap class path, which is a mere + * artifact of our implementation and not something that developers + * should use. + * + * Classpath wildcards are only expanded in the Java launcher code, + * supporting the use of wildcards on the command line and in the + * CLASSPATH environment variable. We do not support the use of + * wildcards by applications that embed the JVM. + */ + +#include +#include +#include +#include +#include +#include "java.h" /* Strictly for PATH_SEPARATOR/FILE_SEPARATOR */ +#include "jli_util.h" + +#ifdef _WIN32 +#include +#else /* Unix */ +#include +#include +#endif /* Unix */ + +static int +exists(const char* filename) +{ +#ifdef _WIN32 + return _access(filename, 0) == 0; +#else + return access(filename, F_OK) == 0; +#endif +} + +#define NEW_(TYPE) ((TYPE) JLI_MemAlloc(sizeof(struct TYPE##_))) + +/* + * Wildcard directory iteration. + * WildcardIterator_for(wildcard) returns an iterator. + * Each call to that iterator's next() method returns the basename + * of an entry in the wildcard's directory. The basename's memory + * belongs to the iterator. The caller is responsible for prepending + * the directory name and file separator, if necessary. + * When done with the iterator, call the close method to clean up. + */ +typedef struct WildcardIterator_* WildcardIterator; + +#ifdef _WIN32 +struct WildcardIterator_ +{ + HANDLE handle; + char *firstFile; /* Stupid FindFirstFile...FindNextFile */ +}; +// since this is used repeatedly we keep it here. +static WIN32_FIND_DATA find_data; +static WildcardIterator +WildcardIterator_for(const char *wildcard) +{ + WildcardIterator it = NEW_(WildcardIterator); + HANDLE handle = FindFirstFile(wildcard, &find_data); + if (handle == INVALID_HANDLE_VALUE) { + JLI_MemFree(it); + return NULL; + } + it->handle = handle; + it->firstFile = find_data.cFileName; + return it; +} + +static char * +WildcardIterator_next(WildcardIterator it) +{ + if (it->firstFile != NULL) { + char *firstFile = it->firstFile; + it->firstFile = NULL; + return firstFile; + } + return FindNextFile(it->handle, &find_data) + ? find_data.cFileName : NULL; +} + +static void +WildcardIterator_close(WildcardIterator it) +{ + if (it) { + FindClose(it->handle); + JLI_MemFree(it->firstFile); + JLI_MemFree(it); + } +} + +#else /* Unix */ +struct WildcardIterator_ +{ + DIR *dir; +}; + +static WildcardIterator +WildcardIterator_for(const char *wildcard) +{ + DIR *dir; + int wildlen = JLI_StrLen(wildcard); + if (wildlen < 2) { + dir = opendir("."); + } else { + char *dirname = JLI_StringDup(wildcard); + dirname[wildlen - 1] = '\0'; + dir = opendir(dirname); + JLI_MemFree(dirname); + } + if (dir == NULL) + return NULL; + else { + WildcardIterator it = NEW_(WildcardIterator); + it->dir = dir; + return it; + } +} + +static char * +WildcardIterator_next(WildcardIterator it) +{ + struct dirent* dirp = readdir(it->dir); + return dirp ? dirp->d_name : NULL; +} + +static void +WildcardIterator_close(WildcardIterator it) +{ + if (it) { + closedir(it->dir); + JLI_MemFree(it); + } +} +#endif /* Unix */ + +static int +equal(const char *s1, const char *s2) +{ + return JLI_StrCmp(s1, s2) == 0; +} + +/* + * FileList ADT - a dynamic list of C filenames + */ +struct FileList_ +{ + char **files; + int size; + int capacity; +}; +typedef struct FileList_ *FileList; + +static FileList +FileList_new(int capacity) +{ + FileList fl = NEW_(FileList); + fl->capacity = capacity; + fl->files = (char **) JLI_MemAlloc(capacity * sizeof(fl->files[0])); + fl->size = 0; + return fl; +} + + + +static void +FileList_free(FileList fl) +{ + if (fl) { + if (fl->files) { + int i; + for (i = 0; i < fl->size; i++) + JLI_MemFree(fl->files[i]); + JLI_MemFree(fl->files); + } + JLI_MemFree(fl); + } +} + +static void +FileList_ensureCapacity(FileList fl, int capacity) +{ + if (fl->capacity < capacity) { + while (fl->capacity < capacity) + fl->capacity *= 2; + fl->files = JLI_MemRealloc(fl->files, + fl->capacity * sizeof(fl->files[0])); + } +} + +static void +FileList_add(FileList fl, char *file) +{ + FileList_ensureCapacity(fl, fl->size+1); + fl->files[fl->size++] = file; +} + +static void +FileList_addSubstring(FileList fl, const char *beg, int len) +{ + char *filename = (char *) JLI_MemAlloc(len+1); + memcpy(filename, beg, len); + filename[len] = '\0'; + FileList_ensureCapacity(fl, fl->size+1); + fl->files[fl->size++] = filename; +} + +static char * +FileList_join(FileList fl, char sep) +{ + int i; + int size; + char *path; + char *p; + for (i = 0, size = 1; i < fl->size; i++) + size += (int)JLI_StrLen(fl->files[i]) + 1; + + path = JLI_MemAlloc(size); + + for (i = 0, p = path; i < fl->size; i++) { + int len = (int)JLI_StrLen(fl->files[i]); + if (i > 0) *p++ = sep; + memcpy(p, fl->files[i], len); + p += len; + } + *p = '\0'; + + return path; +} + +static FileList +FileList_split(const char *path, char sep) +{ + const char *p, *q; + int len = (int)JLI_StrLen(path); + int count; + FileList fl; + for (count = 1, p = path; p < path + len; p++) + count += (*p == sep); + fl = FileList_new(count); + for (p = path;;) { + for (q = p; q <= path + len; q++) { + if (*q == sep || *q == '\0') { + FileList_addSubstring(fl, p, q - p); + if (*q == '\0') + return fl; + p = q + 1; + } + } + } +} + +static int +isJarFileName(const char *filename) +{ + int len = (int)JLI_StrLen(filename); + return (len >= 4) && + (filename[len - 4] == '.') && + (equal(filename + len - 3, "jar") || + equal(filename + len - 3, "JAR")) && + /* Paranoia: Maybe filename is "DIR:foo.jar" */ + (JLI_StrChr(filename, PATH_SEPARATOR) == NULL); +} + +static char * +wildcardConcat(const char *wildcard, const char *basename) +{ + int wildlen = (int)JLI_StrLen(wildcard); + int baselen = (int)JLI_StrLen(basename); + char *filename = (char *) JLI_MemAlloc(wildlen + baselen); + /* Replace the trailing '*' with basename */ + memcpy(filename, wildcard, wildlen-1); + memcpy(filename+wildlen-1, basename, baselen+1); + return filename; +} + +static FileList +wildcardFileList(const char *wildcard) +{ + const char *basename; + FileList fl = FileList_new(16); + WildcardIterator it = WildcardIterator_for(wildcard); + + if (it == NULL) + { + FileList_free(fl); + return NULL; + } + + while ((basename = WildcardIterator_next(it)) != NULL) + if (isJarFileName(basename)) + FileList_add(fl, wildcardConcat(wildcard, basename)); + WildcardIterator_close(it); + return fl; +} + +static int +isWildcard(const char *filename) +{ + int len = (int)JLI_StrLen(filename); + return (len > 0) && + (filename[len - 1] == '*') && + (len == 1 || IS_FILE_SEPARATOR(filename[len - 2])) && + (! exists(filename)); +} + +static void +FileList_expandWildcards(FileList fl) +{ + int i, j; + for (i = 0; i < fl->size; i++) { + if (isWildcard(fl->files[i])) { + FileList expanded = wildcardFileList(fl->files[i]); + if (expanded != NULL && expanded->size > 0) { + JLI_MemFree(fl->files[i]); + FileList_ensureCapacity(fl, fl->size + expanded->size); + for (j = fl->size - 1; j >= i+1; j--) + fl->files[j+expanded->size-1] = fl->files[j]; + for (j = 0; j < expanded->size; j++) + fl->files[i+j] = expanded->files[j]; + i += expanded->size - 1; + fl->size += expanded->size - 1; + /* fl expropriates expanded's elements. */ + expanded->size = 0; + } + FileList_free(expanded); + } + } +} + +const char * +JLI_WildcardExpandClasspath(const char *classpath) +{ + char *expanded; + FileList fl; + + if (JLI_StrChr(classpath, '*') == NULL) + return classpath; + fl = FileList_split(classpath, PATH_SEPARATOR); + FileList_expandWildcards(fl); + expanded = FileList_join(fl, PATH_SEPARATOR); + FileList_free(fl); + if (getenv(JLDEBUG_ENV_ENTRY) != 0) + printf("Expanded wildcards:\n" + " before: \"%s\"\n" + " after : \"%s\"\n", + classpath, expanded); + return expanded; +} + +#ifdef DEBUG_WILDCARD +static void +FileList_print(FileList fl) +{ + int i; + putchar('['); + for (i = 0; i < fl->size; i++) { + if (i > 0) printf(", "); + printf("\"%s\"",fl->files[i]); + } + putchar(']'); +} + +static void +wildcardExpandArgv(const char ***argv) +{ + int i; + for (i = 0; (*argv)[i]; i++) { + if (equal((*argv)[i], "-cp") || + equal((*argv)[i], "-classpath")) { + i++; + (*argv)[i] = wildcardExpandClasspath((*argv)[i]); + } + } +} + +static void +debugPrintArgv(char *argv[]) +{ + int i; + putchar('['); + for (i = 0; argv[i]; i++) { + if (i > 0) printf(", "); + printf("\"%s\"", argv[i]); + } + printf("]\n"); +} + +int +main(int argc, char *argv[]) +{ + argv[0] = "java"; + wildcardExpandArgv((const char***)&argv); + debugPrintArgv(argv); + /* execvp("java", argv); */ + return 0; +} +#endif /* DEBUG_WILDCARD */ + +/* Cute little perl prototype implementation.... + +my $sep = ($^O =~ /^(Windows|cygwin)/) ? ";" : ":"; + +sub expand($) { + opendir DIR, $_[0] or return $_[0]; + join $sep, map {"$_[0]/$_"} grep {/\.(jar|JAR)$/} readdir DIR; +} + +sub munge($) { + join $sep, + map {(! -r $_ and s/[\/\\]+\*$//) ? expand $_ : $_} split $sep, $_[0]; +} + +for (my $i = 0; $i < @ARGV - 1; $i++) { + $ARGV[$i+1] = munge $ARGV[$i+1] if $ARGV[$i] =~ /^-c(p|lasspath)$/; +} + +$ENV{CLASSPATH} = munge $ENV{CLASSPATH} if exists $ENV{CLASSPATH}; +@ARGV = ("java", @ARGV); +print "@ARGV\n"; +exec @ARGV; + +*/ diff --git a/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/wildcard.h b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/wildcard.h new file mode 100644 index 0000000..1f1aba9 --- /dev/null +++ b/SearchFramework1.0.1/out/production/jdk1.8.0_131/launcher/wildcard.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +#ifndef WILDCARD_H_ +#define WILDCARD_H_ + +const char *JLI_WildcardExpandClasspath(const char *classpath); + +#endif /* include guard */ diff --git a/SearchFramework1.0.1/out/test/SearchFramework1.0.1/xu/problem/pathfinding/PathFeederTest.class b/SearchFramework1.0.1/out/test/SearchFramework1.0.1/xu/problem/pathfinding/PathFeederTest.class new file mode 100644 index 0000000..147bdfc Binary files /dev/null and b/SearchFramework1.0.1/out/test/SearchFramework1.0.1/xu/problem/pathfinding/PathFeederTest.class differ diff --git a/SearchFramework1.0.1/out/test/SearchFramework1.0.1/xu/problem/pathfinding/PathFindingTest.class b/SearchFramework1.0.1/out/test/SearchFramework1.0.1/xu/problem/pathfinding/PathFindingTest.class new file mode 100644 index 0000000..6e6801a Binary files /dev/null and b/SearchFramework1.0.1/out/test/SearchFramework1.0.1/xu/problem/pathfinding/PathFindingTest.class differ diff --git a/SearchFramework1.0.1/out/test/SearchFramework1.0.1/xu/problem/pathfinding/PositionTest.class b/SearchFramework1.0.1/out/test/SearchFramework1.0.1/xu/problem/pathfinding/PositionTest.class new file mode 100644 index 0000000..55e9b21 Binary files /dev/null and b/SearchFramework1.0.1/out/test/SearchFramework1.0.1/xu/problem/pathfinding/PositionTest.class differ diff --git a/SearchFramework1.0.1/out/test/SearchFramework1.0.1/xu/solver/heuristic/LinkedFrontierTest.class b/SearchFramework1.0.1/out/test/SearchFramework1.0.1/xu/solver/heuristic/LinkedFrontierTest.class new file mode 100644 index 0000000..f598b29 Binary files /dev/null and b/SearchFramework1.0.1/out/test/SearchFramework1.0.1/xu/solver/heuristic/LinkedFrontierTest.class differ diff --git a/SearchFramework1.0.1/resources/pathfinding.txt b/SearchFramework1.0.1/resources/pathfinding.txt new file mode 100644 index 0000000..802047f --- /dev/null +++ b/SearchFramework1.0.1/resources/pathfinding.txt @@ -0,0 +1,4 @@ +3 5 0 8 4 2 1 7 3 6 1 2 3 4 5 6 7 8 0 +3 6 4 7 8 5 0 3 2 1 1 2 3 4 5 6 7 8 0 +3 8 6 7 2 5 4 3 0 1 1 2 3 4 5 6 7 8 0 +4 8 13 0 6 1 15 9 14 3 4 5 11 7 2 10 12 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 \ No newline at end of file diff --git a/SearchFramework1.0.1/src/META-INF/MANIFEST.MF b/SearchFramework1.0.1/src/META-INF/MANIFEST.MF new file mode 100644 index 0000000..8b6e977 --- /dev/null +++ b/SearchFramework1.0.1/src/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: runner.SearchRunner + diff --git a/SearchFramework1.0.1/src/algs4/util/In.java b/SearchFramework1.0.1/src/algs4/util/In.java new file mode 100644 index 0000000..3d1c060 --- /dev/null +++ b/SearchFramework1.0.1/src/algs4/util/In.java @@ -0,0 +1,819 @@ +package algs4.util; + +/****************************************************************************** + * Compilation: javac In.java + * Execution: java In (basic test --- see source for required files) + * Dependencies: none + * + * Reads in data of various types from standard input, files, and URLs. + * + ******************************************************************************/ + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.Socket; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.InputMismatchException; +import java.util.Locale; +import java.util.NoSuchElementException; +import java.util.Scanner; +import java.util.regex.Pattern; + +/** + * Input. This class provides methods for reading strings + * and numbers from standard input, file input, URLs, and sockets. + *

+ * The Locale used is: language = English, country = US. This is consistent + * with the formatting conventions with Java floating-point literals, + * command-line arguments (via {@link Double#parseDouble(String)}) + * and standard output. + *

+ * For additional documentation, see + * Section 3.1 of + * Computer Science: An Interdisciplinary Approach + * by Robert Sedgewick and Kevin Wayne. + *

+ * Like {@link Scanner}, reading a token also consumes preceding Java + * whitespace, reading a full line consumes + * the following end-of-line delimeter, while reading a character consumes + * nothing extra. + *

+ * Whitespace is defined in {@link Character#isWhitespace(char)}. Newlines + * consist of \n, \r, \r\n, and Unicode hex code points 0x2028, 0x2029, 0x0085; + * see + * Scanner.java (NB: Java 6u23 and earlier uses only \r, \r, \r\n). + * + * @author David Pritchard + * @author Robert Sedgewick + * @author Kevin Wayne + */ +public final class In { + + ///// begin: section (1 of 2) of code duplicated from In to StdIn. + + // assume Unicode UTF-8 encoding + private static final String CHARSET_NAME = "UTF-8"; + + // assume language = English, country = US for consistency with System.out. + private static final Locale LOCALE = Locale.US; + + // the default token separator; we maintain the invariant that this value + // is held by the scanner's delimiter between calls + private static final Pattern WHITESPACE_PATTERN = Pattern.compile("\\p{javaWhitespace}+"); + + // makes whitespace characters significant + private static final Pattern EMPTY_PATTERN = Pattern.compile(""); + + // used to read the entire input. source: + // http://weblogs.java.net/blog/pat/archive/2004/10/stupid_scanner_1.html + private static final Pattern EVERYTHING_PATTERN = Pattern.compile("\\A"); + + //// end: section (1 of 2) of code duplicated from In to StdIn. + + private Scanner scanner; + + /** + * Initializes an input stream from standard input. + */ + public In() { + scanner = new Scanner(new BufferedInputStream(System.in), CHARSET_NAME); + scanner.useLocale(LOCALE); + } + + /** + * Initializes an input stream from a socket. + * + * @param socket the socket + * @throws IllegalArgumentException if cannot open {@code socket} + * @throws IllegalArgumentException if {@code socket} is {@code null} + */ + public In(Socket socket) { + if (socket == null) throw new IllegalArgumentException("socket argument is null"); + try { + InputStream is = socket.getInputStream(); + scanner = new Scanner(new BufferedInputStream(is), CHARSET_NAME); + scanner.useLocale(LOCALE); + } + catch (IOException ioe) { + throw new IllegalArgumentException("Could not open " + socket, ioe); + } + } + + /** + * Initializes an input stream from a URL. + * + * @param url the URL + * @throws IllegalArgumentException if cannot open {@code url} + * @throws IllegalArgumentException if {@code url} is {@code null} + */ + public In(URL url) { + if (url == null) throw new IllegalArgumentException("url argument is null"); + try { + URLConnection site = url.openConnection(); + InputStream is = site.getInputStream(); + scanner = new Scanner(new BufferedInputStream(is), CHARSET_NAME); + scanner.useLocale(LOCALE); + } + catch (IOException ioe) { + throw new IllegalArgumentException("Could not open " + url, ioe); + } + } + + /** + * Initializes an input stream from a file. + * + * @param file the file + * @throws IllegalArgumentException if cannot open {@code file} + * @throws IllegalArgumentException if {@code file} is {@code null} + */ + public In(File file) { + if (file == null) throw new IllegalArgumentException("file argument is null"); + try { + // for consistency with StdIn, wrap with BufferedInputStream instead of use + // file as argument to Scanner + FileInputStream fis = new FileInputStream(file); + scanner = new Scanner(new BufferedInputStream(fis), CHARSET_NAME); + scanner.useLocale(LOCALE); + } + catch (IOException ioe) { + throw new IllegalArgumentException("Could not open " + file, ioe); + } + } + + + /** + * Initializes an input stream from a filename or web page name. + * + * @param name the filename or web page name + * @throws IllegalArgumentException if cannot open {@code name} as + * a file or URL + * @throws IllegalArgumentException if {@code name} is {@code null} + */ + public In(String name) { + if (name == null) throw new IllegalArgumentException("argument is null"); + if (name.length() == 0) throw new IllegalArgumentException("argument is the empty string"); + try { + // first try to read file from local file system + File file = new File(name); + if (file.exists()) { + // for consistency with StdIn, wrap with BufferedInputStream instead of use + // file as argument to Scanner + FileInputStream fis = new FileInputStream(file); + scanner = new Scanner(new BufferedInputStream(fis), CHARSET_NAME); + scanner.useLocale(LOCALE); + return; + } + + // resource relative to .class file + URL url = getClass().getResource(name); + + // resource relative to classloader root + if (url == null) { + url = getClass().getClassLoader().getResource(name); + } + + // or URL from web + if (url == null) { + url = new URL(name); + } + + URLConnection site = url.openConnection(); + + // in order to set User-Agent, replace above line with these two + // HttpURLConnection site = (HttpURLConnection) url.openConnection(); + // site.addRequestProperty("User-Agent", "Mozilla/4.76"); + + InputStream is = site.getInputStream(); + scanner = new Scanner(new BufferedInputStream(is), CHARSET_NAME); + scanner.useLocale(LOCALE); + } + catch (IOException ioe) { + throw new IllegalArgumentException("Could not open " + name, ioe); + } + } + + /** + * Initializes an input stream from a given {@link Scanner} source; use with + * {@code new Scanner(String)} to read from a string. + *

+ * Note that this does not create a defensive copy, so the + * scanner will be mutated as you read on. + * + * @param scanner the scanner + * @throws IllegalArgumentException if {@code scanner} is {@code null} + */ + public In(Scanner scanner) { + if (scanner == null) throw new IllegalArgumentException("scanner argument is null"); + this.scanner = scanner; + } + + /** + * Returns true if this input stream exists. + * + * @return {@code true} if this input stream exists; {@code false} otherwise + */ + public boolean exists() { + return scanner != null; + } + + //// begin: section (2 of 2) of code duplicated from In to StdIn, + //// with all methods changed from "public" to "public static". + + /** + * Returns true if input stream is empty (except possibly whitespace). + * Use this to know whether the next call to {@link #readString()}, + * {@link #readDouble()}, etc will succeed. + * + * @return {@code true} if this input stream is empty (except possibly whitespace); + * {@code false} otherwise + */ + public boolean isEmpty() { + return !scanner.hasNext(); + } + + /** + * Returns true if this input stream has a next line. + * Use this method to know whether the + * next call to {@link #readLine()} will succeed. + * This method is functionally equivalent to {@link #hasNextChar()}. + * + * @return {@code true} if this input stream has more input (including whitespace); + * {@code false} otherwise + */ + public boolean hasNextLine() { + return scanner.hasNextLine(); + } + + /** + * Returns true if this input stream has more input (including whitespace). + * Use this method to know whether the next call to {@link #readChar()} will succeed. + * This method is functionally equivalent to {@link #hasNextLine()}. + * + * @return {@code true} if this input stream has more input (including whitespace); + * {@code false} otherwise + */ + public boolean hasNextChar() { + scanner.useDelimiter(EMPTY_PATTERN); + boolean result = scanner.hasNext(); + scanner.useDelimiter(WHITESPACE_PATTERN); + return result; + } + + + /** + * Reads and returns the next line in this input stream. + * + * @return the next line in this input stream; {@code null} if no such line + */ + public String readLine() { + String line; + try { + line = scanner.nextLine(); + } + catch (NoSuchElementException e) { + line = null; + } + return line; + } + + /** + * Reads and returns the next character in this input stream. + * + * @return the next {@code char} in this input stream + * @throws NoSuchElementException if the input stream is empty + */ + public char readChar() { + scanner.useDelimiter(EMPTY_PATTERN); + try { + String ch = scanner.next(); + assert ch.length() == 1 : "Internal (Std)In.readChar() error!" + + " Please contact the authors."; + scanner.useDelimiter(WHITESPACE_PATTERN); + return ch.charAt(0); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attempts to read a 'char' value from the input stream, " + + "but no more tokens are available"); + } + } + + + /** + * Reads and returns the remainder of this input stream, as a string. + * + * @return the remainder of this input stream, as a string + */ + public String readAll() { + if (!scanner.hasNextLine()) + return ""; + + String result = scanner.useDelimiter(EVERYTHING_PATTERN).next(); + // not that important to reset delimeter, since now scanner is empty + scanner.useDelimiter(WHITESPACE_PATTERN); // but let's do it anyway + return result; + } + + + /** + * Reads the next token from this input stream and returns it as a {@code String}. + * + * @return the next {@code String} in this input stream + * @throws NoSuchElementException if the input stream is empty + */ + public String readString() { + try { + return scanner.next(); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attempts to read a 'String' value from the input stream, " + + "but no more tokens are available"); + } + } + + /** + * Reads the next token from this input stream, parses it as a {@code int}, + * and returns the {@code int}. + * + * @return the next {@code int} in this input stream + * @throws NoSuchElementException if the input stream is empty + * @throws InputMismatchException if the next token cannot be parsed as an {@code int} + */ + public int readInt() { + try { + return scanner.nextInt(); + } + catch (InputMismatchException e) { + String token = scanner.next(); + throw new InputMismatchException("attempts to read an 'int' value from the input stream, " + + "but the next token is \"" + token + "\""); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attemps to read an 'int' value from the input stream, " + + "but no more tokens are available"); + } + } + + /** + * Reads the next token from this input stream, parses it as a {@code double}, + * and returns the {@code double}. + * + * @return the next {@code double} in this input stream + * @throws NoSuchElementException if the input stream is empty + * @throws InputMismatchException if the next token cannot be parsed as a {@code double} + */ + public double readDouble() { + try { + return scanner.nextDouble(); + } + catch (InputMismatchException e) { + String token = scanner.next(); + throw new InputMismatchException("attempts to read a 'double' value from the input stream, " + + "but the next token is \"" + token + "\""); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attemps to read a 'double' value from the input stream, " + + "but no more tokens are available"); + } + } + + /** + * Reads the next token from this input stream, parses it as a {@code float}, + * and returns the {@code float}. + * + * @return the next {@code float} in this input stream + * @throws NoSuchElementException if the input stream is empty + * @throws InputMismatchException if the next token cannot be parsed as a {@code float} + */ + public float readFloat() { + try { + return scanner.nextFloat(); + } + catch (InputMismatchException e) { + String token = scanner.next(); + throw new InputMismatchException("attempts to read a 'float' value from the input stream, " + + "but the next token is \"" + token + "\""); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attemps to read a 'float' value from the input stream, " + + "but no more tokens are available"); + } + } + + /** + * Reads the next token from this input stream, parses it as a {@code long}, + * and returns the {@code long}. + * + * @return the next {@code long} in this input stream + * @throws NoSuchElementException if the input stream is empty + * @throws InputMismatchException if the next token cannot be parsed as a {@code long} + */ + public long readLong() { + try { + return scanner.nextLong(); + } + catch (InputMismatchException e) { + String token = scanner.next(); + throw new InputMismatchException("attempts to read a 'long' value from the input stream, " + + "but the next token is \"" + token + "\""); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attemps to read a 'long' value from the input stream, " + + "but no more tokens are available"); + } + } + + /** + * Reads the next token from this input stream, parses it as a {@code short}, + * and returns the {@code short}. + * + * @return the next {@code short} in this input stream + * @throws NoSuchElementException if the input stream is empty + * @throws InputMismatchException if the next token cannot be parsed as a {@code short} + */ + public short readShort() { + try { + return scanner.nextShort(); + } + catch (InputMismatchException e) { + String token = scanner.next(); + throw new InputMismatchException("attempts to read a 'short' value from the input stream, " + + "but the next token is \"" + token + "\""); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attemps to read a 'short' value from the input stream, " + + "but no more tokens are available"); + } + } + + /** + * Reads the next token from this input stream, parses it as a {@code byte}, + * and returns the {@code byte}. + *

+ * To read binary data, use {@link BinaryIn}. + * + * @return the next {@code byte} in this input stream + * @throws NoSuchElementException if the input stream is empty + * @throws InputMismatchException if the next token cannot be parsed as a {@code byte} + */ + public byte readByte() { + try { + return scanner.nextByte(); + } + catch (InputMismatchException e) { + String token = scanner.next(); + throw new InputMismatchException("attempts to read a 'byte' value from the input stream, " + + "but the next token is \"" + token + "\""); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attemps to read a 'byte' value from the input stream, " + + "but no more tokens are available"); + } + } + + /** + * Reads the next token from this input stream, parses it as a {@code boolean} + * (interpreting either {@code "true"} or {@code "1"} as {@code true}, + * and either {@code "false"} or {@code "0"} as {@code false}). + * + * @return the next {@code boolean} in this input stream + * @throws NoSuchElementException if the input stream is empty + * @throws InputMismatchException if the next token cannot be parsed as a {@code boolean} + */ + public boolean readBoolean() { + try { + String token = readString(); + if ("true".equalsIgnoreCase(token)) return true; + if ("false".equalsIgnoreCase(token)) return false; + if ("1".equals(token)) return true; + if ("0".equals(token)) return false; + throw new InputMismatchException("attempts to read a 'boolean' value from the input stream, " + + "but the next token is \"" + token + "\""); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attempts to read a 'boolean' value from the input stream, " + + "but no more tokens are available"); + } + } + + /** + * Reads all remaining tokens from this input stream and returns them as + * an array of strings. + * + * @return all remaining tokens in this input stream, as an array of strings + */ + public String[] readAllStrings() { + // we could use readAll.trim().split(), but that's not consistent + // since trim() uses characters 0x00..0x20 as whitespace + String[] tokens = WHITESPACE_PATTERN.split(readAll()); + if (tokens.length == 0 || tokens[0].length() > 0) + return tokens; + String[] decapitokens = new String[tokens.length-1]; + for (int i = 0; i < tokens.length-1; i++) + decapitokens[i] = tokens[i+1]; + return decapitokens; + } + + /** + * Reads all remaining lines from this input stream and returns them as + * an array of strings. + * + * @return all remaining lines in this input stream, as an array of strings + */ + public String[] readAllLines() { + ArrayList lines = new ArrayList(); + while (hasNextLine()) { + lines.add(readLine()); + } + return lines.toArray(new String[lines.size()]); + } + + + /** + * Reads all remaining tokens from this input stream, parses them as integers, + * and returns them as an array of integers. + * + * @return all remaining lines in this input stream, as an array of integers + */ + public int[] readAllInts() { + String[] fields = readAllStrings(); + int[] vals = new int[fields.length]; + for (int i = 0; i < fields.length; i++) + vals[i] = Integer.parseInt(fields[i]); + return vals; + } + + /** + * Reads all remaining tokens from this input stream, parses them as longs, + * and returns them as an array of longs. + * + * @return all remaining lines in this input stream, as an array of longs + */ + public long[] readAllLongs() { + String[] fields = readAllStrings(); + long[] vals = new long[fields.length]; + for (int i = 0; i < fields.length; i++) + vals[i] = Long.parseLong(fields[i]); + return vals; + } + + /** + * Reads all remaining tokens from this input stream, parses them as doubles, + * and returns them as an array of doubles. + * + * @return all remaining lines in this input stream, as an array of doubles + */ + public double[] readAllDoubles() { + String[] fields = readAllStrings(); + double[] vals = new double[fields.length]; + for (int i = 0; i < fields.length; i++) + vals[i] = Double.parseDouble(fields[i]); + return vals; + } + + ///// end: section (2 of 2) of code duplicated from In to StdIn */ + + /** + * Closes this input stream. + */ + public void close() { + scanner.close(); + } + + /** + * Reads all integers from a file and returns them as + * an array of integers. + * + * @param filename the name of the file + * @return the integers in the file + * @deprecated Replaced by {@code new In(filename)}.{@link #readAllInts()}. + */ + @Deprecated + public static int[] readInts(String filename) { + return new In(filename).readAllInts(); + } + + /** + * Reads all doubles from a file and returns them as + * an array of doubles. + * + * @param filename the name of the file + * @return the doubles in the file + * @deprecated Replaced by {@code new In(filename)}.{@link #readAllDoubles()}. + */ + @Deprecated + public static double[] readDoubles(String filename) { + return new In(filename).readAllDoubles(); + } + + /** + * Reads all strings from a file and returns them as + * an array of strings. + * + * @param filename the name of the file + * @return the strings in the file + * @deprecated Replaced by {@code new In(filename)}.{@link #readAllStrings()}. + */ + @Deprecated + public static String[] readStrings(String filename) { + return new In(filename).readAllStrings(); + } + + /** + * Reads all integers from standard input and returns them + * an array of integers. + * + * @return the integers on standard input + * @deprecated Replaced by {@link StdIn#readAllInts()}. + */ + @Deprecated + public static int[] readInts() { + return new In().readAllInts(); + } + + /** + * Reads all doubles from standard input and returns them as + * an array of doubles. + * + * @return the doubles on standard input + * @deprecated Replaced by {@link StdIn#readAllDoubles()}. + */ + @Deprecated + public static double[] readDoubles() { + return new In().readAllDoubles(); + } + + /** + * Reads all strings from standard input and returns them as + * an array of strings. + * + * @return the strings on standard input + * @deprecated Replaced by {@link StdIn#readAllStrings()}. + */ + @Deprecated + public static String[] readStrings() { + return new In().readAllStrings(); + } + + /** + * Unit tests the {@code In} data type. + * + * @param args the command-line arguments + */ + public static void main(String[] args) { + In in; + String urlName = "https://introcs.cs.princeton.edu/java/stdlib/InTest.txt"; + + // read from a URL + System.out.println("readAll() from URL " + urlName); + System.out.println("---------------------------------------------------------------------------"); + try { + in = new In(urlName); + System.out.println(in.readAll()); + } + catch (IllegalArgumentException e) { + System.out.println(e); + } + System.out.println(); + + // read one line at a time from URL + System.out.println("readLine() from URL " + urlName); + System.out.println("---------------------------------------------------------------------------"); + try { + in = new In(urlName); + while (!in.isEmpty()) { + String s = in.readLine(); + System.out.println(s); + } + } + catch (IllegalArgumentException e) { + System.out.println(e); + } + System.out.println(); + + // read one string at a time from URL + System.out.println("readString() from URL " + urlName); + System.out.println("---------------------------------------------------------------------------"); + try { + in = new In(urlName); + while (!in.isEmpty()) { + String s = in.readString(); + System.out.println(s); + } + } + catch (IllegalArgumentException e) { + System.out.println(e); + } + System.out.println(); + + + // read one line at a time from file in current directory + System.out.println("readLine() from current directory"); + System.out.println("---------------------------------------------------------------------------"); + try { + in = new In("./InTest.txt"); + while (!in.isEmpty()) { + String s = in.readLine(); + System.out.println(s); + } + } + catch (IllegalArgumentException e) { + System.out.println(e); + } + System.out.println(); + + + // read one line at a time from file using relative path + System.out.println("readLine() from relative path"); + System.out.println("---------------------------------------------------------------------------"); + try { + in = new In("../stdlib/InTest.txt"); + while (!in.isEmpty()) { + String s = in.readLine(); + System.out.println(s); + } + } + catch (IllegalArgumentException e) { + System.out.println(e); + } + System.out.println(); + + // read one char at a time + System.out.println("readChar() from file"); + System.out.println("---------------------------------------------------------------------------"); + try { + in = new In("InTest.txt"); + while (!in.isEmpty()) { + char c = in.readChar(); + System.out.print(c); + } + } + catch (IllegalArgumentException e) { + System.out.println(e); + } + System.out.println(); + System.out.println(); + + // read one line at a time from absolute OS X / Linux path + System.out.println("readLine() from absolute OS X / Linux path"); + System.out.println("---------------------------------------------------------------------------"); + try { + in = new In("/n/fs/introcs/www/java/stdlib/InTest.txt"); + while (!in.isEmpty()) { + String s = in.readLine(); + System.out.println(s); + } + } + catch (IllegalArgumentException e) { + System.out.println(e); + } + System.out.println(); + + + // read one line at a time from absolute Windows path + System.out.println("readLine() from absolute Windows path"); + System.out.println("---------------------------------------------------------------------------"); + try { + in = new In("G:\\www\\introcs\\stdlib\\InTest.txt"); + while (!in.isEmpty()) { + String s = in.readLine(); + System.out.println(s); + } + System.out.println(); + } + catch (IllegalArgumentException e) { + System.out.println(e); + } + System.out.println(); + + } + +} + +/****************************************************************************** + * Copyright 2002-2020, Robert Sedgewick and Kevin Wayne. + * + * This file is part of algs4.jar, which accompanies the textbook + * + * Algorithms, 4th edition by Robert Sedgewick and Kevin Wayne, + * Addison-Wesley Professional, 2011, ISBN 0-321-57351-X. + * http://algs4.cs.princeton.edu + * + * + * algs4.jar is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * algs4.jar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with algs4.jar. If not, see http://www.gnu.org/licenses. + ******************************************************************************/ diff --git a/SearchFramework1.0.1/src/algs4/util/Out.java b/SearchFramework1.0.1/src/algs4/util/Out.java new file mode 100644 index 0000000..1ec583c --- /dev/null +++ b/SearchFramework1.0.1/src/algs4/util/Out.java @@ -0,0 +1,341 @@ +package algs4.util; +/****************************************************************************** + * Compilation: javac Out.java + * Execution: java Out + * Dependencies: none + * + * Writes data of various types to: stdout, file, or socket. + * + ******************************************************************************/ + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.net.Socket; +import java.util.Locale; + +/** + * This class provides methods for writing strings and numbers to + * various output streams, including standard output, file, and sockets. + *

+ * For additional documentation, see + * Section 3.1 of + * Computer Science: An Interdisciplinary Approach + * by Robert Sedgewick and Kevin Wayne. + * + * @author Robert Sedgewick + * @author Kevin Wayne + */ +public class Out { + + // force Unicode UTF-8 encoding; otherwise it's system dependent + private static final String CHARSET_NAME = "UTF-8"; + + // assume language = English, country = US for consistency with In + private static final Locale LOCALE = Locale.US; + + private PrintWriter out; + + /** + * Initializes an output stream from a {@link OutputStream}. + * + * @param os the {@code OutputStream} + */ + public Out(OutputStream os) { + try { + OutputStreamWriter osw = new OutputStreamWriter(os, CHARSET_NAME); + out = new PrintWriter(osw, true); + } + catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Initializes an output stream from standard output. + */ + public Out() { + this(System.out); + } + + /** + * Initializes an output stream from a socket. + * + * @param socket the socket + */ + public Out(Socket socket) { + try { + OutputStream os = socket.getOutputStream(); + OutputStreamWriter osw = new OutputStreamWriter(os, CHARSET_NAME); + out = new PrintWriter(osw, true); + } + catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Initializes an output stream from a file. + * + * @param filename the name of the file + */ + public Out(String filename) { + try { + OutputStream os = new FileOutputStream(filename); + OutputStreamWriter osw = new OutputStreamWriter(os, CHARSET_NAME); + out = new PrintWriter(osw, true); + } + catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Closes the output stream. + */ + public void close() { + out.close(); + } + + /** + * Terminates the current line by printing the line-separator string. + */ + public void println() { + out.println(); + } + + /** + * Prints an object to this output stream and then terminates the line. + * + * @param x the object to print + */ + public void println(Object x) { + out.println(x); + } + + /** + * Prints a boolean to this output stream and then terminates the line. + * + * @param x the boolean to print + */ + public void println(boolean x) { + out.println(x); + } + + /** + * Prints a character to this output stream and then terminates the line. + * + * @param x the character to print + */ + public void println(char x) { + out.println(x); + } + + /** + * Prints a double to this output stream and then terminates the line. + * + * @param x the double to print + */ + public void println(double x) { + out.println(x); + } + + /** + * Prints a float to this output stream and then terminates the line. + * + * @param x the float to print + */ + public void println(float x) { + out.println(x); + } + + /** + * Prints an integer to this output stream and then terminates the line. + * + * @param x the integer to print + */ + public void println(int x) { + out.println(x); + } + + /** + * Prints a long to this output stream and then terminates the line. + * + * @param x the long to print + */ + public void println(long x) { + out.println(x); + } + + /** + * Prints a byte to this output stream and then terminates the line. + *

+ * To write binary data, see {@link BinaryOut}. + * + * @param x the byte to print + */ + public void println(byte x) { + out.println(x); + } + + + + /** + * Flushes this output stream. + */ + public void print() { + out.flush(); + } + + /** + * Prints an object to this output stream and flushes this output stream. + * + * @param x the object to print + */ + public void print(Object x) { + out.print(x); + out.flush(); + } + + /** + * Prints a boolean to this output stream and flushes this output stream. + * + * @param x the boolean to print + */ + public void print(boolean x) { + out.print(x); + out.flush(); + } + + /** + * Prints a character to this output stream and flushes this output stream. + * + * @param x the character to print + */ + public void print(char x) { + out.print(x); + out.flush(); + } + + /** + * Prints a double to this output stream and flushes this output stream. + * + * @param x the double to print + */ + public void print(double x) { + out.print(x); + out.flush(); + } + + /** + * Prints a float to this output stream and flushes this output stream. + * + * @param x the float to print + */ + public void print(float x) { + out.print(x); + out.flush(); + } + + /** + * Prints an integer to this output stream and flushes this output stream. + * + * @param x the integer to print + */ + public void print(int x) { + out.print(x); + out.flush(); + } + + /** + * Prints a long integer to this output stream and flushes this output stream. + * + * @param x the long integer to print + */ + public void print(long x) { + out.print(x); + out.flush(); + } + + /** + * Prints a byte to this output stream and flushes this output stream. + * + * @param x the byte to print + */ + public void print(byte x) { + out.print(x); + out.flush(); + } + + /** + * Prints a formatted string to this output stream, using the specified format + * string and arguments, and then flushes this output stream. + * + * @param format the format string + * @param args the arguments accompanying the format string + */ + public void printf(String format, Object... args) { + out.printf(LOCALE, format, args); + out.flush(); + } + + /** + * Prints a formatted string to this output stream, using the specified + * locale, format string, and arguments, and then flushes this output stream. + * + * @param locale the locale + * @param format the format string + * @param args the arguments accompanying the format string + */ + public void printf(Locale locale, String format, Object... args) { + out.printf(locale, format, args); + out.flush(); + } + + + /** + * A test client. + * + * @param args the command-line arguments + */ + public static void main(String[] args) { + Out out; + + // write to stdout + out = new Out(); + out.println("Test 1"); + out.close(); + + // write to a file + out = new Out("test.txt"); + out.println("Test 2"); + out.close(); + } + +} + +/****************************************************************************** + * Copyright 2002-2020, Robert Sedgewick and Kevin Wayne. + * + * This file is part of algs4.jar, which accompanies the textbook + * + * Algorithms, 4th edition by Robert Sedgewick and Kevin Wayne, + * Addison-Wesley Professional, 2011, ISBN 0-321-57351-X. + * http://algs4.cs.princeton.edu + * + * + * algs4.jar is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * algs4.jar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with algs4.jar. If not, see http://www.gnu.org/licenses. + ******************************************************************************/ diff --git a/SearchFramework1.0.1/src/algs4/util/StdIn.java b/SearchFramework1.0.1/src/algs4/util/StdIn.java new file mode 100644 index 0000000..1123102 --- /dev/null +++ b/SearchFramework1.0.1/src/algs4/util/StdIn.java @@ -0,0 +1,696 @@ +/****************************************************************************** + * Compilation: javac StdIn.java + * Execution: java StdIn (interactive test of basic functionality) + * Dependencies: none + * + * Reads in data of various types from standard input. + * + ******************************************************************************/ + +package algs4.util; + +import java.util.ArrayList; +import java.util.InputMismatchException; +import java.util.Locale; +import java.util.NoSuchElementException; +import java.util.Scanner; +import java.util.regex.Pattern; + +/** + * The {@code StdIn} class provides static methods for reading strings + * and numbers from standard input. + * These functions fall into one of four categories: + *

    + *
  • those for reading individual tokens from standard input, one at a time, + * and converting each to a number, string, or boolean + *
  • those for reading characters from standard input, one at a time + *
  • those for reading lines from standard input, one at a time + *
  • those for reading a sequence of values of the same type from standard input, + * and returning the values in an array + *
+ *

+ * Generally, it is best not to mix functions from the different + * categories in the same program. + *

+ * Getting started. + * To use this class, you must have {@code StdIn.class} in your + * Java classpath. If you used our autoinstaller, you should be all set. + * Otherwise, either download + * stdlib.jar + * and add to your Java classpath or download + * StdIn.java + * and put a copy in your working directory. + *

+ * Reading tokens from standard input and converting to numbers and strings. + * You can use the following methods to read numbers, strings, and booleans + * from standard input one at a time: + *

    + *
  • {@link #isEmpty()} + *
  • {@link #readInt()} + *
  • {@link #readDouble()} + *
  • {@link #readString()} + *
  • {@link #readShort()} + *
  • {@link #readLong()} + *
  • {@link #readFloat()} + *
  • {@link #readByte()} + *
  • {@link #readBoolean()} + *
+ *

+ * The first method returns true if standard input has no more tokens. + * Each other method skips over any input that is whitespace. Then, it reads + * the next token and attempts to convert it into a value of the specified + * type. If it succeeds, it returns that value; otherwise, it + * throws an {@link InputMismatchException}. + *

+ * Whitespace includes spaces, tabs, and newlines; the full definition + * is inherited from {@link Character#isWhitespace(char)}. + * A token is a maximal sequence of non-whitespace characters. + * The precise rules for describing which tokens can be converted to + * integers and floating-point numbers are inherited from + * Scanner, + * using the locale {@link Locale#US}; the rules + * for floating-point numbers are slightly different + * from those in {@link Double#valueOf(String)}, + * but unlikely to be of concern to most programmers. + *

+ * As an example, the following code fragment reads integers from standard input, + * one at a time, and prints them one per line. + *

+ *  while (!StdIn.isEmpty()) {
+ *      double value = StdIn.readDouble();
+ *      StdOut.println(value);
+ *  }
+ *  
+ *

+ * Reading characters from standard input. + * You can use the following two methods to read characters from standard input one at a time: + *

    + *
  • {@link #hasNextChar()} + *
  • {@link #readChar()} + *
+ *

+ * The first method returns true if standard input has more input (including whitespace). + * The second method reads and returns the next character of input on standard + * input (possibly a whitespace character). + *

+ * As an example, the following code fragment reads characters from standard input, + * one character at a time, and prints it to standard output. + *

+ *  while (StdIn.hasNextChar()) {
+ *      char c = StdIn.readChar();
+ *      StdOut.print(c);
+ *  }
+ *  
+ *

+ * Reading lines from standard input. + * You can use the following two methods to read lines from standard input: + *

    + *
  • {@link #hasNextLine()} + *
  • {@link #readLine()} + *
+ *

+ * The first method returns true if standard input has more input (including whitespace). + * The second method reads and returns the remaining portion of + * the next line of input on standard input (possibly whitespace), + * discarding the trailing line separator. + *

+ * A line separator is defined to be one of the following strings: + * {@code \n} (Linux), {@code \r} (old Macintosh), + * {@code \r\n} (Windows), + * {@code \}{@code u2028}, {@code \}{@code u2029}, or {@code \}{@code u0085}. + *

+ * As an example, the following code fragment reads text from standard input, + * one line at a time, and prints it to standard output. + *

+ *  while (StdIn.hasNextLine()) {
+ *      String line = StdIn.readLine();
+ *      StdOut.println(line);
+ *  }
+ *  
+ *

+ * Reading a sequence of values of the same type from standard input. + * You can use the following methods to read a sequence numbers, strings, + * or booleans (all of the same type) from standard input: + *

    + *
  • {@link #readAllDoubles()} + *
  • {@link #readAllInts()} + *
  • {@link #readAllLongs()} + *
  • {@link #readAllStrings()} + *
  • {@link #readAllLines()} + *
  • {@link #readAll()} + *
+ *

+ * The first three methods read of all of remaining token on standard input + * and converts the tokens to values of + * the specified type, as in the corresponding + * {@code readDouble}, {@code readInt}, and {@code readString()} methods. + * The {@code readAllLines()} method reads all remaining lines on standard + * input and returns them as an array of strings. + * The {@code readAll()} method reads all remaining input on standard + * input and returns it as a string. + *

+ * As an example, the following code fragment reads all of the remaining + * tokens from standard input and returns them as an array of strings. + *

+ *  String[] words = StdIn.readAllStrings();
+ *  
+ *

+ * Differences with Scanner. + * {@code StdIn} and {@link Scanner} are both designed to parse + * tokens and convert them to primitive types and strings. + * The main differences are summarized below: + *

    + *
  • {@code StdIn} is a set of static methods and reads + * reads input from only standard input. It is suitable for use before + * a programmer knows about objects. + * See {@link In} for an object-oriented version that handles + * input from files, URLs, + * and sockets. + *
  • {@code StdIn} uses whitespace as the delimiter pattern + * that separates tokens. + * {@link Scanner} supports arbitrary delimiter patterns. + *
  • {@code StdIn} coerces the character-set encoding to UTF-8, + * which is the most widely used character encoding for Unicode. + *
  • {@code StdIn} coerces the locale to {@link Locale#US}, + * for consistency with {@link StdOut}, {@link Double#parseDouble(String)}, + * and floating-point literals. + *
  • {@code StdIn} has convenient methods for reading a single + * character; reading in sequences of integers, doubles, or strings; + * and reading in all of the remaining input. + *
+ *

+ * Historical note: {@code StdIn} preceded {@code Scanner}; when + * {@code Scanner} was introduced, this class was re-implemented to use {@code Scanner}. + *

+ * Using standard input. + * Standard input is a fundamental operating system abstraction on Mac OS X, + * Windows, and Linux. + * The methods in {@code StdIn} are blocking, which means that they + * will wait until you enter input on standard input. + * If your program has a loop that repeats until standard input is empty, + * you must signal that the input is finished. + * To do so, depending on your operating system and IDE, + * use either {@code } or {@code }, on its own line. + * If you are redirecting standard input from a file, you will not need + * to do anything to signal that the input is finished. + *

+ * Known bugs. + * Java's UTF-8 encoding does not recognize the optional + * byte-order mask. + * If the input begins with the optional byte-order mask, {@code StdIn} + * will have an extra character {@code \}{@code uFEFF} at the beginning. + *

+ * Reference. + * For additional documentation, + * see Section 1.5 of + * Computer Science: An Interdisciplinary Approach + * by Robert Sedgewick and Kevin Wayne. + * + * @author Robert Sedgewick + * @author Kevin Wayne + * @author David Pritchard + */ +public final class StdIn { + + /*** begin: section (1 of 2) of code duplicated from In to StdIn. */ + + // assume Unicode UTF-8 encoding + private static final String CHARSET_NAME = "UTF-8"; + + // assume language = English, country = US for consistency with System.out. + private static final Locale LOCALE = Locale.US; + + // the default token separator; we maintain the invariant that this value + // is held by the scanner's delimiter between calls + private static final Pattern WHITESPACE_PATTERN = Pattern.compile("\\p{javaWhitespace}+"); + + // makes whitespace significant + private static final Pattern EMPTY_PATTERN = Pattern.compile(""); + + // used to read the entire input + private static final Pattern EVERYTHING_PATTERN = Pattern.compile("\\A"); + + /*** end: section (1 of 2) of code duplicated from In to StdIn. */ + + private static Scanner scanner; + + // it doesn't make sense to instantiate this class + private StdIn() { } + + //// begin: section (2 of 2) of code duplicated from In to StdIn, + //// with all methods changed from "public" to "public static" + + /** + * Returns true if standard input is empty (except possibly for whitespace). + * Use this method to know whether the next call to {@link #readString()}, + * {@link #readDouble()}, etc will succeed. + * + * @return {@code true} if standard input is empty (except possibly + * for whitespace); {@code false} otherwise + */ + public static boolean isEmpty() { + return !scanner.hasNext(); + } + + /** + * Returns true if standard input has a next line. + * Use this method to know whether the + * next call to {@link #readLine()} will succeed. + * This method is functionally equivalent to {@link #hasNextChar()}. + * + * @return {@code true} if standard input has more input (including whitespace); + * {@code false} otherwise + */ + public static boolean hasNextLine() { + return scanner.hasNextLine(); + } + + /** + * Returns true if standard input has more input (including whitespace). + * Use this method to know whether the next call to {@link #readChar()} will succeed. + * This method is functionally equivalent to {@link #hasNextLine()}. + * + * @return {@code true} if standard input has more input (including whitespace); + * {@code false} otherwise + */ + public static boolean hasNextChar() { + scanner.useDelimiter(EMPTY_PATTERN); + boolean result = scanner.hasNext(); + scanner.useDelimiter(WHITESPACE_PATTERN); + return result; + } + + + /** + * Reads and returns the next line, excluding the line separator if present. + * + * @return the next line, excluding the line separator if present; + * {@code null} if no such line + */ + public static String readLine() { + String line; + try { + line = scanner.nextLine(); + } + catch (NoSuchElementException e) { + line = null; + } + return line; + } + + /** + * Reads and returns the next character. + * + * @return the next {@code char} + * @throws NoSuchElementException if standard input is empty + */ + public static char readChar() { + try { + scanner.useDelimiter(EMPTY_PATTERN); + String ch = scanner.next(); + assert ch.length() == 1 : "Internal (Std)In.readChar() error!" + + " Please contact the authors."; + scanner.useDelimiter(WHITESPACE_PATTERN); + return ch.charAt(0); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attempts to read a 'char' value from standard input, " + + "but no more tokens are available"); + } + } + + + /** + * Reads and returns the remainder of the input, as a string. + * + * @return the remainder of the input, as a string + * @throws NoSuchElementException if standard input is empty + */ + public static String readAll() { + if (!scanner.hasNextLine()) + return ""; + + String result = scanner.useDelimiter(EVERYTHING_PATTERN).next(); + // not that important to reset delimeter, since now scanner is empty + scanner.useDelimiter(WHITESPACE_PATTERN); // but let's do it anyway + return result; + } + + + /** + * Reads the next token from standard input and returns it as a {@code String}. + * + * @return the next {@code String} + * @throws NoSuchElementException if standard input is empty + */ + public static String readString() { + try { + return scanner.next(); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attempts to read a 'String' value from standard input, " + + "but no more tokens are available"); + } + } + + /** + * Reads the next token from standard input, parses it as an integer, and returns the integer. + * + * @return the next integer on standard input + * @throws NoSuchElementException if standard input is empty + * @throws InputMismatchException if the next token cannot be parsed as an {@code int} + */ + public static int readInt() { + try { + return scanner.nextInt(); + } + catch (InputMismatchException e) { + String token = scanner.next(); + throw new InputMismatchException("attempts to read an 'int' value from standard input, " + + "but the next token is \"" + token + "\""); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attemps to read an 'int' value from standard input, " + + "but no more tokens are available"); + } + + } + + /** + * Reads the next token from standard input, parses it as a double, and returns the double. + * + * @return the next double on standard input + * @throws NoSuchElementException if standard input is empty + * @throws InputMismatchException if the next token cannot be parsed as a {@code double} + */ + public static double readDouble() { + try { + return scanner.nextDouble(); + } + catch (InputMismatchException e) { + String token = scanner.next(); + throw new InputMismatchException("attempts to read a 'double' value from standard input, " + + "but the next token is \"" + token + "\""); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attempts to read a 'double' value from standard input, " + + "but no more tokens are available"); + } + } + + /** + * Reads the next token from standard input, parses it as a float, and returns the float. + * + * @return the next float on standard input + * @throws NoSuchElementException if standard input is empty + * @throws InputMismatchException if the next token cannot be parsed as a {@code float} + */ + public static float readFloat() { + try { + return scanner.nextFloat(); + } + catch (InputMismatchException e) { + String token = scanner.next(); + throw new InputMismatchException("attempts to read a 'float' value from standard input, " + + "but the next token is \"" + token + "\""); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attempts to read a 'float' value from standard input, " + + "but there no more tokens are available"); + } + } + + /** + * Reads the next token from standard input, parses it as a long integer, and returns the long integer. + * + * @return the next long integer on standard input + * @throws NoSuchElementException if standard input is empty + * @throws InputMismatchException if the next token cannot be parsed as a {@code long} + */ + public static long readLong() { + try { + return scanner.nextLong(); + } + catch (InputMismatchException e) { + String token = scanner.next(); + throw new InputMismatchException("attempts to read a 'long' value from standard input, " + + "but the next token is \"" + token + "\""); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attempts to read a 'long' value from standard input, " + + "but no more tokens are available"); + } + } + + /** + * Reads the next token from standard input, parses it as a short integer, and returns the short integer. + * + * @return the next short integer on standard input + * @throws NoSuchElementException if standard input is empty + * @throws InputMismatchException if the next token cannot be parsed as a {@code short} + */ + public static short readShort() { + try { + return scanner.nextShort(); + } + catch (InputMismatchException e) { + String token = scanner.next(); + throw new InputMismatchException("attempts to read a 'short' value from standard input, " + + "but the next token is \"" + token + "\""); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attempts to read a 'short' value from standard input, " + + "but no more tokens are available"); + } + } + + /** + * Reads the next token from standard input, parses it as a byte, and returns the byte. + * + * @return the next byte on standard input + * @throws NoSuchElementException if standard input is empty + * @throws InputMismatchException if the next token cannot be parsed as a {@code byte} + */ + public static byte readByte() { + try { + return scanner.nextByte(); + } + catch (InputMismatchException e) { + String token = scanner.next(); + throw new InputMismatchException("attempts to read a 'byte' value from standard input, " + + "but the next token is \"" + token + "\""); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attempts to read a 'byte' value from standard input, " + + "but no more tokens are available"); + } + } + + /** + * Reads the next token from standard input, parses it as a boolean, + * and returns the boolean. + * + * @return the next boolean on standard input + * @throws NoSuchElementException if standard input is empty + * @throws InputMismatchException if the next token cannot be parsed as a {@code boolean}: + * {@code true} or {@code 1} for true, and {@code false} or {@code 0} for false, + * ignoring case + */ + public static boolean readBoolean() { + try { + String token = readString(); + if ("true".equalsIgnoreCase(token)) return true; + if ("false".equalsIgnoreCase(token)) return false; + if ("1".equals(token)) return true; + if ("0".equals(token)) return false; + throw new InputMismatchException("attempts to read a 'boolean' value from standard input, " + + "but the next token is \"" + token + "\""); + } + catch (NoSuchElementException e) { + throw new NoSuchElementException("attempts to read a 'boolean' value from standard input, " + + "but no more tokens are available"); + } + + } + + /** + * Reads all remaining tokens from standard input and returns them as an array of strings. + * + * @return all remaining tokens on standard input, as an array of strings + */ + public static String[] readAllStrings() { + // we could use readAll.trim().split(), but that's not consistent + // because trim() uses characters 0x00..0x20 as whitespace + String[] tokens = WHITESPACE_PATTERN.split(readAll()); + if (tokens.length == 0 || tokens[0].length() > 0) + return tokens; + + // don't include first token if it is leading whitespace + String[] decapitokens = new String[tokens.length-1]; + for (int i = 0; i < tokens.length - 1; i++) + decapitokens[i] = tokens[i+1]; + return decapitokens; + } + + /** + * Reads all remaining lines from standard input and returns them as an array of strings. + * @return all remaining lines on standard input, as an array of strings + */ + public static String[] readAllLines() { + ArrayList lines = new ArrayList(); + while (hasNextLine()) { + lines.add(readLine()); + } + return lines.toArray(new String[lines.size()]); + } + + /** + * Reads all remaining tokens from standard input, parses them as integers, and returns + * them as an array of integers. + * @return all remaining integers on standard input, as an array + * @throws InputMismatchException if any token cannot be parsed as an {@code int} + */ + public static int[] readAllInts() { + String[] fields = readAllStrings(); + int[] vals = new int[fields.length]; + for (int i = 0; i < fields.length; i++) + vals[i] = Integer.parseInt(fields[i]); + return vals; + } + + /** + * Reads all remaining tokens from standard input, parses them as longs, and returns + * them as an array of longs. + * @return all remaining longs on standard input, as an array + * @throws InputMismatchException if any token cannot be parsed as a {@code long} + */ + public static long[] readAllLongs() { + String[] fields = readAllStrings(); + long[] vals = new long[fields.length]; + for (int i = 0; i < fields.length; i++) + vals[i] = Long.parseLong(fields[i]); + return vals; + } + + /** + * Reads all remaining tokens from standard input, parses them as doubles, and returns + * them as an array of doubles. + * @return all remaining doubles on standard input, as an array + * @throws InputMismatchException if any token cannot be parsed as a {@code double} + */ + public static double[] readAllDoubles() { + String[] fields = readAllStrings(); + double[] vals = new double[fields.length]; + for (int i = 0; i < fields.length; i++) + vals[i] = Double.parseDouble(fields[i]); + return vals; + } + + //// end: section (2 of 2) of code duplicated from In to StdIn + + + // do this once when StdIn is initialized + static { + resync(); + } + + /** + * If StdIn changes, use this to reinitialize the scanner. + */ + private static void resync() { + setScanner(new Scanner(new java.io.BufferedInputStream(System.in), CHARSET_NAME)); + } + + private static void setScanner(Scanner scanner) { + StdIn.scanner = scanner; + StdIn.scanner.useLocale(LOCALE); + } + + /** + * Reads all remaining tokens, parses them as integers, and returns + * them as an array of integers. + * @return all remaining integers, as an array + * @throws InputMismatchException if any token cannot be parsed as an {@code int} + * @deprecated Replaced by {@link #readAllInts()}. + */ + @Deprecated + public static int[] readInts() { + return readAllInts(); + } + + /** + * Reads all remaining tokens, parses them as doubles, and returns + * them as an array of doubles. + * @return all remaining doubles, as an array + * @throws InputMismatchException if any token cannot be parsed as a {@code double} + * @deprecated Replaced by {@link #readAllDoubles()}. + */ + @Deprecated + public static double[] readDoubles() { + return readAllDoubles(); + } + + /** + * Reads all remaining tokens and returns them as an array of strings. + * @return all remaining tokens, as an array of strings + * @deprecated Replaced by {@link #readAllStrings()}. + */ + @Deprecated + public static String[] readStrings() { + return readAllStrings(); + } + + + /** + * Interactive test of basic functionality. + * + * @param args the command-line arguments + */ + public static void main(String[] args) { + + StdOut.print("Type a string: "); + String s = StdIn.readString(); + StdOut.println("Your string was: " + s); + StdOut.println(); + + StdOut.print("Type an int: "); + int a = StdIn.readInt(); + StdOut.println("Your int was: " + a); + StdOut.println(); + + StdOut.print("Type a boolean: "); + boolean b = StdIn.readBoolean(); + StdOut.println("Your boolean was: " + b); + StdOut.println(); + + StdOut.print("Type a double: "); + double c = StdIn.readDouble(); + StdOut.println("Your double was: " + c); + StdOut.println(); + } + +} + +/****************************************************************************** + * Copyright 2002-2020, Robert Sedgewick and Kevin Wayne. + * + * This file is part of algs4.jar, which accompanies the textbook + * + * Algorithms, 4th edition by Robert Sedgewick and Kevin Wayne, + * Addison-Wesley Professional, 2011, ISBN 0-321-57351-X. + * http://algs4.cs.princeton.edu + * + * + * algs4.jar is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * algs4.jar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with algs4.jar. If not, see http://www.gnu.org/licenses. + ******************************************************************************/ diff --git a/SearchFramework1.0.1/src/algs4/util/StdOut.java b/SearchFramework1.0.1/src/algs4/util/StdOut.java new file mode 100644 index 0000000..04cd7dc --- /dev/null +++ b/SearchFramework1.0.1/src/algs4/util/StdOut.java @@ -0,0 +1,339 @@ +/****************************************************************************** + * Compilation: javac StdOut.java + * Execution: java StdOut + * Dependencies: none + * + * Writes data of various types to standard output. + * + ******************************************************************************/ + +package algs4.util; + +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.util.Locale; + +/** + * This class provides methods for printing strings and numbers to standard output. + *

+ * Getting started. + * To use this class, you must have {@code StdOut.class} in your + * Java classpath. If you used our autoinstaller, you should be all set. + * Otherwise, either download + * stdlib.jar + * and add to your Java classpath or download + * StdOut.java + * and put a copy in your working directory. + *

+ * Here is an example program that uses {@code StdOut}: + *

+ *   public class TestStdOut {
+ *       public static void main(String[] args) {
+ *           int a = 17;
+ *           int b = 23;
+ *           int sum = a + b;
+ *           StdOut.println("Hello, World");
+ *           StdOut.printf("%d + %d = %d\n", a, b, sum);
+ *       }
+ *   }
+ *  
+ *

+ * Differences with System.out. + * The behavior of {@code StdOut} is similar to that of {@link System#out}, + * but there are a few technical differences: + *

    + *
  • {@code StdOut} coerces the character-set encoding to UTF-8, + * which is a standard character encoding for Unicode. + *
  • {@code StdOut} coerces the locale to {@link Locale#US}, + * for consistency with {@link StdIn}, {@link Double#parseDouble(String)}, + * and floating-point literals. + *
  • {@code StdOut} flushes standard output after each call to + * {@code print()} so that text will appear immediately in the terminal. + *
+ *

+ * Reference. + * For additional documentation, + * see Section 1.5 of + * Computer Science: An Interdisciplinary Approach + * by Robert Sedgewick and Kevin Wayne. + * + * @author Robert Sedgewick + * @author Kevin Wayne + */ +public final class StdOut { + + // force Unicode UTF-8 encoding; otherwise it's system dependent + private static final String CHARSET_NAME = "UTF-8"; + + // assume language = English, country = US for consistency with StdIn + private static final Locale LOCALE = Locale.US; + + // send output here + private static PrintWriter out; + + // this is called before invoking any methods + static { + try { + out = new PrintWriter(new OutputStreamWriter(System.out, CHARSET_NAME), true); + } + catch (UnsupportedEncodingException e) { + System.out.println(e); + } + } + + // don't instantiate + private StdOut() { } + + /** + * Terminates the current line by printing the line-separator string. + */ + public static void println() { + out.println(); + } + + /** + * Prints an object to this output stream and then terminates the line. + * + * @param x the object to print + */ + public static void println(Object x) { + out.println(x); + } + + /** + * Prints a boolean to standard output and then terminates the line. + * + * @param x the boolean to print + */ + public static void println(boolean x) { + out.println(x); + } + + /** + * Prints a character to standard output and then terminates the line. + * + * @param x the character to print + */ + public static void println(char x) { + out.println(x); + } + + /** + * Prints a double to standard output and then terminates the line. + * + * @param x the double to print + */ + public static void println(double x) { + out.println(x); + } + + /** + * Prints an integer to standard output and then terminates the line. + * + * @param x the integer to print + */ + public static void println(float x) { + out.println(x); + } + + /** + * Prints an integer to standard output and then terminates the line. + * + * @param x the integer to print + */ + public static void println(int x) { + out.println(x); + } + + /** + * Prints a long to standard output and then terminates the line. + * + * @param x the long to print + */ + public static void println(long x) { + out.println(x); + } + + /** + * Prints a short integer to standard output and then terminates the line. + * + * @param x the short to print + */ + public static void println(short x) { + out.println(x); + } + + /** + * Prints a byte to standard output and then terminates the line. + *

+ * To write binary data, see {@link BinaryStdOut}. + * + * @param x the byte to print + */ + public static void println(byte x) { + out.println(x); + } + + /** + * Flushes standard output. + */ + public static void print() { + out.flush(); + } + + /** + * Prints an object to standard output and flushes standard output. + * + * @param x the object to print + */ + public static void print(Object x) { + out.print(x); + out.flush(); + } + + /** + * Prints a boolean to standard output and flushes standard output. + * + * @param x the boolean to print + */ + public static void print(boolean x) { + out.print(x); + out.flush(); + } + + /** + * Prints a character to standard output and flushes standard output. + * + * @param x the character to print + */ + public static void print(char x) { + out.print(x); + out.flush(); + } + + /** + * Prints a double to standard output and flushes standard output. + * + * @param x the double to print + */ + public static void print(double x) { + out.print(x); + out.flush(); + } + + /** + * Prints a float to standard output and flushes standard output. + * + * @param x the float to print + */ + public static void print(float x) { + out.print(x); + out.flush(); + } + + /** + * Prints an integer to standard output and flushes standard output. + * + * @param x the integer to print + */ + public static void print(int x) { + out.print(x); + out.flush(); + } + + /** + * Prints a long integer to standard output and flushes standard output. + * + * @param x the long integer to print + */ + public static void print(long x) { + out.print(x); + out.flush(); + } + + /** + * Prints a short integer to standard output and flushes standard output. + * + * @param x the short integer to print + */ + public static void print(short x) { + out.print(x); + out.flush(); + } + + /** + * Prints a byte to standard output and flushes standard output. + * + * @param x the byte to print + */ + public static void print(byte x) { + out.print(x); + out.flush(); + } + + /** + * Prints a formatted string to standard output, using the specified format + * string and arguments, and then flushes standard output. + * + * + * @param format the format string + * @param args the arguments accompanying the format string + */ + public static void printf(String format, Object... args) { + out.printf(LOCALE, format, args); + out.flush(); + } + + /** + * Prints a formatted string to standard output, using the locale and + * the specified format string and arguments; then flushes standard output. + * + * @param locale the locale + * @param format the format string + * @param args the arguments accompanying the format string + */ + public static void printf(Locale locale, String format, Object... args) { + out.printf(locale, format, args); + out.flush(); + } + + /** + * Unit tests some of the methods in {@code StdOut}. + * + * @param args the command-line arguments + */ + public static void main(String[] args) { + + // write to stdout + StdOut.println("Test"); + StdOut.println(17); + StdOut.println(true); + StdOut.printf("%.6f\n", 1.0/7.0); + } + +} + +/****************************************************************************** + * Copyright 2002-2020, Robert Sedgewick and Kevin Wayne. + * + * This file is part of algs4.jar, which accompanies the textbook + * + * Algorithms, 4th edition by Robert Sedgewick and Kevin Wayne, + * Addison-Wesley Professional, 2011, ISBN 0-321-57351-X. + * http://algs4.cs.princeton.edu + * + * + * algs4.jar is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * algs4.jar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with algs4.jar. If not, see http://www.gnu.org/licenses. + ******************************************************************************/ diff --git a/SearchFramework1.0.1/src/algs4/util/StdRandom.java b/SearchFramework1.0.1/src/algs4/util/StdRandom.java new file mode 100644 index 0000000..ac5c56c --- /dev/null +++ b/SearchFramework1.0.1/src/algs4/util/StdRandom.java @@ -0,0 +1,674 @@ +/****************************************************************************** + * Compilation: javac StdRandom.java + * Execution: java StdRandom + * Dependencies: StdOut.java + * + * A library of static methods to generate pseudo-random numbers from + * different distributions (bernoulli, uniform, gaussian, discrete, + * and exponential). Also includes a method for shuffling an array. + * + * + * % java StdRandom 5 + * seed = 1316600602069 + * 59 16.81826 true 8.83954 0 + * 32 91.32098 true 9.11026 0 + * 35 10.11874 true 8.95396 3 + * 92 32.88401 true 8.87089 0 + * 72 92.55791 true 9.46241 0 + * + * % java StdRandom 5 + * seed = 1316600616575 + * 96 60.17070 true 8.72821 0 + * 79 32.01607 true 8.58159 0 + * 81 59.49065 true 9.10423 1 + * 96 51.65818 true 9.02102 0 + * 99 17.55771 true 8.99762 0 + * + * % java StdRandom 5 1316600616575 + * seed = 1316600616575 + * 96 60.17070 true 8.72821 0 + * 79 32.01607 true 8.58159 0 + * 81 59.49065 true 9.10423 1 + * 96 51.65818 true 9.02102 0 + * 99 17.55771 true 8.99762 0 + * + * + * Remark + * ------ + * - Relies on randomness of nextDouble() method in java.util.Random + * to generate pseudo-random numbers in [0, 1). + * + * - This library allows you to set and get the pseudo-random number seed. + * + * - See http://www.honeylocust.com/RngPack/ for an industrial + * strength random number generator in Java. + * + ******************************************************************************/ + +package algs4.util; + +import java.util.Random; + +/** + * The {@code StdRandom} class provides static methods for generating + * random number from various discrete and continuous distributions, + * including uniform, Bernoulli, geometric, Gaussian, exponential, Pareto, + * Poisson, and Cauchy. It also provides method for shuffling an + * array or subarray and generating random permutations. + *

+ * By convention, all intervals are half open. For example, + * uniform(-1.0, 1.0) returns a random number between + * -1.0 (inclusive) and 1.0 (exclusive). + * Similarly, shuffle(a, lo, hi) shuffles the hi - lo + * elements in the array a[], starting at index lo + * (inclusive) and ending at index hi (exclusive). + *

+ * For additional documentation, + * see Section 2.2 of + * Computer Science: An Interdisciplinary Approach + * by Robert Sedgewick and Kevin Wayne. + * + * @author Robert Sedgewick + * @author Kevin Wayne + */ +public final class StdRandom { + + private static Random random; // pseudo-random number generator + private static long seed; // pseudo-random number generator seed + + // static initializer + static { + // this is how the seed was set in Java 1.4 + seed = System.currentTimeMillis(); + random = new Random(seed); + } + + // don't instantiate + private StdRandom() { } + + /** + * Sets the seed of the pseudo-random number generator. + * This method enables you to produce the same sequence of "random" + * number for each execution of the program. + * Ordinarily, you should call this method at most once per program. + * + * @param s the seed + */ + public static void setSeed(long s) { + seed = s; + random = new Random(seed); + } + + /** + * Returns the seed of the pseudo-random number generator. + * + * @return the seed + */ + public static long getSeed() { + return seed; + } + + /** + * Returns a random real number uniformly in [0, 1). + * + * @return a random real number uniformly in [0, 1) + */ + public static double uniform() { + return random.nextDouble(); + } + + /** + * Returns a random integer uniformly in [0, n). + * + * @param n number of possible integers + * @return a random integer uniformly between 0 (inclusive) and {@code n} (exclusive) + * @throws IllegalArgumentException if {@code n <= 0} + */ + public static int uniform(int n) { + if (n <= 0) throw new IllegalArgumentException("argument must be positive: " + n); + return random.nextInt(n); + } + + + /** + * Returns a random long integer uniformly in [0, n). + * + * @param n number of possible {@code long} integers + * @return a random long integer uniformly between 0 (inclusive) and {@code n} (exclusive) + * @throws IllegalArgumentException if {@code n <= 0} + */ + public static long uniform(long n) { + if (n <= 0L) throw new IllegalArgumentException("argument must be positive: " + n); + + // https://docs.oracle.com/javase/8/docs/api/java/util/Random.html#longs-long-long-long- + long r = random.nextLong(); + long m = n - 1; + + // power of two + if ((n & m) == 0L) { + return r & m; + } + + // reject over-represented candidates + long u = r >>> 1; + while (u + m - (r = u % n) < 0L) { + u = random.nextLong() >>> 1; + } + return r; + } + + /////////////////////////////////////////////////////////////////////////// + // STATIC METHODS BELOW RELY ON JAVA.UTIL.RANDOM ONLY INDIRECTLY VIA + // THE STATIC METHODS ABOVE. + /////////////////////////////////////////////////////////////////////////// + + /** + * Returns a random real number uniformly in [0, 1). + * + * @return a random real number uniformly in [0, 1) + * @deprecated Replaced by {@link #uniform()}. + */ + @Deprecated + public static double random() { + return uniform(); + } + + /** + * Returns a random integer uniformly in [a, b). + * + * @param a the left endpoint + * @param b the right endpoint + * @return a random integer uniformly in [a, b) + * @throws IllegalArgumentException if {@code b <= a} + * @throws IllegalArgumentException if {@code b - a >= Integer.MAX_VALUE} + */ + public static int uniform(int a, int b) { + if ((b <= a) || ((long) b - a >= Integer.MAX_VALUE)) { + throw new IllegalArgumentException("invalid range: [" + a + ", " + b + ")"); + } + return a + uniform(b - a); + } + + /** + * Returns a random real number uniformly in [a, b). + * + * @param a the left endpoint + * @param b the right endpoint + * @return a random real number uniformly in [a, b) + * @throws IllegalArgumentException unless {@code a < b} + */ + public static double uniform(double a, double b) { + if (!(a < b)) { + throw new IllegalArgumentException("invalid range: [" + a + ", " + b + ")"); + } + return a + uniform() * (b-a); + } + + /** + * Returns a random boolean from a Bernoulli distribution with success + * probability p. + * + * @param p the probability of returning {@code true} + * @return {@code true} with probability {@code p} and + * {@code false} with probability {@code 1 - p} + * @throws IllegalArgumentException unless {@code 0} ≤ {@code p} ≤ {@code 1.0} + */ + public static boolean bernoulli(double p) { + if (!(p >= 0.0 && p <= 1.0)) + throw new IllegalArgumentException("probability p must be between 0.0 and 1.0: " + p); + return uniform() < p; + } + + /** + * Returns a random boolean from a Bernoulli distribution with success + * probability 1/2. + * + * @return {@code true} with probability 1/2 and + * {@code false} with probability 1/2 + */ + public static boolean bernoulli() { + return bernoulli(0.5); + } + + /** + * Returns a random real number from a standard Gaussian distribution. + * + * @return a random real number from a standard Gaussian distribution + * (mean 0 and standard deviation 1). + */ + public static double gaussian() { + // use the polar form of the Box-Muller transform + double r, x, y; + do { + x = uniform(-1.0, 1.0); + y = uniform(-1.0, 1.0); + r = x*x + y*y; + } while (r >= 1 || r == 0); + return x * Math.sqrt(-2 * Math.log(r) / r); + + // Remark: y * Math.sqrt(-2 * Math.log(r) / r) + // is an independent random gaussian + } + + /** + * Returns a random real number from a Gaussian distribution with mean μ + * and standard deviation σ. + * + * @param mu the mean + * @param sigma the standard deviation + * @return a real number distributed according to the Gaussian distribution + * with mean {@code mu} and standard deviation {@code sigma} + */ + public static double gaussian(double mu, double sigma) { + return mu + sigma * gaussian(); + } + + /** + * Returns a random integer from a geometric distribution with success + * probability p. + * The integer represents the number of independent trials + * before the first success. + * + * @param p the parameter of the geometric distribution + * @return a random integer from a geometric distribution with success + * probability {@code p}; or {@code Integer.MAX_VALUE} if + * {@code p} is (nearly) equal to {@code 1.0}. + * @throws IllegalArgumentException unless {@code p >= 0.0} and {@code p <= 1.0} + */ + public static int geometric(double p) { + if (!(p >= 0)) { + throw new IllegalArgumentException("probability p must be greater than 0: " + p); + } + if (!(p <= 1.0)) { + throw new IllegalArgumentException("probability p must not be larger than 1: " + p); + } + // using algorithm given by Knuth + return (int) Math.ceil(Math.log(uniform()) / Math.log(1.0 - p)); + } + + /** + * Returns a random integer from a Poisson distribution with mean λ. + * + * @param lambda the mean of the Poisson distribution + * @return a random integer from a Poisson distribution with mean {@code lambda} + * @throws IllegalArgumentException unless {@code lambda > 0.0} and not infinite + */ + public static int poisson(double lambda) { + if (!(lambda > 0.0)) + throw new IllegalArgumentException("lambda must be positive: " + lambda); + if (Double.isInfinite(lambda)) + throw new IllegalArgumentException("lambda must not be infinite: " + lambda); + // using algorithm given by Knuth + // see http://en.wikipedia.org/wiki/Poisson_distribution + int k = 0; + double p = 1.0; + double expLambda = Math.exp(-lambda); + do { + k++; + p *= uniform(); + } while (p >= expLambda); + return k-1; + } + + /** + * Returns a random real number from the standard Pareto distribution. + * + * @return a random real number from the standard Pareto distribution + */ + public static double pareto() { + return pareto(1.0); + } + + /** + * Returns a random real number from a Pareto distribution with + * shape parameter α. + * + * @param alpha shape parameter + * @return a random real number from a Pareto distribution with shape + * parameter {@code alpha} + * @throws IllegalArgumentException unless {@code alpha > 0.0} + */ + public static double pareto(double alpha) { + if (!(alpha > 0.0)) + throw new IllegalArgumentException("alpha must be positive: " + alpha); + return Math.pow(1 - uniform(), -1.0/alpha) - 1.0; + } + + /** + * Returns a random real number from the Cauchy distribution. + * + * @return a random real number from the Cauchy distribution. + */ + public static double cauchy() { + return Math.tan(Math.PI * (uniform() - 0.5)); + } + + /** + * Returns a random integer from the specified discrete distribution. + * + * @param probabilities the probability of occurrence of each integer + * @return a random integer from a discrete distribution: + * {@code i} with probability {@code probabilities[i]} + * @throws IllegalArgumentException if {@code probabilities} is {@code null} + * @throws IllegalArgumentException if sum of array entries is not (very nearly) equal to {@code 1.0} + * @throws IllegalArgumentException unless {@code probabilities[i] >= 0.0} for each index {@code i} + */ + public static int discrete(double[] probabilities) { + if (probabilities == null) throw new IllegalArgumentException("argument array must not be null"); + double EPSILON = 1.0E-14; + double sum = 0.0; + for (int i = 0; i < probabilities.length; i++) { + if (!(probabilities[i] >= 0.0)) + throw new IllegalArgumentException("array entry " + i + " must be non-negative: " + probabilities[i]); + sum += probabilities[i]; + } + if (sum > 1.0 + EPSILON || sum < 1.0 - EPSILON) + throw new IllegalArgumentException("sum of array entries does not approximately equal 1.0: " + sum); + + // the for loop may not return a value when both r is (nearly) 1.0 and when the + // cumulative sum is less than 1.0 (as a result of floating-point roundoff error) + while (true) { + double r = uniform(); + sum = 0.0; + for (int i = 0; i < probabilities.length; i++) { + sum = sum + probabilities[i]; + if (sum > r) return i; + } + } + } + + /** + * Returns a random integer from the specified discrete distribution. + * + * @param frequencies the frequency of occurrence of each integer + * @return a random integer from a discrete distribution: + * {@code i} with probability proportional to {@code frequencies[i]} + * @throws IllegalArgumentException if {@code frequencies} is {@code null} + * @throws IllegalArgumentException if all array entries are {@code 0} + * @throws IllegalArgumentException if {@code frequencies[i]} is negative for any index {@code i} + * @throws IllegalArgumentException if sum of frequencies exceeds {@code Integer.MAX_VALUE} (231 - 1) + */ + public static int discrete(int[] frequencies) { + if (frequencies == null) throw new IllegalArgumentException("argument array must not be null"); + long sum = 0; + for (int i = 0; i < frequencies.length; i++) { + if (frequencies[i] < 0) + throw new IllegalArgumentException("array entry " + i + " must be non-negative: " + frequencies[i]); + sum += frequencies[i]; + } + if (sum == 0) + throw new IllegalArgumentException("at least one array entry must be positive"); + if (sum >= Integer.MAX_VALUE) + throw new IllegalArgumentException("sum of frequencies overflows an int"); + + // pick index i with probabilitity proportional to frequency + double r = uniform((int) sum); + sum = 0; + for (int i = 0; i < frequencies.length; i++) { + sum += frequencies[i]; + if (sum > r) return i; + } + + // can't reach here + assert false; + return -1; + } + + /** + * Returns a random real number from an exponential distribution + * with rate λ. + * + * @param lambda the rate of the exponential distribution + * @return a random real number from an exponential distribution with + * rate {@code lambda} + * @throws IllegalArgumentException unless {@code lambda > 0.0} + */ + public static double exp(double lambda) { + if (!(lambda > 0.0)) + throw new IllegalArgumentException("lambda must be positive: " + lambda); + return -Math.log(1 - uniform()) / lambda; + } + + /** + * Rearranges the elements of the specified array in uniformly random order. + * + * @param a the array to shuffle + * @throws IllegalArgumentException if {@code a} is {@code null} + */ + public static void shuffle(Object[] a) { + validateNotNull(a); + int n = a.length; + for (int i = 0; i < n; i++) { + int r = i + uniform(n-i); // between i and n-1 + Object temp = a[i]; + a[i] = a[r]; + a[r] = temp; + } + } + + /** + * Rearranges the elements of the specified array in uniformly random order. + * + * @param a the array to shuffle + * @throws IllegalArgumentException if {@code a} is {@code null} + */ + public static void shuffle(double[] a) { + validateNotNull(a); + int n = a.length; + for (int i = 0; i < n; i++) { + int r = i + uniform(n-i); // between i and n-1 + double temp = a[i]; + a[i] = a[r]; + a[r] = temp; + } + } + + /** + * Rearranges the elements of the specified array in uniformly random order. + * + * @param a the array to shuffle + * @throws IllegalArgumentException if {@code a} is {@code null} + */ + public static void shuffle(int[] a) { + validateNotNull(a); + int n = a.length; + for (int i = 0; i < n; i++) { + int r = i + uniform(n-i); // between i and n-1 + int temp = a[i]; + a[i] = a[r]; + a[r] = temp; + } + } + + /** + * Rearranges the elements of the specified array in uniformly random order. + * + * @param a the array to shuffle + * @throws IllegalArgumentException if {@code a} is {@code null} + */ + public static void shuffle(char[] a) { + validateNotNull(a); + int n = a.length; + for (int i = 0; i < n; i++) { + int r = i + uniform(n-i); // between i and n-1 + char temp = a[i]; + a[i] = a[r]; + a[r] = temp; + } + } + + /** + * Rearranges the elements of the specified subarray in uniformly random order. + * + * @param a the array to shuffle + * @param lo the left endpoint (inclusive) + * @param hi the right endpoint (exclusive) + * @throws IllegalArgumentException if {@code a} is {@code null} + * @throws IllegalArgumentException unless {@code (0 <= lo) && (lo < hi) && (hi <= a.length)} + * + */ + public static void shuffle(Object[] a, int lo, int hi) { + validateNotNull(a); + validateSubarrayIndices(lo, hi, a.length); + + for (int i = lo; i < hi; i++) { + int r = i + uniform(hi-i); // between i and hi-1 + Object temp = a[i]; + a[i] = a[r]; + a[r] = temp; + } + } + + /** + * Rearranges the elements of the specified subarray in uniformly random order. + * + * @param a the array to shuffle + * @param lo the left endpoint (inclusive) + * @param hi the right endpoint (exclusive) + * @throws IllegalArgumentException if {@code a} is {@code null} + * @throws IllegalArgumentException unless {@code (0 <= lo) && (lo < hi) && (hi <= a.length)} + */ + public static void shuffle(double[] a, int lo, int hi) { + validateNotNull(a); + validateSubarrayIndices(lo, hi, a.length); + + for (int i = lo; i < hi; i++) { + int r = i + uniform(hi-i); // between i and hi-1 + double temp = a[i]; + a[i] = a[r]; + a[r] = temp; + } + } + + /** + * Rearranges the elements of the specified subarray in uniformly random order. + * + * @param a the array to shuffle + * @param lo the left endpoint (inclusive) + * @param hi the right endpoint (exclusive) + * @throws IllegalArgumentException if {@code a} is {@code null} + * @throws IllegalArgumentException unless {@code (0 <= lo) && (lo < hi) && (hi <= a.length)} + */ + public static void shuffle(int[] a, int lo, int hi) { + validateNotNull(a); + validateSubarrayIndices(lo, hi, a.length); + + for (int i = lo; i < hi; i++) { + int r = i + uniform(hi-i); // between i and hi-1 + int temp = a[i]; + a[i] = a[r]; + a[r] = temp; + } + } + + /** + * Returns a uniformly random permutation of n elements. + * + * @param n number of elements + * @throws IllegalArgumentException if {@code n} is negative + * @return an array of length {@code n} that is a uniformly random permutation + * of {@code 0}, {@code 1}, ..., {@code n-1} + */ + public static int[] permutation(int n) { + if (n < 0) throw new IllegalArgumentException("n must be non-negative: " + n); + int[] perm = new int[n]; + for (int i = 0; i < n; i++) + perm[i] = i; + shuffle(perm); + return perm; + } + + /** + * Returns a uniformly random permutation of k of n elements. + * + * @param n number of elements + * @param k number of elements to select + * @throws IllegalArgumentException if {@code n} is negative + * @throws IllegalArgumentException unless {@code 0 <= k <= n} + * @return an array of length {@code k} that is a uniformly random permutation + * of {@code k} of the elements from {@code 0}, {@code 1}, ..., {@code n-1} + */ + public static int[] permutation(int n, int k) { + if (n < 0) throw new IllegalArgumentException("n must be non-negative: " + n); + if (k < 0 || k > n) throw new IllegalArgumentException("k must be between 0 and n: " + k); + int[] perm = new int[k]; + for (int i = 0; i < k; i++) { + int r = uniform(i+1); // between 0 and i + perm[i] = perm[r]; + perm[r] = i; + } + for (int i = k; i < n; i++) { + int r = uniform(i+1); // between 0 and i + if (r < k) perm[r] = i; + } + return perm; + } + + // throw an IllegalArgumentException if x is null + // (x can be of type Object[], double[], int[], ...) + private static void validateNotNull(Object x) { + if (x == null) { + throw new IllegalArgumentException("argument must not be null"); + } + } + + // throw an exception unless 0 <= lo <= hi <= length + private static void validateSubarrayIndices(int lo, int hi, int length) { + if (lo < 0 || hi > length || lo > hi) { + throw new IllegalArgumentException("subarray indices out of bounds: [" + lo + ", " + hi + ")"); + } + } + + /** + * Unit tests the methods in this class. + * + * @param args the command-line arguments + */ + public static void main(String[] args) { + int n = Integer.parseInt(args[0]); + if (args.length == 2) StdRandom.setSeed(Long.parseLong(args[1])); + double[] probabilities = { 0.5, 0.3, 0.1, 0.1 }; + int[] frequencies = { 5, 3, 1, 1 }; + String[] a = "A B C D E F G".split(" "); + + StdOut.println("seed = " + StdRandom.getSeed()); + for (int i = 0; i < n; i++) { + StdOut.printf("%2d ", uniform(100)); + StdOut.printf("%8.5f ", uniform(10.0, 99.0)); + StdOut.printf("%5b ", bernoulli(0.5)); + StdOut.printf("%7.5f ", gaussian(9.0, 0.2)); + StdOut.printf("%1d ", discrete(probabilities)); + StdOut.printf("%1d ", discrete(frequencies)); + StdOut.printf("%11d ", uniform(100000000000L)); + StdRandom.shuffle(a); + for (String s : a) + StdOut.print(s); + StdOut.println(); + } + } + +} + +/****************************************************************************** + * Copyright 2002-2020, Robert Sedgewick and Kevin Wayne. + * + * This file is part of algs4.jar, which accompanies the textbook + * + * Algorithms, 4th edition by Robert Sedgewick and Kevin Wayne, + * Addison-Wesley Professional, 2011, ISBN 0-321-57351-X. + * http://algs4.cs.princeton.edu + * + * + * algs4.jar is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * algs4.jar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with algs4.jar. If not, see http://www.gnu.org/licenses. + ******************************************************************************/ diff --git a/SearchFramework1.0.1/src/algs4/util/Stopwatch.java b/SearchFramework1.0.1/src/algs4/util/Stopwatch.java new file mode 100644 index 0000000..b8d228b --- /dev/null +++ b/SearchFramework1.0.1/src/algs4/util/Stopwatch.java @@ -0,0 +1,110 @@ +/****************************************************************************** + * Compilation: javac Stopwatch.java + * Execution: java Stopwatch n + * Dependencies: none + * + * A utility class to measure the running time (wall clock) of a program. + * + * % java8 Stopwatch 100000000 + * 6.666667e+11 0.5820 seconds + * 6.666667e+11 8.4530 seconds + * + ******************************************************************************/ + +package algs4.util; + +/** + * The {@code Stopwatch} data type is for measuring + * the time that elapses between the start and end of a + * programming task (wall-clock time). + * + * See {@link StopwatchCPU} for a version that measures CPU time. + * For additional documentation, + * see Section 1.4 of + * Algorithms, 4th Edition by Robert Sedgewick and Kevin Wayne. + * + * @author Robert Sedgewick + * @author Kevin Wayne + */ + + +public class Stopwatch { + + private final long start; + + /** + * Initializes a new stopwatch. + */ + public Stopwatch() { + start = System.currentTimeMillis(); + } + + + /** + * Returns the elapsed CPU time (in seconds) since the stopwatch was created. + * + * @return elapsed CPU time (in seconds) since the stopwatch was created + */ + public double elapsedTime() { + long now = System.currentTimeMillis(); + return (now - start) / 1000.0; + } + + + /** + * Unit tests the {@code Stopwatch} data type. + * Takes a command-line argument {@code n} and computes the + * sum of the square roots of the first {@code n} positive integers, + * first using {@code Math.sqrt()}, then using {@code Math.pow()}. + * It prints to standard output the sum and the amount of time to + * compute the sum. Note that the discrete sum can be approximated by + * an integral - the sum should be approximately 2/3 * (n^(3/2) - 1). + * + * @param args the command-line arguments + */ + public static void main(String[] args) { + int n = Integer.parseInt(args[0]); + + // sum of square roots of integers from 1 to n using Math.sqrt(x). + Stopwatch timer1 = new Stopwatch(); + double sum1 = 0.0; + for (int i = 1; i <= n; i++) { + sum1 += Math.sqrt(i); + } + double time1 = timer1.elapsedTime(); + StdOut.printf("%e (%.2f seconds)\n", sum1, time1); + + // sum of square roots of integers from 1 to n using Math.pow(x, 0.5). + Stopwatch timer2 = new Stopwatch(); + double sum2 = 0.0; + for (int i = 1; i <= n; i++) { + sum2 += Math.pow(i, 0.5); + } + double time2 = timer2.elapsedTime(); + StdOut.printf("%e (%.2f seconds)\n", sum2, time2); + } +} + +/****************************************************************************** + * Copyright 2002-2020, Robert Sedgewick and Kevin Wayne. + * + * This file is part of algs4.jar, which accompanies the textbook + * + * Algorithms, 4th edition by Robert Sedgewick and Kevin Wayne, + * Addison-Wesley Professional, 2011, ISBN 0-321-57351-X. + * http://algs4.cs.princeton.edu + * + * + * algs4.jar is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * algs4.jar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with algs4.jar. If not, see http://www.gnu.org/licenses. + ******************************************************************************/ diff --git a/SearchFramework1.0.1/src/algs4/util/StopwatchCPU.java b/SearchFramework1.0.1/src/algs4/util/StopwatchCPU.java new file mode 100644 index 0000000..4102749 --- /dev/null +++ b/SearchFramework1.0.1/src/algs4/util/StopwatchCPU.java @@ -0,0 +1,112 @@ +/****************************************************************************** + * Compilation: javac StopwatchCPU.java + * Execution: java StopwtachCPU n + * Dependencies: none + * + * A version of Stopwatch.java that measures CPU time on a single + * core or processor (instead of wall clock time). + * + * % java8 StopwatchCPU 100000000 + * 6.666667e+11 (1.05 seconds) + * 6.666667e+11 (7.50 seconds) + * + ******************************************************************************/ + +package algs4.util; + +import java.lang.management.ThreadMXBean; +import java.lang.management.ManagementFactory; + +/** + * The {@code StopwatchCPU} data type is for measuring + * the CPU time used during a programming task. + * + * See {@link Stopwatch} for a version that measures wall-clock time + * (the real time that elapses). + * + * @author Josh Hug + * @author Robert Sedgewick + * @author Kevin Wayne + */ + +public class StopwatchCPU { + private static final double NANOSECONDS_PER_SECOND = 1_000_000_000; + + private final ThreadMXBean threadTimer; + private final long start; + + /** + * Initializes a new stopwatch. + */ + public StopwatchCPU() { + threadTimer = ManagementFactory.getThreadMXBean(); + start = threadTimer.getCurrentThreadCpuTime(); + } + + /** + * Returns the elapsed CPU time (in seconds) since the stopwatch was created. + * + * @return elapsed CPU time (in seconds) since the stopwatch was created + */ + public double elapsedTime() { + long now = threadTimer.getCurrentThreadCpuTime(); + return (now - start) / NANOSECONDS_PER_SECOND; + } + + /** + * Unit tests the {@code StopwatchCPU} data type. + * Takes a command-line argument {@code n} and computes the + * sum of the square roots of the first {@code n} positive integers, + * first using {@code Math.sqrt()}, then using {@code Math.pow()}. + * It prints to standard output the sum and the amount of time to + * compute the sum. Note that the discrete sum can be approximated by + * an integral - the sum should be approximately 2/3 * (n^(3/2) - 1). + * + * @param args the command-line arguments + */ + public static void main(String[] args) { + int n = Integer.parseInt(args[0]); + + // sum of square roots of integers from 1 to n using Math.sqrt(x). + StopwatchCPU timer1 = new StopwatchCPU(); + double sum1 = 0.0; + for (int i = 1; i <= n; i++) { + sum1 += Math.sqrt(i); + } + double time1 = timer1.elapsedTime(); + StdOut.printf("%e (%.2f seconds)\n", sum1, time1); + + // sum of square roots of integers from 1 to n using Math.pow(x, 0.5). + StopwatchCPU timer2 = new StopwatchCPU(); + double sum2 = 0.0; + for (int i = 1; i <= n; i++) { + sum2 += Math.pow(i, 0.5); + } + double time2 = timer2.elapsedTime(); + StdOut.printf("%e (%.2f seconds)\n", sum2, time2); + } +} + +/****************************************************************************** + * Copyright 2002-2020, Robert Sedgewick and Kevin Wayne. + * + * This file is part of algs4.jar, which accompanies the textbook + * + * Algorithms, 4th edition by Robert Sedgewick and Kevin Wayne, + * Addison-Wesley Professional, 2011, ISBN 0-321-57351-X. + * http://algs4.cs.princeton.edu + * + * + * algs4.jar is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * algs4.jar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with algs4.jar. If not, see http://www.gnu.org/licenses. + ******************************************************************************/ diff --git a/SearchFramework1.0.1/src/core/problem/Action.java b/SearchFramework1.0.1/src/core/problem/Action.java new file mode 100644 index 0000000..757b6fe --- /dev/null +++ b/SearchFramework1.0.1/src/core/problem/Action.java @@ -0,0 +1,6 @@ +package core.problem; + +public abstract class Action { + public abstract void draw(); + public abstract int stepCost(); +} diff --git a/SearchFramework1.0.1/src/core/problem/Problem.java b/SearchFramework1.0.1/src/core/problem/Problem.java new file mode 100644 index 0000000..9499a33 --- /dev/null +++ b/SearchFramework1.0.1/src/core/problem/Problem.java @@ -0,0 +1,143 @@ +package core.problem; + +import core.solver.Node; +import core.solver.heuristic.Predictor; + +import java.util.ArrayList; +import java.util.Deque; + +/** + * 所有问题的抽象超类 + * initialState + * goal + */ +public abstract class Problem { + //成员变量 + protected State initialState; + protected State goal; + protected int size; //问题的规模:15-puzzle为4;寻路问题为Grid的边长;野人传教士为野人与传教士的人数 + + public Problem(State initialState, State goal) { + this.initialState = initialState; + this.goal = goal; + } + + public Problem(State initialState, State goal, int size) { + this(initialState, goal); + this.size = size; + } + + public State getInitialState() { + return initialState; + } + + public State getGoal() { + return goal; + } + + public int getSize() { + return size; + } + + public void setSize(int size) { + this.size = size; + } + + public void setInitialState(State initialState) { + this.initialState = initialState; + } + + public void setGoal(State goal) { + this.goal = goal; + } + + /** + * 当前问题是否有解 + * @return 有解,true; 无解,false + * + */ + public abstract boolean solvable(); + + /** + * 从初始状态产生搜索树的根节点 + * @param predictor 启发函数 + * @return 当前问题的根结点 + */ + public final Node root(Predictor predictor) { + + return new Node(initialState, null, null, + 0, predictor.heuristics(initialState, goal)); + } + + /** + * 生成node的所有合法的后继结点 + * @param parent 父结点 + * @param predictor 启发函数 + * + * @return parent结点的所有子结点 + */ + public final Iterable childNodes(Node parent, Predictor predictor) { + ArrayList nodes = new ArrayList<>(); + //父结点的状态 + State parentState = parent.getState(); + //对于parentState上所有可能的action,但有的不可行 + for (Action action : parentState.actions()){ + //如果父结点状态下的动作是可行的 + if (applicable(parentState, action)){ + //得到后继状态 + State state = parentState.next(action); + //计算路径长度 = 父结点路径长度 + 进入后继状态所采取的动作的代价 + int pathCost = parent.getPathCost() + stepCost(state, action); + //使用predictor对state与goal的距离进行估值 + int heuristics = predictor.heuristics(state, goal); + //生成子结点 + Node child = new Node(state, parent, action, pathCost, heuristics); + nodes.add(child); + } + } + return nodes; + } + + /** + * + * @param state 当前状态 + * @param action 进入当前状态所采取的Action + * @return 进入当前状态的代价 + */ + public abstract int stepCost(State state, Action action); + + /** + * 在状态state上的action是否可用? + * @param state 当前状态 + * @param action 当前状态下所采用的动作 + * @return true:可用;false:不可用 + */ + protected abstract boolean applicable(State state, Action action); + + /** + * 判断某个状态state是否到达目标状态,多数情况下是判断跟目标状态是否相等。 + * + * @param state 要判断的状态 + * @return true:要判断的状态已经是目标状态;否则,false + */ + public boolean goal(State state){ + return state.equals(goal); + } + + /** + * 解路径的可视化 + * @param path 解路径 + */ + public abstract void showSolution(Deque path); + + /** + * 打印当前问题实例 + */ + public abstract void draw(); + + /** + * 打印解路径 + * @param path 解路径 + */ + public abstract void printPath(Deque path); +} diff --git a/SearchFramework1.0.1/src/core/problem/State.java b/SearchFramework1.0.1/src/core/problem/State.java new file mode 100644 index 0000000..b624a7b --- /dev/null +++ b/SearchFramework1.0.1/src/core/problem/State.java @@ -0,0 +1,24 @@ +package core.problem; + +import g04.problem.npuzzle.PuzzleState; + +/** + * + */ +public abstract class State { + + public abstract void draw(); // 在Console上,输出该状态 + + /** + * 当前状态采用action而进入的下一个状态 + * @param action 当前状态下,一个可行的action + * @return 后继状态 + */ + public abstract State next(Action action); + + /** + * 当前状态下所有可能的Action,但不一定都可行 + * @return 所有可能的Action的可迭代集合 + */ + public abstract Iterable actions(); +} \ No newline at end of file diff --git a/SearchFramework1.0.1/src/core/runner/EngineFeeder.java b/SearchFramework1.0.1/src/core/runner/EngineFeeder.java new file mode 100644 index 0000000..a7207b7 --- /dev/null +++ b/SearchFramework1.0.1/src/core/runner/EngineFeeder.java @@ -0,0 +1,85 @@ +package core.runner; + +import core.problem.Problem; +import core.problem.State; +import core.solver.Searcher; +import core.solver.heuristic.AbstractFrontier; +import core.solver.heuristic.BestFirstSearch; +import core.solver.heuristic.EvaluationType; +import core.solver.heuristic.Predictor; +import algs4.util.In; +import g04.problem.npuzzle.PuzzleState; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Scanner; +import java.util.Set; + +/** + * 为搜索算法提供各样素材。包括 + * 问题problem, + * 使用的Frontier, + * 使用的估值函数 h函数,启发式函数 + * IDA Star搜索算法的一个实现 + * + */ +public abstract class EngineFeeder { + + /** + * 从文件输入流中读入NPuzzle问题的实例 + * @param io 输入流 + * @return 文件中所有NPuzzle实例 + */ + public abstract ArrayList getProblems(In io); + public abstract ArrayList getProblems(Scanner scanner); + /** + * 生成采取某种估值机制的Frontier + * @param type 结点评估器的类型 + * @return 使用该评估机制的一个Frontier实例 + */ + public abstract AbstractFrontier getFrontier(EvaluationType type); + + /** + * 获得对状态进行估值的Predictor + * @param type 估值函数的类型 + * @return 启发函数 + */ + public abstract Predictor getPredictor(HeuristicType type); + + /** + * 生成IdaStar搜索的一个实例,用来做对比实验 + */ + public abstract Searcher getIdaStar(); + + /** + * 用来提交头歌评分的Searcher + * @return 小组目前最佳的搜索引擎 + */ + public abstract Searcher getScoreSearcher(); + + /** + * 用来做对比实验的AStar, 对所有问题都是一样的 + * 使用不同的启发函数的AStar + */ + public Searcher getAStar(HeuristicType type){ + //获取Frontier,其Node以g(n)+h(n)的升序排列 + AbstractFrontier frontier = getFrontier(EvaluationType.FULL); + //以HashSet作为Explored表 + Set explored = new HashSet<>(); + //根据explored和frontier生成AStar引擎,并使用类型为type的启发函数 + return new BestFirstSearch(explored, frontier, PuzzleState.predictor(type)); + } + + /** + * 用来做对比实验的Dijkstra,对所有的问题都是一样的 + * @return Dijkstra搜索算法 + */ + public Searcher getDijkstra(){ + //获取Frontier,其Node以g(n)+h(n)的升序排列 + AbstractFrontier frontier = getFrontier(EvaluationType.PATH_COST); + //以HashSet作为Explored表 + Set explored = new HashSet<>(); + //根据explored和frontier生成AStar引擎,并使用曼哈顿距离作为启发函数 + return new BestFirstSearch(explored, frontier, (state, goal) -> 0); + } +} \ No newline at end of file diff --git a/SearchFramework1.0.1/src/core/runner/HeuristicType.java b/SearchFramework1.0.1/src/core/runner/HeuristicType.java new file mode 100644 index 0000000..40cd2e1 --- /dev/null +++ b/SearchFramework1.0.1/src/core/runner/HeuristicType.java @@ -0,0 +1,16 @@ +package core.runner; + +public enum HeuristicType { + //Npuzzle的启发函数 + MISPLACED, // 不在位将牌 + MANHATTAN, // 曼哈顿距离 + DISJOINT_PATTERN, + + //PathFinding的启发函数 (8方向的情况) + PF_EUCLID, // 欧几里得距离 + PF_MANHATTAN, // 8方向移动时,不是admissible的 + PF_GRID, // 尽可能走对角线,然后平行走,>= EUCLID + + //野人传教士问题 + MC_HARMONY //去掉野人会吃人的约束 +} diff --git a/SearchFramework1.0.1/src/core/runner/ProblemType.java b/SearchFramework1.0.1/src/core/runner/ProblemType.java new file mode 100644 index 0000000..3e07510 --- /dev/null +++ b/SearchFramework1.0.1/src/core/runner/ProblemType.java @@ -0,0 +1,8 @@ +package core.runner; + +public enum ProblemType { + NPUZZLE, // NPuzzle问题 + PATHFINDING, // 寻路问题 + SLIDING_BLOCKS, // 滑动积木块问题 + MISSIONARY_AND_CARNIVAL //野人传教士问题 +} diff --git a/SearchFramework1.0.1/src/core/runner/SearchRunner.java b/SearchFramework1.0.1/src/core/runner/SearchRunner.java new file mode 100644 index 0000000..6edcc75 --- /dev/null +++ b/SearchFramework1.0.1/src/core/runner/SearchRunner.java @@ -0,0 +1,74 @@ +package core.runner; + +import algs4.util.Stopwatch; +import core.problem.Problem; +import core.solver.Node; +import algs4.util.In; +import core.solver.heuristic.BestFirstSearch; +import g04.problem.npuzzle.MyFeeder; +import g04.solver.heuristic.IDAStarSearch; + +import java.util.ArrayList; +import java.util.Deque; + +public class SearchRunner { + + public static void main(String[] args) { + + //从文件中读入问题的实例,寻路问题 + In problemInput = new In("resources/pathfinding.txt"); + + //生成一个具体的EngineFeeder:FeederXu,引擎饲养员徐老师:) + EngineFeeder feeder = new MyFeeder(); + + //feeder从文件获取所有问题实例 + ArrayList problems = feeder.getProblems(problemInput); + + //从Feeder获取所使用的搜索引擎 AStar + /* + BestFirstSearch astar = (BestFirstSearch) feeder.getScoreSearcher(); + for (Problem problem : problems){ + Stopwatch stopwatch = new Stopwatch(); + //使用AStar引擎求解问题 + Deque path = astar.search(problem); + //解的可视化 + problem.showSolution(path); + //仅打印路径 + problem.printPath(path); + System.out.println(astar.expandedNode()); + System.out.println(path.size()); + System.out.println(stopwatch.elapsedTime()); + } + System.out.println("=============================================================="); + */ + //从Feeder获取所使用的搜索引擎 IDAStar + + IDAStarSearch idastar = (IDAStarSearch) feeder.getIdaStar(); + for (Problem problem : problems){ + Stopwatch stopwatch = new Stopwatch(); + //使用AStar引擎求解问题 + Deque path = idastar.search(problem); + //解的可视化 + problem.showSolution(path); + //仅打印路径 + //problem.printPath(path); + System.out.println(path.size()); + System.out.println(stopwatch.elapsedTime()); + System.out.println("=============================================================="); + } + + //从Feeder获取所使用的搜索引擎 Dijkstra + /* + BestFirstSearch dijkstra = (BestFirstSearch) feeder.getDijkstra(); + for (Problem problem : problems){ + //使用AStar引擎求解问题 + Deque path = dijkstra.search(problem); + //解的可视化 + problem.showSolution(path); + //仅打印路径 + problem.printPath(path); + System.out.println(dijkstra.expandedNode()); + System.out.println(); + }*/ + } +} \ No newline at end of file diff --git a/SearchFramework1.0.1/src/core/solver/Node.java b/SearchFramework1.0.1/src/core/solver/Node.java new file mode 100644 index 0000000..d3a7221 --- /dev/null +++ b/SearchFramework1.0.1/src/core/solver/Node.java @@ -0,0 +1,149 @@ +package core.solver; + +import core.problem.Action; +import core.problem.State; +import core.solver.heuristic.EvaluationType; +import core.solver.heuristic.Predictor; + +import java.util.Comparator; +import java.util.EnumMap; + +import static core.solver.heuristic.EvaluationType.*; + +public final class Node{ + + //不考虑路径代价的Node + + /** + * + * @param state 当前结点 + * @param parent 父结点 + * @param action 从父结点到当前结点所采取的Action + */ + public Node(State state, Node parent, Action action){ + this(state, parent, action, 0, 0); + } + + //考虑路径代价的Node + + /** + * + * @param state 当前结点 + * @param parent 父结点 + * @param action 从父结点到当前结点所采取的Action + * @param pathCost 从根结点到当前结点的耗散值 + * @param heuristic 从当前结点到目标结点的距离估计值 + */ + public Node(State state, Node parent, Action action, int pathCost, int heuristic) { + super(); + this.state = state; + this.parent = parent; + this.action = action; + this.pathCost = pathCost; + this.heuristic = heuristic; + } + + /** + * + * @param action:当前结点状态所使用的Action + * @param predictor:用于计算h值的启发函数 + * @param goal: 作为启发函数的参数,用于计算子结点状态的h值 + * @return 当前结点的子结点 + */ + public Node childNode(Action action, Predictor predictor, State goal) { + return new Node(state.next(action), this, action, + pathCost + action.stepCost(), + predictor.heuristics(state, goal)); + } + + private final State state; // the state in the state space to which the node corresponds + private final Node parent; // the node in the search tree which generated this node + + public Action getAction() { + return action; + } + + private final Action action; // the action that was applied to the parent to generate the node + private final int pathCost; // the cost of the path from the initial state to this node + private final int heuristic; // estimated cost of the cheapest path from the state of this node to a goal state + + //返回当前Node的f值 f = g + h + public int evaluation() + { + return pathCost + heuristic; + } + + public State getState() { + return state; + } + + public Node getParent() { + return parent; + } + + public int getPathCost() { + return pathCost; + } + + public int getHeuristic() { + return heuristic; + } + + /** + * Node的状态相同,即认为他们是相同的 + */ + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + + if (obj instanceof Node) { + Node another = (Node) obj; + //两个Node对象的状态相同,则认为是相同的 + return this.getState().equals(another.getState()); + } + return false; + //Node another = (Node) obj; + //return obj == this || this.getState().equals(another.getState()); + } + + public void draw() { + System.out.println(this); + } + + /** + * 不同估值函数的枚举映射表 + */ + private static final EnumMap> evaluators = new EnumMap<>(EvaluationType.class); + //枚举映射表的初始化 + static{ + //f = g + h FULL + evaluators.put(FULL, + Comparator.comparingInt(Node::evaluation) + ); + + //g PATH_COST + evaluators.put(PATH_COST, + Comparator.comparingInt(Node::getPathCost) + ); + + //h HEURISTIC + evaluators.put(HEURISTIC, + Comparator.comparingInt(Node::getHeuristic) + ); + } + + /** + * + * @param type 结点评估器的类型 + * @return 相关类型的结点评估器 + */ + public static Comparator evaluator(EvaluationType type) { + return evaluators.get(type); + } + + @Override + public String toString() { + return "[" + state.toString() + "⬅" + "[" + parent.getState().toString() + ", " + action.toString() + "], " + pathCost + ", " + heuristic + "]"; + } + +} diff --git a/SearchFramework1.0.1/src/core/solver/Searcher.java b/SearchFramework1.0.1/src/core/solver/Searcher.java new file mode 100644 index 0000000..2ee6875 --- /dev/null +++ b/SearchFramework1.0.1/src/core/solver/Searcher.java @@ -0,0 +1,29 @@ +package core.solver; + +import core.problem.Problem; +import java.util.ArrayDeque; +import java.util.Deque; + +public interface Searcher { + + /** + * @problem 要解决的问题 + * @return 当前问题的解路径。如果没有解,则返回null + */ + Deque search(Problem problem); + + /** + * 默认实现,从目标结点,反向回溯得到一条路径 + * @param node 目标结点 + * @return 倒推生成的从根结点到目标结点的路径,栈底是目标结点,栈顶是根结点 + */ + default Deque generatePath(Node node) { + Deque stack = new ArrayDeque<>(); + + while (node.getParent() != null) { + stack.push(node); + node = node.getParent(); + } + return stack; + } +} \ No newline at end of file diff --git a/SearchFramework1.0.1/src/core/solver/blinded/BreadthFirstSearch.java b/SearchFramework1.0.1/src/core/solver/blinded/BreadthFirstSearch.java new file mode 100644 index 0000000..5718576 --- /dev/null +++ b/SearchFramework1.0.1/src/core/solver/blinded/BreadthFirstSearch.java @@ -0,0 +1,4 @@ +package core.solver.blinded; + +public class BreadthFirstSearch { +} diff --git a/SearchFramework1.0.1/src/core/solver/blinded/DepthFirstSearch.java b/SearchFramework1.0.1/src/core/solver/blinded/DepthFirstSearch.java new file mode 100644 index 0000000..4783a88 --- /dev/null +++ b/SearchFramework1.0.1/src/core/solver/blinded/DepthFirstSearch.java @@ -0,0 +1,4 @@ +package core.solver.blinded; + +public class DepthFirstSearch { +} diff --git a/SearchFramework1.0.1/src/core/solver/heuristic/AbstractFrontier.java b/SearchFramework1.0.1/src/core/solver/heuristic/AbstractFrontier.java new file mode 100644 index 0000000..08a2163 --- /dev/null +++ b/SearchFramework1.0.1/src/core/solver/heuristic/AbstractFrontier.java @@ -0,0 +1,70 @@ +package core.solver.heuristic; + +import core.problem.State; +import core.solver.Node; + +import java.util.*; + +/** + * AbstractQueue的子类, + * 其存放的元素的类型为 core.solver.Node + */ +public abstract class AbstractFrontier extends AbstractQueue { + + public AbstractFrontier(Comparator evaluator) { + this.evaluator = evaluator; + } + + public Comparator getEvaluator() { + return evaluator; + } + + // 节点优先级比较器,在Node类中定义了三个不同的比较器(Dijkstra, Greedy Best-First, and Best-First) + // 不同的选择对应不同的算法。 + protected final Comparator evaluator; + + /** + * 获取 Frontier 中,状态为 s 的节点 + * @param s 状态 + * @return 存在: 相应的状态为 s 的节点; + * 不存在:null + */ + protected abstract Node getNode(State s); + + /** + * 如果Frontier中已经存在与node状态相同的结点, + * 则舍弃掉二者之间不好的那一个。 + * @param node 结点 + * @return 插入成功返回true + */ + public final boolean discardOrReplace(Node node){ + if (node == null) + throw new NullPointerException(); + + //结点node是否出现在frontier中; null: not revisited + Node oldNode = getNode(node.getState()); + //如果oldNode为null,则当前结点node的状态不在Frontier中,那么肯定在explored表中, + // 又因为h函数是consistent的,所以discard + //如果oldNode不为null,则在oldNode已经在Frontier中,并且旧的估值比新的大,即新生成的结点更好 + if (oldNode != null && evaluator.compare(oldNode, node) > 0){ + //则,用新节点替换旧节点 + replace(oldNode, node); + } + return true; + } + + /** + * 用节点 e 替换掉具有相同状态的旧节点 oldNode + * + * @param oldNode 被替换的结点 + * @param newNode 新结点 + */ + public void replace(Node oldNode, Node newNode) { + this.remove(oldNode); + this.add(newNode); + } + + public boolean contains(Node node) { + return false; + } +} diff --git a/SearchFramework1.0.1/src/core/solver/heuristic/BestFirstSearch.java b/SearchFramework1.0.1/src/core/solver/heuristic/BestFirstSearch.java new file mode 100644 index 0000000..efde515 --- /dev/null +++ b/SearchFramework1.0.1/src/core/solver/heuristic/BestFirstSearch.java @@ -0,0 +1,77 @@ +package core.solver.heuristic; + +import java.util.*; + +import core.problem.Problem; +import core.problem.State; +import core.solver.*; +import g04.problem.npuzzle.PuzzleState; + +/** + * 不能被继承的类,final类 + */ +public final class BestFirstSearch implements Searcher { + + //已经访问过的节点集合 + private final Set explored; + + //还未扩展的节点队列 + private final AbstractFrontier frontier; + + private final Predictor predictor; + /** + * 构造函数 + * @param explored 具体的状态类的Set hashSet + * @param frontier Node对象的一个优先队列,可以确定一个状态所对应的结点是否在frontier中, + */ + public BestFirstSearch(Set explored, AbstractFrontier frontier, Predictor predictor) { + this.explored = explored; + this.frontier = frontier; + this.predictor = predictor; + } + + @Override + public Deque search(Problem problem) + { + //如果可直接判断问题是否可解,无解时直接返回解路径为null + if (!problem.solvable()){ + return null; + } + frontier.clear(); + explored.clear(); + //搜索树的根节点 + Node root = problem.root(predictor); + this.frontier.add(root); + //int i = 0; + while (true) { + if (frontier.isEmpty()) + return null; //失败 + Node node = frontier.poll(); //choose the lowest-cost node in frontier + //如果已经到达目标状态, + if (problem.goal(node.getState())) { + return generatePath(node); + } + //将当前结点放入explored表中 + explored.add(node.getState()); + //System.out.println(i++); + for (Node child : problem.childNodes(node, predictor)) { + // 如果新扩展的节点,没有在Explored和Fringe中出现过。 + // 因为两个node的状态相同,则视为二者相同(equals函数), + // 所以contains函数判断frontier中是否存在跟child的状态相同的结点 + if (!explored.contains(child.getState()) && !frontier.contains(child)) { + frontier.offer(child); + } + else { + //child出现在Explored或Fringe中 + //在启发函数满足单调条件的前提下,如果child是出现在Explored表里的节点,肯定不在Fringe中; + //而且到达这个节点的新路径肯定不会比旧路径更优 + frontier.discardOrReplace(child); + } + } + } + } + + public int expandedNode(){ + return explored.size(); + } +} \ No newline at end of file diff --git a/SearchFramework1.0.1/src/core/solver/heuristic/EvaluationType.java b/SearchFramework1.0.1/src/core/solver/heuristic/EvaluationType.java new file mode 100644 index 0000000..46e7981 --- /dev/null +++ b/SearchFramework1.0.1/src/core/solver/heuristic/EvaluationType.java @@ -0,0 +1,11 @@ +package core.solver.heuristic; + +/** + * Best-First搜索的三类不同的估值策略 + * 对所有问题都是通用的 + */ +public enum EvaluationType { + FULL, + PATH_COST, + HEURISTIC //对于不同的问题,启发策略又可能又多种。 +} diff --git a/SearchFramework1.0.1/src/core/solver/heuristic/Predictor.java b/SearchFramework1.0.1/src/core/solver/heuristic/Predictor.java new file mode 100644 index 0000000..436d0cb --- /dev/null +++ b/SearchFramework1.0.1/src/core/solver/heuristic/Predictor.java @@ -0,0 +1,18 @@ +package core.solver.heuristic; + +import core.problem.State; + +/** + * + * + */ +public interface Predictor { + /** + * + * @param + * state 被评估的状态 + * goal 目标状态 + * @return 该状态到目标状态的启发值 + */ + int heuristics(State state, State goal); +} diff --git a/SearchFramework1.0.1/src/g04/problem/npuzzle/MyFeeder.java b/SearchFramework1.0.1/src/g04/problem/npuzzle/MyFeeder.java new file mode 100644 index 0000000..3eb4718 --- /dev/null +++ b/SearchFramework1.0.1/src/g04/problem/npuzzle/MyFeeder.java @@ -0,0 +1,84 @@ +package g04.problem.npuzzle; + +import algs4.util.In; +import core.problem.Problem; +import core.runner.EngineFeeder; +import core.runner.HeuristicType; +import core.solver.Node; +import core.solver.Searcher; +import core.solver.heuristic.AbstractFrontier; +import core.solver.heuristic.EvaluationType; +import core.solver.heuristic.Predictor; +import g04.solver.heuristic.IDAStarSearch; +import g04.solver.heuristic.MyFrontier; + +import java.util.ArrayList; +import java.util.Scanner; + +public class MyFeeder extends EngineFeeder { + /** + * 从文件中读取所有的NPuzzle问题 + * @param io 输入流 + * @return 所有的NPuzzle问题 + */ + @Override + public ArrayList getProblems(In io) { + ArrayList problems = new ArrayList(); + while (io.hasNextLine()){ + //棋盘大小 + int size = io.readInt(); + int[][] board = new int[size][size]; + //读入初始状态 + for (int i = 0; i < size; i++) + for (int j = 0; j < size; j++) + board[i][j] = io.readInt(); + PuzzleState initState = new PuzzleState(board, size); + //读入目标状态 + for (int i = 0; i < size; i++) + for (int j = 0; j < size; j++) + board[i][j] = io.readInt(); + PuzzleState goal = new PuzzleState(board, size); + Puzzle puzzleProblem = new Puzzle(initState, goal, size); + //添加到问题列表 + problems.add(puzzleProblem); + } + return problems; + } + + @Override + public ArrayList getProblems(Scanner scanner) { + return null; + } + + @Override + public AbstractFrontier getFrontier(EvaluationType type) { + return new MyFrontier(Node.evaluator(type)); + } + + /** + * 获取对应的启发函数 + * @param type 估值函数的类型 + * @return 对应的启发函数 + */ + @Override + public Predictor getPredictor(HeuristicType type) { + return PuzzleState.predictor(type); + } + + /** + * 获取IDA*算法的搜索器 + * @return IDA*算法的搜索器 + */ + @Override + public Searcher getIdaStar() { + return new IDAStarSearch(PuzzleState.predictor(HeuristicType.MANHATTAN)); + } + + /** + * @return A*算法的搜索器 + */ + @Override + public Searcher getScoreSearcher() { + return getAStar(HeuristicType.MANHATTAN); + } +} diff --git a/SearchFramework1.0.1/src/g04/problem/npuzzle/Puzzle.java b/SearchFramework1.0.1/src/g04/problem/npuzzle/Puzzle.java new file mode 100644 index 0000000..f3520f9 --- /dev/null +++ b/SearchFramework1.0.1/src/g04/problem/npuzzle/Puzzle.java @@ -0,0 +1,155 @@ +package g04.problem.npuzzle; + +import core.problem.Action; +import core.problem.Problem; +import core.problem.State; +import core.solver.Node; +import core.solver.heuristic.Predictor; + +import java.util.ArrayList; +import java.util.Deque; +import java.util.Random; + +public class Puzzle extends Problem { + + //Zobrist哈希随机值 + public static int[][][] Zobrist; + //目标状态到默认状态的曼哈顿距离(默认状态为按顺序放置位将牌,空格最后) + public static int[][][] goalmanhattan; + + /** + * 构造函数 + * @param initialState 初始状态 + * @param goal 目标状态 + * @param size 棋盘大小 + */ + public Puzzle(State initialState, State goal, int size) { + super(initialState, goal, size); + Random r = new Random(); + goalmanhattan = new int[size][size][2]; + Zobrist = new int[size][size][size * size]; + for(int i = 0; i < size; i++) { + for(int j = 0; j < size; j++) { + goalmanhattan[i][j][0] = (((PuzzleState)goal).getBoardAt(i, j) - 1) / size;; + goalmanhattan[i][j][1] = (((PuzzleState)goal).getBoardAt(i, j) - 1) % size;;; + for(int k = 0; k < size * size; k++) { + Zobrist[i][j][k] = r.nextInt(); + } + } + } + } + + /** + * + * @param i 行坐标 + * @param j 列坐标 + * @param state 状态 + * @return 该状态对应位置处的Zobrist随机值 + */ + public static int getZobristAt(int i, int j, int state) { + return Zobrist[i][j][state]; + } + + /** + * 比较两个状态的奇偶性是否相等 + * @return + */ + @Override + public boolean solvable() { + return ((PuzzleState)initialState).parity() == ((PuzzleState)goal).parity(); + } + + @Override + public int stepCost(State state, Action action) { + return 1; + } + + /** + * + * @param state 当前状态 + * @param action 当前状态下所采用的动作 + * @return 当前action是否可行,true: 可行,false: 不可行 + */ + @Override + protected boolean applicable(State state, Action action) { + //获取action对应的位移量 + int[] next = ((PuzzleAction)action).getNext(); + //空白位移动后是否越界 + int row = ((PuzzleState)state).getBlank(0) + next[0]; + int col = ((PuzzleState)state).getBlank(1) + next[1]; + return row >= 0 && row < size && col >= 0 && col < size; + } + + @Override + public void showSolution(Deque path) { + + } + + /** + * 输出初始状态和目标状态 + */ + @Override + public void draw() { + initialState.draw(); + System.out.println(); + goal.draw(); + } + + /** + * 打印解路径 + * @param path 解路径 + */ + @Override + public void printPath(Deque path) { + if (path == null){ + System.out.println("No Solution."); + return; + } + initialState.draw(); + for (Node node : path) { + PuzzleAction puzzleAction = (PuzzleAction) node.getAction(); + puzzleAction.draw(); + PuzzleState puzzleState = (PuzzleState) node.getState(); + puzzleState.draw(); + } + System.out.println(); + } + + public final Iterable childs(Node parent) { + ArrayList nodes = new ArrayList<>(); + //父结点的状态 + State parentState = parent.getState(); + //对于parentState上所有可能的action,但有的不可行 + //parentState.draw(); + for (Action action : parentState.actions()){ + //如果父结点状态下的动作是可行的 + if (applicable(parentState, action)){ + //得到后继状态 + State state = parentState.next(action); + //计算路径长度 = 父结点路径长度 + 进入后继状态所采取的动作的代价 + int pathCost = parent.getPathCost() + stepCost(state, action); + //根据曼哈顿距离特性,只需要计算被移动的位将牌改变的曼哈顿距离 + int heuristics = parent.getHeuristic() - nextManhattan((PuzzleState)parentState, (PuzzleState)state); + //生成子结点 + Node child = new Node(state, parent, action, pathCost, heuristics); + nodes.add(child); + } + } + return nodes; + } + + /** + * 计算被移动的位将牌改变的曼哈顿距离 + * @param parent 父状态 + * @param child 子状态 + * @return 改变的曼哈顿距离 + */ + public int nextManhattan(PuzzleState parent, PuzzleState child) { + //被移动的位将牌对应数字 + int n = parent.getBoardAt(child.getBlank(0), child.getBlank(1)); + int x = (n - 1) / size; + int y = (n - 1) % size; + return Math.abs(goalmanhattan[x][y][0] - child.getBlank(0)) + Math.abs(goalmanhattan[x][y][1] - child.getBlank(1)) + - Math.abs(goalmanhattan[x][y][0] - parent.getBlank(0)) - Math.abs(goalmanhattan[x][y][1] - parent.getBlank(1)); + } +} diff --git a/SearchFramework1.0.1/src/g04/problem/npuzzle/PuzzleAction.java b/SearchFramework1.0.1/src/g04/problem/npuzzle/PuzzleAction.java new file mode 100644 index 0000000..26e5fc6 --- /dev/null +++ b/SearchFramework1.0.1/src/g04/problem/npuzzle/PuzzleAction.java @@ -0,0 +1,40 @@ +package g04.problem.npuzzle; + +import core.problem.Action; + +public class PuzzleAction extends Action { + + /* + * 移动一步 + * 0: Up, 1: Right, 2: Down, 3: Right + */ + private final int dir; + // 移动方向 + private static final char[] direction = {'R', 'D', 'L', 'U'}; + private static final int[][] next = { + {0, 1}, {1, 0}, {0, -1}, {-1, 0} + }; + + public PuzzleAction(int dir) { + this.dir = dir; + } + + public int[] getNext() { + return next[dir]; + } + + /** + * 打印输出action + */ + @Override + public void draw() { + System.out.println(" ↓"); + System.out.println(" ↓-(#, " + direction[dir] + ")"); + System.out.println(" ↓"); + } + + @Override + public int stepCost() { + return 1; + } +} diff --git a/SearchFramework1.0.1/src/g04/problem/npuzzle/PuzzleState.java b/SearchFramework1.0.1/src/g04/problem/npuzzle/PuzzleState.java new file mode 100644 index 0000000..43588c4 --- /dev/null +++ b/SearchFramework1.0.1/src/g04/problem/npuzzle/PuzzleState.java @@ -0,0 +1,252 @@ +/** + * + */ +package g04.problem.npuzzle; + +import core.problem.Action; +import core.problem.State; +import core.runner.HeuristicType; +import core.solver.heuristic.Predictor; +import xu.problem.pathfinding.Direction; +import xu.problem.pathfinding.Move; +import xu.problem.pathfinding.Position; + +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.Objects; +import java.util.Scanner; + + +/** + * 类描述: + * 作者: wanwenlong + * 创建日期:2021年3月28日 + * 修改人: + * 修改日期: + * 修改内容: + * 版本号: 1.0.0 + */ +public class PuzzleState extends State { + + private final int size; + //该状态每个位置的位将牌数字 + private final int[][] board; + //空格对应位置 + private int[] blank; + + /** + * 构造函数 + */ + public PuzzleState(int[][] board, int size) { + this.size = size; + this.board = new int[size][size]; + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + this.board[i][j] = board[i][j]; + if (board[i][j] == 0) + this.blank = new int[]{i, j}; + } + } + } + + /** + * 拷贝构造 + */ + public PuzzleState(PuzzleState puzzleState) { + this.size = puzzleState.size; + this.board = new int[size][size]; + for (int i = 0; i < size; i++) { + System.arraycopy(puzzleState.board[i], 0, this.board[i], 0, size); + } + this.blank = new int[]{puzzleState.blank[0], puzzleState.blank[1]}; + } + + public int getSize() { + return size; + } + + public int getBoardAt(int i, int j) { + return board[i][j]; + } + + public int getBoardAt(int i) { + return board[i/size][i%size]; + } + + public int getBlank(int i) { + return blank[i]; + } + + /** + * 输出当前状态 + */ + @Override + public void draw() { + drawLine(); + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + System.out.print("| " + String.valueOf(board[i][j]) + " "); + } + System.out.println("|"); + drawLine(); + } + } + + /** + * 画线 + */ + public void drawLine() { + for (int i = 0; i < size; i++) + System.out.print("+---"); + System.out.println("+"); + } + + /** + * 当前状态采用action而进入的下一个状态 + * @param action + * @return + */ + @Override + public State next(Action action) { + PuzzleState nextState = new PuzzleState(this); + int[] next = ((PuzzleAction)action).getNext(); + nextState.blank[0] += next[0]; + nextState.blank[1] += next[1]; + nextState.board[this.blank[0]][this.blank[1]] = this.board[nextState.blank[0]][nextState.blank[1]]; + nextState.board[nextState.blank[0]][nextState.blank[1]] = 0; + return nextState; + } + + /** + * 当前状态下可以采用的所有Action + * @return 所有Action + */ + @Override + public Iterable actions() { + ArrayList actions = new ArrayList(); + for (int d = 0; d < 4; d++) + actions.add(new PuzzleAction(d)); + return actions; + } + + /** + * NPuzzle状态的奇偶性 + * @return 1:奇 0:偶 + */ + public int parity() { + int n = (size % 2 == 0) ? blank[0] + 1 : 0; + for (int i = 0; i < size * size; i++) { + for (int j = 0; j < i; j++) { + if (this.getBoardAt(i) != 0 && this.getBoardAt(j) != 0 && this.getBoardAt(i) < this.getBoardAt(j)) + n++; + } + } + return n % 2; + } + + @Override + public boolean equals(Object obj) { + for (int i = 0; i < size * size - 1; i++) { + if (this.getBoardAt(i) != ((PuzzleState) obj).getBoardAt(i)) + return false; + } + return true; + //return this.hashCode() == obj.hashCode(); + } + + /** + * Zobrist哈希 + * @return 哈希值 + */ + @Override + public int hashCode() { + int hash = 0; + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + hash ^= Puzzle.getZobristAt(i, j, board[i][j]); + } + } + return hash; + } + + //枚举映射,存放不同类型的启发函数 + private static final EnumMap predictors = new EnumMap<>(HeuristicType.class); + static{ + predictors.put(HeuristicType.MISPLACED, + (state, goal) -> ((PuzzleState)state).misPlaced((PuzzleState)goal)); + predictors.put(HeuristicType.MANHATTAN, + (state, goal) -> ((PuzzleState)state).manhattan((PuzzleState)goal)); + predictors.put(HeuristicType.DISJOINT_PATTERN, + (state, goal) -> ((PuzzleState)state).disjointPattern((PuzzleState)goal)); + } + public static Predictor predictor(HeuristicType type){ + return predictors.get(type); + } + + /** + * 不在位将牌 + */ + private int misPlaced(PuzzleState goal) { + int heuristics = 0; + int size = goal.getSize(); + for (int i = 0; i < size * size - 1; i++) { + if (this.getBoardAt(i) != 0 && this.getBoardAt(i) != goal.getBoardAt(i)) + heuristics++; + } + return heuristics; + } + + /** + * 曼哈顿距离 + */ + private int manhattan(PuzzleState goal) { + int heuristics = 0; + int[][][] m = new int[size][size][2]; + int x, y; + //第一步,计算当前状态到默认状态曼哈顿距离 + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + if (this.board[i][j] == 0) + continue; + x = (this.board[i][j] - 1) / size; + y = (this.board[i][j] - 1) % size; + m[x][y][0] = x - i; + m[x][y][1] = y - j; + } + } + //第二步,计算默认状态到目标状态曼哈顿距离 + //结合两步即为当前状态到目标状态曼哈顿距离 + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + if (goal.board[i][j] == 0) + continue; + x = (goal.board[i][j] - 1) / size; + y = (goal.board[i][j] - 1) % size; + heuristics += Math.abs(m[x][y][0] + i - x) + Math.abs(m[x][y][1] + j - y); + } + } + return heuristics; + } + + /** + * Disjoint pattern heuristic + */ + private int disjointPattern(PuzzleState goal) { + return 0; + } + + public static void main(String[] args) { + int[][] a = new int[][]{{8, 13, 0, 6}, {1, 15, 9, 14}, {3, 4, 5, 11}, {7, 2, 10, 12}}; + int[][] g = new int[][]{{1, 2, 3}, {4, 5, 6}, {7, 8, 0}}; + PuzzleState puzzleState = new PuzzleState(a, 4); + int n = 0; + for (int i = 0; i < 4 * 4; i++) { + for (int j = 0; j < i; j++) { + if (puzzleState.getBoardAt(i) != 0 && puzzleState.getBoardAt(j) != 0 && puzzleState.getBoardAt(i) < puzzleState.getBoardAt(j)) + n++; + } + System.out.println(n); + } + System.out.println(n); + } +} \ No newline at end of file diff --git a/SearchFramework1.0.1/src/g04/solver/heuristic/IDAStarSearch.java b/SearchFramework1.0.1/src/g04/solver/heuristic/IDAStarSearch.java new file mode 100644 index 0000000..3bdebab --- /dev/null +++ b/SearchFramework1.0.1/src/g04/solver/heuristic/IDAStarSearch.java @@ -0,0 +1,65 @@ +package g04.solver.heuristic; + +import core.problem.Problem; +import core.solver.Node; +import core.solver.Searcher; +import core.solver.heuristic.Predictor; +import g04.problem.npuzzle.Puzzle; + +import java.util.Deque; +import java.util.Stack; + +public class IDAStarSearch implements Searcher { + + private final Predictor predictor; + + //裁剪阈值 + private int cutoff; + //下一轮迭代的裁剪阈值 + private int newCutoff; + //最大迭代深度 + private int maxIteratorDepth = 256; + + private final Stack openStack; + private final Stack closeStack; + + public IDAStarSearch(Predictor predictor) { + this.predictor = predictor; + openStack = new Stack(); + closeStack = new Stack(); + } + + @Override + public Deque search(Problem problem) { + //获取根节点 + openStack.clear(); + Node root = problem.root(predictor); + cutoff = root.evaluation(); + while (cutoff < maxIteratorDepth) { + openStack.push(root); + newCutoff = cutoff; + //当栈未空时继续,执行带裁剪值的深度优先搜索 + while (!openStack.empty()) { + Node node = openStack.pop(); + //更新裁剪值为未被探索节点中最小的评估值 + newCutoff = (newCutoff > cutoff) ? (Math.min(node.evaluation(), newCutoff)) : node.evaluation(); + if (problem.goal(node.getState())) { + return generatePath(node); + } + //当小于等于裁剪值时,继续向深处搜索 + if (node.evaluation() <= cutoff) { + for (Node child : ((Puzzle)problem).childs(node)) { + //剪枝,防止节点探索回到父节点 + if (node.getParent() == null || !node.getParent().equals(child)) { + openStack.push(child); + } + } + } + } + //更新裁剪值 + cutoff = newCutoff; + //System.out.println(cutoff); + } + return null; + } +} diff --git a/SearchFramework1.0.1/src/g04/solver/heuristic/MyFrontier.java b/SearchFramework1.0.1/src/g04/solver/heuristic/MyFrontier.java new file mode 100644 index 0000000..43aa3b1 --- /dev/null +++ b/SearchFramework1.0.1/src/g04/solver/heuristic/MyFrontier.java @@ -0,0 +1,125 @@ +package g04.solver.heuristic; + +import core.problem.State; +import core.solver.Node; +import core.solver.heuristic.AbstractFrontier; + +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.PriorityQueue; + +/** + * S18020031073开发的”超级棒“的Frontier数据结构 + */ +public class MyFrontier extends AbstractFrontier { + + /** + * 优先队列,节点根据评估值排序 + */ + PriorityQueue frontier = new PriorityQueue(new Comparator(){ + public int compare(Node a, Node b){ + return evaluator.compare(a, b); + } + }); + //增加Map集合,使得节点的查找时间复杂度降低至O(1) + HashMap hashMap=new HashMap(); + + /** + * + * @param comparator + */ + public MyFrontier(Comparator comparator) { + super(comparator); + } + + /** + * 获取 Frontier 中,状态为 s 的节点 + * + * @param s 状态 + * @return 存在: 相应的状态为 s 的节点; + * 不存在:null + */ + @Override + protected Node getNode(State s) { + return hashMap.get(s.hashCode()); + } + + /** + * 用节点 e 替换掉具有相同状态的旧节点 oldNode + * + * @param oldNode + * @param e + */ + @Override + public void replace(Node oldNode, Node e) { + hashMap.put(oldNode.getState().hashCode(), e); + //frontier.remove(oldNode); + frontier.offer(e); + } + + /** + * Returns an iterator over the elements contained in this collection. + * + * @return an iterator over the elements contained in this collection + */ + @Override + public Iterator iterator() { + return frontier.iterator(); + } + + @Override + public int size() { + return frontier.size(); + } + + /** + * Inserts the specified element into this queue if it is possible to do + * so immediately without violating capacity restrictions. + * When using a capacity-restricted queue, this method is generally + * preferable to {@link #add}, which can fail to insert an element only + * by throwing an exception. + * + * @param node the element to add + * @return {@code true} if the element was added to this queue, else + * {@code false} + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this queue + * @throws NullPointerException if the specified element is null and + * this queue does not permit null elements + * @throws IllegalArgumentException if some property of this element + * prevents it from being added to this queue + */ + @Override + public boolean offer(Node node) { + hashMap.put(node.getState().hashCode(), node); + frontier.offer(node); + return true; + } + + @Override + public Node poll(){ + try { + Node node = frontier.poll(); + hashMap.remove(node.getState().hashCode()); + return node; + } catch (Exception e) { + } + return null; + } + + @Override + public Node peek() { + return frontier.peek(); + } + + /** + * 判断是否含有该节点 + * @param node + * @return + */ + @Override + public boolean contains(Node node) { + return hashMap.get(node.getState().hashCode()) != null; + } +} diff --git a/SearchFramework1.0.1/src/g04/solver/heuristic/VeryEffecientFrontier.java b/SearchFramework1.0.1/src/g04/solver/heuristic/VeryEffecientFrontier.java new file mode 100644 index 0000000..575e296 --- /dev/null +++ b/SearchFramework1.0.1/src/g04/solver/heuristic/VeryEffecientFrontier.java @@ -0,0 +1,147 @@ +package g04.solver.heuristic; + +import core.problem.State; +import core.solver.Node; +import core.solver.heuristic.AbstractFrontier; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; + +/** + * S18020031073开发的”超级棒“的Frontier数据结构 + */ +public class VeryEffecientFrontier extends AbstractFrontier { + + /** + * My secret wonderful data structures! :) + * + */ + ArrayList frontier = new ArrayList(); + HashMap hashMap=new HashMap(); + + /** + * + * @param comparator + */ + public VeryEffecientFrontier(Comparator comparator) { + super(comparator); + } + + /** + * 获取 Frontier 中,状态为 s 的节点 + * + * @param s 状态 + * @return 存在: 相应的状态为 s 的节点; + * 不存在:null + */ + @Override + protected Node getNode(State s) { + /*for (Node node : frontier) { + if (node.getState().equals(s)) { + return node; + } + } + return null;*/ + return hashMap.get(s.hashCode()); + } + + /** + * 用节点 e 替换掉具有相同状态的旧节点 oldNode + * + * @param oldNode + * @param e + */ + @Override + public void replace(Node oldNode, Node e) { + //hashMap.put(oldNode.getState().hashCode(), e); + //frontier.set(frontier.indexOf(oldNode), e); + this.remove(oldNode); + this.offer(e); + } + + /** + * Returns an iterator over the elements contained in this collection. + * + * @return an iterator over the elements contained in this collection + */ + @Override + public Iterator iterator() { + return frontier.iterator(); + } + + @Override + public int size() { + return frontier.size(); + } + + /** + * Inserts the specified element into this queue if it is possible to do + * so immediately without violating capacity restrictions. + * When using a capacity-restricted queue, this method is generally + * preferable to {@link #add}, which can fail to insert an element only + * by throwing an exception. + * + * @param node the element to add + * @return {@code true} if the element was added to this queue, else + * {@code false} + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this queue + * @throws NullPointerException if the specified element is null and + * this queue does not permit null elements + * @throws IllegalArgumentException if some property of this element + * prevents it from being added to this queue + */ + @Override + public boolean offer(Node node) { + int j = 0; + for (Node value : frontier) { + if (evaluator.compare(value, node) >= 0) { + break; + } + j++; + } + frontier.add(j, node); + hashMap.put(node.getState().hashCode(), node); + return true; + } + + @Override + public Node poll(){ + try { + Node node = frontier.get(0); + frontier.remove(0); + hashMap.remove(node.getState().hashCode()); + return node; + } catch (Exception e) { + } + return null; + } + + @Override + public Node peek() { + try { + return frontier.get(0); + } catch (Exception e) { + } + return null; + } + + @Override + public boolean contains(Node node) { + /*for (Node oldNode : frontier) { + if (oldNode.equals(node)) { + return true; + } + } + return false;*/ + return hashMap.get(node.getState().hashCode()) != null; + } + + public void remove(Node node) { + //frontier.remove(node); + hashMap.remove(node.getState().hashCode()); + } + +} diff --git a/SearchFramework1.0.1/src/xu/problem/pathfinding/Direction.java b/SearchFramework1.0.1/src/xu/problem/pathfinding/Direction.java new file mode 100644 index 0000000..e5d0f90 --- /dev/null +++ b/SearchFramework1.0.1/src/xu/problem/pathfinding/Direction.java @@ -0,0 +1,60 @@ +package xu.problem.pathfinding; + +import java.util.EnumMap; + +public enum Direction { + N('↑'), //北 + NE('↗'), //东北 + E('→'), //东 + SE('↘'), //东南 + S('↓'), //南 + SW('↙'), //西南 + W('←'), //西 + NW('↖'); //西北 + + Direction(char symbol){ + this.symbol = symbol; + } + private final char symbol; + public char symbol(){ + return symbol; + } + + //各个方向移动的代价,直线为10,斜线为14 + private static final EnumMap DIRECTION_COST = new EnumMap<>(Direction.class); + static{ + int scale = Position.SCALE; + int diagonal = (int) (scale * Position.ROOT2); + + DIRECTION_COST.put(N, scale); + DIRECTION_COST.put(NE, diagonal); + DIRECTION_COST.put(E, scale); + DIRECTION_COST.put(SE, diagonal); + DIRECTION_COST.put(S, scale); + DIRECTION_COST.put(SW, diagonal); + DIRECTION_COST.put(W, scale); + DIRECTION_COST.put(NW, diagonal); + } + + //各个方向移动的坐标位移量 + private static final EnumMap DIRECTION_OFFSET = new EnumMap<>(Direction.class); + static{ + //列号(或横坐标)增加量;行号(或纵坐标)增加量 + DIRECTION_OFFSET.put(N, new int[]{0, -1}); + DIRECTION_OFFSET.put(NE, new int[]{1, -1}); + DIRECTION_OFFSET.put(E, new int[]{1, 0}); + DIRECTION_OFFSET.put(SE, new int[]{1, 1}); + DIRECTION_OFFSET.put(S, new int[]{0, 1}); + DIRECTION_OFFSET.put(SW, new int[]{-1, 1}); + DIRECTION_OFFSET.put(W, new int[]{-1, 0}); + DIRECTION_OFFSET.put(NW, new int[]{-1, -1}); + } + + public static int[] offset(Direction dir){ + return DIRECTION_OFFSET.get(dir); + } + + public static int cost(Direction dir){ + return DIRECTION_COST.get(dir); + } +} diff --git a/SearchFramework1.0.1/src/xu/problem/pathfinding/FeederXu.java b/SearchFramework1.0.1/src/xu/problem/pathfinding/FeederXu.java new file mode 100644 index 0000000..0517ed0 --- /dev/null +++ b/SearchFramework1.0.1/src/xu/problem/pathfinding/FeederXu.java @@ -0,0 +1,109 @@ +package xu.problem.pathfinding; + +import algs4.util.In; +import core.problem.Problem; +import core.problem.State; +import core.runner.EngineFeeder; +import core.runner.HeuristicType; +import core.solver.Node; +import core.solver.Searcher; +import core.solver.heuristic.AbstractFrontier; +import core.solver.heuristic.BestFirstSearch; +import core.solver.heuristic.EvaluationType; +import core.solver.heuristic.Predictor; +import xu.solver.heuristic.LinkedFrontier; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Scanner; +import java.util.Set; + +/** + * 寻路问题的EngineFeeder + */ +public class FeederXu extends EngineFeeder { + /** + * 从文件输入流中读入NPuzzle问题的实例 + * + * @param io 输入流 + * @return 文件中所有NPuzzle实例 + */ + @Override + public ArrayList getProblems(In io) { + + ArrayList problems = new ArrayList<>(); + //地图的大小 + int size = io.readInt(); + //读入地图 + GridType[][] grids = new GridType[size][]; + for (int i = 0; i < size; i++){ + grids[i] = new GridType[size]; + for (int j = 0; j < size; j++){ + int cellType = io.readInt(); + grids[i][j] = GridType.values()[cellType]; + } + } + while (io.hasNextLine()){ + //读入初始状态 + int row = io.readInt(); + int col = io.readInt(); + Position initialState = new Position(row, col); + //读入目标状态 + row = io.readInt(); + col = io.readInt(); + Position goal = new Position(row, col); + //生成寻路问题的实例,并设置其地图 + PathFinding problem = new PathFinding(initialState, goal, size); + problem.setGrids(grids); + //添加到问题列表 + problems.add(problem); + } + return problems; + } + + @Override + public ArrayList getProblems(Scanner scanner) { + return null; + } + + /** + * 生成采取某种估值机制的Frontier + * + * @param type 结点评估器的类型 + * @return 使用该评估机制的一个Frontier实例 + */ + @Override + public AbstractFrontier getFrontier(EvaluationType type) { + return new LinkedFrontier(Node.evaluator(type)); + } + + /** + * 获得对状态进行估值的Predictor + * + * @param type 估值函数的类型 + * @return 估值函数 + */ + @Override + public Predictor getPredictor(HeuristicType type) { + return Position.predictor(type); + } + + /** + * 生成IdaStar搜索的一个实例 + */ + @Override + public Searcher getIdaStar() { + return null; + } + + /** + * 用来提交头歌评分的Searcher + * + * @return 搜索引擎 + */ + @Override + public Searcher getScoreSearcher() { + return getAStar(HeuristicType.PF_GRID); + } + +} diff --git a/SearchFramework1.0.1/src/xu/problem/pathfinding/GridType.java b/SearchFramework1.0.1/src/xu/problem/pathfinding/GridType.java new file mode 100644 index 0000000..e71409a --- /dev/null +++ b/SearchFramework1.0.1/src/xu/problem/pathfinding/GridType.java @@ -0,0 +1,23 @@ +package xu.problem.pathfinding; + +public enum GridType { + EMPTY('0'), // 空地 + GRASS('#'), // 草地,通过的代价高,普通代价的2倍 + //MUDDY, // 泥地,通过代价为3倍 + WALL('*'); // 石墙,无法通过 + + private final char symbol; + + GridType(char symbol){ + this.symbol = symbol; + } + + public char symbol(){ + return symbol; + } + + @Override + public String toString() { + return symbol + ""; + } +} diff --git a/SearchFramework1.0.1/src/xu/problem/pathfinding/Move.java b/SearchFramework1.0.1/src/xu/problem/pathfinding/Move.java new file mode 100644 index 0000000..14a0054 --- /dev/null +++ b/SearchFramework1.0.1/src/xu/problem/pathfinding/Move.java @@ -0,0 +1,43 @@ +package xu.problem.pathfinding; + +import core.problem.Action; + +public class Move extends Action { + + private final Direction direction; + + public Move(Direction direction) { + this.direction = direction; + } + + public Direction getDirection() { + return direction; + } + + @Override + public void draw() { + System.out.println(toString()); + } + + @Override + public int stepCost() { + return Direction.cost(direction); + } + + @Override + public String toString() { + return direction.symbol() + ""; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + + if (obj instanceof Move) { + Move another = (Move) obj; + //两个Node对象的状态相同,则认为是相同的 + return this.direction.equals(another.direction); + } + return false; + } +} diff --git a/SearchFramework1.0.1/src/xu/problem/pathfinding/PathFinding.java b/SearchFramework1.0.1/src/xu/problem/pathfinding/PathFinding.java new file mode 100644 index 0000000..f6f5c1c --- /dev/null +++ b/SearchFramework1.0.1/src/xu/problem/pathfinding/PathFinding.java @@ -0,0 +1,146 @@ +package xu.problem.pathfinding; + +import core.problem.Action; +import core.problem.Problem; +import core.problem.State; +import core.solver.Node; +import java.util.Deque; + +/** + * 寻路问题 + */ +public class PathFinding extends Problem { + + //地图信息 + GridType[][] grids; + + public PathFinding(State initialState, State goal) { + super(initialState, goal); + } + + public PathFinding(State initialState, State goal, int size) { + super(initialState, goal, size); + grids = new GridType[size][size]; + } + + public GridType[][] getGrids() { + return grids; + } + + public void setGrids(GridType[][] grids) { + for (int i = 0; i < size; i++){ + System.arraycopy(grids[i], 0, this.grids[i], 0, size); + } + } + + /** + * 当前问题是否有解 + * 因为只有通过搜索来判断,所以先默认为true + * @return 有解,true; 无解,false + */ + @Override + public boolean solvable() { + return true; + } + + @Override + public int stepCost(State state, Action action) { + Position position = (Position) state ; + GridType type = grids[position.getRow() - 1][position.getCol() - 1]; + if (type == GridType.EMPTY) + return action.stepCost(); + if (type == GridType.GRASS) + return action.stepCost() * 5; + return Integer.MIN_VALUE; + } + + @Override + protected boolean applicable(State state, Action action) { + int[] offsets = Direction.offset(((Move)action).getDirection()); + int row = ((Position)state).getRow() + offsets[1]; + int col = ((Position)state).getCol() + offsets[0]; + return row > 0 && row <= size && + col > 0 && col <= size && + grids[row - 1][col - 1] != GridType.WALL; + } + + @Override + public void showSolution(Deque path) { + //将地图转换为字符数组 + char[][] grids = new char[size][]; + for (int i = 0; i < size; i++){ + grids[i] = new char[size]; + for (int j = 0; j < size; j++) { + grids[i][j] = this.grids[i][j].symbol(); + } + } + //标记起点 + int row = ((Position)initialState).getRow(); + int col = ((Position)initialState).getCol(); + grids[row - 1][col - 1] = '@'; + //和终点 + row = ((Position)goal).getRow(); + col = ((Position)goal).getCol(); + grids[row - 1][col - 1] = '&'; + + //打印寻路问题。 + System.out.println(initialState + "→" + goal); + //将解路径中的动作符号写入字符数组grids + for (Node node : path) { + Position p = (Position) node.getState(); + Move move = (Move) node.getAction(); + Direction d = move.getDirection(); + grids[p.getRow() - 1][p.getCol() - 1] = d.symbol(); + } + + //打印字符数组 + drawGrid(grids); + } + + private void drawGrid(char[][] grids) { + for (int i = 0; i < size; i++){ + for (int j = 0; j < size; j++) { + System.out.print(grids[i][j] + " "); + } + System.out.println(); + } + } + + /** + * 打印当前问题的起点→终点 + * 和 地图 + */ + @Override + public void draw() { + System.out.println(initialState + "→" + goal); + for (GridType[] rows : grids){ + for (GridType type : rows){ + System.out.print(type.symbol() + " "); + } + System.out.println(); + } + } + + /** + * 打印解路径所采取的动作序列 + * @param path 解路径 + */ + @Override + public void printPath(Deque path) { + if (path == null){ + System.out.println("No Solution."); + return; + } + for (Node node : path) { + Move move = (Move) node.getAction(); + System.out.print(move.getDirection().name() + " "); + } + System.out.println(); + + } + + @Override + public String toString() { + return super.toString(); + } +} diff --git a/SearchFramework1.0.1/src/xu/problem/pathfinding/Point.java b/SearchFramework1.0.1/src/xu/problem/pathfinding/Point.java new file mode 100644 index 0000000..7a3e5e7 --- /dev/null +++ b/SearchFramework1.0.1/src/xu/problem/pathfinding/Point.java @@ -0,0 +1,107 @@ +package xu.problem.pathfinding; + +import java.util.ArrayList; +import java.util.Comparator; + +import static java.util.Comparator.*; + +public class Point implements Comparable{ + + public int getX() { + return x; + } + public void setX(int x) { + this.x = x; + } + public int getY() { + return y; + } + public void setY(int y) { + this.y = y; + } + public Point(int x, int y) { + super(); + this.x = x; + this.y = y; + } + private int x; + private int y; + @Override + public String toString() { + return "(" + x + "," + y + ")"; + } + + public static final Comparator RowColComparator = naturalOrder(); + + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj instanceof Point){ + Point p = (Point) obj; + return this.x == p.x && this.y == p.y; + } + return false; + } + + @Override + public int hashCode() { + return x << 3 | y; + } + + //根据x坐标比较 + public static final Comparator TestComparator = comparingInt(arg0 -> arg0.x); + + //根据到原点的曼哈顿距离进行比较 + public static final Comparator ManhattanComparator = comparingInt(arg0 -> arg0.manhattan(new Point(0, 0))); + + /** + * 当前点对象与参数p之间的曼哈顿距离 + * @param p 另一个点p + * @return 当前点对象与p的曼哈顿距离 + */ + public int manhattan(Point p){ + return Math.abs(this.x - p.x) + Math.abs(this.y - p.y); + } + + /** + * 当前点对象与参数p之间的欧几里得距离,取整 + * @param p 另一个点p + * @return 当前点对象与p的欧几里得距离 + */ + public double euclid(Point p){ + int x = this.x - p.x; + int y = this.y - p.y; + return Math.sqrt(x * x + y * y); + } + + /** + * 自然序,先比较横坐标,再比较纵坐标 + */ + @Override + public int compareTo(Point p) { + if (this.x == p.x) + return this.y - p.y; + + return this.x - p.x; + } + + public static void main(String[] args) { + ArrayList treeset = new ArrayList<>(); + Point p = new Point(3, 5); + treeset.add(p); + p = new Point(4, 5); + treeset.add(p); + p = new Point(2, 7); + treeset.add(p); + p = new Point(3, 7); + treeset.add(p); + p = new Point(3, 1); + treeset.add(p); + treeset.sort(ManhattanComparator); + + for (Point point : treeset) { + System.out.println(point); + } + } +} diff --git a/SearchFramework1.0.1/src/xu/problem/pathfinding/Position.java b/SearchFramework1.0.1/src/xu/problem/pathfinding/Position.java new file mode 100644 index 0000000..244b264 --- /dev/null +++ b/SearchFramework1.0.1/src/xu/problem/pathfinding/Position.java @@ -0,0 +1,132 @@ +package xu.problem.pathfinding; + +import core.problem.Action; +import core.problem.State; +import core.runner.HeuristicType; +import core.solver.Node; +import core.solver.heuristic.Predictor; +import java.util.ArrayList; +import java.util.EnumMap; + +/** + * PathFinding问题的状态 + * 位置状态,表示寻路机器人在什么位置 + */ +public class Position extends State { + public static final int SCALE = 10; //单元格的边长 + public static final double ROOT2 = 1.4; //2的平方根 + + //可移动的方向:四个方向或者八个方向 + private static final int MOVETYPE = 1; //八个方向移动 + private static final Direction[][] directions = new Direction[2][]; + static{ + //四个方向移动 + directions[0] = new Direction[]{Direction.N, Direction.E, Direction.S, Direction.W}; + //八个方向移动 + directions[1] = Direction.values(); + } + + //机器人在场地中的位置 + private final Point point; + + public Position(int row, int col) { + this.point = new Point(row, col); + } + + @Override + public void draw() { + System.out.println(this); + } + + /** + * 当前状态采用action而进入的下一个状态 + * + * @param action 当前状态下,一个可行的action + * @return 下一个状态 + */ + @Override + public State next(Action action) { + //当前Action所带来的位移量 + Direction dir = ((Move)action).getDirection(); + int[] offsets = Direction.offset(dir); + //生成新状态所在的点 + int col = getCol() + offsets[0]; + int row = getRow() + offsets[1]; + + return new Position(row, col); + } + + @Override + public Iterable actions() { + ArrayList moves = new ArrayList<>(); + for (Direction d : directions[MOVETYPE]) + moves.add(new Move(d)); + return moves; + } + + //枚举映射,存放不同类型的启发函数 + private static final EnumMap predictors = new EnumMap<>(HeuristicType.class); + static{ + predictors.put(HeuristicType.PF_EUCLID, + (state, goal) -> ((Position)state).euclid((Position)goal)); + predictors.put(HeuristicType.PF_MANHATTAN, + (state, goal) -> ((Position)state).manhattan((Position)goal)); + predictors.put(HeuristicType.PF_GRID, + (state, goal) -> ((Position)state).gridDistance((Position)goal)); + } + public static Predictor predictor(HeuristicType type){ + return predictors.get(type); + } + + //两个点之间的Grid距离,尽量走对角线 + private int gridDistance(Position goal) { + int width = Math.abs(this.getCol() - goal.getCol()); + int height = Math.abs(this.getRow() - goal.getRow()); + if (width > height) { + return (width - height) * SCALE + height * (int) (SCALE * ROOT2); + } + else{ + return (height - width) * SCALE + width * (int) (SCALE * ROOT2); + } + } + + //两个点之间的曼哈顿距离乘以SCALE + private int manhattan(Position goal) { + return this.point.manhattan(goal.point) * SCALE; + } + + //两个点之间的欧几里德距离 + private int euclid(Position goal) { + return (int) (this.point.euclid(goal.point) * SCALE); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + + if (obj instanceof Position ) { + Position another = (Position) obj; + //两个Node对象的状态相同,则认为是相同的 + return this.point.equals(another.point); + } + return false; + } + + @Override + public int hashCode() { + return point.hashCode(); + } + + @Override + public String toString() { + return point.toString(); + } + + public int getRow() { + return point.getX(); + } + + public int getCol() { + return point.getY(); + } +} diff --git a/SearchFramework1.0.1/src/xu/solver/heuristic/LinkedFrontier.java b/SearchFramework1.0.1/src/xu/solver/heuristic/LinkedFrontier.java new file mode 100644 index 0000000..6079aab --- /dev/null +++ b/SearchFramework1.0.1/src/xu/solver/heuristic/LinkedFrontier.java @@ -0,0 +1,89 @@ +package xu.solver.heuristic; + +import core.problem.State; +import core.solver.Node; +import core.solver.heuristic.AbstractFrontier; + +import java.util.Comparator; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Collection; +/** + * 封装了LinkedList数据结构的Frontier + */ +public class LinkedFrontier extends AbstractFrontier { + //底层实现用的是LinkedList + private final LinkedList nodeList = new LinkedList<>(); + + public LinkedFrontier(Comparator evaluator) { + super(evaluator); + } + + /** + * 获取 Frontier 中,状态为 s 的节点 + * + * @param s 状态 + * @return 存在: 相应的状态为 s 的节点; + * 不存在:null + */ + @Override + protected Node getNode(State s) { + for (Node node: nodeList){ + if (node.getState().equals(s)){ + return node; + } + } + return null; + } + + @Override + public boolean remove(Object o) { + return nodeList.remove(o); + } + + /** + * 将结点node插入到当前有序链表中 + * @param node 要插入的结点 + * @return 插入成功返回true + */ + @Override + public boolean add(Node node) { + int j = 0; + + for (Node value : nodeList) { + if (evaluator.compare(value, node) >= 0) { + break; + } + j++; + } + + nodeList.add(j, node); + + return true; + } + + @Override + public Iterator iterator() { + return nodeList.iterator(); + } + + @Override + public int size() { + return nodeList.size(); + } + + @Override + public boolean offer(Node node) { + return this.add(node); + } + + @Override + public Node poll() { + return nodeList.poll(); + } + + @Override + public Node peek() { + return nodeList.peek(); + } +} diff --git a/SearchFramework1.0.1/test/xu/problem/pathfinding/PathFeederTest.java b/SearchFramework1.0.1/test/xu/problem/pathfinding/PathFeederTest.java new file mode 100644 index 0000000..ca37a20 --- /dev/null +++ b/SearchFramework1.0.1/test/xu/problem/pathfinding/PathFeederTest.java @@ -0,0 +1,29 @@ +package xu.problem.pathfinding; + +import algs4.util.In; +import core.problem.Problem; +import core.runner.EngineFeeder; +import org.junit.jupiter.api.Test; + + + +import java.util.ArrayList; + +class PathFeederTest { + + @Test + void getProblems() { + //生成一个具体的EngineFeeder:FeederXu,引擎饲养员徐老师:) + EngineFeeder feeder = new FeederXu(); + + //从文件中读入问题的实例,NPuzzle问题 + In problemInput = new In("resources/pathfinding.txt"); + //feeder从文件获取所有问题实例 + ArrayList problems = feeder.getProblems(problemInput); + + for (Problem problem : problems){ + problem.draw(); + } + + } +} \ No newline at end of file diff --git a/SearchFramework1.0.1/test/xu/problem/pathfinding/PathFindingTest.java b/SearchFramework1.0.1/test/xu/problem/pathfinding/PathFindingTest.java new file mode 100644 index 0000000..18e57e8 --- /dev/null +++ b/SearchFramework1.0.1/test/xu/problem/pathfinding/PathFindingTest.java @@ -0,0 +1,28 @@ +package xu.problem.pathfinding; + +import algs4.util.In; +import core.problem.Problem; +import core.runner.EngineFeeder; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; + +import static org.junit.jupiter.api.Assertions.*; + +class PathFindingTest { + + @Test + void applicable() { + //生成一个具体的EngineFeeder:FeederXu,引擎饲养员徐老师:) + EngineFeeder feeder = new FeederXu(); + + //从文件中读入问题的实例,NPuzzle问题 + In problemInput = new In("resources/pathfinding.txt"); + //feeder从文件获取所有问题实例 + ArrayList problems = feeder.getProblems(problemInput); + + Position position = new Position(7, 4); + assertFalse(((PathFinding)problems.get(0)).applicable(position, new Move(Direction.S))); + assertTrue(((PathFinding)problems.get(0)).applicable(position, new Move(Direction.E))); + } +} \ No newline at end of file diff --git a/SearchFramework1.0.1/test/xu/problem/pathfinding/PositionTest.java b/SearchFramework1.0.1/test/xu/problem/pathfinding/PositionTest.java new file mode 100644 index 0000000..8eb5411 --- /dev/null +++ b/SearchFramework1.0.1/test/xu/problem/pathfinding/PositionTest.java @@ -0,0 +1,20 @@ +package xu.problem.pathfinding; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class PositionTest { + + @Test + void next() { + Position position = new Position(5, 6); + assertEquals(position.next(new Move(Direction.S)), new Position(6, 6)); + + Position next = (Position) position.next(new Move(Direction.E)); // (5,7) + assertEquals(next, new Position(5, 7)); + assertEquals(next.next(new Move(Direction.N)), new Position(4, 7)); + assertEquals(next.next(new Move(Direction.W)), new Position(5, 6)); + + } +} \ No newline at end of file diff --git a/SearchFramework1.0.1/test/xu/solver/heuristic/LinkedFrontierTest.java b/SearchFramework1.0.1/test/xu/solver/heuristic/LinkedFrontierTest.java new file mode 100644 index 0000000..37007dc --- /dev/null +++ b/SearchFramework1.0.1/test/xu/solver/heuristic/LinkedFrontierTest.java @@ -0,0 +1,65 @@ +package xu.solver.heuristic; + +import core.problem.State; +import core.solver.Node; +import core.solver.heuristic.EvaluationType; +import xu.problem.pathfinding.Direction; +import xu.problem.pathfinding.Move; +import xu.problem.pathfinding.Point; +import xu.problem.pathfinding.Position; + +import static org.junit.jupiter.api.Assertions.*; + +class LinkedFrontierTest { + + @org.junit.jupiter.api.Test + void offer() { + LinkedFrontier frontier = new LinkedFrontier(Node.evaluator(EvaluationType.FULL)); + State position = new Position(4, 4); + Node parent = new Node(position, null, null, 0, 15); + + position = new Position(5, 5); + Node node = new Node(position, parent, new Move(Direction.SE), 0, 15); + frontier.offer(node); + + position = new Position(5, 6); + node = new Node(position, node, new Move(Direction.S), 1, 13); + frontier.offer(node); + position = new Position(6, 6); + node = new Node(position, node, new Move(Direction.E), 2, 13); + frontier.offer(node); + position = new Position(7, 6); + node = new Node(position, node, new Move(Direction.E), 3, 9); + frontier.offer(node); + + for (Node node1: frontier){ + System.out.println(node1); + } + System.out.println(); + + position = new Position(9, 6); + node = new Node(position, node, new Move(Direction.E), 2, 13); + + System.out.println(frontier.getNode(node.getState())); + + position = new Position(6, 6); + node = new Node(position, node, new Move(Direction.W), 22, 13); + + System.out.println(frontier.contains(node)); + + System.out.println(); + + position = new Position(5, 6); + node = new Node(position, node, new Move(Direction.S), 3, 10); + frontier.discardOrReplace(node); + + for (Node node1: frontier){ + System.out.println(node1); + } + + System.out.println(); + while (!frontier.isEmpty()){ + frontier.poll().draw(); + } + } +} \ No newline at end of file