1#!/bin/sh
2# genbox.sh - generate the aruu-box dispatch table
3#
4# does one thing: given a list of object file paths on argv, each one
5# of BOX_OBJ's own outputs (".box/cmd/<category>/<tool>.o"), emit the C
6# source for aruu-box's dispatch table and main() on stdout
7#
8set -e
9
10[ $# -gt 0 ] || {
11 printf "genbox: no object paths given\n" >&2
12 exit 1
13}
14
15# derive category, tool basestem, and C symbol from one BOX_OBJ output
16# path. the symbol transform (tr '.-' '__', append _main) must match
17# BOX_OBJ's own objcopy step exactly, see the CATEGORY_OF/symbol
18# comment in ninqu.rules for why this is a shell transform and not a
19# map
20path_category() {
21 rest=${1#.box/cmd/}
22 printf "%s\n" "${rest%%/*}"
23}
24
25path_tool() {
26 rest=${1##*/}
27 printf "%s\n" "${rest%.o}"
28}
29
30path_symbol() {
31 tool=$(path_tool "$1")
32 printf "%s\n" "$(echo "$tool" | tr '.-' '__')_main"
33}
34
35cat << 'HEAD'
36/* this file is autogenerated by genbox.sh. do not edit */
37
38#include "wexec.h"
39#include "util.h"
40
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <unistd.h>
45
46HEAD
47
48# extern decls, in the order ninqu passed the objects in (BOX_OBJ's
49# own glob order, one category at a time)
50for obj in "$@"; do
51 sym=$(path_symbol "$obj")
52 echo "int ${sym}(int, char **);"
53done
54
55cat << 'MID'
56
57struct Cmd {
58 const char *name;
59 int (*fn)(int, char **);
60 const char *category;
61};
62
63static struct Cmd cmds[] = {
64MID
65
66categories=$(
67 for obj in "$@"; do
68 path_category "$obj"
69 done | sort -u
70)
71
72for category in $categories; do
73 for obj in "$@"; do
74 [ "$(path_category "$obj")" = "$category" ] || continue
75 tool=$(path_tool "$obj")
76 sym=$(path_symbol "$obj")
77 printf '\t{ "%s", %s, "%s" },\n' "$tool" "$sym" "$category"
78 if [ "$tool" = "test" ]; then
79 printf '\t{ "[", %s, "%s" },\n' "$sym" "$category"
80 fi
81 if [ "$tool" = "xinstall" ]; then
82 printf '\t{ "install", %s, "%s" },\n' "$sym" "$category"
83 fi
84 done
85done
86
87cat << 'TAIL'
88 { NULL, NULL, NULL }
89};
90
91static void
92usage(void)
93{
94 struct Cmd *c;
95 const char *last;
96 int col;
97
98 last = NULL;
99 col = 0;
100 fprintf(stderr, "usage: %s [-i path] [command [args...]]\n", argv0);
101 for (c = cmds; c->name; c++) {
102 if (!last || strcmp(c->category, last) != 0) {
103 if (last)
104 fprintf(stderr, "\n\n");
105 last = c->category;
106 fprintf(stderr, "%s:\n", last);
107 col = 0;
108 }
109 if (col == 0) {
110 fprintf(stderr, "\t%s", c->name);
111 col = 8 + strlen(c->name);
112 } else if (col + 2 + strlen(c->name) >= 78) {
113 fprintf(stderr, ",\n\t%s", c->name);
114 col = 8 + strlen(c->name);
115 } else {
116 fprintf(stderr, ", %s", c->name);
117 col += 2 + strlen(c->name);
118 }
119 }
120 if (last)
121 fputc('\n', stderr);
122 exit(1);
123}
124
125static void
126x_install(const char *path)
127{
128 struct Cmd *c;
129 char buf[4096];
130 int r;
131
132 for (c = cmds; c->name; c++) {
133 r = snprintf(buf, sizeof buf, "%s/%s", path, c->name);
134 if (r < 0 || r >= (int)sizeof buf)
135 eprintf("install: '%s/%s': path too long\n", path, c->name);
136 remove(buf);
137 if (symlink("aruu-box", buf) < 0)
138 eprintf("install: symlink '%s':", buf);
139 }
140}
141
142int
143main(int argc, char *argv[])
144{
145 struct Cmd *c;
146 char *s;
147
148 argv0 = argv[0];
149
150 for (c = cmds; c->name; c++)
151 wexec_register(c->name, c->fn);
152
153 s = strrchr(argv[0], '/');
154 if (s)
155 s++;
156 else
157 s = argv[0];
158
159 if (strcmp(s, "aruu-box") == 0) {
160 if (argc < 2)
161 usage();
162 argc--;
163 argv++;
164 if (strcmp(argv[0], "-i") == 0) {
165 if (argc < 2)
166 eprintf("usage: aruu-box -i path\n");
167 x_install(argv[1]);
168 return 0;
169 }
170 s = strrchr(argv[0], '/');
171 if (s)
172 s++;
173 else
174 s = argv[0];
175 }
176 for (c = cmds; c->name; c++) {
177 if (strcmp(c->name, s) == 0) {
178 argv0 = (char *)c->name;
179 argv[0] = (char *)c->name;
180 return c->fn(argc, argv);
181 }
182 }
183 enprintf(127, "%s: not found\n", s);
184 return 1;
185}
186TAIL