one of the last commit

This commit is contained in:
2026-04-26 23:51:55 +02:00
parent edc421996f
commit 46d24f5367
3 changed files with 437 additions and 9 deletions

325
start.sh Executable file
View File

@@ -0,0 +1,325 @@
#!/usr/bin/env bash
set -u
set -o pipefail
ROOT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
TMP_DIR=$(mktemp -d "${TMPDIR:-/tmp}/cowsay-tour.XXXXXX")
trap 'rm -rf "$TMP_DIR"' EXIT
AUTO_RUN=0
COUNTDOWN=10
STOP_TOUR=0
COMPILER=""
usage() {
cat <<'EOF'
Usage:
./tour_programmes.sh
./tour_programmes.sh --auto
Options:
--auto starts immediately without waiting
-h, --help shows this help
EOF
}
while (($# > 0)); do
case "$1" in
--auto)
AUTO_RUN=1
;;
-h | --help)
usage
exit 0
;;
*)
printf 'Unknown option: %s\n\n' "$1" >&2
usage >&2
exit 1
;;
esac
shift
done
hr() {
printf '\n============================================================\n'
}
show_intro() {
hr
printf 'Quick cowsay program tour\n'
if ((AUTO_RUN == 1)); then
printf 'Auto mode: demos start immediately.\n'
else
printf 'The first demo starts after %d seconds.\n' "$COUNTDOWN"
printf 'After each demo, the tour waits %d seconds before the next one.\n' "$COUNTDOWN"
printf 'Press Enter to continue faster, or type n then Enter to stop.\n'
fi
}
need_commands() {
local missing=0
local cmd
for cmd in "$@"; do
if ! command -v "$cmd" >/dev/null 2>&1; then
printf 'Missing dependency: %s\n' "$cmd" >&2
missing=1
fi
done
return "$missing"
}
detect_compiler() {
if [[ -n "$COMPILER" ]]; then
return 0
fi
local candidate
for candidate in cc clang gcc; do
if command -v "$candidate" >/dev/null 2>&1; then
COMPILER="$candidate"
return 0
fi
done
printf 'No C compiler found.\n' >&2
return 1
}
compile_c() {
local source="$1"
local output="$2"
detect_compiler || return 1
"$COMPILER" -std=c99 -Wall -Wextra -O2 -D_DEFAULT_SOURCE "$source" -o "$output"
}
run_command() {
"$@"
}
run_command_with_input() {
local input="$1"
shift
printf '%s' "$input" | "$@"
}
announce_demo() {
local name="$1"
local description="$2"
hr
printf '%s: %s\n' "$name" "$description"
}
drain_stdin() {
if [[ ! -t 0 ]]; then
return 0
fi
while IFS= read -r -t 0; do
:
done
}
timed_continue() {
local prompt="$1"
if ((AUTO_RUN == 1)) || [[ ! -t 0 ]]; then
printf 'Starting...\n'
return 0
fi
drain_stdin
printf '%s' "$prompt"
local answer=""
if IFS= read -r -t "$COUNTDOWN" answer; then
printf '\n'
case "${answer,,}" in
n)
STOP_TOUR=1
return 1
;;
*)
return 0
;;
esac
fi
printf '\n'
return 0
}
run_demo() {
local name="$1"
local function_name="$2"
"$function_name"
local status=$?
if ((status != 0)); then
printf '%s: failed (%d)\n' "$name" "$status" >&2
fi
}
demo_cow_kindergarten() {
need_commands cowsay || return 1
run_command bash "$ROOT_DIR/src/bash_scripts/cow_kindergarten.sh"
}
demo_cow_primaryschool() {
need_commands cowsay || return 1
run_command bash "$ROOT_DIR/src/bash_scripts/cow_primaryschool.sh" 3
}
demo_cow_highschool() {
need_commands cowsay || return 1
run_command bash "$ROOT_DIR/src/bash_scripts/cow_highschool.sh" 3
}
demo_cow_college() {
need_commands cowsay || return 1
run_command bash "$ROOT_DIR/src/bash_scripts/cow_college.sh" 5
}
demo_cow_university() {
need_commands cowsay || return 1
run_command bash "$ROOT_DIR/src/bash_scripts/cow_university.sh" 12
}
demo_smart_cow() {
need_commands cowsay bc || return 1
run_command bash "$ROOT_DIR/src/bash_scripts/smart_cow.sh" '4+13'
}
demo_crazy_cow() {
need_commands cowsay || return 1
run_command_with_input $'5\n' bash "$ROOT_DIR/src/bash_scripts/crazy_cow.sh"
}
demo_newcow() {
local bin="$TMP_DIR/newcow"
compile_c "$ROOT_DIR/src/C/newcow.c" "$bin" || return 1
run_command "$bin" -e "^^"
}
demo_newcowt() {
local bin="$TMP_DIR/newcowT"
compile_c "$ROOT_DIR/src/C/newcows/newcowT.c" "$bin" || return 1
run_command "$bin" -T "U"
}
demo_newcowp() {
local bin="$TMP_DIR/newcowp"
compile_c "$ROOT_DIR/src/C/newcows/newcowp.c" "$bin" || return 1
run_command "$bin" -p "Hello"
}
demo_newcow2() {
local bin="$TMP_DIR/newcow2"
compile_c "$ROOT_DIR/src/C/newcow2.c" "$bin" || return 1
run_command "$bin" blink
}
demo_reading_cow() {
local bin="$TMP_DIR/reading_cow"
local sample="$TMP_DIR/reading_demo.txt"
compile_c "$ROOT_DIR/src/C/reading_cow.c" "$bin" || return 1
printf 'Hello.\nI read.\n' >"$sample"
run_command "$bin" --i 0.10 "$sample"
}
demo_tamagoshi_cow() {
local bin="$TMP_DIR/tamagoshi_cow"
if ((AUTO_RUN == 1)) || [[ ! -t 0 ]]; then
printf 'Tamagoshi skipped in auto mode.\n'
return 0
fi
compile_c "$ROOT_DIR/src/C/tamagoshi_cow.c" "$bin" || return 1
run_command "$bin"
}
visit_programs() {
local -a names=(
'cow_kindergarten.sh'
'cow_primaryschool.sh'
'cow_highschool.sh'
'cow_college.sh'
'cow_university.sh'
'smart_cow.sh'
'crazy_cow.sh'
'newcow.c'
'newcowT.c'
'newcowp.c'
'newcow2.c'
'reading_cow.c'
'tamagoshi_cow.c'
)
local -a descriptions=(
'Counts from 1 to 10.'
'Counts up to n.'
'Shows square numbers.'
'Shows Fibonacci.'
'Shows prime numbers.'
'Calculates an expression.'
'Generates a weird sequence.'
'Basic cow.'
'Cow with a tongue option.'
'Cow with a speech bubble.'
'Compiles a .c file into .out.'
'Animates the cow.'
'The cow reads a file.'
'Small cow game.'
)
local -a functions=(
'demo_cow_kindergarten'
'demo_cow_primaryschool'
'demo_cow_highschool'
'demo_cow_college'
'demo_cow_university'
'demo_smart_cow'
'demo_crazy_cow'
'demo_newcow'
'demo_newcowt'
'demo_newcowp'
'demo_newcow2'
'demo_reading_cow'
'demo_tamagoshi_cow'
)
local total=${#names[@]}
local i
for ((i = 0; i < total; i++)); do
announce_demo "${names[i]}" "${descriptions[i]}"
if ((i == 0)); then
timed_continue "Press Enter to start, type n then Enter to stop, auto-start in ${COUNTDOWN} seconds... " || return
else
timed_continue "Press Enter to start the next program, type n then Enter to stop, or wait ${COUNTDOWN} seconds... " || return
fi
run_demo "${names[i]}" "${functions[i]}"
((STOP_TOUR == 1)) && return
done
}
show_outro() {
hr
if ((STOP_TOUR == 1)); then
printf 'Tour stopped.\n'
else
printf 'End of tour.\n'
fi
}
show_intro
visit_programs
show_outro