first commit
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
#!/bin/sh
|
||||
# lshar.sh - Luxferre's shell archiver
|
||||
# Outputs to stdout only (for GNU and BSD shar compatibility)
|
||||
# No external deps for .shars (sh commands required: mkdir, printf)
|
||||
# Archive creation also depends on sort (Busybox, Toybox or GNU Coreutils)
|
||||
# Works with any text or binary files and directory structures
|
||||
# Created by Luxferre in 2023, released into public domain
|
||||
|
||||
# a portable, compact, no-deps serializer of any file into printf sequence
|
||||
f2p() {
|
||||
c=0 # init counter
|
||||
l="$2" # get chunk length
|
||||
[ -z "$l" ] && l=4096 # 4096-byte chunks by default (shouldn't be a problem)
|
||||
cprefix="printf '%b' '" # pattern to prepend to every chunk
|
||||
csuffix="' >> '$1'\n" # pattern to append to every chunk
|
||||
printf '%b' "$cprefix" # always start with the prefix
|
||||
IFS='' # separator
|
||||
while read -r -s -d '' -n1 b; do # convert every byte
|
||||
if [ "$c" == "$l" ]; then # roll over and output suffix+prefix
|
||||
c=0 # reinit counter
|
||||
printf '%b' "$csuffix" # end the chunk
|
||||
printf '%b' "$cprefix" # begin a new chunk
|
||||
else
|
||||
c="$(( c + 1 ))" # increment c
|
||||
fi
|
||||
bcode="$(printf '%d' "'$b")" # get the ASCII code of the byte
|
||||
if [ "$bcode" -gt 32 ] && [ "$bcode" -lt 127 ] &&
|
||||
[ "$bcode" -ne 39 ] && [ "$bcode" -ne 92 ]
|
||||
then # printable and not a single quote or a backslash
|
||||
printf '%b' "$b" # codes from 34 to 126 are safe to print
|
||||
else # subject to escaping, print the hex representation
|
||||
printf '\\x%02x' "$bcode"
|
||||
fi
|
||||
done <"$1"
|
||||
printf '%b' "$csuffix" # always end with the suffix
|
||||
}
|
||||
|
||||
# main code
|
||||
LF=$'\n' # cache the linefeed character
|
||||
flist='' # pre-build the file list from args
|
||||
dlist='' # pre-build the directory list from args
|
||||
for i; do # iterate over args
|
||||
bname="${i##*/}" # get the basename
|
||||
if [ -d "$i" ]; then # it's a directory, we skip . and ..
|
||||
[ "$bname" == '.' ] || [ "$bname" == '..' ] && continue
|
||||
dlist="${dlist}${i%/}${LF}" # append the directory
|
||||
else # it's a file
|
||||
dname="${i%%$bname}" # get the basedir
|
||||
dlist="${dlist}${dname%/}${LF}" # append the basedir
|
||||
flist="${flist}${i}${LF}" # append the file
|
||||
fi
|
||||
done
|
||||
flist="$(printf '%s' "$flist" | sort -u)" # remove file duplicates
|
||||
dlist="$(printf '%s' "$dlist" | sort -u)" # remove directory duplicates
|
||||
printf '%s\n' '#!/bin/sh' # output the shebang, just in case
|
||||
IFS="$LF" # update the separator
|
||||
for indir in $dlist; do # create the directory structure first
|
||||
[ -z "$indir" ] && continue # skip empty names
|
||||
printf '# dir: %s\n' "$indir"
|
||||
printf "printf 'c - %%s\\\n' '%s'\n" "$indir" # announce creation
|
||||
printf "mkdir -p '%s' > /dev/null 2>&1\n" "$indir" # create the dir
|
||||
done
|
||||
for infile in $flist; do # iterate over the file list afterwards
|
||||
[ -z "$infile" ] && continue # skip empty names
|
||||
printf '# file: %s\n' "$infile"
|
||||
printf "printf 'x - %%s\\\n' '%s'\n" "$infile" # announce unrolling
|
||||
printf "printf '' > '%s'\n" "$infile" # clear the file
|
||||
f2p "$infile" # run the serializer
|
||||
IFS="$LF" # update the separator
|
||||
done
|
||||
Reference in New Issue
Block a user