├── gradle.properties
├── graphics
├── ic_launcher.png
├── screenshot1.png
├── screenshot2.png
├── screenshot3.png
├── feature_graphic.png
├── ic_launcher.svg
└── feature_graphic.svg
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── src
└── main
│ ├── res
│ ├── drawable-hdpi
│ │ └── ic_launcher.png
│ ├── drawable-ldpi
│ │ └── ic_launcher.png
│ ├── drawable-mdpi
│ │ └── ic_launcher.png
│ ├── drawable-xhdpi
│ │ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ │ └── ic_launcher.png
│ ├── xml
│ │ ├── backup_rules.xml
│ │ └── preferences.xml
│ ├── values
│ │ ├── theme.xml
│ │ └── strings.xml
│ ├── layout
│ │ ├── result.xml
│ │ ├── about.xml
│ │ ├── search.xml
│ │ └── main.xml
│ ├── drawable
│ │ └── ic_menu.xml
│ ├── drawable-night
│ │ └── ic_menu.xml
│ └── menu
│ │ └── navigation.xml
│ ├── java
│ └── com
│ │ └── ids1024
│ │ └── whitakerswords
│ │ ├── AboutFragment.kt
│ │ ├── SettingsFragment.kt
│ │ ├── SearchAdapter.kt
│ │ ├── parse_words.kt
│ │ ├── SearchFragment.kt
│ │ ├── WhitakersWords.kt
│ │ └── WordsWrapper.kt
│ └── AndroidManifest.xml
├── settings.gradle
├── .gitignore
├── words
├── Dockerfile
├── WORD.MDV
└── build-words.sh
├── .github
└── workflows
│ └── ci.yml
├── .travis
└── bintray.json.in
├── words.LICENSE
├── fetch-words-bintray.sh
├── LICENSE
├── .travis.yml
├── README.md
├── gradlew.bat
└── gradlew
/gradle.properties:
--------------------------------------------------------------------------------
1 | android.useAndroidX=true
2 |
--------------------------------------------------------------------------------
/graphics/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ids1024/whitakers-words-android/HEAD/graphics/ic_launcher.png
--------------------------------------------------------------------------------
/graphics/screenshot1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ids1024/whitakers-words-android/HEAD/graphics/screenshot1.png
--------------------------------------------------------------------------------
/graphics/screenshot2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ids1024/whitakers-words-android/HEAD/graphics/screenshot2.png
--------------------------------------------------------------------------------
/graphics/screenshot3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ids1024/whitakers-words-android/HEAD/graphics/screenshot3.png
--------------------------------------------------------------------------------
/graphics/feature_graphic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ids1024/whitakers-words-android/HEAD/graphics/feature_graphic.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ids1024/whitakers-words-android/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ids1024/whitakers-words-android/HEAD/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/src/main/res/drawable-ldpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ids1024/whitakers-words-android/HEAD/src/main/res/drawable-ldpi/ic_launcher.png
--------------------------------------------------------------------------------
/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ids1024/whitakers-words-android/HEAD/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ids1024/whitakers-words-android/HEAD/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | gradlePluginPortal()
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ids1024/whitakers-words-android/HEAD/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/main/res/values/theme.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 | bin/
3 | gen/
4 | local.properties
5 | .gradle/
6 | build/
7 | *.iml
8 | .idea/
9 | release.keystore
10 | words/words-build
11 | words/wordsall.zip
12 | words.tar.xz
13 | .travis/bintray.json
14 | src/main/assets/words
15 | libs/
16 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Mar 26 17:54:49 PDT 2021
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip
7 |
--------------------------------------------------------------------------------
/words/Dockerfile:
--------------------------------------------------------------------------------
1 | # sudo podman run --rm --privileged docker.io/multiarch/qemu-user-static --reset -p yes -c yes
2 | # podman build --arch arm64 --tag words-build .
3 |
4 | # Issue with dos2unix version in jammy
5 | FROM alpine:edge
6 | RUN apk update && apk add gcc-gnat unzip wget dos2unix musl-dev
7 |
8 |
--------------------------------------------------------------------------------
/src/main/res/layout/result.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | on: [push, pull_request]
2 |
3 | name: ci
4 |
5 | jobs:
6 | ci:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v2
10 | - run: ./build-words-docker.sh
11 | - run: ./gradlew assembleDebug
12 | - run: ./gradlew lint
13 | # - run: ./gradlew dokka
14 | - run: ./gradlew ktlintCheck
15 |
--------------------------------------------------------------------------------
/src/main/res/drawable/ic_menu.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/main/res/drawable-night/ic_menu.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/main/res/layout/about.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/.travis/bintray.json.in:
--------------------------------------------------------------------------------
1 | {
2 | "package": {
3 | "subject": "ids1024",
4 | "repo": "whitakers-words-android",
5 | "name": "master"
6 | },
7 | "version": {
8 | "name": "%VERSION%"
9 | },
10 | "files": [
11 | {
12 | "includePattern": "words.tar.xz",
13 | "uploadPattern": "words-%VERSION%.tar.xz"
14 | },
15 | {
16 | "includePattern": "build/outputs/apk/debug/(whitakers-words-android-debug).apk",
17 | "uploadPattern": "$1-%VERSION%.apk"
18 | }
19 | ],
20 | "publish": true
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/ids1024/whitakerswords/AboutFragment.kt:
--------------------------------------------------------------------------------
1 | package com.ids1024.whitakerswords
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.fragment.app.Fragment
8 |
9 | /**
10 | * Fragment for the about page.
11 | */
12 | class AboutFragment : Fragment() {
13 | override fun onCreateView(
14 | inflater: LayoutInflater,
15 | container: ViewGroup?,
16 | savedInstanceState: Bundle?
17 | ): View {
18 | return inflater.inflate(R.layout.about, container, false)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/words.LICENSE:
--------------------------------------------------------------------------------
1 | WORDS, a Latin dictionary, by Colonel William Whitaker (USAF, Retired)
2 |
3 | Copyright William A. Whitaker (1936–2010)
4 |
5 | This is a free program, which means it is proper to copy it and pass
6 | it on to your friends. Consider it a developmental item for which
7 | there is no charge. However, just for form, it is Copyrighted
8 | (c). Permission is hereby freely given for any and all use of program
9 | and data. You can sell it as your own, but at least tell me.
10 |
11 | This version is distributed without obligation, but the developer
12 | would appreciate comments and suggestions.
13 |
14 | All parts of the WORDS system, source code and data files, are made freely
15 | available to anyone who wishes to use them, for whatever purpose.
16 |
--------------------------------------------------------------------------------
/fetch-words-bintray.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 |
5 | version=$(curl https://bintray.com/api/v1/packages/ids1024/whitakers-words-android/master | \
6 | python -c 'import json, sys; print(json.load(sys.stdin)["latest_version"])')
7 |
8 | rm -f words.tar.xz
9 | curl -L https://dl.bintray.com/ids1024/whitakers-words-android/words-$version.tar.xz -o words.tar.xz
10 |
11 | rm -rf src/main/assets/words
12 | mkdir -p src/main/assets
13 | tar xf words.tar.xz -C src/main/assets
14 | echo "Words extracted to src/main/assets/words from $version on bintray."
15 |
16 | rm -rf libs
17 | mkdir -p libs/{armeabi-v7a,arm64-v8a}
18 | cp src/main/assets/words/words libs/armeabi-v7a/libwords.so
19 | cp src/main/assets/words/words libs/arm64-v8a/libwords.so
20 | echo "Copied to libs/"
21 |
--------------------------------------------------------------------------------
/src/main/java/com/ids1024/whitakerswords/SettingsFragment.kt:
--------------------------------------------------------------------------------
1 | package com.ids1024.whitakerswords
2 |
3 | import android.os.Bundle
4 | import androidx.preference.Preference
5 | import androidx.preference.PreferenceFragmentCompat
6 |
7 | /**
8 | * Fragment for the settings page.
9 | */
10 | class SettingsFragment : PreferenceFragmentCompat() {
11 | override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
12 | setPreferencesFromResource(R.xml.preferences, rootKey)
13 | }
14 |
15 | override fun onPreferenceTreeClick(preference: Preference): Boolean {
16 | return if (preference.key == "light_theme") {
17 | requireActivity().recreate()
18 | true
19 | } else {
20 | false
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/res/layout/search.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
15 |
20 |
21 |
--------------------------------------------------------------------------------
/src/main/res/menu/navigation.xml:
--------------------------------------------------------------------------------
1 |
19 |
--------------------------------------------------------------------------------
/src/main/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
20 |
21 |
--------------------------------------------------------------------------------
/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015-2019 Ian D. Scott
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/src/main/java/com/ids1024/whitakerswords/SearchAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.ids1024.whitakerswords
2 |
3 | import android.text.SpannableStringBuilder
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.TextView
8 | import androidx.recyclerview.widget.RecyclerView
9 | import java.util.ArrayList
10 |
11 | class SearchAdapter(private var results: ArrayList) : RecyclerView.Adapter() {
12 |
13 | override fun getItemCount(): Int {
14 | return results.size
15 | }
16 |
17 | override fun onBindViewHolder(holder: ViewHolder, position: Int) {
18 | holder.text_view.text = results[position]
19 | }
20 |
21 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
22 | val view = LayoutInflater.from(parent.context)
23 | .inflate(R.layout.result, parent, false)
24 | return ViewHolder(view)
25 | }
26 |
27 | class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
28 | val text_view: TextView = view.findViewById(R.id.result_text)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/words/WORD.MDV:
--------------------------------------------------------------------------------
1 | HAVE_STATISTICS_FILE N
2 | WRITE_STATISTICS_FILE N
3 | SHOW_DICTIONARY N
4 | SHOW_DICTIONARY_LINE N
5 | SHOW_DICTIONARY_CODES Y
6 | DO_PEARSE_CODES Y
7 | DO_ONLY_INITIAL_WORD N
8 | FOR_WORD_LIST_CHECK N
9 | DO_ONLY_FIXES N
10 | DO_FIXES_ANYWAY N
11 | USE_PREFIXES Y
12 | USE_SUFFIXES Y
13 | USE_TACKONS Y
14 | DO_MEDIEVAL_TRICKS Y
15 | DO_SYNCOPE Y
16 | DO_TWO_WORDS Y
17 | INCLUDE_UNKNOWN_CONTEXT Y
18 | NO_MEANINGS N
19 | OMIT_ARCHAIC Y
20 | OMIT_MEDIEVAL N
21 | OMIT_UNCOMMON Y
22 | DO_I_FOR_J N
23 | DO_U_FOR_V N
24 | PAUSE_IN_SCREEN_OUTPUT N
25 | NO_SCREEN_ACTIVITY N
26 | UPDATE_LOCAL_DICTIONARY N
27 | UPDATE_MEANINGS N
28 | MINIMIZE_OUTPUT Y
29 | START_FILE_CHARACTER '@'
30 | CHANGE_PARAMETERS_CHARACTER '#'
31 | CHANGE_DEVELOPER_MODES_CHARACTER '!'
32 |
--------------------------------------------------------------------------------
/words/build-words.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 |
5 | export PATH=$PWD/toolchain/bin:$PATH
6 | # TARGET=arm-linux-androideabi-
7 | # QEMU=qemu-arm
8 | ANDROID_SYSROOT="$PWD/ndk-chain/sysroot"
9 | BUILD_ARGS="-cargs -fPIE -largs -pie"
10 | STATIC_ARGS="-bargs -static -largs -static"
11 |
12 | echo "Removing directories..."
13 | rm -rf words words-build
14 |
15 | echo "Downloading words source..."
16 | if [ ! -f wordsall.zip ]
17 | then
18 | wget https://archives.nd.edu/whitaker/old/wordsall.zip
19 | fi
20 |
21 | mkdir words-build
22 | cd words-build
23 | echo "Extracting words..."
24 | unzip ../wordsall.zip
25 |
26 | echo "Fix line endings..."
27 | dos2unix -O ADDONS.LAT > ADDONS.LAT.new
28 | mv ADDONS.LAT.new ADDONS.LAT
29 |
30 | echo "Building words..."
31 | ${TARGET}gnatmake -O3 words $STATIC_ARGS
32 | ${TARGET}gnatmake makedict $STATIC_ARGS
33 | ${TARGET}gnatmake makestem $STATIC_ARGS
34 | ${TARGET}gnatmake makeefil $STATIC_ARGS
35 | ${TARGET}gnatmake makeinfl $STATIC_ARGS
36 |
37 | echo "Building data files in qemu..."
38 | echo G | $QEMU ./makedict
39 | echo G | $QEMU ./makestem
40 | echo G | $QEMU ./makeefil
41 | echo G | $QEMU ./makeinfl | sed '/\*\*\*\*/d'
42 |
43 | echo "Copying output to 'words'..."
44 | mkdir ../words
45 | cp ADDONS.LAT DICTFILE.GEN EWDSFILE.GEN INDXFILE.GEN INFLECTS.SEC STEMFILE.GEN UNIQUES.LAT words ../WORD.MDV ../words
46 | cd ..
47 |
48 | echo "Stripping words..."
49 | ${TARGET}strip words/words
50 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: android
2 | sudo: required
3 |
4 | git:
5 | # Do not use shallow clone, so git "rev-list --count" works
6 | depth: false
7 |
8 | services:
9 | - docker
10 |
11 | android:
12 | components:
13 | - build-tools-30.0.3
14 | - android-30
15 |
16 | script:
17 | - ./build-words-docker.sh
18 | - ./gradlew assembleDebug
19 | - ./gradlew lint
20 | - ./gradlew dokka
21 | - ./gradlew ktlintCheck
22 |
23 | before_deploy:
24 | - cd src/main/assets && tar cJf ../../../words.tar.xz words && cd ../../..
25 | - |
26 | sed s/%VERSION%/$(printf "r%s.%s" \
27 | "$(git rev-list --count HEAD)" \
28 | "$(git rev-parse --short HEAD)")/ \
29 | .travis/bintray.json.in > .travis/bintray.json
30 |
31 | deploy:
32 | - provider: bintray
33 | skip_cleanup: true
34 | file: .travis/bintray.json
35 | user: ids1024
36 | key:
37 | secure: "G0XaLMNJE2DmTbHCQ348vu+R3BREsQl2+smmRuB7T4GME5BSiN/7+acwYa24EiFMZ/1bKeKfKlqPktgiz72ySSQL2Pd624MIh7OPhtWS6RdXKdI8z3OZe7A+cxAV151qWDBpU8KjflcrRXlnsTKS9dW/IIYUTXEWo1qG5zUFSlkDVlP5SLB/7/PHY5A8U7n+Kp1wp/dIMQQyCzjGIr3BqaPYZByQXV2kTxVWMNfVjN9bliptfbZwnqfPrMruSJPiXYLsdP7VSEqazri3zPn9W3tdoku1MIuIEl9HXPVx1OflI/n5nTzOvun054J6kxxcoqFZZNXa879dyh7bJ9vN7KzP1Ksi2CZXh9G1vSaKRBELsoNJhNP9u6n9koZjqkgzzQwTbAvNqzazSXnR0w5PSjRpvSZrHbrjUpv7xAF2W5DljNYI7039Wne/N5V1Gfin+cW+NHD6BXoXKGfR4mWHRMUp3JQjZjbf+a5Js/cYfMivJTfXGj7f4FBbo3BPN9sR77RNeFihbbTLOEFNQFZhgT7Gz8Cj6633dOA/K1/5Ag6NS38QQX1/3kyOOPKDyU7Nd1sg2ntPQFa1mAQb4mnh8qu+J13stDstaGxg3bi/nsBdwZpOo8WYrFux9j7syfymmIkjzaQWBcURlqMe8AG/QAd+ATtV9vJj4v/l5L6MMg4="
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Whitaker's Words for Android
2 | ============================
3 |
4 | [](https://travis-ci.org/ids1024/whitakers-words-android)
5 |
6 | [`words`](http://archives.nd.edu/whitaker/words.htm) is a dictionary and morphological analysis tool by Colonel William Whitaker for Latin that accepts words of any form and gives the case/tense/etc. along with a short definition. This app provides a native Android interface that wraps the original command line program.
7 |
8 | This app is on [Google Play](https://play.google.com/store/apps/details?id=com.ids1024.whitakerswords).
9 |
10 | License
11 | -------
12 |
13 | Whitaker's Ada code is under the license in the [`words.LICENSE`](words.LICENSE) file, while all the code here is under the [MIT license](LICENSE).
14 |
15 | Compiling
16 | ---------
17 |
18 | ### Downloading or building the words executable and data files
19 |
20 | Building the Ada code is problematic, since Android's NDK only supports C and C++. The `words` directory has scripts for building a copy of GCC with Ada support, targeting Android. Moreover, it has data files that need to be build, and potentially differ by architecture. So the build script here uses `qemu` to generate those.
21 |
22 | To provide such I toolchain, I've built a [docker image](https://hub.docker.com/r/ids1024/ada-android/), which you can download and use, or [build yourself](https://github.com/ids1024/ada-android-docker) (given enough CPU time and disk space). Prebuilt copies of words, automatically built by Travis CI, are available on [Bintray](https://bintray.com/ids1024/whitakers-words-android/master).
23 |
24 | To compile this app, you'll need to obtain a copy of words in one of two ways:
25 |
26 | Download prebuilt words from Bintray:
27 |
28 | ```bash
29 | ./fetch-words-bintray.sh
30 | ```
31 |
32 | Or, download the docker image and build words:
33 |
34 | ```bash
35 | ./build-words-docker.sh
36 | ```
37 |
38 | ### Compiling the app
39 |
40 | This uses the standard gradle build system for Android, so any documentation on that will apply, or you can use Android Studio.
41 |
42 | For instance, `./gradlew installDebug` will build the app and install it on your device.
43 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/graphics/ic_launcher.svg:
--------------------------------------------------------------------------------
1 |
2 |
67 |
--------------------------------------------------------------------------------
/graphics/feature_graphic.svg:
--------------------------------------------------------------------------------
1 |
2 |
68 |
--------------------------------------------------------------------------------
/src/main/java/com/ids1024/whitakerswords/parse_words.kt:
--------------------------------------------------------------------------------
1 | package com.ids1024.whitakerswords
2 |
3 | import android.graphics.Color
4 | import android.graphics.Typeface
5 | import android.text.SpannableStringBuilder
6 | import android.text.TextUtils
7 | import android.text.style.ForegroundColorSpan
8 | import android.text.style.StyleSpan
9 |
10 | /**
11 | * Parses plain text from `words` to add basic formatting (such as italics).
12 | */
13 | fun parse_words(input: String): ArrayList {
14 | val results = ArrayList()
15 |
16 | var processed_result = SpannableStringBuilder()
17 | for (line in input.split("\n".toRegex())) {
18 | val words = line.split(" +".toRegex())
19 | var handled_line = TextUtils.join(" ", words)
20 | var pearse_code = 0
21 | if (words.isNotEmpty() && words[0].length == 2) {
22 | try {
23 | pearse_code = Integer.parseInt(words[0])
24 | handled_line = handled_line.substring(3)
25 | } catch (e: NumberFormatException) {
26 | }
27 | }
28 | // Indent meanings
29 | if (pearse_code == 3) {
30 | handled_line = " $handled_line"
31 | }
32 |
33 | if (line.isEmpty() || line == "*") {
34 | if (line == "*") {
35 | processed_result.append("*")
36 | }
37 | val finalresult = processed_result.toString().trim()
38 | if (finalresult.isNotEmpty()) {
39 | results.add(processed_result)
40 | }
41 | processed_result = SpannableStringBuilder()
42 | continue
43 | }
44 |
45 | val startindex = processed_result.length
46 | processed_result.append(handled_line + "\n")
47 |
48 | var span: Any? = null
49 | var endindex = processed_result.length
50 | when (pearse_code) {
51 | // Forms
52 | 1 -> {
53 | span = StyleSpan(Typeface.BOLD)
54 | endindex = startindex + words[1].length
55 | }
56 | // Dictionary forms
57 | 2 -> {
58 | // A HACK(?) for parsing output of searches like
59 | // "quod", which show shorter output for dictionary forms
60 | if (!words[1].startsWith("[")) {
61 | var index = 1
62 | endindex = startindex
63 | do {
64 | endindex += words[index].length + 1
65 | index += 1
66 | } while (words[index - 1].endsWith(","))
67 |
68 | span = StyleSpan(Typeface.BOLD)
69 | }
70 | }
71 | // Meaning
72 | 3 -> span = StyleSpan(Typeface.ITALIC)
73 | // Not found
74 | 4 -> span = ForegroundColorSpan(Color.RED)
75 | // Addons
76 | 5 -> {
77 | }
78 | // Tricks/syncope/addons?
79 | 6 -> {
80 | }
81 | }
82 | processed_result.setSpan(span, startindex, endindex, 0)
83 | }
84 | val finalresult = processed_result.toString().trim()
85 | if (finalresult.isNotEmpty()) {
86 | results.add(processed_result)
87 | }
88 |
89 | return results
90 | }
91 |
--------------------------------------------------------------------------------
/src/main/java/com/ids1024/whitakerswords/SearchFragment.kt:
--------------------------------------------------------------------------------
1 | package com.ids1024.whitakerswords
2 |
3 | import android.content.SharedPreferences
4 | import android.os.Bundle
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.Toast
9 | import androidx.appcompat.widget.SearchView.OnQueryTextListener
10 | import androidx.fragment.app.Fragment
11 | import androidx.preference.PreferenceManager
12 | import androidx.recyclerview.widget.DividerItemDecoration
13 | import androidx.recyclerview.widget.LinearLayoutManager
14 | import com.ids1024.whitakerswords.databinding.SearchBinding
15 | import java.io.IOException
16 |
17 | /**
18 | * Fragment providing the search UI.
19 | */
20 | class SearchFragment(var english_to_latin: Boolean) : Fragment() {
21 | private var search_term: String = ""
22 | private lateinit var preferences: SharedPreferences
23 | private lateinit var words: WordsWrapper
24 | private lateinit var binding: SearchBinding
25 |
26 | constructor() : this(false)
27 |
28 | override fun onCreate(savedInstanceState: Bundle?) {
29 | super.onCreate(savedInstanceState)
30 |
31 | preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
32 | words = WordsWrapper(requireContext())
33 | preferences.registerOnSharedPreferenceChangeListener { _, _ ->
34 | words.updateConfigFile()
35 | }
36 | }
37 |
38 | override fun onCreateView(
39 | inflater: LayoutInflater,
40 | container: ViewGroup?,
41 | savedInstanceState: Bundle?
42 | ): View {
43 | binding = SearchBinding.inflate(inflater, container, false)
44 | return binding.root
45 | }
46 |
47 | override fun onDestroyView() {
48 | binding.searchView.setOnQueryTextListener(null)
49 | super.onDestroyView()
50 | }
51 |
52 | override fun onActivityCreated(savedInstanceState: Bundle?) {
53 | super.onActivityCreated(savedInstanceState)
54 |
55 | binding.recyclerView.layoutManager = LinearLayoutManager(context)
56 | binding.recyclerView.addItemDecoration(DividerItemDecoration(binding.recyclerView.context, DividerItemDecoration.VERTICAL))
57 |
58 | if (english_to_latin) {
59 | binding.searchView.queryHint = resources.getString(R.string.english_to_latin)
60 | } else {
61 | binding.searchView.queryHint = resources.getString(R.string.latin_to_english)
62 | }
63 |
64 | binding.searchView.setOnQueryTextListener(object : OnQueryTextListener {
65 | override fun onQueryTextSubmit(query: String): Boolean {
66 | searchWord(query)
67 | binding.searchView.clearFocus()
68 | return true
69 | }
70 |
71 | override fun onQueryTextChange(query: String): Boolean {
72 | if (preferences.getBoolean("search_on_keypress", true)) {
73 | searchWord(query)
74 | }
75 | return true
76 | }
77 | })
78 |
79 | if (savedInstanceState != null) {
80 | english_to_latin = savedInstanceState.getBoolean("english_to_latin")
81 | searchWord(savedInstanceState.getString("search_term")!!)
82 | } else if (search_term != "") {
83 | searchWord(search_term)
84 | }
85 | }
86 |
87 | override fun onSaveInstanceState(outState: Bundle) {
88 | outState.putString("search_term", search_term)
89 | outState.putBoolean("english_to_latin", english_to_latin)
90 | super.onSaveInstanceState(outState)
91 | }
92 |
93 | private fun searchWord(search_term: String) {
94 | this.search_term = search_term
95 |
96 | val result: String
97 | try {
98 | result = words.executeWords(search_term, english_to_latin)
99 | } catch (ex: IOException) {
100 | val toast = Toast.makeText(context, "Failed to execute words!", Toast.LENGTH_SHORT)
101 | toast.show()
102 | return
103 | }
104 |
105 | val results = parse_words(result)
106 | binding.recyclerView.adapter = SearchAdapter(results)
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Whitaker\'s Words
4 | Settings
5 | Latin-English
6 | English-Latin
7 |
8 | Open drawer
9 | Close drawer
10 |
11 |
12 | Words Settings
13 | Miscellaneous
14 |
15 | Trim output
16 | Removes least likely results. If results have been trimmed, output will be followed by an astrisk (*). Default: true
17 | Do unknowns only
18 | Show only unrecognized words. Default: false
19 | Ignore unknown names
20 | Ignore capitalized words longer than three letters if they are not in the dictionary, instead of printing UNKNOWN. Default: true
21 | Ignore unknown caps
22 | Ignore words in all caps if they are not in the dictionary, instead of printing UNKNOWN. Default: true
23 | Do compounds
24 | Look ahead for the verb TO_BE (or iri) when it finds a verb participle, with the expectation of finding a compound perfect tense or periphastic. Default: true
25 | Do fixes
26 | When a result for a word is not found, try again with various prefixes and suffixes. Generally useful, but sometimes yields false positives. Default: true
27 | Do tricks
28 | When a result is not found, try replacements like cl -> cul, vul -> vol, ads -> ass, inp -> imp, etc., to provide for recognized variants of classical spelling, though false positives can result. Default: true
29 | Do dictionary forms
30 | Output line with forms associated with dictionary entry (nom/gen for noun, etc.). Default: true
31 | Show age
32 | Show what during periods a word/inflection was in use. Default: true
33 | Show frequency
34 | Show how frequently a word/inflection was used. Default: true
35 | Do examples
36 | Provide examples for usage of case/tenses/etc. Produces lengthy output. Default: false
37 | Do only meanings
38 | Output meaning without inflection details. Default: false
39 | Do stems for unknown
40 | When unable to find a proper match in the dictionary, list the dictionary entries around the unknown. This will likely catch a substantive for which only the ADJ stem appears in dictionary, an ADJ for which there is only a N stem, etc. Default: false
41 |
42 | Search on keypress
43 | Displays result while you type, without needing to press search. Default: true
44 |
45 |
46 | About
47 | About Whitaker\'s Words
48 |
49 | The \'words\' program was created by Wiliam Whitaker. It is open
50 | source, under the following terms:\n\n
51 |
52 | \"All parts of the WORDS system, source code and data files, are made freely available to anyone who wishes to use them, for whatever purpose.\"\n\n
53 |
54 | An archieved version of Whitaker\'s website is available at
55 | http://archives.nd.edu/whitaker/words.htm.\n\n
56 |
57 | This app is Open Source. Other than Whitaker\'s code, it under the MIT
58 | License. The source code is available at
59 | https://github.com/ids1024/whitakers-words-android.\n\n
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/src/main/res/xml/preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
13 |
19 |
25 |
31 |
37 |
43 |
49 |
55 |
61 |
67 |
73 |
79 |
85 |
86 |
89 |
95 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/src/main/java/com/ids1024/whitakerswords/WhitakersWords.kt:
--------------------------------------------------------------------------------
1 | package com.ids1024.whitakerswords
2 |
3 | import android.content.res.Configuration
4 | import android.os.Bundle
5 | import android.view.MenuItem
6 | import androidx.appcompat.app.ActionBarDrawerToggle
7 | import androidx.appcompat.app.AppCompatActivity
8 | import androidx.appcompat.app.AppCompatDelegate
9 | import androidx.fragment.app.Fragment
10 | import androidx.preference.PreferenceManager
11 | import com.ids1024.whitakerswords.databinding.MainBinding
12 |
13 | class WhitakersWords : AppCompatActivity() {
14 | private var fragments = HashMap()
15 | private lateinit var action_bar_drawer_toggle: ActionBarDrawerToggle
16 |
17 | override fun onCreate(savedInstanceState: Bundle?) {
18 | super.onCreate(savedInstanceState)
19 | val binding = MainBinding.inflate(layoutInflater)
20 | setContentView(binding.root)
21 |
22 | val preferences = PreferenceManager.getDefaultSharedPreferences(this)
23 | val nightMode = if (preferences.getBoolean("light_theme", false)) {
24 | AppCompatDelegate.MODE_NIGHT_NO
25 | } else {
26 | AppCompatDelegate.MODE_NIGHT_YES
27 | }
28 | AppCompatDelegate.setDefaultNightMode(nightMode)
29 |
30 | supportActionBar!!.setDisplayHomeAsUpEnabled(true)
31 |
32 | supportFragmentManager.addOnBackStackChangedListener {
33 | val fragment = supportFragmentManager.findFragmentById(R.id.content)
34 |
35 | val (title, item) = when (fragment) {
36 | is SearchFragment -> {
37 | if (fragment.english_to_latin) {
38 | Pair(R.string.app_name, R.id.action_english_to_latin)
39 | } else {
40 | Pair(R.string.app_name, R.id.action_latin_to_english)
41 | }
42 | }
43 | is SettingsFragment ->
44 | Pair(R.string.settings, R.id.action_settings)
45 | is AboutFragment ->
46 | Pair(R.string.about_long_title, R.id.action_about)
47 | else -> throw RuntimeException() // Unreachable
48 | }
49 |
50 | supportActionBar!!.title = resources.getString(title)
51 | binding.navView.setCheckedItem(item)
52 | }
53 |
54 | var cur_fragment = R.id.action_latin_to_english
55 | if (savedInstanceState != null) {
56 | for (k in savedInstanceState.keySet()) {
57 | if (k.startsWith("fragment_")) {
58 | val fragment = supportFragmentManager.getFragment(savedInstanceState, k)!!
59 | fragments[k.substring(9).toInt()] = fragment
60 | }
61 | }
62 | cur_fragment = savedInstanceState.getInt("cur_fragment", cur_fragment)
63 | }
64 | supportFragmentManager.beginTransaction()
65 | .replace(R.id.content, getFragment(cur_fragment))
66 | .addToBackStack(null)
67 | .commit()
68 |
69 | binding.navView.inflateMenu(R.menu.navigation)
70 | binding.navView.setNavigationItemSelectedListener { item ->
71 | binding.drawerLayout.closeDrawers()
72 | val fragment = getFragment(item.itemId)
73 | supportFragmentManager.beginTransaction()
74 | .addToBackStack(null)
75 | .replace(R.id.content, fragment)
76 | .commit()
77 |
78 | true
79 | }
80 |
81 | action_bar_drawer_toggle = ActionBarDrawerToggle(
82 | this, binding.drawerLayout, R.string.open_drawer,
83 | R.string.close_drawer
84 | )
85 | }
86 |
87 | override fun onSaveInstanceState(outState: Bundle) {
88 | val cur_fragment = supportFragmentManager.findFragmentById(R.id.content)
89 | for ((k, v) in fragments) {
90 | if (cur_fragment == v) {
91 | outState.putInt("cur_fragment", k)
92 | }
93 | supportFragmentManager.putFragment(outState, "fragment_$k", v)
94 | }
95 | super.onSaveInstanceState(outState)
96 | }
97 |
98 | override fun onOptionsItemSelected(item: MenuItem): Boolean {
99 | return action_bar_drawer_toggle.onOptionsItemSelected(item)
100 | }
101 |
102 | override fun onConfigurationChanged(newConfig: Configuration) {
103 | super.onConfigurationChanged(newConfig)
104 | action_bar_drawer_toggle.onConfigurationChanged(newConfig)
105 | }
106 |
107 | private fun getFragment(id: Int): Fragment {
108 | var fragment = fragments[id]
109 | if (fragment == null) {
110 | fragment = when (id) {
111 | R.id.action_latin_to_english ->
112 | SearchFragment(false)
113 | R.id.action_english_to_latin ->
114 | SearchFragment(true)
115 | R.id.action_settings ->
116 | SettingsFragment()
117 | R.id.action_about ->
118 | AboutFragment()
119 | else ->
120 | throw RuntimeException() // Unreachable
121 | }
122 |
123 | fragments[id] = fragment
124 | }
125 | return fragment
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/src/main/java/com/ids1024/whitakerswords/WordsWrapper.kt:
--------------------------------------------------------------------------------
1 | // libwords.so is really an executable, named that way because of how Android does things.
2 | // See https://stackoverflow.com/questions/63800440/android-cant-execute-process-for-android-api-29-android-10-from-lib-arch
3 |
4 | package com.ids1024.whitakerswords
5 |
6 | import android.content.Context
7 | import android.util.Log
8 | import androidx.preference.PreferenceManager
9 | import java.io.BufferedReader
10 | import java.io.File
11 | import java.io.FileOutputStream
12 | import java.io.IOException
13 | import java.io.InputStreamReader
14 | import java.io.StringWriter
15 | import java.util.Locale
16 |
17 | private const val TAG = "words"
18 |
19 | private fun emptyDirectory(f: File) {
20 | val directoryContents = f.listFiles()
21 | if (directoryContents != null) {
22 | for (subFile in directoryContents) {
23 | if (!subFile.deleteRecursively()) {
24 | Log.w(TAG, "Unable to delete ${f.path}")
25 | }
26 | }
27 | } else {
28 | Log.w(TAG, "Unable to clear ${f.path}")
29 | }
30 | }
31 |
32 | /**
33 | * Wraps the `words` binary. This handles extraction from the apk and execution.
34 | */
35 | class WordsWrapper(private val context: Context) {
36 | // The version number of the APK as specified in the manifest.
37 | private val apkVersion = context.packageManager
38 | .getPackageInfo(context.packageName, 0)
39 | .versionCode
40 | private val preferences = PreferenceManager.getDefaultSharedPreferences(context)
41 |
42 | init {
43 | copyFiles()
44 | }
45 |
46 | /** Deletes all files under the files directory. */
47 | private fun deleteLegacyDataDirectoryContents() {
48 | emptyDirectory(context.filesDir)
49 | }
50 |
51 | /** Ensures the appropriate versioned cache directory is created. The
52 | * version number is derived from the APK version code.
53 | *
54 | *
55 | * Older directories and their contents from a prior APK version will be
56 | * removed automatically.
57 | */
58 | private fun createAndCleanupCacheDirectories() {
59 | val versionedCacheDir = getFile("")
60 |
61 | if (versionedCacheDir.exists()) {
62 | return
63 | }
64 |
65 | // delete the entire contents of cache and then create the versioned directory
66 | emptyDirectory(context.cacheDir)
67 | versionedCacheDir.mkdirs()
68 | }
69 |
70 | private fun getFile(filename: String): File {
71 | return File(context.cacheDir, "$apkVersion/$filename")
72 | }
73 |
74 | @Throws(IOException::class)
75 | private fun copyFiles() {
76 | deleteLegacyDataDirectoryContents()
77 | createAndCleanupCacheDirectories()
78 |
79 | for (filename in context.assets.list("words")!!) {
80 | copyFile(filename)
81 | }
82 |
83 | updateConfigFile()
84 | }
85 |
86 | @Throws(IOException::class)
87 | private fun copyFile(filename: String) {
88 | val outputFile = getFile(filename)
89 | // if the file already exists, don't copy it again
90 | if (outputFile.exists()) {
91 | return
92 | }
93 |
94 | context.assets.open("words/$filename").use { ins ->
95 | FileOutputStream(outputFile).use { fos ->
96 | ins.copyTo(fos)
97 | }
98 | }
99 | }
100 |
101 | // TODO(tcj): Execute this is another thread to prevent UI deadlocking
102 | /**
103 | * Executes `words`.
104 | */
105 | @Throws(IOException::class)
106 | fun executeWords(text: String, english_to_latin: Boolean): String {
107 | val wordspath = context.applicationInfo.nativeLibraryDir + "/libwords.so"
108 | val command = if (english_to_latin) {
109 | arrayOf(wordspath, "~E", text)
110 | } else {
111 | arrayOf(wordspath, text)
112 | }
113 | val process = Runtime.getRuntime().exec(command, null, getFile(""))
114 |
115 | val output = StringWriter()
116 | BufferedReader(InputStreamReader(process.inputStream)).use { ins ->
117 | ins.copyTo(output)
118 | }
119 |
120 | try {
121 | process.waitFor()
122 |
123 | val exitValue = process.exitValue()
124 | if (exitValue != 0) {
125 | Log.e(TAG, "words subprocess returned $exitValue")
126 | }
127 | } catch (ex: InterruptedException) {
128 | Thread.currentThread().interrupt()
129 | throw RuntimeException(ex)
130 | }
131 |
132 | return output.toString()
133 | }
134 |
135 | /**
136 | * Generates `WORDS.MOD` file from the app's preferences.
137 | */
138 | @Throws(IOException::class)
139 | fun updateConfigFile() {
140 | val file = getFile("WORD.MOD")
141 | val fos = FileOutputStream(file)
142 | for (setting in arrayOf("trim_output", "do_unknowns_only", "ignore_unknown_names", "ignore_unknown_caps", "do_compounds", "do_fixes", "do_dictionary_forms", "show_age", "show_frequency", "do_examples", "do_only_meanings", "do_stems_for_unknown")) {
143 | if (preferences.contains(setting)) {
144 | val value = if (preferences.getBoolean(setting, false)) "Y" else "N"
145 | val line = setting.uppercase(Locale.US) + " " + value + "\n"
146 | fos.write(line.toByteArray())
147 | }
148 | }
149 | fos.close()
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn ( ) {
37 | echo "$*"
38 | }
39 |
40 | die ( ) {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------