/*
 * The contents of this file are subject to the AOLserver Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://aolserver.com/.
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and limitations
 * under the License.
 *
 * The Original Code is AOLserver Code and related documentation
 * distributed by AOL.
 * 
 * The Initial Developer of the Original Code is America Online,
 * Inc. Portions created by AOL are Copyright (C) 1999 America Online,
 * Inc. All Rights Reserved.
 *
 * Alternatively, the contents of this file may be used under the terms
 * of the GNU General Public License (the "GPL"), in which case the
 * provisions of GPL are applicable instead of those above.  If you wish
 * to allow use of your version of this file only under the terms of the
 * GPL and not to allow others to use your version of this file under the
 * License, indicate your decision by deleting the provisions above and
 * replace them with the notice and other provisions required by the GPL.
 * If you do not delete the provisions above, a recipient may use your
 * version of this file under either the License or the GPL.
 */


/*
 * pathname.c --
 *
 *	Functions that manipulate or return paths. 
 */

static const char *RCSID = "@(#) $Header: /cvsroot/aolserver/aolserver/nsd/pathname.c,v 1.14 2006/04/19 17:48:57 jgdavidson Exp $, compiled: " __DATE__ " " __TIME__;

#include "nsd.h"

#define isslash(c)	((c) == '/' || (c) == '\\')

/*
 * Local functions defined in this file.
 */

static char *MakePath(Ns_DString *dest, va_list *pap);


/*
 *----------------------------------------------------------------------
 *
 * Ns_PathIsAbsolute --
 *
 *	Boolean: is the path absolute? 
 *
 * Results:
 *	NS_TRUE if it is, NS_FALSE if not. 
 *
 * Side effects:
 *	None. 
 *
 *----------------------------------------------------------------------
 */

int
Ns_PathIsAbsolute(char *path)
{
#ifdef _WIN32
    if (isalpha(*path) && path[1] == ':') {
	path += 2;
    }
#endif
    if (isslash(*path)) {
	return NS_TRUE;
    }
    return NS_FALSE;
}


/*
 *----------------------------------------------------------------------
 *
 * Ns_NormalizePath --
 *
 *	Remove "..", "." from paths. 
 *
 * Results:
 *	dsPtr->string 
 *
 * Side effects:
 *	Will append to dsPtr. Assumes an absolute path.
 *
 *----------------------------------------------------------------------
 */

char *
Ns_NormalizePath(Ns_DString *dsPtr, char *path)
{
    char end;
    register char *src, *part, *slash;
    Ns_DString tmp;

    Ns_DStringInit(&tmp);
    src = Ns_DStringAppend(&tmp, path);
#ifdef _WIN32
    if (isalpha(*src) && src[1] == ':') {
	if (isupper(*src)) {
	    *src = tolower(*src);
	}
	Ns_DStringNAppend(dsPtr, src, 2);
	src += 2;
    }
#endif

    /*
     * Move past leading slash(es)
     */
    
    while (isslash(*src)) {
	++src;
    }
    do {
	part = src;

	/*
	 * Move to next slash
	 */
	
	while (*src && !isslash(*src)) {
	    ++src;
	}
	end = *src;
	*src++ = '\0';

	if (part[0] == '.' && part[1] == '.' && part[2] == '\0') {

	    /*
	     * There's a "..", so wipe out one path backwards.
	     */
	    
	    slash = strrchr(dsPtr->string, '/');
	    if (slash != NULL) {
		Ns_DStringTrunc(dsPtr, slash - dsPtr->string);
	    }
	} else if (part[0] != '\0' &&
		   (part[0] != '.' || part[1] != '\0')) {

	    /*
	     * There's something non-null and not ".".
	     */

	    Ns_DStringNAppend(dsPtr, "/", 1);
	    Ns_DStringAppend(dsPtr, part);
	}
    } while (end != '\0');

    /*
     * If what remains is an empty string, change it to "/".
     */

    if (dsPtr->string[0] == '\0') {
	Ns_DStringNAppend(dsPtr, "/", 1);
    }
    Ns_DStringFree(&tmp);

    return dsPtr->string;
}


/*
 *----------------------------------------------------------------------
 *
 * Ns_MakePath --
 *
 *	Append all the elements together with slashes between them. 
 *	Stop at NULL. 
 *
 * Results:
 *	dest->string 
 *
 * Side effects:
 *	Will append to dest. 
 *
 *----------------------------------------------------------------------
 */

char *
Ns_MakePath(Ns_DString *dest, ...)
{
    va_list  ap;
    char    *path;

    va_start(ap, dest);
    path = MakePath(dest, &ap);
    va_end(ap);
    return path;
}


/*
 *----------------------------------------------------------------------
 *
 * Ns_LibPath --
 *
 *	Returns the path where AOLserver libraries exist, with 
 *	varargs appended to it with slashes between each, stopping at 
 *	null arg. 
 *
 * Results:
 *	dest->string
 *
 * Side effects:
 *	Appends to dest. 
 *
 *----------------------------------------------------------------------
 */

char *
Ns_LibPath(Ns_DString *dest, ...)
{
    va_list  ap;
    char    *path;

    Ns_HomePath(dest, "lib", NULL);
    va_start(ap, dest);
    path = MakePath(dest, &ap);
    va_end(ap);
    return path;
}


/*
 *----------------------------------------------------------------------
 *
 * Ns_BinPath --
 *
 *	Returns the path where AOLserver binaries exist, with 
 *	varargs appended to it with slashes between each, stopping at 
 *	null arg. 
 *
 * Results:
 *	dest->string
 *
 * Side effects:
 *	Appends to dest. 
 *
 *----------------------------------------------------------------------
 */

char *
Ns_BinPath(Ns_DString *dest, ...)
{
    va_list  ap;
    char    *path;

    Ns_HomePath(dest, "bin", NULL);
    va_start(ap, dest);
    path = MakePath(dest, &ap);
    va_end(ap);
    return path;
}


/*
 *----------------------------------------------------------------------
 *
 * Ns_HomePath --
 *
 *	Build a path relative to AOLserver's home dir. 
 *
 * Results:
 *	dest->string 
 *
 * Side effects:
 *	Appends to dest. 
 *
 *----------------------------------------------------------------------
 */

char *
Ns_HomePath(Ns_DString *dest, ...)
{
    va_list  ap;
    char    *path;

    Ns_MakePath(dest, Ns_InfoHomePath(), NULL);
    va_start(ap, dest);
    path = MakePath(dest, &ap);
    va_end(ap);
    return path;
}


/*
 *----------------------------------------------------------------------
 *
 * Ns_ModulePath --
 *
 *	Append a path to dest:
 *	server-home/?servers/hserver?/?modules/hmodule?/...
 *	server and module may both be null.
 *
 * Results:
 *	dest->string 
 *
 * Side effects:
 *	Appends to dest. 
 *
 *----------------------------------------------------------------------
 */

char *
Ns_ModulePath(Ns_DString *dest, char *server, char *module, ...)
{
    va_list         ap;
    char           *path;

    Ns_HomePath(dest, NULL);
    if (server != NULL) {
       Ns_MakePath(dest, "servers", server, NULL);
    }
    if (module != NULL) {
       Ns_MakePath(dest, "modules", module, NULL);
    }
    va_start(ap, module);
    path = MakePath(dest, &ap);
    va_end(ap);
    return path;
}


/*
 *----------------------------------------------------------------------
 *
 * NsTclModulePathObjCmd --
 *
 *	Implements ns_modulepath command; basically a wrapper around 
 *	Ns_ModulePath. 
 *
 * Results:
 *	Tcl result. 
 *
 * Side effects:
 *	None (deprecated) 
 *
 *----------------------------------------------------------------------
 */

int
NsTclModulePathObjCmd(ClientData arg, Tcl_Interp *interp, int objc,
		      Tcl_Obj *CONST objv[])
{
    Ns_DString      ds;
    int		    i;
    char	   *module;

    Ns_DStringInit(&ds);
    if (objc < 2) {
        Tcl_WrongNumArgs(interp, 1, objv, "server ?module ...?");
        return TCL_ERROR;
    }
    module = objc > 2 ? Tcl_GetString(objv[2]) : NULL;
    Ns_ModulePath(&ds, Tcl_GetString(objv[1]), module, NULL);
    for (i = 3; i < objc; ++i) {
	Ns_MakePath(&ds, Tcl_GetString(objv[i]), NULL);
    }
    Tcl_DStringResult(interp, &ds);
    Ns_DStringFree(&ds);
    return TCL_OK;
}


/*
 *----------------------------------------------------------------------
 *
 * MakePath --
 *
 *	Append the args with slashes between them to dest. 
 *
 * Results:
 *	dest->string 
 *
 * Side effects:
 *	None. 
 *
 *----------------------------------------------------------------------
 */

static char *
MakePath(Ns_DString *dest, va_list *pap)
{
    char *s;
    int len;

    while ((s = va_arg(*pap, char *)) != NULL) {
        if (isalpha(*s) && s[1] == ':') {
            char temp = *(s+2);
            *(s + 2) = 0;
            Ns_DStringNAppend(dest, s, 2);
            *(s + 2) = temp;
            s += 2;
        }
	while (*s) {
	    while (isslash(*s)) {
	        ++s;
	    }
	    if (*s) {
	    	Ns_DStringNAppend(dest, "/", 1);
		len = 0;
		while (s[len] != '\0' && !isslash(s[len])) {
		    ++len;
		}
	    	Ns_DStringNAppend(dest, s, len);
	    	s += len;
	    }
	}
    }
    return dest->string;
}
