/*
 * fname.c
 *
 * filename processing functions
 *
 * Copyright (C) 1994,95,96  Thomas Aglassinger
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * updated: 27-Oct-1996
 * created: 24-May-1994
 *
 *-------------------------------------------------------------------
 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "utypes.h"
#include "umemory.h"
#include "ustring.h"
#include "expstr.h"

#define NOEXTERN_UGLY_FNAME_H
#include "fname.h"

/*
 * get_fext
 *
 * get filename extension
 *
 * params: fn...full filename to examine
 * result: extension of _fn or NULL, if fn was also NULL
 *
 */
BOOL get_fext(EXPSTR * dest, CONSTRPTR fn)
{
    CONSTRPTR fn_ext = fn;      /* result var */

    /* search for end of string */
    while (fn_ext[0])
        fn_ext++;

    /* search string backwards for "." or PATH_SEPARATOR */
    do
        /* nufin */ ;
    while ((fn_ext != fn)       /* beginning of name reached? */
           && (fn_ext--)        /* process next char */
           && (fn_ext[0] != '.')
           && (strchr(PATH_SEPARATOR, fn_ext[0]) == NULL));

    /* copy extension to dest */
    if (fn_ext[0] == '.')
        set_estr(dest, ++fn_ext);
    else
        clr_estr(dest);

    return (ok_fnl_fext(dest));
}

/*
 * get_fname
 *
 *
 */
BOOL get_fname(EXPSTR * dest, CONSTRPTR fn)
{
    CONSTRPTR fn_name = fn;

    fn_name = ustrrpbrk(fn_name, PATH_SEPARATOR);

    /* copy extension to dest */
    if (fn_name)
        set_estr(dest, ++fn_name);
    else
        set_estr(dest, fn);

    return (ok_fnl_fname(dest));
}

/*
 * get_fpath
 *
 *
 */
BOOL get_fpath(EXPSTR * dest, CONSTRPTR fn)
{
    STRPTR pa_name = ustrrpbrk(fn, PATH_SEPARATOR);

    if (pa_name)
    {
        set_estrn(dest, fn, strlen(fn) - strlen(pa_name) + 1);
    }
    else
        clr_estr(dest);

    return (ok_fnl_fpath(dest));
}

/*
 * get_fsdir: get next subdirectory (including separator)
 *
 */
BOOL get_fsdir(EXPSTR * dest, CONSTRPTR fn)
{
    STRPTR fn_name = strpbrk(fn, PATH_SEPARATOR);

    if (fn_name)
    {
        set_estrn(dest, fn, strlen(fn) - strlen(fn_name) + 1);
    }
    else
        clr_estr(dest);

    return (ok_fnl_fpath(dest));
}

/*
 * get_fdrive
 *
 *
 */
BOOL get_fdrive(EXPSTR * dest, CONSTRPTR fn)
{
    set_estr(dest, fn);         /* dummy data */
    clr_estr(dest);
    return (ok_fnl_fpath(dest));
}

/*
 * fextidx: get filename extension index of string
 *
 * params: fn...filename to examine
 * result: index in _fn, where extension starts
 *
 * NOTE: if _fn has an extension at all, _fn[i] is equal to '.', else
 *       _fn has no extension (e.g. "TESTFILE") and _fn[i] is equal
 *       to '\0'.
 *
 * (internal function)
 *
 */
static size_t fextidx(CONSTRPTR fn)
{
    size_t i;                   /* string index counter */

    i = strlen(fn) - 1;         /* scan string backwards... */
    while ((i) && (fn[i] != '.')
           && (strchr(PATH_SEPARATOR, fn[i]) == NULL))
        i--;
    if (fn[i] != '.')
        i = strlen(fn);

    return i;                   /* return result */
}

/*
 * clr_fext: clear filename extension
 *
 * params: dest...string that contains filename to strip
 *
 * EXAMPLE: "testfile.txt" -> "testfile"
 *
 */
BOOL clr_fext(EXPSTR * dest)
{
    BOOL ok;
    size_t extidx = fextidx(estr2str(dest));
    /* index, where extension starts */
    ok = set_estrn(dest, estr2str(dest), extidx);
    ok &= ok_fnl_fpath(dest);

    return (ok);
}

/*
 * set_fext: set new (last) extension for filename
 *
 * params: dest....string that contains old filename
 *         newext..new extension to set
 *
 * EXAMPLE: "testfile.txt", "lha" -> "testfile.lha"
 *          "hugo.tar.gz" , "lha" -> "hugo.tar.lha"
 */
BOOL set_fext(EXPSTR * dest, CONSTRPTR newext)
{
    BOOL ok;

    ok = clr_fext(dest);
    ok &= app_estrch(dest, '.');
    ok &= app_estr(dest, newext);

    ok &= ok_fnl_fpath(dest);

    return (ok);
}

/*
 * app_fext: append extension to filename
 *
 * EXAMPLE: ("testfile.txt", "lha") -> "testfile.txt.lha"
 *                                  -> "testfile.lha"     (msdos)
 */
BOOL app_fext(EXPSTR * dest, CONSTRPTR newext)
{
    BOOL ok = app_estrch(dest, '.');

    ok &= app_estr(dest, newext);
    ok &= ok_fnl_fpath(dest);

    return (ok);
}

/*
 * set_fextIdx: set file name index extension
 *
 * params: dest..destination string with new extension
 *         fn....source string with extension to replace
 *         idx...extension index
 */
BOOL set_fnameIdx(EXPSTR * dest, int idx)
{
    char fn_ext[12];            /* index extension */
    sprintf(fn_ext, "%03d", idx);       /* create index string */

    return (set_fext(dest, fn_ext));
}

/*
 * link_fname: link directory and filename together
 *
 * params: dest..where to store result
 *         dir...directoryname
 *         fn....filename to append
 *
 * NOTE: a PATHSEPARATOR[0] is append to dir, if none exists
 * NOTE: dir and fn MUST NOT be part of dest,
 *       when invoking this funtion
 */
BOOL link_fname(EXPSTR * dest, STRPTR dir, STRPTR fn)
{
    BOOL anydir;                /* TRUE, if any dir passed as arg */
    BOOL ok = TRUE;

    /* is a dir passed? */
    anydir = (dir != NULL);
    if (anydir)
        anydir = (strlen(dir) != 0);

    if (anydir)
    {
        /* clone dir, if any
         *
         * NOTE: it's neccesarry to work with a copy do `dir',
         * because if `dir' is part or `dest', this could lead
         * to a mungwall hit */
        STRPTR dir_clone = strclone(dir);       /* clone of `dir' */

        set_estr(dest, dir_clone);
        /* check, if the last char of dir is a path separator */
        /* ->if not, append a direcory separator */
        if (!strchr(PATH_SEPARATOR, dir_clone[strlen(dir_clone) - 1]))
            app_estrch(dest, DIR_SEPARATOR);

        /* free cloned dir */
        ufreestr(dir_clone);
    }
    else
        clr_estr(dest);

    /* append filename */
    if (fn)
        app_estr(dest, fn);

    ok &= ok_fnl_fpath(dest);

    return ok;
}

/*
 * link_envfname: link content of an environment variable,
 *                directory and filename together
 *
 * params: dest..where to store result
 *         env...name of environment variable
 *         dir...directoryname
 *         fn....filename to append
 *
 * result: FALSE, if envvar could not be found or
 *         filename got too long
 */
BOOL link_envfname(EXPSTR * dest, STRPTR envname, STRPTR dir, STRPTR fn)
{
    BOOL ok = FALSE;
    STRPTR env = getenv(envname);

    if (env)
    {
        STRPTR env1 = strclone(env);        /* copy envvar to own memory area */
        EXPSTR *tmpstr = init_estr(32);

        /* strip linefeeds from hscenv */
        while (strlen(env1) && (env1[strlen(env1)] == '\n'))
            env1[strlen(env1)] = '\0';

        if (dir)
        {
            link_fname(tmpstr, env1, dir);
        }
        else
        {
            set_estr(tmpstr, env1);
        }

        ok = link_fname(dest, estr2str(tmpstr), fn);

        del_estr(tmpstr);
        ufreestr(env1);
    }
    else
    {
        clr_estr(dest);
    }

    return ok;
}

/*
 * tmpnamstr: alloc & create a string with a temp. filename
 *
 * result: string containig filename;
 *         MUST be release using ufreestr() by caller
 * errors: return NULL; this can be because auf no more
 *         temp. files available or out of mem
 *
 * IMPORTANT: you need to copy the filename, if you
 *           call this function frquently
 */
static size_t adjust_prefixlen(size_t prefixlen)
{
#ifdef MSDOS
    if (prefixlen > MAX_FNAME - 4)
        prefixlen = MAX_FNAME - 4;
#else
    if (prefixlen > MAX_FNAME - 8)
        prefixlen = MAX_FNAME - 8;
#endif

    return (prefixlen);
}

STRPTR tmpnamstr(STRPTR prefix)
{
    STRARR buf[256 + 32];
    LONG fileidx = 0;
    STRPTR s = NULL;
    FILE *file = NULL;
    size_t prefixlen = 0;

    if (prefix)
        /* copy prefix to buffer */
        prefixlen = adjust_prefixlen(strlen(prefix));
    else
        prefix = "";

    /* copy prefix to buffer */
    strcpy(buf, prefix);

    /* add address of buffer to prefix */
    sprintf(&(buf[strlen(prefix)]), "%p", tmpnamstr);

    prefixlen = adjust_prefixlen(strlen(buf));
    buf[prefixlen] = '\0';

    /* try to open tmpfile for input until it fails */
    do
    {
        fileidx++;
        sprintf(&(buf[prefixlen]), "%04lx", fileidx);
        strcat(buf, ".tmp");
        file = fopen(buf, "r");
        if (file)
        {
            if (fileidx == 0xffff)
                fileidx = 0;    /* ran out of names */
        }
    }
    while (fileidx && file);

    if (fileidx)
    {
        s = buf;
    }

    return (s);
}

/*
 * get_relfname: get relative filename, according to given path
 *
 * params: absn..absolute filename
 *         curp..current path
 *
 * EXAMPLE:
 *  "image/back.gif" and "image/hugo/" -> "/back.gif"
 *  "image/back.gif" and ""            -> "image/back.gif"
 *  "image/back.gif" and "people/"     -> "/image/back.gif"
 */
BOOL get_relfname(EXPSTR * dest, STRPTR absn, STRPTR curp)
{
    EXPSTR *fname = init_estr(32);      /* file name only */
    EXPSTR *abspa = init_estr(32);      /* absolute path only */
    EXPSTR *tmpp1 = init_estr(32);      /* temp pointer */
    EXPSTR *tmpp2 = init_estr(32);
    STRPTR rest_absp = NULL;    /* rest of current path */
    STRPTR absp = NULL;         /* path processing */
    int cmp_result;             /* stores result returned by upstrcmp */

    /* init string array */
    clr_estr(dest);
    get_fname(fname, absn);
    get_fpath(abspa, absn);
    absp = estr2str(abspa);

    /*
     * skip all equal subdirs
     */
    do
    {
        get_fsdir(tmpp1, absp);
        get_fsdir(tmpp2, curp);
        cmp_result = upstrcmp(estr2str(tmpp1), estr2str(tmpp2));

        if (!cmp_result)
        {
            absp += estrlen(tmpp1);
            curp += estrlen(tmpp2);
        }
    }
    while (estrlen(tmpp1)
           && estrlen(tmpp2)
           && (!cmp_result));

    /* remember equal part of path */
    rest_absp = absp;

    /*
     * for every subdir in absp unequal to
     * corresponding subdir curp, insert a parent dir
     */
    if (curp[0])
        do
        {
            get_fsdir(tmpp1, absp);
            get_fsdir(tmpp2, curp);
            cmp_result = upstrcmp(estr2str(tmpp1), estr2str(tmpp2));

            if (cmp_result)
            {
                absp += estrlen(tmpp1);
                curp += estrlen(tmpp2);
                app_estr(dest, PARENT_DIR);
#if 0
                printf("absp: (tmpp1) [%d] `%s'\n", estrlen(tmpp1), absp);
                printf("curp: (tmpp2) [%d] `%s'\n", estrlen(tmpp2), curp);
                printf("dest: `%s'\n", estr2str(dest));
#endif
            }
        }
        while (strlen(curp) && cmp_result);

    /* append equal part of path */
    app_estr(dest, rest_absp);

    /* append name of file */
    app_estr(dest, estr2str(fname));

    /* relaese resources */
    del_estr(fname);
    del_estr(abspa);
    del_estr(tmpp1);
    del_estr(tmpp2);

    return (ok_fnl_fpath(dest));
}

