1c5f9ac7eSStefano Ceccherini // query.cpp
2c5f9ac7eSStefano Ceccherini //
3c5f9ac7eSStefano Ceccherini // A shell utility for somewhat emulating the Tracker's "Find By Formula"
4c5f9ac7eSStefano Ceccherini // functionality.
5c5f9ac7eSStefano Ceccherini //
6c5f9ac7eSStefano Ceccherini // by Ficus Kirkpatrick (ficus@ior.com)
7c5f9ac7eSStefano Ceccherini //
8c5f9ac7eSStefano Ceccherini // Modified by Jerome Duval on November 03, 2003
9c5f9ac7eSStefano Ceccherini //
10c5f9ac7eSStefano Ceccherini // Filtering capability added by Stefano Ceccherini on January 14, 2005
11c5f9ac7eSStefano Ceccherini
12c5f9ac7eSStefano Ceccherini
13c5f9ac7eSStefano Ceccherini #include <stdio.h>
14c5f9ac7eSStefano Ceccherini #include <string.h>
15c5f9ac7eSStefano Ceccherini #include <stdlib.h>
16c5f9ac7eSStefano Ceccherini #include <unistd.h>
17c5f9ac7eSStefano Ceccherini
18c5f9ac7eSStefano Ceccherini #include <Path.h>
19c5f9ac7eSStefano Ceccherini #include <Query.h>
20c5f9ac7eSStefano Ceccherini #include <Entry.h>
21c5f9ac7eSStefano Ceccherini #include <Volume.h>
22c5f9ac7eSStefano Ceccherini #include <VolumeRoster.h>
23c5f9ac7eSStefano Ceccherini #include <SupportDefs.h>
24c5f9ac7eSStefano Ceccherini #include <String.h>
25c5f9ac7eSStefano Ceccherini
26c5f9ac7eSStefano Ceccherini #include "FilteredQuery.h"
27c5f9ac7eSStefano Ceccherini
28c5f9ac7eSStefano Ceccherini extern const char *__progname;
29c5f9ac7eSStefano Ceccherini
30c5f9ac7eSStefano Ceccherini struct folder_params
31c5f9ac7eSStefano Ceccherini {
32c5f9ac7eSStefano Ceccherini BPath path;
33c5f9ac7eSStefano Ceccherini bool includeSubFolders;
34c5f9ac7eSStefano Ceccherini };
35c5f9ac7eSStefano Ceccherini
36c5f9ac7eSStefano Ceccherini
37c5f9ac7eSStefano Ceccherini static bool
FilterByFolder(const entry_ref * ref,void * arg)38c5f9ac7eSStefano Ceccherini FilterByFolder(const entry_ref *ref, void *arg)
39c5f9ac7eSStefano Ceccherini {
40c5f9ac7eSStefano Ceccherini folder_params* params = static_cast<folder_params*>(arg);
41c5f9ac7eSStefano Ceccherini BPath& wantedPath = params->path;
42c5f9ac7eSStefano Ceccherini bool includeSub = params->includeSubFolders;
43c5f9ac7eSStefano Ceccherini
44c5f9ac7eSStefano Ceccherini BPath path(ref);
45c5f9ac7eSStefano Ceccherini if (includeSub) {
46c5f9ac7eSStefano Ceccherini if (!strncmp(path.Path(), wantedPath.Path(),
47c5f9ac7eSStefano Ceccherini strlen(wantedPath.Path())))
48c5f9ac7eSStefano Ceccherini return true;
49c5f9ac7eSStefano Ceccherini } else {
50c5f9ac7eSStefano Ceccherini if (path.GetParent(&path) == B_OK &&
51c5f9ac7eSStefano Ceccherini path == wantedPath)
52c5f9ac7eSStefano Ceccherini return true;
53c5f9ac7eSStefano Ceccherini }
54c5f9ac7eSStefano Ceccherini return false;
55c5f9ac7eSStefano Ceccherini }
56c5f9ac7eSStefano Ceccherini
57c5f9ac7eSStefano Ceccherini
58c5f9ac7eSStefano Ceccherini // Option variables.
59c5f9ac7eSStefano Ceccherini bool o_all_volumes = false; // Query all volumes?
60c5f9ac7eSStefano Ceccherini bool o_escaping = true; // Escape metacharacters?
61c5f9ac7eSStefano Ceccherini bool o_subfolders = false;
62c5f9ac7eSStefano Ceccherini
63c5f9ac7eSStefano Ceccherini void
usage(void)64c5f9ac7eSStefano Ceccherini usage(void)
65c5f9ac7eSStefano Ceccherini {
66*49f7074bSChris Roberts printf("usage: %s [ -e ] [ -p <path-to-search> ] [ -s ] [ -a || -v <path-to-volume> ] expression\n"
67c5f9ac7eSStefano Ceccherini " -e\t\tdon't escape meta-characters\n"
68*49f7074bSChris Roberts " -p <path>\tsearch only in the given path. Defaults to the current directory.\n"
69*49f7074bSChris Roberts " -s\t\tinclude subfolders\n"
70c5f9ac7eSStefano Ceccherini " -a\t\tperform the query on all volumes\n"
71c5f9ac7eSStefano Ceccherini " -v <file>\tperform the query on just one volume; <file> can be any\n"
72c5f9ac7eSStefano Ceccherini "\t\tfile on that volume. Defaults to the current volume.\n"
73c5f9ac7eSStefano Ceccherini " Hint: '%s name=foo' will find files named \"foo\"\n",
74c5f9ac7eSStefano Ceccherini __progname, __progname);
75c5f9ac7eSStefano Ceccherini exit(0);
76c5f9ac7eSStefano Ceccherini }
77c5f9ac7eSStefano Ceccherini
78c5f9ac7eSStefano Ceccherini
79c5f9ac7eSStefano Ceccherini void
perform_query(BVolume & volume,const char * predicate,const char * filterpath)80c5f9ac7eSStefano Ceccherini perform_query(BVolume &volume, const char *predicate, const char *filterpath)
81c5f9ac7eSStefano Ceccherini {
82c5f9ac7eSStefano Ceccherini TFilteredQuery query;
83c5f9ac7eSStefano Ceccherini
84c5f9ac7eSStefano Ceccherini // Set up the volume and predicate for the query.
85c5f9ac7eSStefano Ceccherini query.SetVolume(&volume);
86c5f9ac7eSStefano Ceccherini query.SetPredicate(predicate);
87c5f9ac7eSStefano Ceccherini folder_params options;
88*49f7074bSChris Roberts if (filterpath != NULL) {
89c5f9ac7eSStefano Ceccherini options.path = filterpath;
90c5f9ac7eSStefano Ceccherini options.includeSubFolders = o_subfolders;
91c5f9ac7eSStefano Ceccherini query.AddFilter(FilterByFolder, &options);
92c5f9ac7eSStefano Ceccherini }
93c5f9ac7eSStefano Ceccherini
94c5f9ac7eSStefano Ceccherini status_t status = query.Fetch();
95c5f9ac7eSStefano Ceccherini if (status == B_BAD_VALUE) {
96c5f9ac7eSStefano Ceccherini // the "name=" part may be omitted in our arguments
97c5f9ac7eSStefano Ceccherini BString string = "name=";
98c5f9ac7eSStefano Ceccherini string << predicate;
99c5f9ac7eSStefano Ceccherini
100c5f9ac7eSStefano Ceccherini query.SetPredicate(string.String());
101c5f9ac7eSStefano Ceccherini status = query.Fetch();
102c5f9ac7eSStefano Ceccherini }
103c5f9ac7eSStefano Ceccherini if (status != B_OK) {
104c5f9ac7eSStefano Ceccherini printf("query: bad query expression\n");
105c5f9ac7eSStefano Ceccherini return;
106c5f9ac7eSStefano Ceccherini }
107c5f9ac7eSStefano Ceccherini
108c5f9ac7eSStefano Ceccherini BEntry entry;
109c5f9ac7eSStefano Ceccherini BPath path;
110c5f9ac7eSStefano Ceccherini while (query.GetNextEntry(&entry) == B_OK) {
111c5f9ac7eSStefano Ceccherini if (entry.GetPath(&path) < B_OK) {
112c5f9ac7eSStefano Ceccherini fprintf(stderr, "%s: could not get path for entry\n", __progname);
113c5f9ac7eSStefano Ceccherini continue;
114c5f9ac7eSStefano Ceccherini }
115c5f9ac7eSStefano Ceccherini
116c5f9ac7eSStefano Ceccherini printf("%s\n", o_escaping ?
117c5f9ac7eSStefano Ceccherini BString().CharacterEscape(path.Path(), " ()?*&\"'[]^\\~|;!<>*$", '\\').String()
118c5f9ac7eSStefano Ceccherini : path.Path());
119c5f9ac7eSStefano Ceccherini }
120c5f9ac7eSStefano Ceccherini }
121c5f9ac7eSStefano Ceccherini
122c5f9ac7eSStefano Ceccherini
123c5f9ac7eSStefano Ceccherini int
main(int32 argc,const char ** argv)124c5f9ac7eSStefano Ceccherini main(int32 argc, const char **argv)
125c5f9ac7eSStefano Ceccherini {
126c5f9ac7eSStefano Ceccherini // Make sure we have the minimum number of arguments.
127c5f9ac7eSStefano Ceccherini if (argc < 2)
128c5f9ac7eSStefano Ceccherini usage();
129c5f9ac7eSStefano Ceccherini
130c5f9ac7eSStefano Ceccherini // Which volume do we make the query on?
131c5f9ac7eSStefano Ceccherini // Default to the current volume.
132c5f9ac7eSStefano Ceccherini char volumePath[B_FILE_NAME_LENGTH];
133c5f9ac7eSStefano Ceccherini char directoryPath[B_PATH_NAME_LENGTH];
134c5f9ac7eSStefano Ceccherini
135c5f9ac7eSStefano Ceccherini strcpy(volumePath, ".");
136c5f9ac7eSStefano Ceccherini strcpy(directoryPath, ".");
137c5f9ac7eSStefano Ceccherini
138c5f9ac7eSStefano Ceccherini // Parse command-line arguments.
139c5f9ac7eSStefano Ceccherini int opt;
140*49f7074bSChris Roberts while ((opt = getopt(argc, (char **)argv, "easv:p:")) != -1) {
141c5f9ac7eSStefano Ceccherini switch(opt) {
142c5f9ac7eSStefano Ceccherini case 'a':
143c5f9ac7eSStefano Ceccherini o_all_volumes = true;
144c5f9ac7eSStefano Ceccherini break;
145c5f9ac7eSStefano Ceccherini
146c5f9ac7eSStefano Ceccherini case 'e':
147c5f9ac7eSStefano Ceccherini o_escaping = false;
148c5f9ac7eSStefano Ceccherini break;
149c5f9ac7eSStefano Ceccherini
150c5f9ac7eSStefano Ceccherini case 'v':
151c5f9ac7eSStefano Ceccherini strncpy(volumePath, optarg, B_FILE_NAME_LENGTH);
152c5f9ac7eSStefano Ceccherini break;
153c5f9ac7eSStefano Ceccherini
154c5f9ac7eSStefano Ceccherini case 'p':
155c5f9ac7eSStefano Ceccherini strncpy(directoryPath, optarg, B_PATH_NAME_LENGTH);
156c5f9ac7eSStefano Ceccherini break;
157c5f9ac7eSStefano Ceccherini
158c5f9ac7eSStefano Ceccherini case 's':
159c5f9ac7eSStefano Ceccherini o_subfolders = true;
160c5f9ac7eSStefano Ceccherini break;
161c5f9ac7eSStefano Ceccherini
162c5f9ac7eSStefano Ceccherini default:
163c5f9ac7eSStefano Ceccherini usage();
164c5f9ac7eSStefano Ceccherini break;
165c5f9ac7eSStefano Ceccherini }
166c5f9ac7eSStefano Ceccherini }
167c5f9ac7eSStefano Ceccherini
168c5f9ac7eSStefano Ceccherini BVolume volume;
169c5f9ac7eSStefano Ceccherini
170c5f9ac7eSStefano Ceccherini if (!o_all_volumes) {
171c5f9ac7eSStefano Ceccherini // Find the volume that the query should be performed on,
172c5f9ac7eSStefano Ceccherini // and set the query to it.
173c5f9ac7eSStefano Ceccherini BEntry entry(volumePath);
174c5f9ac7eSStefano Ceccherini if (entry.InitCheck() != B_OK) {
175c5f9ac7eSStefano Ceccherini printf("query: %s is not a valid file\n", volumePath);
176c5f9ac7eSStefano Ceccherini exit(1);
177c5f9ac7eSStefano Ceccherini }
178c5f9ac7eSStefano Ceccherini
179c5f9ac7eSStefano Ceccherini status_t status = entry.GetVolume(&volume);
180c5f9ac7eSStefano Ceccherini if (status != B_OK) {
181c5f9ac7eSStefano Ceccherini fprintf(stderr, "%s: could not get volume: %s\n", __progname, strerror(status));
182c5f9ac7eSStefano Ceccherini exit(1);
183c5f9ac7eSStefano Ceccherini }
184c5f9ac7eSStefano Ceccherini
185c5f9ac7eSStefano Ceccherini if (!volume.KnowsQuery())
186c5f9ac7eSStefano Ceccherini printf("query: volume containing %s is not query-enabled\n", volumePath);
187c5f9ac7eSStefano Ceccherini else
188c5f9ac7eSStefano Ceccherini perform_query(volume, argv[optind], directoryPath);
189c5f9ac7eSStefano Ceccherini } else {
190c5f9ac7eSStefano Ceccherini // Okay, we want to query all the disks -- so iterate over
191c5f9ac7eSStefano Ceccherini // them, one by one, running the query.
192c5f9ac7eSStefano Ceccherini BVolumeRoster volumeRoster;
193c5f9ac7eSStefano Ceccherini while (volumeRoster.GetNextVolume(&volume) == B_OK) {
194c5f9ac7eSStefano Ceccherini // We don't print errors here -- this will catch /pipe and
195c5f9ac7eSStefano Ceccherini // other filesystems we don't care about.
196c5f9ac7eSStefano Ceccherini if (volume.KnowsQuery())
197c5f9ac7eSStefano Ceccherini perform_query(volume, argv[optind], directoryPath);
198c5f9ac7eSStefano Ceccherini }
199c5f9ac7eSStefano Ceccherini }
200c5f9ac7eSStefano Ceccherini
201c5f9ac7eSStefano Ceccherini return 0;
202c5f9ac7eSStefano Ceccherini }
203