Applied duck-typing in plain C
c, duck-typing
Solution
It sounds like you want function variables, which you would pass as a parameter. C can do them, but the syntax isn't very pretty.
There probably is a bit of runtime overhead, but not much.
How do you pass a function as a parameter in C?
Problem
In my open-source plain C code I use this simple structure to read and parse data from a string buffer: ``` typedef struct lts_LoadState { const unsigned char * pos; size_t unread; } lts_LoadState; ``` The buffer is accessed with this simple API: ``` /* Initialize buffer */ void ltsLS_init(lts_LoadState * ls,const unsigned char * data, size_t len); /* Do we have something to read? (Actually a macro.) */ BOOL ltsLS_good(ls); /* How much do we have to read? (Actually a macro.) */ size_t ltsLS_unread(ls); /* Eat given number of characters, return pointer to beginning of eaten data */ const unsigned char * ltsLS_eat(lts_LoadState * ls, size_t len); ``` Note: `ltsLS_unread` may be replaced with `return (ltsLS_good(ls)) ? SIZE_MAX : 0` without breaking the current implementation. This code is used to load some data in a custom format from a string buffer. (This may be a better illustration.) Now I need to load data not from a string buffer, but from a `FILE` pointer. I would hate to copy-paste the implementation, and would like to reuse existing code instead. (I'm OK with refactoring/adapting it, of course.) This is a textbook stuff in C++, but how to do that in plain C without incurring runtime overhead? Here is an example function that uses the `lts_LoadState` API and that is not to be copy-pasted (but may be changed, of course, to support both string buffer and `FILE *`): ``` static int ltsLS_readline( lts_LoadState * ls, const unsigned char ** dest, size_t * len ) { const unsigned char * origin = ls->pos; unsigned char last = 0; size_t read = 0; while (ltsLS_good(ls)) { if (ltsLS_unread(ls) > 0) { unsigned char b = *ls->pos; /* OK, this should be ltsLS_eat_char macro. */ ++ls->pos; --ls->unread; if (b == '\n') { *dest = origin; *len = (last == '\r') ? read - 1 : read; return LUATEXTS_ESUCCESS; } last = b; ++read; } else { ls->unread = 0; ls->pos = NULL; } } return LUATEXTS_ECLIPPED; } ```