#!/bin/bash # reformat gameshark retroarch or pcsxr # doesn't work for xploder codes if [[ -n "${@:1}" && -f "${@:1}" ]]; then tmpfile=$(mktemp) exec {FD_W}>"$tmpfile" exec {FD_R}<"$tmpfile" rm "$tmpfile" # create temp file file="$(echo "$(realpath "${@:1}")" | perl -pe 's/((|_pcsxr|_retro).cht)//gi')" # strip _pcsxr.cht, _retro.cht, and .cht extension to get root filename if [[ -n "$(pcre2grep -Mio 'cheat\d+_desc.*(?s)\s+(?-s)cheat\d+_code.+?[[:xdigit:]?X]{8}.[[:xdigit:]?X]{4,8}' "${@:1}")" ]] ; then # when file contains cheat desc and hex (8 4-8) format codes convert to pcsxr file=""$file"_pcsxr.cht" echo -e "\n ** RetroArch '.cht' file detected, converting to PCSXR format. **\n Processing ... \n" # append _pcsxr to root filename for output if [[ -n "$(pcre2grep -Mio '(cheat(\d+)_)desc(?=.*\n(?!cheat\2_code))' "${@:1}")" ]]; then echo ' ** Cheat names found without matching codes **' read -r -p ' treat as categories and merge together? [y/N] ' chse echo if [[ "$chse" =~ ^([yY][eE][sS]|[yY])+$ ]]; then chse=1 else unset chse fi fi if [[ -z "$chse" ]]; then readarray -t hdng < <(pcre2grep -Mio 'cheat(\d+)_desc.*\ncheat\1_code.*' "${@:1}" | pcre2grep -io '(?<=_desc = )\".*\"' | perl -pe 's|'\''||g ; s#(?<=\")[\t ]+|[\t ]+(?=\")##g ; s|^\"\"$| |g ; s|\"||g') else readarray -t hdng < <(perl -0777 -pe 's|(cheat(\d+)_)desc(?=.*\n(?!cheat\2_code))|\1cat|gi' "${@:1}" | perl -ne '$cat = $1 if s/^cheat\d+_cat = \"(.*)\".*\n// ; print if s/^cheat\d+_desc = \"(.*\")/"$cat, $1/' | perl -pe 's|'\''||g ; s#(?<=\")[\t ]+|[\t ]+(?=\")##g ; s|^\"\"$| |g ; s|\"||g') fi # capture heading names, strip leading/trailing spaces, # replace empty name with space, strip quotes readarray -t code < <(pcre2grep -Mio 'cheat(\d+)_desc.*\ncheat\1_code.*' "${@:1}" | pcre2grep -io '(?<=_code = )\".*\"' | perl -pe 's#(?<=\")[\t ]+|[\t ]+(?=\")##g ; s|^\"\"$| |g ; s|\"||g ; s|^((?![[:xdigit:]?X]{8}.[[:xdigit:]?X]{4,8}).)*$| |gi ; s|([\w]{8})[ :+]([\w?]{4,8}[\+\n])|\1 \2|g ; s|O|0|g') # capture code lines, strip leading/trailing spaces, replace empty code # with space, replace invalid code with space, strip quotes, replace # delimiter in center of (8 4-8) format with space, replace 'O' with '0' ctr=0 until [ $ctr = ${#hdng[@]} ] ; do # loop for the total number of headers if [[ "${code[$ctr]}" != ' ' ]]; then # only write headers with non-blank codes echo "[${hdng[$ctr]}]" >&$FD_W # write bracketed header to temp file echo -e "$(echo "${code[$ctr]}" | tr '+' '\n')" >&$FD_W # write codes, reformatted to multiline, to temp file fi ((ctr++)) done # write temp file to disk cat <&$FD_R > "$file" echo -e " Complete, output file is: \n $file\n" elif [[ -n "$(pcre2grep -Mio '\[.*\].*(?s)\s+(?-s)[[:xdigit:]?X]{8}.[[:xdigit:]?X]{4,8}' "${@:1}")" ]] ; then # when file contains bracketed headers and hex (8 4-8) format codes convert to retroarch file=""$file"_retro.cht" # append _retro to root filename for output echo -e "\n ** PCSXR '.cht' file detected, converting to RetroArch format. **\n Processing ... \n" readarray -t hdng < <(pcre2grep -io '(^\[.*\]|[[:xdigit:]?X]{8}.[[:xdigit:]?X]{4,8})' "${@:1}" | perl -0777 -pe 's|\[.+?\](?=\n\[)||g ; s#(?<=\[)[*\t ]+|[\t ]+(?=\])##g ; s|\\|, |gi ; s#(?<=\[)(?=\])# #g' | pcre2grep -io '(?<=^\[).*(?=\])') # capture only codes/headings then remove bracketed # lines without subtending codes, remove leading spaces # (and asterisk), plus trailing spaces within bracketed lines, # stuff empty brackets with space, capture all non blank lines readarray -t code < <(pcre2grep -io '(^\[.*\]|[[:xdigit:]?X]{8}.[[:xdigit:]?X]{4,8})' "${@:1}" | perl -0777 -pe 's|\[.+?\]||g ; s|O|0|g ; s#(\w.+?)\n(?!\n|\Z)#\1+#g' | pcre2grep -io '\w.*') # capture only codes/headings then replace bracketed lines # with blank, replace 'O' with '0', concatenate consecutive # codes separated by plus sign, capture all non blank lines ctr=0 until [ $ctr = ${#hdng[@]} ] ; do echo "cheat"$ctr"_desc = \"${hdng[$ctr]}\"" >&$FD_W # write cheat heading to temp file echo "cheat"$ctr"_code = \"${code[$ctr]}\"" >&$FD_W # write single line cheat code to temp file echo -e "cheat"$ctr"_enable = false\n" >&$FD_W # write code enable status to temp file ((ctr++)) done cat >&"$file"< <(echo -e "cheats = ${#hdng[@]}\n" ; cat <&$FD_R) # write heading, after count, to beginning of file echo -e " Complete, output file is: \n $file\n" fi else echo -e "\n ** PCSXR or RetroArch '.cht' file required. **\n ** Script will convert back and forth. **\n" fi