#!/bin/sh
cat << 'EEE' > /dev/null
/* fnf .... find file, find parser
 * Copyright (C) 2017-2019 Momi-g
 *
 * This program 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.
 *
 * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
 */
EEE

#	cmd='-h	bool 0
#	     -r	int	-1	
#	     -o	bool 0'
#	buf=`prsopt "$cmd"`
#	eval "$buf"
#	if [ $? -ne 0 ] ; then echo "$0: optErr. $OPTARG" >/dev/stderr ; exit 1; fi
#	

func_rdopt() {
	(
rdopt_fmt="$1"	#	":ab:c"	etc. format.
shift

#ck quiet mode
rdopt_quiet=1
rdopt_buf=${rdopt_fmt%%[!:]*}
if [ "$rdopt_buf" != ':' ] ; then
	rdopt_quiet=0
	rdopt_fmt=':'"$rdopt_fmt"
fi

#--inicialize	make list opt_a='', ...

#ab:c -> 'a' \n 'b' \n 'c' \n
rdopt_buf='s/://g
s/./&\
/g'
rdopt_zerolist=`echo "$rdopt_fmt" | sed -e "$rdopt_buf" | sed -e "
/^$/d
s/^/opt_/g
s/$/=''/g
" `

#--- local vars
# rdopt_fmt="$1"	#	":ab:c"		opt format
# rdopt_quiet=1
# rdopt_zerolist=`echo "$rdopt_fmt" | sed -e "$rdopt_buf" | sed -e "
# rdopt_buf='s/://g

rdopt_out=""
rdopt_opt=""
rdopt_skip=""
rdopt_err=""

rdopt_safe="
s#'#'\"'\"'#g
1 s/^/'/g
$ s/$/'/g"

#---getopts loop. break if all args read or detect '--'
while :
do
if [ 0 -eq "$#" ] || [ "$rdopt_err" = "1" ] ; then
	break
fi
if [ "$1" = "--" ] ; then
	shift ; break
fi

getopts "$rdopt_fmt" rdopt_opt "$@"	# ":a:bc:f:" etc...
# err detect@silent mode
# $?=1 ... detect optend or '--'. '--' is removed at previous line.
# ':' ... detect option, but dont have subargs (OPTARG="factor").
# '?' ... detect unsupported option char (OPTARG="factor") or args end (OPTARG="blank").
# OPTARG ... "" is optend. "a/b/c..." is invalid option 
# OPTIND ... if err, OPTIND indicates next (new) arg pos. 

if [ "$?" = "1" ] ; then 		# normal end (detect normal args). save general args.
	shift $((OPTIND - 1))
	if [ "$#" -eq "0" ] ; then
		break
	fi
	# new set make
	rdopt_buf=`printf '%s' "$1" | sed -e "$rdopt_safe"`
	rdopt_skip="$rdopt_skip $rdopt_buf"
	shift
	OPTIND=1
	continue
fi

if [ "$rdopt_opt" = "?" ] || [ "$rdopt_opt" = ":" ] ; then 	# detect invalid opt
	rdopt_err=1		#OPTARG has err option char.
	continue
fi

# normal. detect option.
if [ "$OPTARG" = "" ] ; then	# no subargs 
	rdopt_out="$rdopt_out
opt_$rdopt_opt"'=1'
else	# exist subargs 
rdopt_buf=`printf "%s\n" "$OPTARG" | sed -e "$rdopt_safe" `
	rdopt_out="$rdopt_out
opt_$rdopt_opt"'='"$rdopt_buf"
fi
done
# exit parse

if [ "$rdopt_err" = "1" ] ; then
	if [ "$rdopt_quiet" = "0" ] ; then
		rdopt_buf=${0##*/}
		echo "$rdopt_buf: invalid option. sleep. ( $OPTARG )" >/dev/stderr
		while :
		do
			sleep 1000
		done
	else
		rdopt_out="OPTARG=$OPTARG
OPTIND=1
test 1 = 0"
	fi
else

#	'--' end
	if [ "$#" != "0" ] ; then
	rdopt_buf=`cat << 'EEE'
for ii
do
	printf '%s' "$ii" | sed -e "
s#'#'\"'\"'#g
1 s/^/'/g
$ s/$/' /g"
done 
EEE
`
	rdopt_buf=`eval "$rdopt_buf"`
	rdopt_skip="$rdopt_skip $rdopt_buf"
	fi

	rdopt_out="OPTIND=1

$rdopt_zerolist
$rdopt_out
set -- $rdopt_skip
"
fi



printf '%s\n' "$rdopt_out"

# clean
OPTIND=1
rdopt_fmt=""
rdopt_quiet=""
rdopt_zerolist=""
rdopt_buf=""

rdopt_out=""
rdopt_opt=""
rdopt_skip=""
rdopt_err=""
rdopt_safe=""
)
OPTIND=1
}





buf=`func_rdopt "hr:oP" "$@"`
eval "$buf"
if [ $? -ne 0 ] ; then echo "$0: optErr. $OPTARG" >/dev/stderr ; exit 1; fi

if [ "$opt_h" = '1' ] ; then
cat << 'EEE'
HowTo (find file/directry)
option: -h(elp), -r(ecurse -1(dfl),0,1,2..), -o(ctal output)
------
ex.) ~$ fnf txt unko (-r -1)	#search files from ./ 
>>> ./unko___uh.txt	
    ./unko.txt
    ./unkotxt/
...show include 'txt' + 'unko' (fixed)string in filepath (not file name)
...recursive search (-1:non stop 0:pwd 1:pwd+next)
...directry(or directry link) is end with '/'.

ex.) ~$ fnf '/u' unko //uh
>>>	./unko.txt	>>>	'//' means 'not'. '/u' && 'unko' && !'uh'
... normal filepath probably should not contain '//'.	(./aaa//bbb/c.txt etc)

ex.) ~$ fnf txt unko -o
>>>	\001\004\123...	>>> printf '\001\004\123...'  ->  ./unko___uh.txt
	\111\333...
... output in octal number. You can safely handle filenames containing
 newlines and unicode characters. ("./aaa/bb\n\n\123  b/ccc.txt" etc)
EEE
exit 0
fi

#	-Pのデフォで普通にmaxつけて検索。type lでシンボリックリンクを探し出して頭に//0みたいな
#	フラグをつけて再検索させるとか。maxdepthが使えねー。微妙だ。第一階層、第二階層って感じに
#	検索させてスラッシュカウントpurneでぶっちぎるとか。loop対策がどーよ？
#	findはパターンがシェルパターンなので、そのへんも。-pathでパス健作になる
#	find . -path ./src/emacs -prune -o -print
#	findは確固,-o -aと否定のみ規程。
#	find . -path '*/*/*' -prune



find -print0 --version >/dev/null 2>&1
if [ "$?" = "0" ] && [ "$opt_P" != "1" ]; then
	echo "// (stderr info) detect gnu-find. use fastmode." >/dev/stderr
	gnumode=1
fi


if [ "$opt_r" != "-1" ] && [ "$opt_r" != "" ] ; then
	ptn='*/*/*'		#>> pwdは/一つだけ。//はサブディレクトリ。///はサブサブ。
	for ii in `seq 1 $opt_r `
	do
		ptn="$ptn"'/*'
	done
else
	ptn='*//*'	# 基本的に//を含むファイルは存在し得ない。ファイル名に\000と/は使えないため。
#	null_hitで枝刈りを防ぐ。
fi
# maxdepthがfindで使えないので代替。posix.

outstr='cat -'
if [ "$opt_o" != "1" ] ; then
	outstr='while read -r aa
do
	printf "$aa"
	echo
done'
fi
#	syscallオーバーヘッドが重いけど、awkとかeval使えないし。%bもシェルだけだし。
#	printf自体はbuilt-inだから、致命的に遅い
#	ってほどじゃない。awkに比べたら500%プラスってとこ。 awk 10ms -> while print 50ms


# 20ms






# 固定文字検索のみに絞る。検索文字も生だと扱いにくいので8進にしとく。
buf=`for ii in "$@"
do
	printf '%s\000' "$ii"
done | od -An -to1 -w16 -v | tr -d '\n' | sed -e 's# 000#@#g' | tr ' ' 'o' | tr '@' '\n' `

filter=""
for ii in $buf
do
	buf=${ii#o057o057}	# //bbb みたいな'//'付き文字列は否定。not.
	if [ "$buf" != "$ii" ] ; then
		filter="$filter
/$buf/ d"
	else
		filter="$filter
/$buf/ ! d"
	fi
done
filter="sed -e '$filter'"
# echo "$filter"
# exit

#	sed -e '
#	/o141o141/ ! d
#	/o163o163/ ! d
#	/o144o144/ d'

#	sed -e ''


# ---main
# -Lはtypeでフォルダ系の表示の尻尾に/を判別するとき、dirリンク時に情報が欲しいので。
# . と./で混在してる。変。lsは--indiで/指定できるけど、findにはない。
# -L ./ と -L .で違う。バグってほどじゃないけど注意が必要。
# echo "$ptn"
# exit

# -execが遅いみたい。20ms -> 800ms

# 20ms time find -L ./ -path "@@" -prune -o -print
# 700ms time find -L ./ -path "@@" -prune -o -exec printf '%s\n' '{}' ';'
# syscallが遅いから//を使って何とかできんか。...無理。出力する方法がない。
# execでまとめられてしまってる。gnuとスイッチかな。


# gnu can use -printf ... fast output(40ms)
if [ "$gnumode" = "1" ] ; then
	cmd=`cat << 'EEE'
find -L ./ -path "$ptn" -prune \
-o -type d -a '!' -path '*/' -a -printf '%p/\000' \
-o -printf '%p\000'
EEE
`

else	# posix & syscall. slow. 800ms
	cmd=`cat << 'EEE'
find -L ./ -path "$ptn" -prune \
-o -type d -a '!' -path '*/' -a -exec printf '%s/\000' '{}' ';' \
-o -exec printf '%s\000' '{}' ';'
EEE
`

fi


eval "$cmd" |
	od -An -to1 -w16 -v | sed -e 's# 000#@#g' | tr -d '\n' | 
	tr ' ' 'o' | tr '@' '\n' | eval "$filter" | tr 'o' '\134' | eval "$outstr"

#	. パスから探し出した一つ一つのファイルに大して
#	pathnameがptnに一致したら握りつぶす。その先のフォルダも見なかったことにされる。(prune)
#	-o or. 握りつぶされなかった生き残りに対して
#	-o type d 対象ファイル名がディレクトリかつ(-a) path名が/で終わってない(!...否定)
#	のならば、{}/\000を出力。返り値はここでtrueなので後ろの評価はスキップされる。
#	-o 上が失敗、つまりディレクトリとかじゃないのならば{}\000を出力。
#	-oはelseに近い。
#	
#	等価コード
#	loop:
#	
#	mode=read_linkend_data();		(-L)
#	obj=search(dir);
#	
#	if (pathname == $ptn ){		ptnはシェルパターン. */とか??123*/とか。
#		next
#	} else if (obj==dir && pathname != '*/') {
#		printf obj + '/' + '\000'
#		next
#	} else {
#		printf obj + '\000'
#		next
#	}
#	loopend
#	
