paul@0 | 1 | #!/bin/sh |
paul@0 | 2 | |
paul@21 | 3 | # Search for a definition in the definitions file, expanding it recursively to |
paul@21 | 4 | # provide a complete description. |
paul@15 | 5 | # |
paul@15 | 6 | # Copyright (C) 2019 Paul Boddie <paul@boddie.org.uk> |
paul@15 | 7 | # |
paul@15 | 8 | # This program is free software; you can redistribute it and/or modify it under |
paul@15 | 9 | # the terms of the GNU General Public License as published by the Free Software |
paul@15 | 10 | # Foundation; either version 3 of the License, or (at your option) any later |
paul@15 | 11 | # version. |
paul@15 | 12 | # |
paul@15 | 13 | # This program is distributed in the hope that it will be useful, but WITHOUT |
paul@15 | 14 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
paul@15 | 15 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
paul@15 | 16 | # details. |
paul@15 | 17 | # |
paul@15 | 18 | # You should have received a copy of the GNU General Public License along with |
paul@15 | 19 | # this program. If not, see <http://www.gnu.org/licenses/>. |
paul@15 | 20 | |
paul@0 | 21 | |
paul@0 | 22 | PROGNAME=`basename "$0"` |
paul@0 | 23 | THISDIR=`dirname "$0"` |
paul@0 | 24 | |
paul@21 | 25 | COMMON="$THISDIR/makesd-common" |
paul@14 | 26 | DEFS="$THISDIR/makesd-defs" |
paul@0 | 27 | |
paul@21 | 28 | . "$COMMON" |
paul@21 | 29 | |
paul@0 | 30 | |
paul@0 | 31 | |
paul@21 | 32 | # lookup <definition> |
paul@0 | 33 | # |
paul@21 | 34 | # Search for the given definition in the definitions file. Emit the full |
paul@21 | 35 | # definition. |
paul@0 | 36 | |
paul@0 | 37 | lookup() |
paul@0 | 38 | { |
paul@0 | 39 | local LINENUM |
paul@0 | 40 | |
paul@0 | 41 | # Obtain the line number of the matching definition. |
paul@0 | 42 | |
paul@21 | 43 | LINENUM=`search "^$1$" "$DEFS"` |
paul@0 | 44 | |
paul@0 | 45 | if [ "$LINENUM" ] ; then |
paul@0 | 46 | |
paul@21 | 47 | # Read from the definition until a blank line or the end of file is |
paul@21 | 48 | # encountered. Line continuations are observed. |
paul@21 | 49 | |
paul@21 | 50 | tail -n "+$(($LINENUM + 1))" "$DEFS" | while read LINE ; do |
paul@21 | 51 | |
paul@21 | 52 | # Detect end of definition. |
paul@0 | 53 | |
paul@21 | 54 | if [ ! "$LINE" ] ; then |
paul@21 | 55 | break |
paul@21 | 56 | fi |
paul@21 | 57 | |
paul@21 | 58 | # Show definition lines. |
paul@21 | 59 | |
paul@0 | 60 | echo "$LINE" |
paul@21 | 61 | done |
paul@0 | 62 | fi |
paul@0 | 63 | } |
paul@0 | 64 | |
paul@21 | 65 | # consolidate |
paul@0 | 66 | # |
paul@22 | 67 | # Eliminate duplicate properties, preserving only the final definition, except |
paul@22 | 68 | # for certain properties. |
paul@21 | 69 | |
paul@21 | 70 | consolidate() |
paul@21 | 71 | { |
paul@22 | 72 | sort -k1,1 -t: -s | show_last 'expand' |
paul@21 | 73 | } |
paul@21 | 74 | |
paul@22 | 75 | # show_last [ <property> ... ] |
paul@22 | 76 | # |
paul@22 | 77 | # Show only the last property of any given name, preserving duplicate entries |
paul@22 | 78 | # only for any given properties. |
paul@22 | 79 | |
paul@21 | 80 | show_last() |
paul@21 | 81 | { |
paul@21 | 82 | local FIELD LAST LASTLINE |
paul@21 | 83 | |
paul@21 | 84 | LAST= |
paul@21 | 85 | LASTLINE= |
paul@21 | 86 | |
paul@21 | 87 | while read LINE ; do |
paul@21 | 88 | |
paul@21 | 89 | # Inspect the property details. |
paul@0 | 90 | |
paul@21 | 91 | FIELD=`get_field "$LINE"` |
paul@21 | 92 | |
paul@21 | 93 | # With a differing property from any previous one, emit the previous |
paul@22 | 94 | # one. With a preserved property, also emit the previous line. |
paul@21 | 95 | |
paul@22 | 96 | if [ "$LAST" ] && [ "$FIELD" != "$LAST" ] || is_in "$FIELD" $* ; then |
paul@21 | 97 | echo "$LASTLINE" |
paul@21 | 98 | fi |
paul@21 | 99 | |
paul@21 | 100 | # Retain this property definition for possible future emission. |
paul@21 | 101 | |
paul@21 | 102 | LAST=$FIELD |
paul@21 | 103 | LASTLINE=$LINE |
paul@21 | 104 | done |
paul@21 | 105 | |
paul@21 | 106 | # Emit any remaining line, also indicating whether any lines were processed. |
paul@21 | 107 | |
paul@21 | 108 | if [ "$LASTLINE" ] ; then |
paul@21 | 109 | echo "$LASTLINE" |
paul@0 | 110 | return 0 |
paul@0 | 111 | else |
paul@0 | 112 | return 1 |
paul@0 | 113 | fi |
paul@0 | 114 | } |
paul@0 | 115 | |
paul@21 | 116 | # expand <definition> |
paul@0 | 117 | # |
paul@0 | 118 | # Expand the given definition name to its value, recursively expanding any |
paul@0 | 119 | # definition names found in the value text. |
paul@0 | 120 | |
paul@0 | 121 | expand() |
paul@0 | 122 | { |
paul@21 | 123 | local TYPE |
paul@21 | 124 | |
paul@21 | 125 | TYPE=`echo "$1" | cut -d' ' -f1` |
paul@0 | 126 | |
paul@21 | 127 | # Look up the definition and read each line. |
paul@21 | 128 | |
paul@21 | 129 | lookup "$1" | expand_def "$TYPE" |
paul@21 | 130 | } |
paul@0 | 131 | |
paul@21 | 132 | expand_def() |
paul@21 | 133 | { |
paul@21 | 134 | local FIELD LINE RESULT TYPE VALUE |
paul@0 | 135 | |
paul@21 | 136 | RESULT=1 |
paul@0 | 137 | |
paul@21 | 138 | while read LINE ; do |
paul@21 | 139 | RESULT=0 |
paul@0 | 140 | |
paul@21 | 141 | # Inspect the line and find any references to other definitions. |
paul@0 | 142 | |
paul@21 | 143 | FIELD=`get_field "$LINE"` |
paul@21 | 144 | VALUE=`get_value "$LINE"` |
paul@21 | 145 | |
paul@21 | 146 | # Merge definitions that are adapted. |
paul@0 | 147 | |
paul@21 | 148 | if [ "$FIELD" = 'adapts' ] ; then |
paul@21 | 149 | expand "$TYPE $VALUE" |
paul@21 | 150 | |
paul@21 | 151 | # Aggregate system components such as partitions and regions. |
paul@0 | 152 | |
paul@21 | 153 | elif [ "$TYPE" = 'system' ] && ( |
paul@21 | 154 | [ "$FIELD" = 'partition' ] || [ "$FIELD" = 'region' ] ) ; then |
paul@21 | 155 | |
paul@21 | 156 | # Declare regions and partitions in the output. |
paul@0 | 157 | |
paul@21 | 158 | echo "$FIELD" |
paul@21 | 159 | expand "$FIELD $VALUE" | consolidate |
paul@21 | 160 | echo |
paul@0 | 161 | |
paul@21 | 162 | # Otherwise, emit properties of the definition. |
paul@21 | 163 | |
paul@0 | 164 | else |
paul@21 | 165 | echo "$LINE" |
paul@0 | 166 | fi |
paul@0 | 167 | done |
paul@0 | 168 | |
paul@21 | 169 | return $RESULT |
paul@0 | 170 | } |
paul@0 | 171 | |
paul@0 | 172 | |
paul@0 | 173 | |
paul@21 | 174 | # Obtain the requested system name. |
paul@21 | 175 | |
paul@21 | 176 | if [ ! "$1" ] || [ "$1" = '--help' ] ; then |
paul@21 | 177 | cat 1>&2 <<EOF |
paul@21 | 178 | Usage: $PROGNAME <system> |
paul@21 | 179 | $PROGNAME -a | --all | --defs |
paul@21 | 180 | |
paul@21 | 181 | Search for a definition of the given system in the definitions file: |
paul@21 | 182 | |
paul@21 | 183 | $DEFS |
paul@21 | 184 | |
paul@21 | 185 | If the definition can be found, the value of the definition is emitted and an |
paul@21 | 186 | exit value of 0 returned. Otherwise, no output is produced and an exit value of |
paul@21 | 187 | 1 is returned. |
paul@21 | 188 | |
paul@21 | 189 | $(show_definitions_description) |
paul@21 | 190 | EOF |
paul@21 | 191 | exit 1 |
paul@21 | 192 | fi |
paul@21 | 193 | |
paul@21 | 194 | # Show definitions if requested. |
paul@21 | 195 | |
paul@21 | 196 | if [ "$1" = '-a' ] || [ "$1" = '--all' ] || [ "$1" = '--defs' ] ; then |
paul@21 | 197 | grep '^system' "$DEFS" | sed 's/^system //' | sort |
paul@21 | 198 | exit 0 |
paul@21 | 199 | fi |
paul@21 | 200 | |
paul@0 | 201 | # Expand the definition and return the result code. |
paul@0 | 202 | |
paul@21 | 203 | DEF=$1 |
paul@21 | 204 | |
paul@21 | 205 | expand "system $DEF" |
paul@0 | 206 | exit $? |