Beispiel #1
0
/**
 * \brief Creates a new file in the override directory.
 * \param self Paths.
 * \param name Filename.
 * \param config One for a config file, zero for a data file.
 * \return path Absolute path or NULL.
 */
const char* lipth_paths_create_file (
	LIPthPaths* self,
	const char* name,
	int         config)
{
	char* path;
	LIAlgStrdicNode* node;

	/* Format the path. */
	if (config)
		path = lisys_path_concat (self->module_config, name, NULL);
	else
		path = lisys_path_concat (self->module_data_save, name, NULL);
	if (path == NULL)
		return NULL;

	/* Register the file. */
	node = lialg_strdic_find_node (self->files, name);
	if (node != NULL)
	{
		lisys_free (node->value);
		node->value = path;
	}
	else
		lialg_strdic_insert (self->files, name, path);

	return path;
}
Beispiel #2
0
/**
 * \brief Finds the data of a config file by a path relative to the data directory root.
 * \param self Paths.
 * \param path Path relative to the data directory root.
 * \param config Nonzero for a config file, zero for a data file.
 * \return Absolute path or NULL.
 */
char* lipth_paths_find_path (
	const LIPthPaths* self,
	const char*       path,
	int               config)
{
	char* path1;

	/* Try the config/save path. */
	if (config)
		path1 = lisys_path_concat (self->module_config, path, NULL);
	else
		path1 = lisys_path_concat (self->module_data_save, path, NULL);
	if (path1 == NULL)
		return NULL;
	if (lisys_filesystem_access (path1, LISYS_ACCESS_READ))
		return path1;
	lisys_free (path1);

	/* Try the data path. */
	path1 = lisys_path_concat (self->module_data, path, NULL);
	if (lisys_filesystem_access (path1, LISYS_ACCESS_READ))
		   return path1;
	lisys_free (path1);

	return NULL;
}
Beispiel #3
0
/**
 * \brief Gets the home data directory.
 *
 * Follows the XDG Base Directory Specification:
 * http://www.freedesktop.org/Standards/basedir-spec
 *
 * \return New string or NULL.
 */
char* lisys_paths_get_data_home ()
{
#ifdef __WIN32__
	int i;
	char tmp[MAX_PATH];

	if (!SHGetSpecialFolderPath (NULL, tmp, CSIDL_PERSONAL, TRUE))
		return NULL;
	for (i = 0 ; tmp[i] != '\0' ; i++)
	{
		if (tmp[i] == '\\')
			tmp[i] = '/';
	}
	return lisys_path_concat (tmp, "My Games", NULL);
#else
	char* ret;
	char* tmp;
	const char* dir;

	dir = getenv ("XDG_DATA_HOME");
	if (dir != NULL && dir[0] != '\0')
		return lisys_string_dup  (dir);
	tmp = lisys_paths_get_home ();
	if (tmp == NULL)
		return NULL;
	ret = lisys_path_concat (tmp, ".local/share", NULL);
	lisys_free (tmp);

	return ret;
#endif
}
Beispiel #4
0
/**
 * \brief Adds a data directory lookup path.
 * \param self Paths.
 * \param path Module root relative path.
 */
int lipth_paths_add_path (
	LIPthPaths* self,
	const char* path)
{
	int ret = 1;
	char* path1;

	/* Add the module directory. */
	path1 = lisys_path_concat (self->module_data, path, NULL);
	if (path1 != NULL)
	{
		if (!lipth_paths_add_path_abs (self, path1))
			ret = 0;
		lisys_free (path1);
	}
	else
		ret = 0;

	/* Add the override directory. */
	path1 = lisys_path_concat (self->module_data_save, path, NULL);
	if (path1 != NULL)
	{
		lipth_paths_add_path_abs (self, path1);
		lisys_free (path1);
	}
	else
		ret = 0;

	return ret;
}
Beispiel #5
0
/**
 * \brief Gets the path to an SQL database.
 *
 * Calling this function will create the save directory if it doesn't exist
 * yet. If the creation fails or the function runs out of memory, NULL is
 * returned and the error message is set.
 *
 * \param self Paths object.
 * \param name File name.
 * \return Newly allocated absolute path or NULL.
 */
char* lipth_paths_get_sql (
	const LIPthPaths* self,
	const char*       name)
{
	char* path;

	/* Format the path. */
	path = lisys_path_concat (self->module_state, name, NULL);
	if (path == NULL)
		return NULL;

	/* Check if the save directory exists. */
	if (lisys_filesystem_access (self->module_state, LISYS_ACCESS_EXISTS))
	{
		if (!lisys_filesystem_access (self->module_state, LISYS_ACCESS_WRITE))
		{
			lisys_error_set (EINVAL, "save path `%s' is not writable", path);
			lisys_free (path);
			return NULL;
		}
		return path;
	}

	/* Create the save directory. */
	if (!lisys_filesystem_makepath (self->module_state))
	{
		lisys_free (path);
		return NULL;
	}

	return path;
}
Beispiel #6
0
/**
 * \brief Gets the path to a sound file.
 *
 * \param self Paths object.
 * \param name File name.
 * \return Full path or NULL.
 */
char* lipth_paths_get_sound (
	const LIPthPaths* self,
	const char*       name)
{
	char* path;

	/* Try the override path. */
	path = lisys_path_concat (self->override_data, "sounds", name, NULL);
	if (path == NULL)
		return NULL;
	if (lisys_filesystem_access (path, LISYS_ACCESS_READ))
		return path;
	lisys_free (path);

	/* Try the real path. */
	return lisys_path_concat (self->module_data, "sounds", name, NULL);
}
Beispiel #7
0
/**
 * \brief Gets the global data directory.
 *
 * Follows the XDG Base Directory Specification:
 * http://www.freedesktop.org/Standards/basedir-spec
 *
 * \param path Relative path being searched for.
 * \return New string or NULL.
 */
char* lisys_paths_get_data_global (
	const char* path)
{
#ifdef __WIN32__
	return NULL;
#else
	int last;
	char* dup;
	char* ptr;
	char* ret;
	char* start;
	const char* dirs;

	/* Get the list of global data directories. */
	dirs = getenv ("XDG_DATA_DIRS");
	if (dirs == NULL || dirs[0] == '\0')
		return NULL;
	dup = lisys_string_dup  (dirs);
	if (dup == NULL)
		return NULL;

	/* Loop through all directories. */
	ptr = start = dup;
	ret = NULL;
	last = 0;
	while (1)
	{
		/* Search for the delimiter. */
		last = (*ptr == '\0');
		if (*ptr != ':' && !last)
		{
			ptr++;
			continue;
		}
		*ptr = '\0';

		/* Test if the path is valid. */
		ret = lisys_path_concat (start, path, NULL);
		if (ret != NULL)
		{
			if (lisys_filesystem_access (ret, LISYS_ACCESS_READ))
				break;
			lisys_free (ret);
			ret = NULL;
		}

		/* Check if more candidates exist. */
		if (last)
			break;
		ptr++;
		start = ptr;
	}

	/* Return the result or NULL. */
	lisys_free (dup);
	return ret;
#endif
}
Beispiel #8
0
/**
 * \brief Gets the home cache directory.
 *
 * Follows the XDG Base Directory Specification:
 * http://www.freedesktop.org/Standards/basedir-spec
 *
 * \return New string or NULL.
 */
char* lisys_paths_get_cache_home ()
{
#ifdef __WIN32__
	return lisys_paths_get_data_home ();
#else
	char* ret;
	char* tmp;
	const char* dir;

	dir = getenv ("XDG_CACHE_HOME");
	if (dir != NULL && dir[0] != '\0')
		return lisys_string_dup  (dir);
	tmp = lisys_paths_get_home ();
	if (tmp == NULL)
		return NULL;
	ret = lisys_path_concat (tmp, ".cache", NULL);
	lisys_free (tmp);

	return ret;
#endif
}
Beispiel #9
0
/**
 * \brief Creates a new paths object.
 *
 * \param path Package root directory or NULL for auto-detect.
 * \param name Module name.
 * \return Paths or NULL.
 */
LIPthPaths* lipth_paths_new (
	const char* path,
	const char* name)
{
	char* tmp;
	LIPthPaths* self;

	/* Allocate self. */
	self = lisys_calloc (1, sizeof (LIPthPaths));
	if (self == NULL)
		return NULL;

	/* Allocate the file lookup table. */
	self->files = lialg_strdic_new ();
	if (self->files == NULL)
	{
		lipth_paths_free (self);
		return NULL;
	}

	/* Set the module name. */
	self->module_name = lisys_string_dup (name);
	if (self->module_name == NULL)
	{
		lipth_paths_free (self);
		return NULL;
	}

	/* Set the root directory. */
	if (path != NULL)
	{
		self->root = lisys_string_dup (path);
		if (self->root == NULL)
		{
			lipth_paths_free (self);
			return NULL;
		}
	}
	else
	{
		self->root = lipth_paths_get_root ();
		if (self->root == NULL)
		{
			lipth_paths_free (self);
			return NULL;
		}
	}

	/* Get the data directory root. */
	/* This is where modules and system scripts are located. If relative paths
	   are enabled, the directory of the executable is searched for a data
	   directory. Failing that, XDG data directories are searched for the game
	   directory. As the last resort, the hardcoded data directory is used. */
#ifdef LI_RELATIVE_PATHS
	self->global_data = lisys_path_concat (self->root, "data", NULL);
	if (!private_validate_dir (&self->global_data))
#endif
	{
		self->global_data = lisys_paths_get_data_global ("lipsofsuna");
		private_validate_dir (&self->global_data);
		if (self->global_data == NULL)
		{
#ifdef LIDATADIR
			self->global_data = lisys_string_dup (LIDATADIR);
			if (!private_validate_dir (&self->global_data))
#endif
			{
				lisys_error_set (EINVAL, "cannot find the data directory");
				lipth_paths_free (self);
				return NULL;
			}
		}
	}

	/* Get the data directory of the current module. */
	/* This is where the data files of the module are installed. The directory
	   functions as a fallback for both data and configuration files. */
	self->module_data = lisys_path_concat (self->global_data, name, NULL);
	if (!private_validate_dir (&self->module_data))
	{
		lisys_error_set (EINVAL, "cannot find the module data directory");
		lipth_paths_free (self);
		return NULL;
	}

	/* Get the data save directory. */
	/* This is where save files are written and where the user can copy any
	   custom data files or mods. It's the first place where data files are
	   looked for. */
	tmp = lisys_paths_get_data_home ();
	if (tmp == NULL)
	{
		lipth_paths_free (self);
		return NULL;
	}
	self->module_data_save = lisys_path_concat (tmp, "lipsofsuna", name, NULL);
	lisys_free (tmp);
	if (self->module_data_save == NULL)
	{
		lipth_paths_free (self);
		return NULL;
	}

	/* Get the config directory. */
	/* This is where configuration files are stored. It's separate from the save
	   directory since in Linux that's the case. In Windows it's actually the
	   save directory. */
	tmp = lisys_paths_get_config_home ();
	if (tmp == NULL)
	{
		lipth_paths_free (self);
		return NULL;
	}
	self->module_config = lisys_path_concat (tmp, "lipsofsuna", name, NULL);
	lisys_free (tmp);
	if (self->module_config == NULL)
	{
		lipth_paths_free (self);
		return NULL;
	}

	/* Get the extension directory. */
	/* This directory is reserved for potential third party extension libraries.
	   The path is lib/extensions either in the relative path, XDG data path or
	   the hardcoded extension directory. */
#ifdef LI_RELATIVE_PATHS
	self->global_exts = lisys_path_concat (self->global_data, "lib", "extensions", NULL);
	if (!private_validate_dir (&self->global_exts))
#endif
	{
		self->global_exts = lisys_paths_get_data_global ("lipsofsuna/lib/extensions");
#ifdef LIEXTSDIR
		if (!private_validate_dir (&self->global_exts))
		{
			self->global_exts = lisys_string_dup (LIEXTSDIR);
			private_validate_dir (&self->global_exts);
		}
#endif
	}

	/* Create the save directories. */
	if (!private_create_save_path (self, self->module_data_save) ||
	    !private_create_save_path (self, self->module_config))
	{
		lipth_paths_free (self);
		return NULL;
	}

	/* Add the base data directory. */
	lipth_paths_add_path (self, "");

	return self;
}
Beispiel #10
0
/**
 * \brief Creates a new paths object.
 *
 * \param path Package root directory or NULL for auto-detect.
 * \param name Module name.
 * \return Paths or NULL.
 */
LIPthPaths* lipth_paths_new (
	const char* path,
	const char* name)
{
	char* tmp;
	LIPthPaths* self;
	LISysStat stat;

	self = lisys_calloc (1, sizeof (LIPthPaths));
	if (self == NULL)
		return NULL;

	/* Set module name. */
	self->module_name = lisys_string_dup (name);
	if (self->module_name == NULL)
		goto error;

	/* Set root directory. */
	if (path != NULL)
	{
		self->root = lisys_string_dup (path);
		if (self->root == NULL)
			goto error;
	}
	else
	{
		self->root = lipth_paths_get_root ();
		if (self->root == NULL)
			goto error;
	}

	/* Get data directory. */
#ifdef LI_RELATIVE_PATHS
	self->global_data = lisys_path_concat (self->root, "data", NULL);
	if (self->global_data == NULL)
		goto error;
#else
	self->global_data = LIDATADIR;
#endif
	self->module_data = lisys_path_concat (self->global_data, name, NULL);
	if (self->module_data == NULL)
		goto error;

	/* Get data override directory. */
	tmp = lisys_paths_get_data_home ();
	if (tmp == NULL)
		goto error;
	self->override_data = lisys_path_concat (tmp, "lipsofsuna", "data", name, NULL);
	if (self->override_data == NULL)
	{
		lisys_free (tmp);
		goto error;
	}

	/* Get save directory. */
	self->global_state = lisys_path_concat (tmp, "lipsofsuna", "save", NULL);
	lisys_free (tmp);
	if (self->global_state == NULL)
		goto error;
	self->module_state = lisys_path_concat (self->global_state, name, NULL);
	if (self->module_state == NULL)
		goto error;

	/* Get extension directory. */
#ifdef LI_RELATIVE_PATHS
	self->global_exts = lisys_path_concat (self->global_data, "lib", "extensions", NULL);
	if (self->global_exts == NULL)
		goto error;
#else
	self->global_exts = LIEXTSDIR;
#endif

	/* Check for valid data directory. */
	if (!lisys_filesystem_stat (self->module_data, &stat))
	{
		lisys_error_set (EIO, "missing data directory `%s'", self->module_data);
		goto error;
	}
	if (stat.type != LISYS_STAT_DIRECTORY && stat.type != LISYS_STAT_LINK)
	{
		lisys_error_set (EIO, "invalid data directory `%s': not a directory", self->module_data);
		goto error;
	}

	return self;

error:
	lipth_paths_free (self);
	return NULL;
}