#!/bin/bash

###########################################################
## Copyright (c) 2002-2023 Alexey Kuryakin daqgroup@mail.ru
###########################################################

###########################################################
## fixeol files => fix (validate) EOL of files (CRLF to LF)
## checks files before conversion, convert only files which
## really needed to be fixed and keep other files unchanged
## can use dos2unix or fixeol programs as primary converter
###########################################################

function selfname(){
 echo "$(basename ${BASH_SOURCE[0]})";
};
function print_version(){
 echo "$(selfname) version 1.0";
};
function print_copyright(){
 echo "Copyright (c) 2002-2023 Alexey Kuryakin daqgroup@mail.ru";
};
function print_help(){
 print_version;
 print_copyright;
 echo "about:";
 echo " $(selfname) is utility to fix (validate) text file(s) EOL.";
 echo " EOL is End Of Line marker use to separate text lines.";
 echo " Usually it's: CRLF on Windows, LF on Unix, CR on MAC.";
 echo " $(selfname) converts any text EOL to current system's EOL.";
 echo "usage:";
 echo " $(selfname) [options] [parameters]";
 echo "options:";
 echo " --version - print version";
 echo " -h,--help - print help screen";
 echo " -t,--test - run in test mode, no file conversion";
 echo "parameters:";
 echo " text file(s) to fix EOL";
 echo " if '-' or no parameters";
 echo " then uses stdin/stdout";
 echo "examples:";
 echo " $(selfname) -h";
 echo " $(selfname) *.txt";
 echo " $(selfname) -t test.txt";
 echo " cat test.txt | $(selfname) > fixed.txt";
};

# detect location of script (with symlink resolved)

readonly scriptfile="${BASH_SOURCE[0]}";          # caller location of script
readonly scriptFILE="$(realpath $scriptfile)";    # physic location of script
readonly scriptHOME="$(dirname  $scriptFILE)";    # physic location of folder

# choose and test base checker and converter: 1=dos2unix, 2=fixeol
# checker make preliminary conversion to check file really test.txt need to fix EOL(s)
# converter make real conversion for files which tested by checker
# dos2unix skip binary files so it's good tool for safe checking

function choose_chkeol(){
 case $1 in
  1) readonly chkeol="$(which dos2unix)"; ;;
  2) readonly chkeol="$(realpath $scriptHOME/../fixeol/fixeol)"; ;;
  *) 1>&2 echo "fixeol: wrong checker $checker"; ;;
 esac;
 if [ -z "$chkeol" ] || [ ! -e "$chkeol" ]; then
  1>&2 echo "fixeol: checker not found";
  exit 1;
 fi;
};

function choose_fixeol(){
 case $1 in
  1) readonly fixeol="$(which dos2unix)"; ;;
  2) readonly fixeol="$(realpath $scriptHOME/../fixeol/fixeol)"; ;;
  *) 1>&2 echo "fixeol: wrong converter $converter"; ;;
 esac;
 if [ -z "$fixeol" ] || [ ! -e "$fixeol" ]; then
  1>&2 echo "fixeol: converter not found";
  exit 1;
 fi;
};

# octal file mode like 755
function oct_file_mode(){
 if [ -n "$1" ] && [ -e "$1" ]; then
  stat -c "%a %n" $1 | cut -d ' ' -f 1;
 fi;
};

# for each file check and call converter if needed

function main(){
 ######################################
 choose_chkeol 1; # 1/2=dos2unix/fixeol
 choose_fixeol 2; # 1/2=dos2unix/fixeol
 ######################################
 if [ $# = 0 ] || [ "$1" = "-" ]; then
  exec $fixeol;
  return $?;
 fi;
 local code=0; # exit code
 local test=0; # test mode
 case $1 in
  -t|--test) test=1; shift; ;;
  -h|--help) print_help; return 0; ;;
  --version) print_version; return 0; ;;
  -*)        1>&2 echo "fixeol: invalid option $1"; exit 1; ;;
  *)         ;;
 esac;
 for file in "$@"; do
  if [ -e $file ]; then
   if [ -d $file ]; then continue; fi; # skip directories
   if [ -L $file ]; then continue; fi; # skip symbolic links
   if [ ! -f $file ]; then continue; fi; # only regular files
   local diff="$($chkeol < $file | cmp - $file 2>/dev/null)";
   if [ -n "$diff" ]; then
    if [ $test = 1 ]; then
     echo "fixeol: faulty - $file";
     code=1;
     continue;
    fi;
    local mode="$(oct_file_mode $file)";
    if $fixeol $file >/dev/null 2>&1; then
     echo "fixeol: fixed  - $file";
     chmod -f $mode $file;
    else
     1>&2 echo "fixeol: failed - $file";
     code=1;
    fi;
   else
    1>&2 echo "fixeol: passed - $file";
   fi;
  else
   1>&2 echo "fixeol: missed - $file";
   code=1;
  fi;
 done;
 return $code;
};

main "$@";

##############
## END OF FILE
##############
