From ac6e348c052820fafd569549622246b4d238a231 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sun, 29 Jan 2023 09:41:46 -0700 Subject: hstow: use globs in .hstow-always-adopt & convert to EREs for awk --- bin/hstow | 15 ++++------ lib-src/globs2ere.awk | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 10 deletions(-) create mode 100644 lib-src/globs2ere.awk diff --git a/bin/hstow b/bin/hstow index c7f783ed..b54b9c94 100755 --- a/bin/hstow +++ b/bin/hstow @@ -77,12 +77,6 @@ readlinks () { rm "$fields_temp" "$targets_temp" } -disjoin_file () { - while read -r line; do - [ -n "$line" ] && printf "|$2" "$line" - done <"$DIR/$1" | sed 's#^.##; s#/#\\/#g' -} - globs_to_find_args () { local file="$DIR/$1"; shift printf '%s\n' "$@" | cat - $([ -e "$file" ] && echo "$file") \ @@ -135,13 +129,14 @@ stow1 () { elif ! [ -e .hstow-always-adopt ]; then adoptp=0 else - # EREs matching files that (i) always/often have their symlinks + # Globs matching files that (i) always/often have their symlinks # replaced with regular files when applications access them; and # (ii) we don't ever want to edit the copy under $DIR directly, # but only via the link/copy under $HOME. - # We might list globs in this file & convert them to EREs here. - adoptp="$(printf 'rel ~ /^(%s)/' \ - "$(disjoin_file .hstow-always-adopt "%s")")" + adoptp="$(printf \ + 'rel ~ /%s/' \ + "$(awk -f ~/src/dotfiles/lib-src/globs2ere.awk \ + .hstow-always-adopt)")" fi find . $(globs_to_find_args .hstow-local-ignore ".git/*") \ ! -name . ! -type d ! -name "$cchars" ! -name .gitignore \ diff --git a/lib-src/globs2ere.awk b/lib-src/globs2ere.awk new file mode 100644 index 00000000..a7038800 --- /dev/null +++ b/lib-src/globs2ere.awk @@ -0,0 +1,83 @@ +# Copyright (C) 2023 Sean Whitton +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or (at +# your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Where each input record is a glob, output a single ERE matching the +# disjunction of all the non-empty input records. +# This is for matching, not expansion: '/' and '.' are not treated specially. +# There is no shell quotation removal, and we do not yet support collating +# symbols or equivalence classes within bracket expressions. +# There is no input validation. + +# One field per record. +BEGIN { FS = RS } + +function getchar () { c = substr($0, ++i, 1) } + +length { + res[++rl] = "^" + while (i < length) { + getchar() + if (c == "*") { + if (rl == 1) + rl-- + else if (res[rl] != ".*") + res[++rl] = ".*" + } else if (c == "?") + res[++rl] = "." + else if (c == "[") { + res[++rl] = "["; getchar() + if (c == "!") { res[++rl] = "^"; getchar() } + if (c == "]") { res[++rl] = "]"; getchar() } + if (c == "^") { circ = 1; getchar() } else circ = 0 + while (c != "]") { + rest = substr($0, i) + if (match(rest, /^\[:[a-z]+:\]/) == 1) { + res[++rl] = substr(rest, 1, RLENGTH) + i += RLENGTH; c = substr($0, i, 1) + } else + res[++rl] = c; getchar() + } + res[++rl] = circ ? "^]" : "]" + } else if (c == "\\") { + getchar() + escaped(c) + } else + escaped(c) + } + if (res[rl] == ".*") + rl-- + else + res[++rl] = "$" + + j++ + for (i = 1; i <= rl; i++) + all[j] = all[j] res[i] + + i = 0; rl = 0; split("", res) +} + +# In an ERE, we can use a backslash to escape any character. +# However, it is good to avoid generating longer EREs than are necessary. +# We do escape forward slashes, for ease of use with awk. +function escaped (c) { res[++rl] = c ~ /[[.(*+?{|^$\/\\]/ ? "\\" c : c } + +END { + if (j) { + printf all[1] + for (i = 2; i <= j; i++) + printf "|%s", all[i] + printf ORS + } +} -- cgit v1.2.3