master xplshn/aruu / scripts / genbox.sh
  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