/*
** fmt_new.c -- read format file/string and normalize
**
** This code is Copyright (c) 2002, by the authors of nmh.  See the
** COPYRIGHT file in the root directory of the nmh distribution for
** complete copyright information.
*/

#include <h/mh.h>
#include <h/utils.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sysexits.h>

static char *formats = NULL;

/*
** static prototypes
*/
static void normalize(char *);


/*
** Copy first available format string, store in static memory and normalize it.
*/
char *
new_fs(char *form, char *def_form)
{
	struct stat st;
	FILE *fp;

	if (formats) {
		mh_free0(&formats);
	}

	if (form) {
		if (*form == '=') {
			formats = mh_xstrdup(form+1);
		} else {
			if ((fp = fopen(etcpath(form), "r")) == NULL) {
				adios(EX_IOERR, form, "unable to open format file");
			}
			if (fstat(fileno(fp), &st) == -1) {
				adios(EX_IOERR, form, "unable to stat format file");
			}
			formats = mh_xcalloc(st.st_size + 1, sizeof(char));
			if (read(fileno(fp), formats, (int)st.st_size) != st.st_size) {
				adios(EX_IOERR, form, "error reading format file");
			}
			formats[st.st_size] = '\0';
			fclose(fp);
		}
	} else if (def_form) {
		if (*def_form == '=') {
			formats = mh_xstrdup(def_form+1);
		} else {
			if ((fp = fopen(etcpath(def_form), "r")) == NULL) {
				adios(EX_IOERR, def_form, "unable to open format file");
			}
			if (fstat(fileno(fp), &st) == -1) {
				adios(EX_IOERR, def_form, "unable to stat format file");
			}
			formats = mh_xcalloc(st.st_size + 1, sizeof(char));
			if (read(fileno(fp), formats, (int)st.st_size) != st.st_size) {
				adios(EX_IOERR, def_form, "error reading format file");
			}
			formats[st.st_size] = '\0';
			fclose(fp);
		}
	}
	normalize(formats);  /* expand escapes */

	return formats;
}


/*
** Expand escapes in format strings
*/
static void
normalize(char *cp)
{
	char *dp;

	for (dp = cp; *cp; cp++) {
		if (*cp != '\\') {
			*dp++ = *cp;
			continue;
		}

		switch (*++cp) {
		case 'b':
			*dp++ = '\b';
			break;
		case 'f':
			*dp++ = '\f';
			break;
		case 'n':
			*dp++ = '\n';
			break;
		case 'r':
			*dp++ = '\r';
			break;
		case 't':
			*dp++ = '\t';
			break;
		case '\n':
			break;
		case '\0':
			cp--;
			/* fall */
		default:
			*dp++ = *cp;
			break;
		}
	}
	*dp = '\0';
}
