2015-05-13 23:41:11 -07:00
|
|
|
/* EINA - EFL data type library
|
|
|
|
* Copyright (C) 2015 Carsten Haitzler
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library 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
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library;
|
|
|
|
* if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2015-05-04 19:35:16 -07:00
|
|
|
#include "eina_debug.h"
|
|
|
|
|
|
|
|
#ifdef EINA_HAVE_DEBUG
|
|
|
|
|
|
|
|
static unsigned int _table_num = 0;
|
|
|
|
static unsigned int _table_size = 0;
|
|
|
|
static const char **_table = NULL;
|
|
|
|
|
|
|
|
// a very simple "fast lookup" of a filename to a path. we expect this table
|
|
|
|
// of lookups to remain very small as it most likely includes just the
|
|
|
|
// application executable itself as this was run from $PATH or using
|
|
|
|
// a relative path relative to cwd of shell at time of exec. this is really
|
|
|
|
// the only likely content, but just in case, handle more. it is much faster
|
|
|
|
// than going through systemcalls like realpath() every time (well this libc
|
|
|
|
// function will at least be a system call or use system calls to do its work)
|
|
|
|
static const char *
|
|
|
|
_eina_debug_file_lookup(const char *fname)
|
|
|
|
{
|
|
|
|
unsigned int n;
|
|
|
|
|
|
|
|
if (!_table) return NULL;
|
|
|
|
for (n = 0; _table[n]; n += 2)
|
|
|
|
{
|
|
|
|
if (!strcmp(_table[n], fname)) return _table[n + 1];
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// record a new filename -> path entry in our table. the table really is just
|
|
|
|
// odd/even strings like fname, path, fname2, path2, fnamr3, path3, ...
|
|
|
|
// and we are unlikely to have much more than 1 entry here. see above
|
|
|
|
static const char *
|
|
|
|
_eina_debug_file_store(const char *fname, const char *file)
|
|
|
|
{
|
|
|
|
static const char **table2;
|
|
|
|
|
|
|
|
_table_num += 2;
|
|
|
|
if (_table_num >= _table_size)
|
|
|
|
{
|
|
|
|
_table_size += 32;
|
|
|
|
table2 = _eina_debug_chunk_realloc(_table_size * sizeof(const char *));
|
|
|
|
if (!table2) return NULL;
|
|
|
|
_table = table2;
|
|
|
|
}
|
|
|
|
_table[_table_num - 2] = _eina_debug_chunk_strdup(fname);
|
|
|
|
_table[_table_num - 1] = _eina_debug_chunk_strdup(file);
|
|
|
|
return _table[_table_num - 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
// do a "fast lookup" of a filename to a file path for debug output. this
|
|
|
|
// relies on caching to avoid system calls and assumes that once we know
|
|
|
|
// the full path of a given filename, we can know its full path reliably.
|
|
|
|
// if we can't we'd be in trouble anyway as the filename and path lookup
|
|
|
|
// failure is due maybe to a deleted file or renamed file and then we are
|
|
|
|
// going to have a bad day either way.
|
|
|
|
const char *
|
|
|
|
_eina_debug_file_get(const char *fname)
|
|
|
|
{
|
|
|
|
char buf[4096];
|
|
|
|
const char *file;
|
|
|
|
static const char **path = NULL;
|
|
|
|
static char *pathstrs = NULL;
|
|
|
|
|
|
|
|
// no filename provided
|
|
|
|
if ((!fname) || (!fname[0])) return NULL;
|
|
|
|
// it's a full path so return as-is
|
|
|
|
if (fname[0] == '/') return fname;
|
|
|
|
// first look in cache for filename -> full path lookup and if
|
|
|
|
// there, return that (yes - assuming filesystem paths doesn't change
|
|
|
|
// which is unlikely as they were set up at star most likely)
|
|
|
|
eina_spinlock_take(&_eina_debug_lock);
|
|
|
|
file = _eina_debug_file_lookup(fname);
|
|
|
|
eina_spinlock_release(&_eina_debug_lock);
|
|
|
|
if (file) return file;
|
|
|
|
|
|
|
|
// store PATH permanently - yes. if it changes runtime it will break.
|
|
|
|
// for speed reasons we need to assume it won't change. store path broken
|
|
|
|
// down into an array of ptrs to strings with NULL ptr at the end. this
|
|
|
|
// will only execute once as an "init" for a breoken up path so it should
|
|
|
|
// not matter speed-wise
|
|
|
|
eina_spinlock_take(&_eina_debug_lock);
|
|
|
|
if (!path)
|
|
|
|
{
|
|
|
|
unsigned int n;
|
|
|
|
char *p1, *p2;
|
|
|
|
const char *p;
|
|
|
|
const char *pathstr = getenv("PATH");
|
|
|
|
|
|
|
|
if (!pathstr) return NULL;
|
|
|
|
// dup the entire env as we will rpelace : with 0 bytes to break str
|
|
|
|
pathstrs = _eina_debug_chunk_strdup(pathstr);
|
|
|
|
for (n = 0, p = pathstr; *p;)
|
|
|
|
{
|
|
|
|
n++;
|
|
|
|
p = strchr(p, ':');
|
|
|
|
if (!p) break;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
path = _eina_debug_chunk_push(sizeof(const char *) * (n + 1));
|
|
|
|
for (n = 0, p1 = pathstrs; *p1; n++)
|
|
|
|
{
|
|
|
|
path[n] = p1;
|
|
|
|
p2 = strchr(p1, ':');
|
|
|
|
if (!p2) break;
|
|
|
|
*p2 = 0;
|
|
|
|
p1 = p2 + 1;
|
|
|
|
}
|
|
|
|
path[n] = NULL;
|
|
|
|
}
|
|
|
|
eina_spinlock_release(&_eina_debug_lock);
|
|
|
|
|
|
|
|
// a relative path - resolve with realpath. due to the cache store above
|
|
|
|
// we shouldn't have to do this very often
|
|
|
|
if ((!strncmp(fname, "./", 2)) || (!strncmp(fname, "../", 3)))
|
|
|
|
{ // relative path
|
|
|
|
if (realpath(fname, buf)) file = buf;
|
|
|
|
else file = NULL;
|
|
|
|
}
|
|
|
|
// search in $PATH for the file then - this should also be very rare as
|
|
|
|
// we will store and cache results permanently
|
|
|
|
else if (path)
|
|
|
|
{
|
|
|
|
struct stat st;
|
|
|
|
unsigned int n;
|
|
|
|
|
|
|
|
for (n = 0; path[n]; n++)
|
|
|
|
{
|
|
|
|
snprintf(buf, sizeof(buf), "%s/%s", path[n], fname);
|
|
|
|
if (stat(buf, &st) == 0)
|
|
|
|
{
|
|
|
|
file = buf;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// if it's found - store it in cache for later
|
|
|
|
if (file)
|
|
|
|
{
|
|
|
|
eina_spinlock_take(&_eina_debug_lock);
|
|
|
|
file = _eina_debug_file_store(fname, file);
|
|
|
|
eina_spinlock_release(&_eina_debug_lock);
|
|
|
|
}
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
#endif
|