feat(user/mw_create_subpage_navlinks.sh):Add script
[BK-2020-03.git] / user / mw_create_subpage_navlinks.sh
1 #!/bin/bash
2 # Desc: Generates Mediawiki subpage navigation links
3 # Input: file text file with list of chapters
4 # stdin text with list of chapters
5 # Output: [[../Chapter 4|Next]], [[../Chapter 2|Previous]], [[../|Up]]
6 # Version: 0.0.1
7 # Attrib: Steven Baltakatei Sandoval. (2024-01-29). reboil.com
8 # License: GPLv3+
9
10 yell() { echo "$0: $*" >&2; } # print script path and all args to stderr
11 die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status
12 must() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails
13 read_input() {
14 # Note: May accept specified file or stdin, but not both
15 # Input: arg input text (newline delimited)
16 # stdin input text (newline delimited)
17 # Output: stdout output text (newline delimited)
18 # Depends: BK-2020-03 read_stdin (v0.1.1), yell(), die()
19
20 # Parse args
21 ## Only 1 argument.
22 if [[ "$#" -gt 1 ]]; then die "FATAL:Too many arguments ($#):$*"; fi;
23 ## File specified.
24 if [[ "$#" -eq 1 ]] && [[ -f "$1" ]] && [[ ! -p /dev/stdin ]]; then
25 while read -r line; do
26 printf "%s\n" "$line";
27 done < "$1" && return 0; fi;
28 if [[ "$#" -eq 0 ]] && [[ -p /dev/stdin ]]; then
29 read_stdin && return 0; fi;
30 die "FATAL:Unknown error.";
31 };
32 read_stdin() {
33 # Desc: Consumes stdin; outputs as stdout lines
34 # Input: stdin (consumes)
35 # Output: stdout (newline delimited)
36 # return 0 stdin read
37 # return 1 stdin not present
38 # Example: printf "foo\nbar\n" | read_stdin
39 # Depends: GNU bash (version 5.1.16), GNU Coreutils 8.32 (cat)
40 # Version: 0.1.1
41 # Attrib: Steven Baltakatei Sandoval (2024-01-29). reboil.com
42 local input_stdin output;
43
44 # Store stdin
45 if [[ -p /dev/stdin ]]; then
46 input_stdin="$(cat -)" || {
47 echo "FATAL:Error reading stdin." 1>&2; return 1; };
48 else
49 return 1;
50 fi;
51
52 # Store as output array elements
53 ## Read in stdin
54 if [[ -n $input_stdin ]]; then
55 while read -r line; do
56 output+=("$line");
57 done < <(printf "%s\n" "$input_stdin") || {
58 echo "FATAL:Error parsing stdin."; return 1; };
59 fi;
60
61 # Print to stdout
62 printf "%s\n" "${output[@]}";
63
64 return 0;
65 }; # read stdin to stdout lines
66 validate_subpage_list() {
67 # Desc: Check for illegal characters in subpage titles
68 # Input: stdin unvalidated subpage list
69 # Output: stdout validated subpage list
70 # Depends: BK-2020-03 read_stdin(), yell(), die()
71 # GNU sed v4.8
72 while read -r line; do
73
74 # Reject chars illegal in Mediawiki page titles.
75 re_illegal='[][><|}{#_]'; # match illegal page names chars #, <, >, [, ], _, {, |, }
76 if [[ "$line" =~ $re_illegal ]]; then
77 die "FATAL:Illegal char. Not allowed: #, <, >, [, ], _, {, |, }:$line";
78 fi;
79
80 # Reject trailing spaces.
81 re_ts=' $'; # match trailing space
82 if [[ "$line" =~ $re_ts ]]; then
83 die "FATAL:Trailing spaces not allowed:$line";
84 fi;
85
86 # Replace some chars with HTML-style codes
87 ## replace ampersand & with &#38 # must be first
88 ## replace double quote " with &#34
89 ## replace single quote ' with &#39
90 line="$(sed \
91 -e 's/&/\&#38;/g' \
92 -e 's/"/\&#34;/g' \
93 -e "s/'/\&#39;/g" \
94 <<< "$line" )" || { echo "FATAL:Error running sed."; };
95 printf "%s\n" "$line";
96 done || {
97 echo "FATAL:Error reading stdin." 1>&2; return 1; };
98 };
99 generate_wikicode() {
100 # Input: stdin validated subpage list
101 # Output: stdout wikicode
102 local lprev lnext;
103
104 n=0;
105 while read -r line; do
106 #yell "$n:Processing line:$line"; # debug
107 lprev="$lcurr";
108 lcurr="$lnext";
109 lnext="$line";
110 #declare -p lprev lcurr lnext; # debug
111
112 # Skip first iteration
113 if [[ "$n" -eq 0 ]]; then
114 # yell "$n:DEBUG:Skipping first iteration."; # debug
115 ((n++));
116 #printf -- "----\n" 1>&2; # debug
117 continue; fi;
118
119 # Handle first valid input set
120 # yell "$n:DEBUG:Handling first valid input set."; # debug
121 if [[ "$n" -eq 1 ]]; then
122 printf "[[../%s|Next]], [[../|Up]]\n" \
123 "$lnext";
124 #printf -- "----\n" 1>&2; # debug
125 ((n++)); continue; fi;
126
127 # Handle middle lines
128 # yell "$n:DEBUG:Handling middle lines."; # debug
129 printf "[[../%s|Next]], [[../%s|Previous]], [[../|Up]]\n" \
130 "$lnext" "$lprev";
131 ((n++));
132 #printf -- "----\n" 1>&2; # debug
133 done;
134
135 # Handle last line
136 lprev="$lcurr";
137 lcurr="$lnext";
138 lnext="$line";
139 printf "[[../%s|Previous]], [[../|Up]]\n" \
140 "$lprev";
141 ((n++));
142 };
143 main() {
144 read_input "$@" | validate_subpage_list | generate_wikicode;
145 }; # main program
146
147 main "$@";