Skip to content

Instantly share code, notes, and snippets.

@mkmik
Created October 15, 2014 15:41
Show Gist options
  • Save mkmik/61026ba399bead6c7e25 to your computer and use it in GitHub Desktop.
Save mkmik/61026ba399bead6c7e25 to your computer and use it in GitHub Desktop.
/*
* Dummy port of the Amiga tag based extensible api. See:
*
* http://amigadev.elowar.com/read/ADCD_2.1/Includes_and_Autodocs_3._guide/node03D6.html
*
*
* note that the amiga api relied on the fact that the calling convention was
* very simple so the vararg stub could just take the pointer to the last argument,
* and get an array of TagItem records.
*
* see:
* http://amigadev.elowar.com/read/ADCD_2.1/Includes_and_Autodocs_3._guide/node03D4.html
*
* we cannot do the same with portable C, so this port uses a slightly different approach,
* taking some ideas from https://gist.github.com/mmikulicic/9a02109c8f3b66092038 .
*
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef int (*tag_func_t)(void* opts, void* data);
typedef void* tag_t;
struct tag_item {
tag_func_t tag;
void* data;
struct tag_item* next;
};
typedef struct tag_item tag_item_t;
int TAG_END(void* opts, void* data) {
return -1;
}
int TAG_IGNORE(void* opts, void* data) {
return -1;
}
void process_tags_va(va_list argp, tag_t tag, void *opts) {
while(1) {
void *data = va_arg(argp, void*);
if (((tag_func_t)tag)(opts, data) == -1) {
break;
}
tag = va_arg(argp, tag_t);
}
}
void process_tag_list(tag_item_t *tags, void *opts) {
while(tags) {
if(tags->tag(opts, tags->data) == -1) {
break;
}
tags = tags->next;
}
}
void tag_add(tag_item_t **tags, tag_item_t *item) {
// yeah its in the revrse order, I'm lazy.
item->next = *tags;
*tags = item;
}
// ----- ns_send
typedef struct {
int deadline;
int n_headers;
} ns_send_opts_t;
int ns_deadline(void* vopts, void* data) {
ns_send_opts_t* opts = (ns_send_opts_t*)vopts;
opts->deadline = (int)data;
printf("processing ns_deadline: %d\n", opts->deadline);
return 0;
}
typedef struct {
char* key;
char* value;
} ns_header_value_t;
int ns_header(void* vopts, void* data) {
ns_header_value_t* args = (ns_header_value_t*)data;
printf("processing ns_header: %s:%s\n", args->key, args->value);
free(args);
ns_send_opts_t* opts = (ns_send_opts_t*)vopts;
opts->n_headers++;
return 0;
}
void* ns_header_value(char* key, char* value) {
ns_header_value_t* args = malloc(sizeof(ns_header_value_t));
args->key = key;
args->value = value;
return args;
}
static ns_send_opts_t ns_send_default_opts = {-1, 0};
void ns_send_opts(char* addr, char* body, ns_send_opts_t opts) {
printf("sending %s to %s, deadline: %d, num headers: %d\n", body, addr, opts.deadline, opts.n_headers);
}
void ns_send_tags(char* addr, char* body, tag_t tag, ...) {
ns_send_opts_t opts = ns_send_default_opts;
va_list argp;
va_start(argp, tag);
process_tags_va(argp, tag, &opts);
va_end(argp);
ns_send_opts(addr, body, opts);
}
void ns_send_tag_list(char* addr, char* body, tag_item_t *tags) {
ns_send_opts_t opts = ns_send_default_opts;
process_tag_list(tags, &opts);
ns_send_opts(addr, body, opts);
}
void ns_send(char* addr, char* body) {
ns_send_tags(addr, body, TAG_END);
}
int main() {
ns_send("foo", "bar");
ns_send_tags("foo", "bar", ns_deadline, 3600, TAG_END);
ns_send_tags("foo", "bar", ns_header, ns_header_value("content-type", "poo"), ns_deadline, 3600, TAG_END);
tag_item_t *tags = {0};
tag_item_t deadline = {ns_deadline, (void*)3600};
tag_add(&tags, &deadline);
tag_item_t header;
if (42==42) {
header = (tag_item_t){ns_header,ns_header_value("content-type", "dummy")};
tag_add(&tags, &header);
}
ns_send_tag_list("foo", "bar", tags);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment