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 done
82done
83
84cat << 'TAIL'
85 { NULL, NULL, NULL }
86};
87
88static void
89usage(void)
90{
91 struct Cmd *c;
92 const char *last;
93 int col;
94
95 last = NULL;
96 col = 0;
97 fprintf(stderr, "usage: %s [-i path] [command [args...]]\n", argv0);
98 for (c = cmds; c->name; c++) {
99 if (!last || strcmp(c->category, last) != 0) {
100 if (last)
101 fprintf(stderr, "\n\n");
102 last = c->category;
103 fprintf(stderr, "%s:\n", last);
104 col = 0;
105 }
106 if (col == 0) {
107 fprintf(stderr, "\t%s", c->name);
108 col = 8 + strlen(c->name);
109 } else if (col + 2 + strlen(c->name) >= 78) {
110 fprintf(stderr, ",\n\t%s", c->name);
111 col = 8 + strlen(c->name);
112 } else {
113 fprintf(stderr, ", %s", c->name);
114 col += 2 + strlen(c->name);
115 }
116 }
117 if (last)
118 fputc('\n', stderr);
119 exit(1);
120}
121
122static void
123x_install(const char *path)
124{
125 struct Cmd *c;
126 char buf[4096];
127 int r;
128
129 for (c = cmds; c->name; c++) {
130 r = snprintf(buf, sizeof buf, "%s/%s", path, c->name);
131 if (r < 0 || r >= (int)sizeof buf)
132 eprintf("install: '%s/%s': path too long\n", path, c->name);
133 remove(buf);
134 if (symlink("aruu-box", buf) < 0)
135 eprintf("install: symlink '%s':", buf);
136 }
137}
138
139int
140main(int argc, char *argv[])
141{
142 struct Cmd *c;
143 char *s;
144
145 argv0 = argv[0];
146
147 for (c = cmds; c->name; c++)
148 wexec_register(c->name, c->fn);
149
150 s = strrchr(argv[0], '/');
151 if (s)
152 s++;
153 else
154 s = argv[0];
155
156 if (strcmp(s, "aruu-box") == 0) {
157 if (argc < 2)
158 usage();
159 argc--;
160 argv++;
161 if (strcmp(argv[0], "-i") == 0) {
162 if (argc < 2)
163 eprintf("usage: aruu-box -i path\n");
164 x_install(argv[1]);
165 return 0;
166 }
167 s = strrchr(argv[0], '/');
168 if (s)
169 s++;
170 else
171 s = argv[0];
172 }
173 for (c = cmds; c->name; c++) {
174 if (strcmp(c->name, s) == 0) {
175 argv0 = (char *)c->name;
176 argv[0] = (char *)c->name;
177 return c->fn(argc, argv);
178 }
179 }
180 enprintf(127, "%s: not found\n", s);
181 return 1;
182}
183TAIL