ekson

The top include for this project is ekson.h. This will define any core pieces used throughout and some functionality which has so far proven too small to warrant splitting out.

Headers

Definition

This starts with the typical preprocessor directive to guard against multiple inclusions. There are several variations on the convention to use, here I’m using the one used within the source of git.

This also includes some standard imports.

#ifndef EKSON_H
#define EKSON_H

#include <stdef.h>

Implementation

The implementation also makes use of some standard includes and specifies _DEFAULT_SOURCE to make use of strdup.

#define _DEFAULT_SOURCE

#include <string.h>
#include "ekson.h"

Ekstraditers

Ekstraditers will provide some support for functional parameters in the spirit of closures. At the moment each Ekstraditer accepts a string as an argument though this is fairly likely to change to a void pointer as the system evolves.

These will commonly exist as automatic objects on the stack and therefore the struct needs to be exposed for the sake of concrete references (which are then likely to be abstracted with macros). Typical usage will involve the calling code owning the object (such that its specifics can be utilized) whereas the code which is passed the Ekstraditer only sees the pointer which acts to abstract the implementation.

typedef struct {
  void (*invoke)(void* ed, const char *s);
} ekstraditer
typedef ekstraditer* Ekstraditer;

Simple

Like the most basic form of ekstradition is one which does not need any additional state and therefore just adapts a function to satisfy the type definition. This therefore basically forwards the call while discarding the extraneous argument.

Definition

The struct stores the underlying function and the macro takes care of adapting that function to act as an Ekstraditer.

typedef struct {
  ekstraditer ed;
  void (*fn)(const char* s);
} SimpleEkstraditer;

void ekstradite_simply(void* ed, const char* s);

#define simple_ekstradition(f) {  \
  .ed.invoke = ekstradite_simply, \
  .fn        = f,                 \
}

Implementation

The implementation forwards to the original funciton.

void
ekstradite_simply(void* ed, const char* s) {
  SimpleEkstraditer* sed = ((SimpleEkstraditer*) sed);
  sed->fn(s);
}

Capturing

A basic pattern for passing a function is to just capture any arguments with which it is called such that they can be handled elsewhere. The capturing Ekstraditer provides this functionality through storing those captured arguments within the struct.

Definition

The struct itself, reference to the invocation handler, and a macro to facilitate use are defined as follows:

typedef struct {
  ekstraditer ed;
  char* capture;
} CapturingEkstraditer;

void ekstradite_capture(void* ed, const char* s);

#define capturing_ekstradition {   \
  .ed.invoke = ekstradite_capture, \
  .capture   = NULL,               \
}

Implementation

The implementation stores the passed argument after casting the instance back to a CapturingEkstraditer.

void
ekstradite_capture(void* ed, const char* msg) {
  CapturingEkstraditer* ced = ((CapturingEkstraditer) ed);
  ced->capture = strdup(msg);
}