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.