imapfilter convenience wrapper

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. #!/bin/bash
  2. # MKit - simple install helper
  3. # See LICENSE file for copyright and license details.
  4. __ini_cat() {
  5. #
  6. # A no-op for text stream
  7. #
  8. local line # each line
  9. while read -r line; do
  10. printf -- '%s\n' "$line"
  11. done
  12. }
  13. __ini_expand() {
  14. #
  15. # Expand reference value (prefix only)
  16. #
  17. local line # each input line
  18. while read -r line; do # [foo:bar]/path
  19. __ini_expandln "$line"
  20. done
  21. }
  22. __ini_expandln() {
  23. #
  24. # Fully expand references in line $1
  25. #
  26. local line_orig=$1 # original line
  27. local line_todo=$line_orig # current state
  28. local line_done # next state
  29. local Depth=0 # current depth
  30. local MaxDepth=10 # maximum depth
  31. while true; do
  32. ((Depth++))
  33. debug_var line_todo
  34. test "$Depth" -le "$MaxDepth" || {
  35. warn "expansion error: reached maximum depth: $Depth > $MaxDepth" \
  36. " original line: $line_orig" \
  37. " expanded line: $line_todo"
  38. return 3
  39. }
  40. line_done=$(__ini_expandln_once "$line_todo")
  41. debug_var line_done
  42. test "$line_done" == "$line_todo" && break
  43. line_todo=$line_done
  44. done
  45. echo "$line_done"
  46. }
  47. __ini_expandln_once() {
  48. #
  49. # Run through line $1 once and replace all references
  50. #
  51. local line=$1 # line to expand
  52. local ref # full reference (incl. brackets)
  53. local ipath # just ini path from ^^ (stripped brackets)
  54. local value # value of reference
  55. local refs=() # all references found in line
  56. mapfile -t refs <<<"$(grep -Eo '[[][^]]+[]]' <<< "$line_todo")"
  57. debug_var refs
  58. for ref in "${refs[@]}"; do
  59. test -n "$ref" || continue
  60. ipath=${ref#[}; ipath=${ipath%]}
  61. value=$(ini 1value "$ipath")
  62. debug_var line ref ipath value
  63. line=${line//"[$ipath]"/"$value"}
  64. done
  65. echo "$line"
  66. }
  67. __ini_grepcmt() {
  68. #
  69. # Remove comments from INI file on stdin
  70. #
  71. grep -v '^[[:space:]]*#'
  72. }
  73. __ini_grepkey() {
  74. #
  75. # Read key from a normalized `key=value` section
  76. #
  77. local wnt=$1 # wanted key
  78. grep '.' \
  79. | grep -e "^$wnt=" \
  80. | cut -d= -f2- \
  81. | __ini_maybe_expand
  82. }
  83. __ini_greppath() {
  84. #
  85. # Read key from the right section
  86. #
  87. # E.g. `files:share:my/lib.sh` should read
  88. #
  89. # [files:share]
  90. # my/lib.sh = proj/my/lib.sh
  91. #
  92. local wnt=$1 # wanted path
  93. local wntkey=${wnt##*:} # ^^ key part
  94. local wntsec=${wnt%:"$wntkey"} # ^^ section part
  95. local override # ENV override (only ENV section)
  96. if test "$wntsec" = 'ENV'; then
  97. override=${!wntkey}
  98. test -n "$override" \
  99. && echo "$override" \
  100. && return
  101. fi
  102. __ini_grepsec "$wntsec" | __ini_grepkey "$wntkey"
  103. }
  104. __ini_grepsec() {
  105. #
  106. # Read one INI section
  107. #
  108. local wnt=$1 # wanted section name
  109. local ok=false # are we in the section?
  110. local line # each input line
  111. grep '.' \
  112. | while read -r line; do
  113. case "$line" in
  114. \["$wnt"\]) ok=true; continue ;;
  115. \[*\]) ok=false; continue ;;
  116. esac
  117. $ok || continue
  118. printf -- '%s\n' "$line"
  119. done \
  120. | grep '^[[:space:]]*[^[:space:]:][^:]*[[:space:]]*[=]' \
  121. | sed -e 's/[[:space:]]*=[[:space:]]*/=/; s/[[:space:]]*$//; s/^[[:space:]]*//;'
  122. }
  123. __ini_lskeys() {
  124. #
  125. # List keys from a section
  126. #
  127. local sct=$1 # section of interest
  128. __ini_grepsec "$sct" | cut -d= -f1 | awk '!x[$0]++'
  129. }
  130. __ini_lssect() {
  131. #
  132. # List all section names
  133. #
  134. grep -x '\[.*\]' | sed 's/^.//; s/.$//'
  135. }
  136. __ini_maybe_expand() {
  137. #
  138. # Decide whether or not to expand
  139. #
  140. if test "$MKIT_INI_EXPAND" -gt 0; then
  141. MKIT_INI_EXPAND=$(( --MKIT_INI_EXPAND )) __ini_expand
  142. else
  143. __ini_cat
  144. fi
  145. }
  146. __ini_body() {
  147. #
  148. # Produce mkit.ini body including INCLUDE
  149. #
  150. # Note: recursive includes are not supported.
  151. #
  152. local inc # file to include
  153. local incre='\[INCLUDE:.*\]' # include directive regex
  154. local iline # include directive line
  155. if iline=$(grep -m1 -xe "$incre" "$MKIT_INI"); then
  156. inc=${iline#*:}; inc=${inc%]}
  157. grep -vxe "$incre" "$inc"
  158. grep -vxe "$incre" "$MKIT_INI"
  159. else
  160. cat "$MKIT_INI"
  161. fi | __ini_grepcmt
  162. }
  163. ini() {
  164. #
  165. # do ini operation
  166. #
  167. local op=$1 # operator
  168. local arg=$2 # argument
  169. local fn # internal function implementing $op
  170. local limit=__ini_cat # limiting internal function
  171. case $op in
  172. lskeys) fn=__ini_lskeys ;;
  173. lssect) fn=__ini_lssect ;;
  174. sec) fn=__ini_grepsec ;;
  175. values) fn=__ini_greppath ;;
  176. 1value) fn=__ini_greppath; limit="tail -1" ;;
  177. *) die "incorrect use of \`ini()\`"
  178. esac
  179. __ini_body | $fn "$arg" | $limit
  180. }