slugify() { printf '%s\n' "$1" | tr '[:upper:]' '[:lower:]' | sed -e 's/[^a-z0-9][^a-z0-9]*/-/g' \ -e 's/^-//' \ -e 's/-$//' \ -e 's/^$/section/' } heading_text() { tag=$1 printf '%s\n' "$2" | awk -v tag="$tag" ' function decode(s) { gsub(/"|"/, "\"", s) gsub(/'|'/, "\047", s) gsub(/<|</, "<", s) gsub(/>|>/, ">", s) gsub(/&|&/, "\\&", s) return s } { line = $0 start = index(line, "<" tag) end = index(line, "") if (!start || !end || end < start) exit head = substr(line, start, end - start) for (i = 1; i <= length(head); i++) if (substr(head, i, 1) == ">") { close_pos = i break } if (!close_pos) exit text = substr(head, close_pos + 1) if (text !~ / "$heading_meta" : > "$section_ids" : > "$subsection_meta" : > "$subsection_parents" current_section= while IFS= read -r line || [ -n "$line" ]; do case $line in *'> "$section_ids" ;; h3) [ -n "$current_section" ] || die "Indexable h3 must follow an h2: $source" parent_id=$current_section printf '%s\t%s\n' "$parent_id" "$heading_id" >> "$subsection_meta" if ! grep -F -x -q -e "$parent_id" "$subsection_parents"; then printf '%s\n' "$parent_id" >> "$subsection_parents" fi subsection_count=$((subsection_count + 1)) ;; esac printf '%s\t%s\t%s\t%s\n' \ "$heading_tag" "$heading_id" "$heading_title" "$parent_id" >> "$heading_meta" done < "$source" }