xref: /haiku/src/bin/filteredquery/query.cpp (revision 2435c1bd28d6ed19c2acf1e45f356e779495784b)
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