1#         $NetBSD: parselist.awk,v 1.17 2024/04/16 23:40:36 christos Exp $
2#
3# Copyright (c) 2002 The NetBSD Foundation, Inc.
4# All rights reserved.
5#
6# This code is derived from software contributed to The NetBSD Foundation
7# by Luke Mewburn of Wasabi Systems.
8#
9# Redistribution and use in source and binary forms, with or without
10# modification, are permitted provided that the following conditions
11# are met:
12# 1. Redistributions of source code must retain the above copyright
13#    notice, this list of conditions and the following disclaimer.
14# 2. Redistributions in binary form must reproduce the above copyright
15#    notice, this list of conditions and the following disclaimer in the
16#    documentation and/or other materials provided with the distribution.
17#
18# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28# POSSIBILITY OF SUCH DAMAGE.
29#
30
31#
32# awk -f parselist.awk -v mode=MODE [var=val ...] file1 [...]
33#
34#         Parse list files file1 [...], generating different output,
35#         depending upon the value of MODE:
36#
37#             crunch          crunchgen(1) config
38#
39#             install         make(1) Makefile to install commands into ${TARGETDIR},
40#                             with an `install' target.
41#                             The following environment variables need to be set:
42#                                 TARGETDIR       Directory to populate
43#
44#             mtree mtree(8) specfile
45#
46#             populate        sh(1) commands to populate ${TARGETDIR} from ${CURDIR}
47#                             The following environment variables need to be set:
48#                                 CURDIR          Source directory; make(1)'s ${.CURDIR}
49#                                 TARGETDIR       Directory to populate
50#
51#         The following environment variables need to be set for all modes:
52#             CRUNCHBIN       Name of crunchgen(1) target binary
53#             OBJDIR          Object directory; make(1)'s ${.OBJDIR}
54#
55#         Each line of the input is either a comment (starts with `#'),
56#         or contains one of the following keywords and arguments.
57#
58#         Before each line is parsed for a keyword, words surrounded by
59#         "${" and "}", and containing only letters, numbers, and `_'
60#         will be replaced by the value of the environment variable of
61#         the same name.  I.e., "${MACHINE_ARCH}" will be replaced with the
62#         value of ENVIRON["MACHINE_ARCH"].
63#
64#         mode key  operation
65#         --------  ---------
66#         C                   crunch
67#         I                   install
68#         M                   mtree
69#         P                   populate
70#
71#         mode      keyword arg1 [...]  description
72#         ----      ------------------  -----------
73#
74#         C         ARGVLN    prog link as per crunchgen(1) `ln'
75#
76#         P         CMD       arg1 [...]          run CMD as a shell command
77#
78#         IMP       COPY      src dest [perm]     copy src to dest. perm defaults to 0444
79#
80#         IMP       COPYDIR   src dest  recursively copy files under src to
81#                                                 dest.  for M, dest is listed first,
82#                                                 followed by the subdirectories in src.
83#                                                 copied directories have mode 0755.
84#                                                 copied files have mode 0444.
85#
86#         C         LIBS      libspec ...         as per crunchgen(1) `libs'
87#
88#         IMP       LINK      src d1 [d2 ...]     hard link src to d1, d2, ...
89#
90#         M         MTREE     arg1 [...]          output arguments `as-is' to specfile
91#
92#         CIMP      PROG      prog [links...]     program(s) to crunch/mtree/populate.
93#                                                 for I, M & P, the first prog listed
94#                                                 is copied from ${OBJDIR}/${CRUNCHBIN}
95#                                                 and then used as the name to link
96#                                                 all other PROG entries to.
97#
98#         C         SPECIAL   prog cmd ...        as per crunchgen(1) `special'
99#
100#         C         SRCDIRS   dirname ...         as per crunchgen(1) `srcdirs'
101#
102#         IMP       SYMLINK src dest [...]        symlink src to dest, [...]
103#
104
105BEGIN \
106{
107          crunchprog = "";
108
109          if (mode != "crunch" && mode != "install" &&
110              mode != "mtree" && mode != "populate")
111                    errx("Unknown parselist mode '" mode "'");
112
113          needvars["CRUNCHBIN"]++
114          needvars["OBJDIR"]++
115          if (mode == "install") {
116                    needvars["TARGETDIR"]++
117          }
118          else if (mode == "populate") {
119                    needvars["CURDIR"]++
120          }
121          for (nv in needvars) {
122                    if (! (nv in ENVIRON))
123                              errx("Environment variable " nv " not defined");
124          }
125
126          print "#";
127          print "# This file is automatically generated by";
128          print "#\tparselist mode=" mode;
129          print "#";
130          print "";
131          if (mode == "install") {
132                    print ".include <bsd.own.mk>"
133                    print "install:"
134          } else if (mode == "mtree") {
135                    print "/unset\tall";
136                    print "/set\ttype=file uname=root gname=wheel";
137                    print;
138          } else if (mode == "populate") {
139                    print "cd " ENVIRON["CURDIR"];
140                    print;
141          }
142}
143
144/^$/ || /^#/ \
145{
146          print;
147          next;
148}
149
150#         replace ${FOO} with ENVIRON["FOO"]
151#
152/\$\{[A-Za-z0-9_]+\}/ \
153{
154          while (match($0, /\$\{[A-Za-z0-9_]+\}/) > 0) {
155                    v = substr($0, RSTART + 2, RLENGTH - 3);
156                    if (! (v in ENVIRON))
157                              err("Variable " v " is not in the environment");
158                    else
159                              sub(/\$\{[A-Za-z0-9_]+\}/, ENVIRON[v]);
160          }
161}
162
163$1 == "COPY" \
164{
165          if (NF < 3 || NF > 4)
166                    err("Usage: COPY src dest [perm]");
167          if (mode == "install" || mode == "mtree" || mode == "populate")
168                    copy($2, $3, $4);
169          next;
170}
171
172$1 == "COPYDIR" \
173{
174          if (NF != 3)
175                    err("Usage: COPYDIR src dest");
176          srcdir=$2;
177          destdir=$3;
178          if (mode == "mtree") {
179                    printf("./%s type=dir mode=755\n", destdir);
180                    command="cd " srcdir " && find . -type d -print | LC_ALL=C sort"
181                    while (command | getline dir) {
182                              gsub(/^\.\//, "", dir);
183                              if (dir == ".")
184                                        continue;
185                              printf("./%s/%s type=dir mode=755\n", destdir, dir);
186                    }
187                    close(command);
188          }
189          if (mode == "install" || mode == "mtree" || mode == "populate") {
190                    command="cd " srcdir " && find . -type f -print | LC_ALL=C sort"
191                    while (command | getline srcfile) {
192                              gsub(/^\.\//, "", srcfile);
193                              copy(srcdir "/" srcfile, destdir "/" srcfile, "");
194                    }
195                    close(command);
196          }
197          next;
198}
199
200$1 == "LIBS" || $1 == "SPECIAL" || $1 == "SRCDIRS" \
201{
202          if (NF < 2)
203                    err("Usage: " $1 " args...");
204          if (mode == "crunch") {
205                    $1 = tolower($1);
206                    print;
207          }
208          next;
209}
210
211$1 == "PROG" \
212{
213          if (NF < 2)
214                    err("Usage: PROG prog [link ...]");
215          if (mode == "crunch") {
216                    prog = basename($2);
217                    print "progs " prog;
218                    for (i = 3; i <= NF; i++)
219                              print "ln " prog " " basename($i);
220          } else {
221                    for (i = 2; i <= NF; i++) {
222                              if (crunchprog == "") {
223                                        crunchprog = $i;
224                                        copy(ENVIRON["OBJDIR"] "/" ENVIRON["CRUNCHBIN"],
225                                            crunchprog, 555);
226                                        continue;
227                              }
228                              link(crunchprog, $i, 555);
229                    }
230          }
231          next;
232}
233
234$1 == "ARGVLN" \
235{
236          if (NF != 3)
237                    err("Usage: ARGVLN prog link");
238          if (mode == "crunch") {
239                    $1 = "ln";
240                    print;
241          }
242          next;
243}
244
245$1 == "LINK" \
246{
247          if (NF < 3)
248                    err("Usage: LINK prog link [...]");
249          if (mode == "install" || mode == "mtree" || mode == "populate") {
250                    for (i = 3; i <= NF; i++)
251                              link($2, $i, 444);
252          }
253          next;
254}
255
256$1 == "SYMLINK" \
257{
258          if (NF < 3)
259                    err("Usage: SYMLINK prog link [...]");
260          if (mode == "install" || mode == "mtree" || mode == "populate") {
261                    for (i = 3; i <= NF; i++)
262                              symlink($2, $i);
263          }
264          next;
265}
266
267$1 == "CMD" \
268{
269          if (NF < 2)
270                    err("Usage: CMD ...");
271          if (mode == "populate") {
272                    printf("(cd %s;", ENVIRON["TARGETDIR"]);
273                    for (i = 2; i <= NF; i++)
274                              printf(" %s", $i);
275                    print ") || exit 1";
276          }
277          next;
278}
279
280$1 == "MTREE" \
281{
282          if (NF < 2)
283                    err("Usage: MTREE ...");
284          if (mode == "mtree") {
285                    sub(/^[^ \t]+[ \t]+/, "");    # strip first word ("MTREE")
286                    print;
287          }
288          next;
289}
290
291
292{
293          err("Unknown keyword '" $1 "'");
294}
295
296
297function basename (file) \
298{
299          gsub(/[^\/]+\//, "", file);
300          return file;
301}
302
303function copy (src, dest, perm) \
304{
305          if (perm == "")
306                    perm = 444;
307          if (mode == "install") {
308                    printf("\t${INSTALL_FILE} -o ${BINOWN} -g ${BINGRP}" \
309                        " -m %s %s %s/%s\n",
310                        perm, src, ENVIRON["TARGETDIR"], dest)
311          } else if (mode == "mtree") {
312                    printf("./%s mode=%s\n", dest, perm);
313          } else {
314                    printf("rm -rf %s/%s\n", ENVIRON["TARGETDIR"], dest);
315                    printf("cp %s %s/%s\n", src, ENVIRON["TARGETDIR"], dest);
316                    printf("chmod %s %s/%s\n", perm, ENVIRON["TARGETDIR"], dest);
317          }
318}
319
320function link (src, dest, perm) \
321{
322          if (mode == "install") {
323                    printf("\t${INSTALL_LINK} -o ${BINOWN} -g ${BINGRP}" \
324                        " -m %s %s/%s %s/%s\n",
325                        perm, ENVIRON["TARGETDIR"], src, ENVIRON["TARGETDIR"], dest)
326          } else if (mode == "mtree") {
327                    printf("./%s mode=%s\n", dest, perm);
328          } else {
329                    printf("rm -rf %s/%s\n", ENVIRON["TARGETDIR"], dest);
330                    printf("(cd %s; ln %s %s) || exit 1\n",
331                        ENVIRON["TARGETDIR"], src, dest);
332          }
333}
334
335function symlink (src, dest) \
336{
337          if (mode == "install") {
338                    printf("\t${INSTALL_SYMLINK} %s/%s %s/%s\n",
339                        ENVIRON["TARGETDIR"], src, ENVIRON["TARGETDIR"], dest)
340          } else if (mode == "mtree") {
341                    printf("./%s type=link link=%s\n", dest, src);
342          } else {
343                    printf("rm -rf %s/%s\n", ENVIRON["TARGETDIR"], dest);
344                    printf("(cd %s; ln -s %s %s) || exit 1\n",
345                        ENVIRON["TARGETDIR"], src, dest);
346          }
347}
348
349function err(msg) \
350{
351          printf("parselist: %s at line %d of input.\n", msg, NR) >"/dev/stderr";
352          exit 1;
353}
354
355function errx(msg) \
356{
357          printf("parselist: %s.\n", msg) >"/dev/stderr";
358          exit 1;
359}
360