314 lines
8.9 KiB
C++
314 lines
8.9 KiB
C++
/*
|
|||
|
|
* Copyright 2013, Ingo Weinhold, [email protected].
|
||
|
|
* Distributed under the terms of the MIT License.
|
||
|
|
*/
|
||
|
|
|
||
|
|
|
||
|
|
#include <getopt.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <string.h>
|
||
|
|
|
||
#include <package/PackageResolvableExpression.h>
|
|||
#include <package/manager/Exceptions.h>
|
|||
#include <Path.h>
|
|||
|
|
#include <PathFinder.h>
|
||
|
|
#include <StringList.h>
|
||
|
|
|
||
|
|
|
||
using namespace BPackageKit::BManager::BPrivate;
|
|||
|
|
|
||
|
|
|
||
extern const char* __progname;
|
|||
|
|
const char* kCommandName = __progname;
|
||
|
|
|
||
|
|
|
||
|
|
struct DirectoryConstantEntry {
|
||
|
|
const char* string;
|
||
|
|
path_base_directory constant;
|
||
|
|
const char* description;
|
||
|
|
};
|
||
|
|
|
||
|
|
#define DEFINE_CONSTANT(constant, description) \
|
||
|
|
{ #constant, constant, description }
|
||
|
|
|
||
|
|
static const DirectoryConstantEntry kDirectoryConstants[] = {
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_INSTALLATION_LOCATION_DIRECTORY,
|
||
|
|
"the installation location"),
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_ADD_ONS_DIRECTORY,
|
||
|
|
"the add-ons directory"),
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_APPS_DIRECTORY,
|
||
|
|
"the applications directory"),
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_BIN_DIRECTORY,
|
||
|
|
"the command line programs directory"),
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_BOOT_DIRECTORY,
|
||
|
|
"the boot data directory"),
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_CACHE_DIRECTORY,
|
||
|
|
"the cache directory"),
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_DATA_DIRECTORY,
|
||
|
|
"the data directory"),
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_DEVELOP_DIRECTORY,
|
||
|
|
"the develop directory"),
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_DEVELOP_LIB_DIRECTORY,
|
||
|
|
"the development libraries directory"),
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_DOCUMENTATION_DIRECTORY,
|
||
|
|
"the documentation directory"),
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_ETC_DIRECTORY,
|
||
|
|
"the Unix etc directory (global settings)"),
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_FONTS_DIRECTORY,
|
||
|
|
"the fonts directory"),
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_HEADERS_DIRECTORY,
|
||
|
|
"the development headers directory"),
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_LIB_DIRECTORY,
|
||
|
|
"the libraries directory"),
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_LOG_DIRECTORY,
|
||
|
|
"the logging directory"),
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_MEDIA_NODES_DIRECTORY,
|
||
|
|
"the media node add-ons directory"),
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_PACKAGES_DIRECTORY,
|
||
|
|
"the packages directory"),
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_PREFERENCES_DIRECTORY,
|
||
|
|
"the preference applications directory"),
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_SERVERS_DIRECTORY,
|
||
|
|
"the server programs directory"),
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_SETTINGS_DIRECTORY,
|
||
|
|
"the global settings directory"),
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_SOUNDS_DIRECTORY,
|
||
|
|
"the sound files directory"),
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_SPOOL_DIRECTORY,
|
||
|
|
"the (mail) spool directory"),
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_TRANSLATORS_DIRECTORY,
|
||
|
|
"the translator add-ons directory"),
|
||
|
|
DEFINE_CONSTANT(B_FIND_PATH_VAR_DIRECTORY,
|
||
|
|
"the Unix var directory (global writable data)"),
|
||
DEFINE_CONSTANT(B_FIND_PATH_PACKAGE_PATH,
|
|||
"the path of the package the file specified via -p belongs to"),
|
|||
|
|
};
|
||
|
|
|
||
|
|
static const size_t kDirectoryConstantCount
|
||
|
|
= sizeof(kDirectoryConstants) / sizeof(kDirectoryConstants[0]);
|
||
|
|
|
||
|
|
|
||
|
|
static const char* kUsage =
|
||
|
|
"Usage: %s [ <options> ] [ <kind> [<subpath>] ]\n"
|
||
|
|
"Prints paths specified by directory constant <kind>. <subpath>, if\n"
|
||
|
|
"specified, is appended to each path. By default a path is printed for\n"
|
||
|
|
"each existing installation location (one per line); the options can\n"
|
||
|
|
"modify this behavior.\n"
|
||
|
|
"\n"
|
||
|
|
"Options:\n"
|
||
" -a <architecture>\n"
|
|||
|
|
" If the path(s) specified by <kind> are architecture specific, use\n"
|
||
|
|
" architecture <architecture>. If not specified, the primary\n"
|
||
|
|
" architecture is used, unless the -p/--path option is specified, in\n"
|
||
|
|
" which case the architecture associated with the given <path> is\n"
|
||
|
|
" used.\n"
|
||
" -c <separator>\n"
|
|||
|
|
" Concatenate the resulting paths, separated only by <separator>,\n"
|
||
|
|
" instead of printing a path per line.\n"
|
||
|
|
" -d, --dependency <dependency>\n"
|
||
|
|
" Modifies the behavior of the -p option. Use the installation "
|
||
|
|
"location\n"
|
||
|
|
" where the dependency <dependency> of the package that the entry\n"
|
||
|
|
" referred to by <path> belongs to is installed.\n"
|
||
|
|
" -e, --existing\n"
|
||
|
|
" Print only paths that refer to existing entries.\n"
|
||
|
|
" -h, --help\n"
|
||
|
|
" Print this usage info.\n"
|
||
|
|
" -l, --list\n"
|
||
|
|
" Print a list of the possible constants for the <kind> parameter.\n"
|
||
|
|
" -p, --path <path>\n"
|
||
|
|
" Print only one path, the one for the installation location that\n"
|
||
|
|
" contains the path <path>.\n"
|
||
" -r, --resolvable <expression>\n"
|
|||
|
|
" Print only one path, the one for the installation location for the\n"
|
||
|
|
" package providing the resolvable matching the expression\n"
|
||
|
|
" <expression>. The expressions can be a simple resolvable name or\n"
|
||
|
|
" a resolvable name with operator and version (e.g.\n"
|
||
|
|
" \"cmd:perl >= 5\"; must be one argument).\n"
|
||
" -R, --reverse\n"
|
|||
|
|
" Print paths in reverse order, i.e. from most general to most\n"
|
||
|
|
" specific.\n"
|
||
;
|
|||
|
|
|
||
|
|
|
||
|
|
static void
|
||
|
|
print_usage_and_exit(bool error)
|
||
|
|
{
|
||
|
|
fprintf(error ? stderr : stdout, kUsage, kCommandName);
|
||
|
|
exit(error ? 1 : 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
int
|
||
|
|
main(int argc, const char* const* argv)
|
||
|
|
{
|
||
const char* architecture = NULL;
|
|||
const char* dependency = NULL;
|
|||
|
|
const char* referencePath = NULL;
|
||
const char* resolvable = NULL;
|
|||
bool existingOnly = false;
|
|||
bool reverseOrder = false;
|
|||
const char* separator = NULL;
|
|||
|
|
|
||
|
|
while (true) {
|
||
|
|
static struct option sLongOptions[] = {
|
||
{ "architecture", required_argument, 0, 'a' },
|
|||
{ "dependency", required_argument, 0, 'd' },
|
|||
|
|
{ "help", no_argument, 0, 'h' },
|
||
{ "list", no_argument, 0, 'l' },
|
|||
{ "path", required_argument, 0, 'p' },
|
|||
{ "resolvable", required_argument, 0, 'pr' },
|
|||
{ "reverse", no_argument, 0, 'R' },
|
|||
{ 0, 0, 0, 0 }
|
|||
|
|
};
|
||
|
|
|
||
|
|
opterr = 0; // don't print errors
|
||
int c = getopt_long(argc, (char**)argv, "+a:c:d:ehlp:r:R",
|
|||
sLongOptions, NULL);
|
|||
|
|
if (c == -1)
|
||
|
|
break;
|
||
|
|
|
||
|
|
switch (c) {
|
||
case 'a':
|
|||
|
|
architecture = optarg;
|
||
|
|
break;
|
||
|
|
|
||
case 'c':
|
|||
|
|
separator = optarg;
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'd':
|
||
|
|
dependency = optarg;
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'e':
|
||
|
|
existingOnly = true;
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'h':
|
||
|
|
print_usage_and_exit(false);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 'l':
|
||
|
|
for (size_t i = 0; i < kDirectoryConstantCount; i++) {
|
||
|
|
const DirectoryConstantEntry& entry
|
||
|
|
= kDirectoryConstants[i];
|
||
|
|
printf("%s\n - %s\n", entry.string, entry.description);
|
||
|
|
}
|
||
|
|
exit(0);
|
||
|
|
|
||
|
|
case 'p':
|
||
|
|
referencePath = optarg;
|
||
|
|
break;
|
||
|
|
|
||
case 'r':
|
|||
|
|
resolvable = optarg;
|
||
|
|
break;
|
||
|
|
|
||
case 'R':
|
|||
|
|
reverseOrder = true;
|
||
|
|
break;
|
||
|
|
|
||
default:
|
|||
|
|
print_usage_and_exit(true);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// The remaining arguments are the kind constant and optionally the subpath.
|
||
|
|
if (optind >= argc || optind + 2 < argc)
|
||
|
|
print_usage_and_exit(true);
|
||
|
|
|
||
|
|
const char* kindConstant = argv[optind++];
|
||
|
|
|
||
|
|
const char* subPath = NULL;
|
||
if (optind < argc)
|
|||
subPath = argv[optind++];
|
|||
|
|
|
||
// only one of path or resolvable may be specified
|
|||
|
|
if (referencePath != NULL && resolvable != NULL)
|
||
|
|
print_usage_and_exit(true);
|
||
|
|
|
||
// resolve the directory constant
|
|||
|
|
path_base_directory baseDirectory = B_FIND_PATH_IMAGE_PATH;
|
||
|
|
bool found = false;
|
||
|
|
for (size_t i = 0; i < kDirectoryConstantCount; i++) {
|
||
|
|
const DirectoryConstantEntry& entry = kDirectoryConstants[i];
|
||
|
|
if (strcmp(kindConstant, entry.string) == 0) {
|
||
|
|
found = true;
|
||
|
|
baseDirectory = entry.constant;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!found) {
|
||
|
|
fprintf(stderr, "Error: Unsupported directory constant \"%s\".\n",
|
||
|
|
kindConstant);
|
||
|
|
exit(1);
|
||
|
|
}
|
||
|
|
|
||
if (referencePath != NULL || resolvable != NULL) {
|
|||
try {
|
|||
|
|
BPathFinder pathFinder;
|
||
|
|
if (referencePath != NULL) {
|
||
|
|
pathFinder.SetTo(referencePath, dependency);
|
||
|
|
} else {
|
||
|
|
pathFinder.SetTo(
|
||
|
|
BPackageKit::BPackageResolvableExpression(resolvable),
|
||
|
|
dependency);
|
||
|
|
}
|
||
|
|||
BPath path;
|
|||
|
|
status_t error = pathFinder.FindPath(architecture, baseDirectory,
|
||
|
|
subPath, existingOnly ? B_FIND_PATH_EXISTING_ONLY : 0, path);
|
||
|
|
if (error != B_OK) {
|
||
|
|
fprintf(stderr, "Error: Failed to find path: %s\n",
|
||
|
|
strerror(error));
|
||
|
|
exit(1);
|
||
|
|
}
|
||
|
|||
printf("%s\n", path.Path());
|
|||
|
|
} catch(BFatalErrorException& exception) {
|
||
|
|
if (!exception.Details().IsEmpty())
|
||
|
|
fprintf(stderr, "%s", exception.Details().String());
|
||
|
|
if (exception.Error() == B_OK) {
|
||
|
|
fprintf(stderr, "Error: %s\n", exception.Message().String());
|
||
|
|
} else {
|
||
|
|
fprintf(stderr, "Error: %s: %s\n", exception.Message().String(),
|
||
|
|
strerror(exception.Error()));
|
||
|
|
}
|
||
|
|
return 1;
|
||
|
|
}
|
||
} else {
|
|||
|
|
BStringList paths;
|
||
status_t error = BPathFinder::FindPaths(architecture, baseDirectory,
|
|||
|
|
subPath, existingOnly ? B_FIND_PATH_EXISTING_ONLY : 0, paths);
|
||
if (error != B_OK) {
|
|||
|
|
fprintf(stderr, "Error: Failed to find paths: %s\n",
|
||
|
|
strerror(error));
|
||
|
|
exit(1);
|
||
|
|
}
|
||
|
|
|
||
int32 count = paths.CountStrings();
|
|||
|
|
if (reverseOrder) {
|
||
|
|
for (int32 i = 0; i < count / 2; i++)
|
||
|
|
paths.Swap(i, count - i - 1);
|
||
|
|
}
|
||
|
|
|
||
if (separator != NULL) {
|
|||
|
|
BString result = paths.Join(separator);
|
||
|
|
if (result.IsEmpty()) {
|
||
|
|
fprintf(stderr, "Error: Out of memory!\n");
|
||
|
|
exit(1);
|
||
|
|
}
|
||
|
|
printf("%s\n", result.String());
|
||
|
|
} else {
|
||
|
|
for (int32 i = 0; i < count; i++)
|
||
|
|
printf("%s\n", paths.StringAt(i).String());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|