Files
OpenFOAM-12/bin/foamFind
2024-06-28 14:25:19 +01:00

420 lines
12 KiB
Bash
Executable File

#!/bin/sh
#------------------------------------------------------------------------------
# ========= |
# \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
# \\ / O peration | Website: https://openfoam.org
# \\ / A nd | Copyright (C) 2024 OpenFOAM Foundation
# \\/ M anipulation |
#------------------------------------------------------------------------------
# License
# This file is part of OpenFOAM.
#
# OpenFOAM 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.
#
# OpenFOAM 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 OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
#
# Script
# foamFind
#
# Description
# Finds one or more files in OpenFOAM and optionally processes the contents
# by printing the file or lines matching a search string
#
#------------------------------------------------------------------------------
usage () {
cat <<USAGE
Usage: ${0##*/} [OPTIONS] <filename>
options:
-a | -applications search for the file from the \$FOAM_APP directory
-d | -dir <dir> specify search directory
-e | -edit open the file in a file editor, see below for info
-f | -files find wmake 'files' file associated with searched file
-h | -help help
-i | -isearch <string> searches files for a <string>, case insensitive
-m | -modules search for the file from the \$FOAM_MODULES directory
-n | -numbers print line numbers with file output
-o | -options find wmake 'options' file associated with searched file
-p | -print print the file(s)
-s | -search <string> searches files for a <string>, case sensitive
-t | -tutorials search for the file from the \$FOAM_TUTORIALS directory
Finds one or more files in OpenFOAM and optionally processes the contents by:
+ printing the file(s) ('-print' option);
+ printing lines within the file matching a search string ('-search' option);
+ opening a single (only) file in a text editor ('-edit' option).
The '-edit' option required the user to specify their choice of text editor by
setting the EDITOR environment variable. For example, to set the 'gedit' editor,
they could add to their \$HOME/.bashrc file, the line:
export EDITOR=gedit
With source code files, can locate the 'files' and 'options' files associated
with their compilation using 'wmake'.
By default, files are searched from the src (\$FOAM_SRC) directory.
Alternatively the '-dir' option allows the user to specify the search directory
The '-applications', '-modules' and '-tutorials' options specifically set the
search path to the \$FOAM_APP, \$FOAM_MODULES and \$FOAM_TUTORIALS directories,
respectively.
Examples:
foamFind -print wallHeatFlux.C | less
+ click space bar to scroll down
+ enter line number (after ":") to jump to line
+ enter "/text" to search for "text" (or any other string)
foamFind -applications -isearch "momentumtransport" -options fluid.C
foamFind -numbers -search laminar BirdCarreau.C
USAGE
}
error() {
exec 1>&2
while [ "$#" -ge 1 ]; do echo "$1"; shift; done
usage
exit 1
}
findWmakeFiles () {
_file="$1" ; shift
_wmakeFiles="$*"
# Check if file is source code
! file -b "$_file" | grep -Eq "C.*source" && \
"'-$_filename' invalid, file is not source code" >&2 && \
return 1
_files=""
while true
do
_oldFile="$_file"
_file="${_file%/*}"
# cannot contract the path further
[ "$_oldFile" = "$_file" ] && break
# search for 'files' and/or 'options'
[ -d "$_file" ] && \
for _w in $_wmakeFiles
do
_files="$(echo "$_files" \
"$(find "$_file" -name "$_w" -type f)" | xargs)"
done
[ "$_files" ] && break
done
! [ "$_files" ] && \
error "no '$_filename' file found for '-files' or '-options'" >&2 && \
return 1
echo "$_files"
return 0
}
nParams () {
[ "$1" ] || return 1
echo "$1" | xargs | awk -F' ' '{print NF}'
return 0
}
selectFile () {
_filename="$1"; shift
_files="$*"
_nFiles="$(nParams "$_files")"
# Return file if only one
[ "$_nFiles" -eq 1 ] && echo "$_files" && exit 0
printf "Multiple files" >&2
[ "$_filename" ] && printf " with name '%s'" "$_filename" >&2
printf " found:\n" >&2
_i=1
for _f in $_files
do
printf "%i) %s\n" "$_i" "$_f" >&2
_i=$((_i + 1))
done
printf "Type ENTER to select all, or " >&2
printf "enter file number (1-%s) for specific file: " \
"$_nFiles" >&2
read -r _nFile
# Enter nothing
[ -z "$_nFile" ] && echo "$_files" && return 0
# Check incorrect number
! [ "$_nFile" -eq "$_nFile" ] 2>/dev/null && \
echo "\"$_nFile\" is not a number" >&2 && \
return 1
{ [ "$_nFile" -lt 1 ] || [ "$_nFile" -gt "$_nFiles" ] ; } && \
echo "\"$_nFile\" is not a number between 1 and $_nFiles" >&2 && \
return 1
# Enter number corresponding to file
# shellcheck disable=SC2086
echo $_files | awk -v n="$_nFile" '{print $n}'
return 0
}
setFile () {
_files="$1"
_n="$2"
echo "$_files" | xargs -n 1 | awk -v n="${_n}" 'NR==n'
}
isSrcDir () {
echo "$1" | grep -wqE "^($FOAM_SRC|$FOAM_APP)"
}
listFiles () {
_dir="$1"
_filename="$2"
_search="$3"
_ins=""
[ "$4" = "on" ] && _ins="i"
# Specify code files if _dir is in $FOAM_SRC or $FOAM_APP
_name="*"
isSrcDir "$dir" && _name="*.[CHL]"
[ "$_filename" ] && _name="$_filename"
[ "$_search" ] && \
find "$_dir" -name "$_name" -type f -print0 | \
xargs -0 grep -l$_ins "$search" && \
return 0
# Remove "\n"
find "$dir" -name "$filename" -type f -print0 | xargs -0
}
grepFile () {
_string="$1"
_file="$2"
_ins=""
[ "$3" = "on" ] && _ins="i"
_arg="$4"
# use $_arg for different cases: test, and with and without line numbers
case "$_arg" in
test)
grep -q"$_ins" "$_string" "$_file"
;;
numbers)
grep -hn"$_ins" "$_string" "$_file" | \
awk '{
split($0,f,":");
sub(/^([^:]+:)/,"",$0);
printf "%6i %s\n", f[1], $0
}'
;;
*)
grep -h"$_ins" "$_string" "$_file"
;;
esac
}
dirError () {
cat<<EOF
Search directory specified with more than one option from '-applications',
'-dir', '-modules' and '-tutorials'. Please specify only one of these options.
EOF
}
editConfigError () {
cat<<EOF
The '-edit' option requires the user to specify their chosen text editor using
the EDITOR environment variable. For example, to set the 'gedit' editor, they
could add to their \$HOME/.bashrc file, the line:
export EDITOR=gedit
EOF
}
searchError () {
cat<<EOF
The '-search' and '-isearch' options are both specified.
Please specify only one of these options, either '-isearch' for a
case-insensitive search or '-search' for case-sensitive.
EOF
}
optionsError () {
cat<<EOF
Two or more of the '-search/-isearch', '-print' and '-edit' options are
specified. Please specify only one of these options, either '-search/-isearch'
to print lines of files(s) matching an expression, or '-print' or '-edit' to
view the entire file(s).
EOF
}
dir=""
print=""
edit=""
wmakeFiles=""
search=""
insensitive=""
numbers=""
filename=""
while [ "$#" -gt 0 ]
do
case "$1" in
-a | -applications)
[ "$dir" ] && error "$(dirError)"
dir="$FOAM_APP"
shift
;;
-d | -dir)
[ "$dir" ] && error "$(dirError)"
[ "$#" -ge 2 ] || error "'$1' option requires an argument"
[ -d "$2" ] || error "'$2' argument to '-dir' option is not a directory"
# shellcheck disable=SC2164
dir="$(cd "$2"; pwd)"
# Check $dir is in OpenFOAM
! echo "$dir" | grep -wq "^$WM_PROJECT_DIR" && \
error "Specified directory '$dir' is not in OpenFOAM installation"
shift 2
;;
-e | -edit)
{ [ "$insensitive" ] || [ "$print" ]; } && error "$(optionsError)"
[ "$EDITOR" ] || error "$(editConfigError)"
edit="$(which "$EDITOR")"
shift
;;
-f | -files)
wmakeFiles="$wmakeFiles files"
shift
;;
-h | -help)
usage
exit
;;
-i | -isearch)
[ "$#" -ge 2 ] || error "'$1' option requires an argument"
[ "$insensitive" ] && error "$(searchError)"
{ [ "$print" ] || [ "$edit" ]; } && error "$(optionsError)"
search="$2"
insensitive=on
shift 2
;;
-m | -modules)
[ "$dir" ] && error "$(dirError)"
dir="$FOAM_MODULES"
shift
;;
-n | -numbers)
numbers="numbers" # flag for line numbers in cat or grep
shift
;;
-o | -options)
wmakeFiles="$wmakeFiles options"
shift
;;
-p | -print)
{ [ "$insensitive" ] || [ "$edit" ]; } && error "$(optionsError)"
print="yes"
shift
;;
-s | -search)
[ "$#" -ge 2 ] || error "'$1' option requires an argument"
[ "$insensitive" ] && error "$(searchError)"
{ [ "$print" ] || [ "$edit" ]; } && error "$(optionsError)"
search="$2"
insensitive=off
shift 2
;;
-t | -tutorials)
[ "$dir" ] && error "$(dirError)"
dir="$FOAM_TUTORIALS"
shift
;;
-*)
error "Invalid option '$1'"
;;
*)
# If filename is already set, then exit
[ "$filename" ] && error "Arguments specified ($#) =/= 1"
filename="$1"
shift
;;
esac
done
# Default search directory if not specified
[ "$dir" ] || dir="$FOAM_SRC"
# Disallow '-files' and '-options' if search directory does not include source code
[ "$wmakeFiles" ] && ! isSrcDir "$dir" && \
error "With search directory '$dir' (not source code)," \
"cannot use '-files' or '-options'"
# Check number of arguments
[ "$#" -eq 0 ] || error "Arguments specified =/= 1 (optional)"
# If filename is not set, check search string is specified
! [ "$filename" ] && ! [ "$search" ] && \
error "<filename> can only be omitted if a search string is specified" \
"with the '-search' option"
# If '-files' or '-options' is selected, ensure <filename> is set
! [ "$filename" ] && [ "$wmakeFiles" ] && \
error "With '-files' or '-options', <filename> must be specified"
# Find files
files="$(listFiles "$dir" "$filename" "$search" "$insensitive")"
# Ensure there is at least one file
nParams "$files" > /dev/null || error "No file '$filename' found in '$dir'"
# Select files when more than one is found
files="$(selectFile "$filename" "$files")" || error
# With '-files' and/or '-options', reuse file variable as the file
{ [ "$wmakeFiles" ] || [ "$edit" ] ; } && \
[ "$(nParams "$files")" -ne 1 ] && \
error "With '-files', '-options' or '-edit', a single file must be selected"
[ "$wmakeFiles" ] &&
! files="$(findWmakeFiles "$files" "$wmakeFiles")" && error
# Output
for f in $files
do
printf "\nFile: %s\n" "$f"
# Printing entire files
[ "$print" ] && \
printf ">>>\n" && \
{ [ "$numbers" ] && cat -n "$f" || cat "$f" ; } && \
printf "<<<\n"
# Opening files in a editor
[ "$edit" ] && "$edit" "$f"
# Printing lines matching strings
[ "$search" ] || continue
! grepFile "$search" "$f" "$insensitive" test && \
echo "Search: no match" && continue
printf ">>>\n"
grepFile "$search" "$f" "$insensitive" "$numbers"
printf "<<<\n"
done