+++ /dev/null
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-enum { F_FILES, F_DIRS };
-
-typedef struct Target {
- struct Target* next;
- char** outputs;
- char** inputs;
- void (*build)(struct Target*);
-} Target;
-
-int MaxJobs = 12;
-
-char* CCCMD[] = {
- "cc",
- "-Wall", "-Wextra", "-Werror",
- "-Iinc/",
- "-I/usr/X11/include/",
- "-I/usr/X11/include/freetype2",
- "-I/usr/include/freetype2/",
- "-g", "-c", "-o",
- /* output */
- /* inputs */
- NULL
-};
-
-char* ARCMD[] = {
- "ar", "rcs",
- NULL
-};
-
-char* LDCMD[] = {
- "cc",
- "-L./build/lib",
- "-L/usr/X11/lib/",
- "-g", "-o",
- /* output */
- /* inputs */
- /* LIBS */
- NULL
-};
-
-char* LIBS[] = {
- "-lnet",
- "-lui",
- "-la",
- "-lX11",
- "-lXft",
- "-lfontconfig",
- NULL
-};
-
-Target* Srcs = NULL;
-Target* Libs = NULL;
-Target* Bins = NULL;
-
-/*
- Helper Routines
-*/
-
-static char* strmcat(char* first, ...)
-{
- va_list args;
- /* calculate the length of the final string */
- size_t len = strlen(first);
- va_start(args, first);
- for (char* s = NULL; (s = va_arg(args, char*));)
- {
- len += strlen(s);
- }
- va_end(args);
- /* allocate the final string and copy the args into it */
- char *str = malloc(len+1), *curr = str;
- while (first && *first)
- {
- *(curr++) = *(first++);
- }
- va_start(args, first);
- for (char* s = NULL; (s = va_arg(args, char*));)
- {
- while (s && *s)
- {
- *(curr++) = *(s++);
- }
- }
- va_end(args);
- /* null terminate and return */
- *curr = '\0';
- return str;
-}
-
-static char** dir_entries(char* path, int flags)
-{
- size_t nentries = 0;
- char** entries = calloc(1, sizeof(char*));
- struct dirent* entry = NULL;
- struct stat attrs = {0};
-
- DIR* dir = opendir(path);
- while ( (entry = readdir(dir)) )
- {
- if (entry->d_name[0] == '.') continue;
- char* epath = strmcat(path, "/", entry->d_name, 0);
- memset(&attrs, 0, sizeof(attrs));
- stat(epath, &attrs);
- if ( ((flags == F_FILES) && !S_ISDIR(attrs.st_mode)) ||
- ((flags == F_DIRS) && S_ISDIR(attrs.st_mode)) )
- {
- entries = realloc(entries, (nentries+2)*sizeof(char*));
- entries[nentries++] = epath;
- entries[nentries] = NULL;
- }
- }
-
- return entries;
-}
-
-char** make_cmd(char*** cmd_parts)
-{
- size_t count = 0;
- char** cmd = NULL;
- for (; *cmd_parts; cmd_parts++)
- {
- char** subpart = *cmd_parts;
- for (; *subpart; subpart++)
- {
- cmd = realloc(cmd, ++count * sizeof(char*));
- cmd[count-1] = *subpart;
- }
- }
- cmd = realloc(cmd, ++count * sizeof(char*));
- cmd[count-1] = NULL;
- return cmd;
-}
-
-void print_cmd(char** cmd)
-{
- for (; *cmd; cmd++)
- {
- printf("%s ", *cmd);
- }
- puts("");
-}
-
-int wait_for_jobs(int count)
-{
- int ret_status = 0;
- do
- {
- int status = 0;
- waitpid(-1, &status, 0);
- if (WIFEXITED(status))
- {
- count--;
- }
- int exitcode = WEXITSTATUS(status);
- ret_status = (!ret_status ? exitcode : ret_status);
- }
- while (count > 0);
- return ret_status;
-}
-
-void make_dirs(char** outputs)
-{
- for (; *outputs; outputs++)
- {
- char* out = strdup(*outputs);
- char* slash = strrchr(out, '/');
- if (slash)
- {
- *slash = '\0';
- mkdir(out, 0755);
- }
- }
-}
-
-time_t timestamp(char* path)
-{
- struct stat s;
- time_t mtime = 0;
- if (!stat(path, &s))
- {
- mtime = s.st_mtime;
- }
- return mtime;
-}
-
-int should_rebuild(char** outputs, char** inputs)
-{
- time_t mtime = 0;
- for (; *outputs; outputs++)
- {
- time_t mt = timestamp(*outputs);
- mtime = (mt > mtime ? mt : mtime);
- }
- for (; *inputs; inputs++)
- {
- time_t mt = timestamp(*inputs);
- if (mt > mtime)
- {
- return 1; /* rebuild! */
- }
- }
- return 0; /* no need to rebuild */
-}
-
-/*
- Build Routines
-*/
-
-void object(Target* tgt)
-{
- char** cmd = make_cmd((char**[]){ CCCMD, tgt->outputs, tgt->inputs, NULL });
- print_cmd(cmd);
- make_dirs(tgt->outputs);
- exit(execvp(cmd[0], cmd));
-}
-
-void library(Target* tgt)
-{
- char** cmd = make_cmd((char**[]){ ARCMD, tgt->outputs, tgt->inputs, NULL });
- print_cmd(cmd);
- exit(execvp(cmd[0], cmd));
-}
-
-void binary(Target* tgt)
-{
- char** cmd = make_cmd((char**[]){
- LDCMD, tgt->outputs, tgt->inputs, LIBS, NULL });
- print_cmd(cmd);
- exit(execvp(cmd[0], cmd));
-}
-
-/*
- Target List Routines
-*/
-
-void add_target(Target** list, char** outputs, char** inputs, void (*build)(Target*))
-{
- Target* tgt = calloc(1, sizeof(Target));
- tgt->next = *list;
- tgt->outputs = outputs;
- tgt->inputs = inputs;
- tgt->build = build;
- *list = tgt;
-}
-
-/*
- Target Routines
-*/
-
-char* add_src(char* src)
-{
- char* obj = strmcat("build/obj/", src, 0);
- obj[strlen(obj)-1] = 'o';
- char** outputs = calloc(2, sizeof(char*));
- outputs[0] = obj;
- char** inputs = calloc(2, sizeof(char*));
- inputs[0] = src;
- add_target(&Srcs, outputs, inputs, object);
- return obj;
-}
-
-char* add_lib(char* path, char** srcs)
-{
- char* libname = strrchr(path, '/') + 1;
- char* lib = strmcat("build/lib/lib", libname, ".a", 0);
- char** outputs = calloc(2, sizeof(char*));
- outputs[0] = lib;
- add_target(&Libs, outputs, srcs, library);
- return lib;
-}
-
-char* add_bin(char* path, char** srcs)
-{
- char* binname = strdup(strrchr(path, '/') + 1);
- char* ext = strrchr(binname, '.');
-
- if (ext)
- {
- *ext = '\0';
- }
- char* bin = strmcat("build/bin/", binname, 0);
- char** outputs = calloc(2, sizeof(char*));
- outputs[0] = bin;
- add_target(&Bins, outputs, srcs, binary);
-
- return bin;
-}
-
-char** add_srcs(char* path)
-{
- char** srcs = dir_entries(path, F_FILES);
- for (char** s = srcs; *s; s++)
- {
- char* obj = add_src(*s);
- *s = obj;
- }
-
- return srcs;
-}
-
-/*
- Build Routines
-*/
-
-void build_targets(Target* targets)
-{
- int exitcode = 0;
- int count = 0;
-
- for (; !exitcode && targets; targets = targets->next)
- {
- count++;
- int pid = fork();
- if (pid == 0)
- {
- if (targets->build == binary || should_rebuild(targets->outputs, targets->inputs))
- {
- targets->build(targets);
- }
- exit(0);
- }
- else if (count >= MaxJobs)
- {
- int code = wait_for_jobs(1);
- exitcode = (!exitcode ? code : exitcode);
- count--;
- }
- }
- int code = wait_for_jobs(count);
- exitcode = (!exitcode ? code : exitcode);
-
- if (exitcode)
- {
- printf("Job Failed!\n");
- exit(exitcode);
- }
-}
-
-/*
- Main Routine
-*/
-
-int main(int argc, char** argv)
-{
- (void)argc, (void)argv;
-
- /* register all of the libraries */
- char** libs = dir_entries("lib", F_DIRS);
- for (; *libs; libs++)
- {
- char** srcs = add_srcs(*libs);
- add_lib(*libs, srcs);
- }
-
- /* register all the complex binaries */
- char** cbins = dir_entries("bin", F_DIRS);
- for (; *cbins; cbins++)
- {
- char** srcs = add_srcs(*cbins);
- add_bin(*cbins, srcs);
- }
-
- /* register all the simple binaries */
- char** sbins = dir_entries("bin", F_FILES);
- for (; *sbins; sbins++)
- {
- char** srcs = calloc(2, sizeof(char*));
- srcs[0] = add_src(*sbins);
- add_bin(*sbins, srcs);
- }
-
- /* create output directories */
- mkdir("build/", 0755);
- mkdir("build/obj/", 0755);
- mkdir("build/obj/bin/", 0755);
- mkdir("build/obj/lib/", 0755);
- mkdir("build/bin/", 0755);
- mkdir("build/lib/", 0755);
-
- /* now build all of the things */
- build_targets(Srcs);
- build_targets(Libs);
- build_targets(Bins);
-
- return 0;
-}
\ No newline at end of file
--- /dev/null
+#!/bin/env ruby
+
+# Base Data Types:
+# String
+# Integer
+# Float
+# Bool
+#
+# Aggregate Types:
+# Array
+# Record
+
+require 'fileutils'
+
+Procedure = Struct.new(:name, :request, :response)
+
+module Generate
+ def self.typedef(f, proto, msg)
+ f.puts "typedef struct {"
+ msg.fields.each do |k,v|
+ f.puts " #{v} #{k};"
+ end
+ f.puts "} #{proto}_#{msg.name}_T;\n\n"
+ end
+
+ def self.prototype(f, proto, obj, terminator = "")
+ if obj.is_a? Procedure
+ req = obj.request
+ res = obj.response
+ args = ["MBusConnection* conn"]
+ args += req.fields.map {|e| "#{e[1]} #{e[0]}" }
+ args += ["#{proto}_#{res.name}_T* res"]
+ f.print "int #{proto}_#{obj.name}(#{args.join(", ")})"
+ else
+ f.print "int #{proto}_#{obj.name}(MBusMessage* data, #{proto}_#{obj.name}_T* msg)"
+ end
+ f.puts terminator
+ end
+
+ def self.declaration(f, proto, proc, terminator = "")
+ prototype(f, proto, proc, terminator)
+ end
+
+ def self.definition(f, proto, obj)
+ if obj.is_a? Procedure
+ procedure(f, proto, obj)
+ else
+ accessor(f, proto, obj)
+ end
+ end
+
+ def self.accessor(f, proto, msg)
+ prototype(f, proto, msg)
+ f.puts "{"
+ f.puts " int status = 1;"
+ msg.fields.each do |k,v|
+ f.puts " status &&= MBus_#{v}(data, &(msg->#{k});"
+ end
+ f.puts " return status;"
+ f.puts "}\n\n"
+ end
+
+ def self.procedure(f, proto, proc)
+ prototype(f, proto, proc)
+ f.puts "{"
+ f.puts " int status = 1;"
+ f.puts " MBusMessage msg;"
+ f.puts " status &&= MBus_MessageCreate(conn, &msg);"
+ f.puts " #{proto}_#{proc.request.name}_T out_data = {"
+ proc.request.fields.each do |name, type|
+ f.puts " .#{name} = #{name},"
+ end
+ f.puts " };"
+ f.puts " status &&= #{proto}_#{proc.request.name}(&msg, &out_data);"
+ f.puts " status &&= MBus_SendRequest(conn, &msg);"
+ f.puts " status &&= #{proto}_#{proc.response.name}(&msg, res);"
+ f.puts " status &&= MBus_MessageDestroy(&msg);"
+ f.puts " return status;"
+ f.puts "}\n\n"
+ end
+end
+
+class Message
+ attr_reader :name
+ attr_reader :fields
+
+ def initialize(name)
+ @name = name
+ @fields = {}
+ end
+
+ def method_missing(sym, *args, &block)
+ @fields[sym] = args[0]
+ self
+ end
+end
+
+class Parser < Object
+ def initialize(path)
+ @protocols = {}
+ instance_eval(File.read(path))
+ end
+
+ def self.const_missing(const)
+ const
+ end
+
+ def dump(hdrpath, srcpath)
+ FileUtils.mkdir_p(hdrpath)
+ FileUtils.mkdir_p(srcpath)
+ @protocols.each do |proto,members|
+ hdr = File.open(File.join(hdrpath, "#{proto}.h"), "wb")
+ src = File.open(File.join(srcpath, "#{proto}.c"), "wb")
+ hdr.print "#include <MBus.h>\n\n"
+ src.print "#include <#{proto}.h>\n\n"
+ members.each do |k,v|
+ if v.is_a? Message
+ Generate.typedef(hdr, proto, v)
+ end
+ Generate.declaration(hdr, proto, v, ";\n\n")
+ Generate.definition(src, proto, v)
+ end
+ end
+ end
+
+ def protocol(name, &block)
+ @protocol = {}
+ instance_eval(&block)
+ @protocols[name] = @protocol
+ @protocol = nil
+ end
+
+ def message(name, &block)
+ @protocol[name] ||= Message.new(name)
+ @protocol[name]
+ end
+
+ def procedure(name, req_msg, resp_msg)
+ req = message(req_msg)
+ res = message(resp_msg)
+ @protocol[name] ||= Procedure.new(name, req, res)
+ end
+end
+
+Parser.new(ARGV[0]).dump(".",".")