#line 45 "infer.c-nw"
#include <config.h>
#include <str.h>

#ifndef HEURISTICS
#define HEURISTICS "heuristics"         /* /usr/local/lib/argo/heuristics */
#endif

#ifndef LOCAL_HEURISTICS
#define LOCAL_HEURISTICS ".argo-heuristics"
#endif

static struct {
    char *pattern;
    Bool binary;
    char *encoding;
    char *type;
} defaults[] = {
    {"*.[Gg][Ii][Ff]",          TRUE,   "8bit",         "image/gif"},
    {"*.[Tt][Ii][Ff][Ff]",      TRUE,   "8bit",         "image/tiff"},
    {"*.[Tt][Ii][Ff]",          TRUE,   "8bit",         "image/tiff"},
    {"*.[Jj][Pp][Ee][Gg]",      TRUE,   "8bit",         "image/jpeg"},
    {"*.[Jj][Pp][Gg]",          TRUE,   "8bit",         "image/jpeg"},
    {"*.bm",                    FALSE,  "7bit",         "image/x-xbm"},
    {"*.xbm",                   FALSE,  "7bit",         "image/x-xbm"},
    {"*.pm",                    FALSE,  "7bit",         "image/x-xpm"},
    {"*.xpm",                   FALSE,  "7bit",         "image/x-xpm"},
    {"*.[Pp][Bb][Mm]",          TRUE,   "8bit",         "image/x-pbm"},
    {"*.[Pp][Gg][Mm]",          TRUE,   "8bit",         "image/x-pgm"},
    {"*.[Pp][PpNn][Mm]",        TRUE,   "8bit",         "image/x-ppm"},

    {"*.[Tt][Xx][Tt]",          FALSE,  "8bit",         "text/plain"},
    {"*.[Hh][Tt][Mm][Ll]",      FALSE,  "8bit",         "text/html"},
    {"*.[Hh][Tt][Mm]",          FALSE,  "8bit",         "text/html"},
    {"*.[Tt][Ee][Xx]",          FALSE,  "8bit",         "text/x-tex"},
    {"*.[Dd][Vv][Ii]",          TRUE,   "8bit",         "application/x-dvi"},
    {"*.[1-9]",                 FALSE,  "7bit",         "text/x-man"},
    {"*.man",                   FALSE,  "7bit",         "text/x-man"},
    {"*/README*",               FALSE,  "8bit",         "text/plain"},

    {"*.tar.Z",                 TRUE,   "x-compress",   "application/x-tar"},
    {"*.tar.z",                 TRUE,   "x-gzip",       "application/x-tar"},
    {"*.tar.gz",                TRUE,   "x-gzip",       "application/x-tar"},

    {"*/Mail/*",                FALSE,  "7bit",         "text/x-mailbox"},

    {"*/.cache",                FALSE,  "8bit",         "text/x-gopher-menu"},

    {"*.Z",                     TRUE,   "x-compress",   "text/plain"},
    {"*.z",                     TRUE,   "x-gzip",       "text/plain"},
    {"*.gz",                    TRUE,   "x-gzip",       "text/plain"},

    {"*.[Uu][Uu][Ee]",          FALSE,  "x-uuencode",   "application/binary"},

    {"*",                       TRUE,   "8bit",         "text/plain"},
    {NULL,                      FALSE,  NULL,           NULL},
};

static Bool infer(FILE *f, char *path, char **type, char **enc, Bool *binary)
{
    char line[BUFSIZ], *pattern, *h, *rest;

    while (fgets(line, sizeof(line), f)) {
        pattern = tokenize(line, " \t\n", &rest);
        if (pattern && pattern[0] != '#' && fnmatch(pattern, path, 0) == 0) {
            h = tokenize(rest, " \t\n", &rest);
            if (binary) *binary = h[0] == 'b';
            if (enc) *enc = newstring(tokenize(rest, " \t\n", &rest));
            if (type) *type = newstring(tokenize(rest, " \t\n", &rest));
            return TRUE;
        }
    }
    return FALSE;
}

static Bool infer_builtin(char *path, char **type, char **enc, Bool *binary)
{
    int i;

    for (i = 0; defaults[i].pattern; i++) {
        if (fnmatch(defaults[i].pattern, path, 0) == 0) {
            if (binary) *binary = defaults[i].binary;
            if (enc) *enc = newstring(defaults[i].encoding);
            if (type) *type = newstring(defaults[i].type);
            return TRUE;
        }
    }
    return FALSE;
}

EXPORT Bool URL_infer_type(char *path, Bool force_binary, char **type,
    char **encoding, Bool *binary)
{
    FILE *f;
    Bool ok = FALSE;

    if ((f = fopen(LOCAL_HEURISTICS, "r"))) {
        ok = infer(f, path, type, encoding, binary);
        fclose(f);
    }
    if (! ok && (f = fopen(HEURISTICS, "r"))) {
        ok = infer(f, path, type, encoding, binary);
        fclose(f);
    }
    if (! ok) {
        ok = infer_builtin(path, type, encoding, binary);
    }
    if (force_binary) *binary = TRUE;
    return ok;
}