]> git.plutz.net Git - shellwiki/blob - tools.sh
Merge commit 'fe19ba17990219b7c16c6e2397975b39377a5db8'
[shellwiki] / tools.sh
1 #!/bin/sh
2
3 [ "$include_tools" ] && return 0
4 include_tools="$0"
5
6 # Copyright 2022 - 2023 Paul Hänsch
7
8 # Permission to use, copy, modify, and/or distribute this software for any
9 # purpose with or without fee is hereby granted, provided that the above
10 # copyright notice and this permission notice appear in all copies.
11
12 # THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
15 # SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
18 # IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 . "${_EXEC}/cgilite/storage.sh"
21
22 md(){
23   local parser
24
25   if [ "$#" = 0 ]; then
26     md "${_EXEC}"/parsers/*
27   elif [ "$#" = 1 ]; then
28     "$1"
29   else
30     parser="$1"
31     shift 1
32     "$parser" |md "$@"
33   fi
34 }
35
36 mdfile(){
37   #  Check if page exists, if possible fall
38   #  back to default page from installation
39   local page="$(PATH "$1")"
40   page="${page%/}"
41
42   # Regular processing, keep in sync with tools.sh
43   if   [ -f "$_DATA/pages/$page/:$LANGUAGE/#page.md"  ]; then
44     printf %s\\n "$_DATA/pages/$page/:$LANGUAGE/#page.md"
45   elif [ -f "$_DATA/pages/$page/#page.md" ]; then
46     printf %s\\n "$_DATA/pages/$page/#page.md"
47   elif [ -f "$_EXEC/pages/$page/:$LANGUAGE/#page.md"  ]; then
48     printf %s\\n "$_EXEC/pages/$page/:$LANGUAGE/#page.md"
49   elif [ -f "$_EXEC/pages/$page/#page.md" ]; then
50     printf %s\\n "$_EXEC/pages/$page/#page.md"
51   else
52     return 1
53   fi 2>&-
54   #  ^^ suppress error messages produced
55   #     by printf when stdout was closed
56
57   return 0
58 }
59
60 size_human(){
61   local size="$1"
62
63   if [ $size -gt $((1024 * 1024 * 1024)) ]; then
64     size=$((size / 1024 / 1024 / 1024 * 10 + size / 1024 / 1024 % 1024 / 100))
65     printf "%i.%i GB" "$((size / 10))" "$((size % 10))"
66
67   elif [ $size -gt $((1024 * 1024)) ]; then
68     size=$((size / 1024 / 1024 * 10 + size / 1024 % 1024 / 100))
69     printf "%i.%i MB" "$((size / 10))" "$((size % 10))"
70
71   elif [ $size -gt $((1024)) ]; then
72     size=$((size / 1024 * 10 + size % 1024 / 100))
73     printf "%i.%i KB" "$((size / 10))" "$((size % 10))"
74
75   else
76     printf "%i B" "$size"
77   fi
78 }
79
80 attachment_glob(){
81   local pattern="${1%/}" IFS=''
82   local glob page pagedir
83
84   page="${pattern%/*}"
85   [ "$page" = "$pattern" ] && page=.
86   [ ! "$page" ] && page=/
87   pattern="${pattern##*/}"
88   [ ! "$pattern" ] && pattern="*"
89
90   case $page in
91   /*)
92     for glob in "$_DATA/pages/$page/#attachments"/$pattern; do printf '%s\n' "${glob#"$_DATA/pages"}"; done
93     for glob in "$_EXEC/pages/$page/#attachments"/$pattern; do printf '%s\n' "${glob#"$_EXEC/pages"}"; done
94     ;;
95   *)
96     for glob in "$_DATA/pages/$PATH_INFO/$page/#attachments"/$pattern; do printf '%s\n' "${glob#"$_DATA/pages/$PATH_INFO/"}"; done
97     for glob in "$_EXEC/pages/$PATH_INFO/$page/#attachments"/$pattern; do printf '%s\n' "${glob#"$_EXEC/pages/$PATH_INFO/"}"; done
98     ;;
99   esac \
100   | sort -u \
101   | while read -r glob; do
102     [ -e "$glob" ] || continue
103     pagedir="$(page_abs "${glob%%/#attachments/*}/")"
104     [ -d "$_DATA/pages/$pagedir" -o -d "$_EXEC/pages/$pagedir" ] \
105     && printf '%s\n' "${glob%%/#attachments/*}/${glob#*/#attachments/}"
106   done
107 }
108
109 page_glob(){
110   local pattern="${1%/}/" depth="${2:-0}" IFS=''
111   local glob page pagedir
112
113   case $pattern in
114   /*)
115     for glob in "$_DATA/pages"$pattern; do printf '%s\n' "${glob#"$_DATA/pages"}"; done
116     for glob in "$_EXEC/pages"$pattern; do printf '%s\n' "${glob#"$_EXEC/pages"}"; done
117     ;;
118   *)
119     for glob in "$_DATA/pages/$PATH_INFO"/$pattern; do printf '%s\n' "${glob#"$_DATA/pages/$PATH_INFO/"}"; done
120     for glob in "$_EXEC/pages/$PATH_INFO"/$pattern; do printf '%s\n' "${glob#"$_EXEC/pages/$PATH_INFO/"}"; done
121     ;;
122   esac \
123   | sort -u \
124   | while read -r page; do
125     # Not a page directory (just a metadata dir)
126     [ ! "${page%%#*}" -o ! "${page%%*/#*}" ] && continue
127
128     # Omit "system" pages unless explicitly wanted
129     [ ! "${page%%\[*\]/*}" -o ! "${page%%*/\[*\]/*}" ] && [ "$glob_system_pages" != true ] && continue
130
131     # Omit translation pages if translations are enabled
132     [ ! "${page%%:*}" -o ! "${page%%*/:*}" ] && [ "$LANGUAGE_DEFAULT" ] && continue
133
134     pagedir="$(page_abs "$page")"
135
136     if [ -d "$_DATA/pages/$pagedir" -o -d "$_EXEC/pages/$pagedir" ]; then
137       printf '%s\n' "$page"
138       if ! [ "$depth" -eq 0 ]; then
139         PATH_INFO="$pagedir" page_glob "*" "$((depth - 1))" \
140         | while read -r glob; do printf %s%s\\n "$page" "$glob"; done
141       fi
142     fi
143   done
144 }
145
146 page_abs(){
147   case $1 in
148     /*) PATH "${1%/}/";;
149     *)  PATH "${PATH_INFO%/*}/${1%/}/";;
150   esac
151 }
152
153 has_tags() {
154   # true if PAGE is tagges with all TAGS
155   local page="$(page_abs "$1")"; shift 1;
156   local tdir="$_DATA/tags" tag dt df
157
158   for tag in "$@"; do
159     tag="$(printf %s "$tag" |awk '{ sub(/^[#!]/, ""); gsub(/[^[:alnum:]]/, "_"); print toupper($0); }')"
160     dt="$(DBM "${tdir}/${tag}" get "${page}")" || return 1
161     df="$(stat -c %Y "$(mdfile "$page")")" || return 1
162     if [ "$df" -gt "$dt" ]; then
163       DBM "${tdir}/${tag}" remove "${page}"
164       return 1
165     fi
166   done
167   return 0
168 }
169
170 has_tag() {
171   # true if PAGE is tagged with any of TAGS
172   local page="$(page_abs "$1")"; shift 1;
173   local tdir="$_DATA/tags" tag dt df
174
175   for tag in "$@"; do
176     tag="$(printf %s "$tag" |awk '{ sub(/^[#!]/, ""); gsub(/[^[:alnum:]]/, "_"); print toupper($0); }')"
177     dt="$(DBM "${tdir}/${tag}" get "${page}")" || continue
178     df="$(stat -c %Y "$(mdfile "$page")")" || return 1
179     if [ "$df" -gt "$dt" ]; then
180       DBM "${tdir}/${tag}" remove "${page}"
181       continue
182     else
183       return 0
184     fi
185   done
186   return 1
187 }
188
189 page_title() {
190   local mdfile PAGE_TITLE
191
192   if ! mdfile="$(mdfile "${1:-${PATH_INFO%/*}}")"; then
193     return 1
194   fi
195   PAGE_TITLE="$(
196     # pick title from %title pragma
197     sed -nE '
198       s;^%title[ \t]+([[:graph:]][[:print:]]+)\r?$;\1;p; tQ;
199       b; :Q q;
200     ' "$mdfile"
201   )"
202   [ ! "${PAGE_TITLE}" ] && PAGE_TITLE="$(
203     # pick title from first h1/h2 headline
204     MD_MACROS="" md <"$mdfile" \
205     | sed -nE '
206       s;^.*<h1[^>]*>(.*>)?([^<]+)(<.*)?</h1>.*$;\2;; tQ;
207       s;^.*<h2[^>]*>(.*>)?([^<]+)(<.*)?</h2>.*$;\2;; tQ;
208       b; :Q
209       # reverse escapes of cgilite HTML function,
210       # to prevent later double escaping
211       # later escaping must not be omited
212       s/&lt;/</g; s/&gt;/>/g;  s/&quot;/'\"'/g; s/&#x27;/'\''/g;
213       s/&#x5B;/[/g; s/&#x5D;/]/g;  s/&#x0D;/\r/g; s/&amp;/\&/g;
214       p; q;
215     '
216   )"
217   if [ ! "${PAGE_TITLE}" ]; then
218     # use last part of page URL as title
219     PAGE_TITLE="${1:-${PATH_INFO}}"
220     PAGE_TITLE="${PAGE_TITLE%/*}"
221     PAGE_TITLE="${PAGE_TITLE##*/}"
222   fi
223   debug "TITLE: $PAGE_TITLE"
224   printf %s\\n "$PAGE_TITLE"
225 }