cser/
/* By Sean Middleditch <elanthis@awemud.net>
   released into public domain, July 8th, 2003 */

#include <stdio.h>

#include "cser.h"

/* serialize a string - make it into one line */
int
_cser_serialize(FILE* file, const char* value, size_t size)
{
	size_t last, cur;

	for (cur = last = 0; cur < size; ++cur) {
		/* escape */
		if (value[cur] == '\\' || value[cur] == '\n' || value[cur] == '\0') {
			if (cur > last)
				fprintf(file, "%.*s", cur - last, &value[last]);
			fprintf(file, "\\%c", value[cur] == '\n' ? 'n' : value[cur] == '\0' ? '0' : value[cur]);
			last = cur + 1;
		}
	}

	/* pump out rest of buffer */
	if (cur > last)
		fprintf(file, "%.*s", cur - last, &value[last]);

	return 0;
}

/* write out a string */
int
cser_write_str(FILE* file, const char* name, const char* value)
{
	fprintf(file, "%s=", name);
	if (_cser_serialize(file, value, strlen(value)))
		return -1;
	fprintf(file, "\n");
	return 0;
}

/* write out a number */
int
cser_write_num(FILE* file, const char* name, long num)
{
	fprintf(file, "%s=%ld\n", name, num);
	return 0;
}

/* read in one line */
int
cser_read(FILE* file, char* buffer, size_t blen, char** name, char** str_value, long* num_value)
{
	size_t bpos = 0, inpos = 0; /* buffer positions */
	char inbuf[512]; /* temporary input buffer */
	char esc = 0; /* are we in escape mode? */

	/* init */
	*name = NULL;
	*str_value = NULL;
	*num_value = 0;

	/* eof? */
	if (feof(file))
		return -1;

	/* loop until eof */
	while (fgets(inbuf, sizeof(inbuf), file) != NULL) {
		/* copy line into buffer, undoing escaping as we go */
		for (inpos = 0; inbuf[inpos] != 0 && inbuf[inpos] != '\n'; ++inpos) {
			/* have we any space left in buffer? */
			if (bpos < blen - 1) {
				/* escaped? */
				if (esc) {
					/* determine type */
					switch(inbuf[inpos]) {
						case '\\': buffer[bpos++] = '\\'; break;
						case 'n': buffer[bpos++] = '\n'; break;
						case '0': buffer[bpos++] = '\0'; break;
						default: break; /* just lose the erroneous escape */
					}
					esc = 0;
				} else 
				/* begin escape? */
				if (inbuf[inpos] == '\\') {
					esc = 1;
				} else
				/* plain text */
				{
					buffer[bpos++] = inbuf[inpos];
				}
			}
		}

		/* break on EOL */
		if (inbuf[inpos] == '\n')
			break;
	}

	/* NUL terminate buffer */
	buffer[bpos] = 0;

	/* find the name/value separator */
	*name = buffer;
	*str_value = strchr(buffer, '=');

	/* is there a value? */
	if (*str_value != NULL) {
		/* break it up properly; NUL terminate name, move forward str value */
		**str_value = 0;
		++ *str_value;

		/* make integer version */
		*num_value = atol(*str_value);
	}

	return 0;
}