#!/bin/sh
# test platform ... devuan dash
# GPL_3+ license
cat << 'EEE' > /dev/null
/* readlinkp .... portable readlink. bourne-shell script
 * Copyright (C) 2018 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

# 2-clause BSD license
# https://sites.google.com/site/jdisnard/realpath
cat << 'EEE' > /dev/null
/* Copyright 2010 Jon Disnard. All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, are
 * permitted provided that the following conditions are met:
 * 
 *    1. Redistributions of source code must retain the above copyright notice, this list of
 *       conditions and the following disclaimer.
 * 
 *    2. Redistributions in binary form must reproduce the above copyright notice, this list
 *       of conditions and the following disclaimer in the documentation and/or other materials
 *       provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY Jon Disnard ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * The views and conclusions contained in the software and documentation are those of the
 * authors and should not be interpreted as representing official policies, either expressed
 * or implied, of Jon Disnard.
 */
EEE

# readlink -f -- *	...  readlinkp -f -- *
# gnu-readlink: 2ms,	this script: 140ms

func_rlp() {
# GPL_3+ license
# '(' ... for local scope
(
# normalize locale
bk_lcl=`set`
export LC_ALL=C
export LANG=C
pf1='( eval "$bk_lcl" ; cat - )'


rlp_input='cat -'	
if [ "$#" != '0' ] ; then
	rlp_input='for ii
do
	printf "%s\000" "$ii"
done'
fi

# ...awk for detect input err.
eval "$rlp_input" | od -An -to1 -w16 -v | awk -v bf="$0" '
BEGIN{err=1} 
$0 ~ /000/ {err=0}
{print $0}
END{
	if(NR > 0 && err == 1 ) {
		printf("%s: link search err. \134000 not found. sleep.\n", bf) > "/dev/stderr"
		for(;;){
			system("sleep 1000")
		}
	}
}' | sed -e 's/ 000/@/g' | tr -d '\n' | 
	tr ' ' '\134' | tr '@' '\n' | while read -r rlp_A
do
	# fname ... dir
	rlp_fin=`printf "$rlp_A"'@'`
	rlp_fin="${rlp_fin%?}"
	

	#	normalize name to have dir data	(aaa.txt -> ./aaa.txt etc)
	rlp_fin="${rlp_fin%/}"
	if [ "${rlp_fin#*/}" = "$rlp_fin" ] ; then
		rlp_fin="./$rlp_fin"
	fi
	
	rlp_ftail=''	#file name only

	
	# kick err files
	if ! [ -e "$rlp_fin" ] ; then
#		echo "$0: link search err. file not found. '$rlp_fname'" > /dev/stderr
		printf '//%s\000' "$rlp_fin"
		continue
	fi
	
	# split dir + name. -f ... cant get ln, pipe etc.
	if ! [ -d "$rlp_fin" ] ; then		# -d ! not dir == files
	#	split dir + filename. and resolve soft link
	# ls --show-control-chars
	#	表示不可能な文字をそのまま表示 (プログラムが  'ls'  で  なかった
	#	り、出力が端末以外の場合は、これがデフォルト動作になる)
	#	...つまり、端末に表示せず変数等に代入する時は正確なファイル名が取得できるはず。

	#	-Lオプションはサイズや日付データのみでファイル名は対象外

		rlp_fname="$rlp_fin"
		while :		# recheck for multiple link (a -> b -> c etc)
		do

		if ! [ -h "$rlp_fname" ] ; then		# -h ... exist & link
			break
		fi


# 2-clause BSD license
# https://sites.google.com/site/jdisnard/realpath
# use 'ls -l' to get link-dst infomation.
# '->' use as string spliter	... http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html
# need LANG=c ? safety?
#	rlp_LANGbk="$LANG"
#	LANG="c"
		rlp_base=`/bin/ls -l "$rlp_fname" ; printf @`	# $() removes end '\n' (posix)
		rlp_base="${rlp_base%??}"	# aaa\n@ -> aaa	... ls add \n (like echo)
		rlp_count=`printf '%s\n' "$rlp_fname" | tr -c '>-' ' ' |
			sed -e 's/->/@/g' | tr -d -c '@' | wc -c`	# check '->' string(filename, username etc)
		rlp_count=$((rlp_count+1))
		
		for ii in `seq 1 $rlp_count `	# ls -h... exist -> 
		do
			rlp_base="${rlp_base#*->}"
		done
		
# debug... ls -al
# /dev/stdin -> /proc/self/fd/0
# /proc/self/fd/0 -> pipe:[3082488]		<<< not file. inode system. needs kick
		test -e '/'"${rlp_base#*/}" || break	
		rlp_fname='/'"${rlp_base#*/}"	# remove head ' '	ls disp filename (linkfile)

		done	#while end
		
		# if files, rlp_ftail != '', 
		rlp_ftail="${rlp_fname##*/}"	# filename only
		rlp_fdir="${rlp_fname%/*}"	# dirname only
	else
		# fin is dir.
		flp_fdir="$rlp_fin"
	fi
	
	# normalized. check path reallink
	# pwd -P: get full realpath. posix. (2001-?)
	# echo @ ... command substitution deletes lineend '\n, \n\n ...'.
	# http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_03
	# pwd permission... dir exec may make some problem. run at subshell.
	
	(
	for ii in skip		# jump emulate
	do
		cd "$rlp_fdir"
		if [ "$?" = "1" ] ; then
			echo "$0: link search err. dir access failed. ($rlp_fdir)" | eval "$pf1" > /dev/stderr
			printf '//%s\000' "$rlp_fdir"
			break
		fi		
		
		rlp_fpath=`pwd -P; printf '@'`
		if [ "$rlp_fpath" = '@' ] && [ "$err" != "" ] ; then
			echo "$0: link search err. pwd -P failed. ($rlp_fdir)" | eval "$pf1" > /dev/stderr
			printf '//%s\000' "$rlp_fdir"
			break
		fi
		
		rlp_fpath=${rlp_fpath%??}	# aaa\n@ -> aaa	... pwd add \n (like echo)
		rlp_fpath=${rlp_fpath%/}	# if aaa/ -> aaa etc
		rlp_fname="$rlp_fpath"'/'"$rlp_ftail"	# dir has end '/' ... 'aaa/' etc
		printf '%s\000' "$rlp_fname"
	done
	)
done | od -An -to1 -w16 -v | tr -d '\n' |
sed -e 's# 000#@#g' | tr ' ' '\134' | tr '@' '\n' | awk -v name="$0" '
	$0 ~ /^.057.057/ {
		gsub(/^.057.057/, "", $0)
		cmd="printf \047" $0 "\012\047 >/dev/stderr"
		printf "%s: link check err. file not found: ", name > "/dev/stderr"
		system(cmd)
		printf "//"
		}
	{print $0}' | eval "$pf1"
)
}


# ---optcheck
flg=''
for ii
do
	if [ "$flg" = "1" ] ; then
		set -- "$@" "$ii"
		shift
		continue
	fi

	if [ "$ii" = "--" ] ; then
		shift
		flg=1
		continue
	fi

	if [ "$ii" = "-h" ] ; then
cat << 'EEE'
HowTo (readlinkp, portable readlink. bourne-shell script)
opt: -h, -f( ignored. adjusted expression to 'readlink -f' )
------
eg.) ~$ readlinkp "$0"
eg.) ~$ readlinkp -f -- *	# all current dir&files. '--' is optend.
eg.) ~$ find ./ -print0 | readlinkp -f		# if noargs, read stdin.
>>	\097\134...  >>  printf '\097...'  >>  /aa/bb.txt, /aa/bb/ etc

input : filename with '\000' end (stdin) or raw filename (args)
output: full-realpath with octal expression. dir has end slash '/'.
err   : output '//\097\097...' style & show errmsg to /dev/stderr.

eg.) ~$ printf '%b\n' `readlinkp -- *`	# all dir&files. %b is shell posix

*** NOTICE ***	...UNIX/Linux filename has all char without '/' or '\0'
if string is end with '\n', command substitution omits '\n' by posix rule.
	buf=`printf '\101\n\n\n'`  >>>  buf has 'A'. ${#buf} is 1 (str length)
add some char then delete to get accurate filename.
	buf=$(printf '\101\n'"@")	>>> buf has 'A\n@' 
	buf=${buf%?}	>>> del end one char ...  buf has 'A\n'. ${#buf} is 2
refs: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_03
EEE
		exit 0
	fi
	
	if [ "$ii" = "-f" ] ; then
		shift
		continue
	fi
done




#--- main
# copy func_rlp() to your code. if no args, func_rlp() read stdin automatically.
#
#	printf "file.txt\000" | func_rlp
#	buf=`func_rlp "file.txt" ; printf @`  +  realfile=${buf%?} ...remove '@'
#	func_rlp *	<< show current dir files/dirs full-realpath (octal)

func_rlp "$@"	# if no args, $# != 1.... $# == 0
