ftp.nice.ch/pub/next/tools/emulators/vice.0.15.0.NeXT.sd.tgz#/vice-0.15.0/src/findpath.c

This is findpath.c in view mode; [Download] [Up]

/*
 * findpath.c - Find a file via search path.
 *
 * Written by
 *  Tomi Ollila <Tomi.Ollila@tfi.net>
 *
 * Minor changes for VICE by
 *  Ettore Perazzoli <ettore@comm2000.it>
 *
 * This file is part of VICE, the Versatile Commodore Emulator.
 * See README for copyright notice.
 *
 *  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., 59 Temple Place, Suite 330, Boston, MA
 *  02111-1307  USA.
 *
 */

#include "vice.h"

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

#include "findpath.h"
#include "utils.h"

/*
 * This function is checked to be robust with all path 3 types possible
 * (cmd has relative, absolute or no path component)
 * The returned path will always contain at least one '/'. (if not NULL).
 * Overflow testing for internal buffer is always done.
 */

char * findpath(const char *cmd, const char *syspath, int mode)
{
    char * pd = NULL;
    PATH_VAR(buf);

    buf[0] = '\0'; /* this will (and needs to) stay '\0' */

    if (strchr(cmd, '/')) /* absolute or relative path given */
    {
	int l, state;
	const char *ps;

	if (cmd[0] != '/')
	{
	    if (getcwd(buf + 1, sizeof buf - 128) == NULL)
		goto fail;

	    l = strlen(buf + 1);
	}
	else l = 0;

	if (l + strlen(cmd) >= sizeof buf - 5)
	    goto fail;

	ps = cmd;
	pd = buf + l; /* buf + 1 + l - 1 */

	if (*pd++ != '/')
	    *pd++ = '/';

	state = 1;

	/* delete extra `/./', '/../' and '//':s from the path */
	while (*ps)
	{
	    switch (state)
	    {
	    case 0: if (*ps == '/') state = 1; else state = 0; break;
	    case 1:
		if (*ps == '.') { state = 2; break; }
		if (*ps == '/') pd--; else state = 0; break;
	    case 2:
		if (*ps == '/') { state = 1; pd -= 2; break; }
		if (*ps == '.') state = 3; else state = 0; break;
	    case 3:
		if (*ps != '/') { state = 0; break; }
		state = 1;
		pd -= 4;
		while (*pd != '/' && *pd != '\0')
		    pd--;
		if (*pd == '\0') pd++;
		state = 1;
		break;
	    }
	    *pd++ = *ps++;
	}

        *pd = '\0';
    }
    else
    {
	const char * path = syspath;
	const char * s;
	int cl = strlen(cmd) + 1;

	for (s = path; s; path = s + 1)
	{
	    char * p;
	    int l;

	    s = strchr(path, FINDPATH_SEPARATOR_CHAR);
	    l = s? (s - path): strlen(path);

	    if (l + cl > sizeof buf - 5)
		continue;

	    memcpy(buf + 1, path, l);

	    p = buf + l;  /* buf + 1 + l - 1 */

	    if (*p++ != '/')
		*p++ = '/';

	    memcpy(p, cmd, cl);

	    if (access(buf + 1, mode) == 0)
	    {
		pd = p /* + cl*/ ;
		break;
	    }
	}
    }

    if (pd)
    {
#if 0
        do pd--;
	while (*pd != '/'); /* there is at least one '/' */

	if (*(pd - 1) == '\0')
	    pd++;
	*pd = '\0';
#endif

	return stralloc(buf + 1);
    }

 fail:
    return NULL;
}


#ifdef _TEST_FINDPATH

void tstpath(char * string)
{
    char * s;
    printf("*** Testing %s: ", string);

    s = findpath(string, getenv("PATH"));

    if (s) { puts(s); free(s); }
    else puts("path not found");
}

void main(int argc, char ** argv)
{

    if (argc > 1)
    {
	tstpath(argv[1]);
    }
    else
    {
	tstpath("/foo/bar");
	tstpath("../bar");
	tstpath("foo/bar");
	tstpath(".////foo/bar");
	tstpath("../../../../../");
	tstpath("../../../..//./foo/../bar");
	tstpath("bar");
	tstpath("gzip");
	tstpath("perl");
    }
    exit(0);
}
#endif

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.