/*
 * functional font
 */

#include	"defs.h"
#include	"global.h"
#include	"funcfont.h"
#ifdef KPATHSEA
#include	<kpathsea/pathsearch.h>
#include	<kpathsea/tex-file.h>
#endif

int functype_init();
int functype_access();
void init_func_fontinfo();
struct fontop funcop = {
    "func",
    functype_init,
    functype_access,
    init_func_fontinfo,
};

functype_init(desc, ff)
char *desc;
struct funcfont **ff;
{
    char *d, *e;
    struct fontop *fop;
    BOOLEAN body;
    int numbody;
    struct ffinfo *ffi;
    struct funcfont *ffs, **nextff;
    struct funcfont *ffnew;
    struct fontop *findcondop();
    extern struct fontop falseop;
    
    for (ffs = NULL, nextff = &ffs, numbody = 0;;) {
	if (!getstrtok(desc, '(', &d))
	    return FALSE;
	if ((fop = findcondop(desc)) != NULL) {
	    body = FALSE;
	} else if ((fop = findfontop(desc)) != NULL && fop != &funcop) {
	    body = TRUE;
	    numbody++;
	} else {
	    Warning("illegal functional font %s", desc);
	    return FALSE;
	}
	if (!getstrtok(d, ')', &e))
	    return FALSE;
	if (!fop->fo_init(d, &ffi))
	    return FALSE;
	ffnew = NEW(struct funcfont, "funcfont init");
	ffnew->ff_fop = fop;
	ffnew->ff_body = body;
	ffnew->ff_info = (struct ffinfo *)ffi;
	ffnew->ff_next = NULL;
	*nextff = ffnew;
	nextff = &(ffnew->ff_next);
	skipstrblank(e, &d);
	if (*d == '\0')
	    break;
	else if (*d == ',')
	    skipstrblank(e+1, &desc);
	else
	    return FALSE;
    }
    if (numbody == 0) {
	ffnew = NEW(struct funcfont, "funcfont init");
	ffnew->ff_fop = &falseop;
	ffnew->ff_body = TRUE;
	ffnew->ff_info = NULL;
	ffnew->ff_next = NULL;
	*nextff = ffnew;
    }
    *ff = ffs;
    return TRUE;
}

functype_access(ff, fe, acca)
struct funcfont *ff;
struct font_entry *fe;
struct accarg *acca;
{
    struct funcfont *ffnew;

    for (; ff != NULL; ff = ff->ff_next) {
#ifdef DEBUG
	if (Debuguser)
	    (void)fprintf(stderr, "trying to apply %s to %s\n",
			  ff->ff_fop->fo_type, fe->n);
#endif
	if (ff->ff_fop->fo_access(ff->ff_info, fe, acca)) {
	    if (ff->ff_body) {
		ffnew = NEW(struct funcfont, "funcfont access");
		*ffnew = *ff;
		ffnew->ff_info = (struct ffinfo *)fe->finfo;
		fe->finfo = (struct finfo *)ffnew;
	    }
	} else
	    return FALSE;
    }
    return TRUE;
}

void
init_func_fontinfo(fe)
struct font_entry *fe;
{
    struct funcfont *ff;

    ff = (struct funcfont *)fe->finfo;
    fe->finfo = (struct finfo *)ff->ff_info;
    ff->ff_fop->fo_initfontinfo(fe);
}


/* funcfont conditions
 */
extern struct fontop
    cexecop,	/* execfont.c */
    existop,
    preop,
    notpreop,
    falseop;
struct fontop *condops[] = {
    &cexecop,
    &existop,
    &preop,
    &notpreop,
    &falseop,
    NULL
};

struct fontop *
findcondop(type)
char *type;
{
    struct fontop **fo;
    
    for (fo = condops; *fo != NULL; fo++)
	if (STREQ((*fo)->fo_type, type))
	    return *fo;
    return NULL;
}

/* ARGSUSED */
void
init_dummy_fontinfo(fe)
struct font_entry *fe;
{
    Fatal("%s implementation error: init_dummy_fontinfo", G_progname);
}


int false_access();
struct fontop falseop = {
    "false",
    pathtype_init,
    false_access,
    init_dummy_fontinfo,	/* never called */
};

/* ARGSUSED */
int
false_access(proto, fe, acca)
char *proto;
struct font_entry *fe;
struct accarg *acca;
{
    return FALSE;
}

int exist_access();
struct fontop existop = {
    "exist",
    pathtype_init,
    exist_access,
    init_dummy_fontinfo,	/* never called */
};

int
exist_access(proto, fe, acca)
char *proto;
struct font_entry *fe;
struct accarg *acca;
{
    BOOLEAN ok;
#ifdef KPATHSEA
    char *path, *base, *filename;
    const_string savepath;
    kpse_format_info_type *spec = &kpse_format_info[kpse_texsource_format];
#endif

#ifdef KPATHSEA
    pavek(fe->name, &path, &base, proto, acca);
    if (path == NULL || base == NULL)
	return FALSE;
    spec->path = NULL;
    spec->override_path = path;
    kpse_init_format(kpse_texsource_format);
    filename = kpse_path_search(spec->path, base, false);
    if (ok = (filename != NULL))
	strcpy(fe->name, filename);
#else
    pave(fe->name, proto, acca);
    ok = access(fe->name, R_OK) == 0;
#endif
#ifdef DEBUG
    if (Debuguser)
	(void)fprintf(stderr, "  condition: exist %s\n", fe->name);
#endif
    return ok;
}

int pre_access();
int notpre_access();
struct fontop preop = {
    "pre",
    pathtype_init,
    pre_access,
    init_dummy_fontinfo,	/* never called */
};
struct fontop notpreop = {
    "!pre",
    pathtype_init,
    notpre_access,
    init_dummy_fontinfo,	/* never called */
};

int
pre_access(proto, fe, acca)
char *proto;
struct font_entry *fe;
struct accarg *acca;
{
#ifdef DEBUG
    if (Debuguser)
	(void)fprintf(stderr, "  condition: pre(%s) %s\n", proto, fe->n);
#endif
    return !strncmp(fe->n, proto, strlen(proto));
}

int
notpre_access(proto, fe, acca)
char *proto;
struct font_entry *fe;
struct accarg *acca;
{
#ifdef DEBUG
    if (Debuguser)
	(void)fprintf(stderr, "  condition: !pre(%s) %s\n", proto, fe->n);
#endif
    return strncmp(fe->n, proto, strlen(proto));
}
