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;
}
 
     
     
     
    