1 /* 2 * Copyright 2005, Haiku Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 * Ficus Kirkpatrick (ficus@ior.com) 7 * Jérôme Duval 8 * Axel Dörfler, axeld@pinc-software.de 9 */ 10 11 /* A shell utility for somewhat emulating the Tracker's "Find By Formula" 12 * functionality. 13 */ 14 15 16 #include <Entry.h> 17 #include <LocaleRoster.h> 18 #include <Path.h> 19 #include <Query.h> 20 #include <String.h> 21 #include <Volume.h> 22 #include <VolumeRoster.h> 23 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <unistd.h> 28 29 30 extern const char *__progname; 31 static const char *kProgramName = __progname; 32 33 // Option variables. 34 static bool sAllVolumes = false; // Query all volumes? 35 static bool sEscapeMetaChars = true; // Escape metacharacters? 36 static bool sFilesOnly = false; // Show only files? 37 static bool sLocalizedAppNames = false; // match localized names 38 39 40 void 41 usage(void) 42 { 43 printf("usage: %s [ -ef ] [ -a || -v <path-to-volume> ] expression\n" 44 " -e\t\tdon't escape meta-characters\n" 45 " -f\t\tshow only files (ie. no directories or symbolic links)\n" 46 " -l\t\tmatch expression with localized application names\n" 47 " -a\t\tperform the query on all volumes\n" 48 " -v <file>\tperform the query on just one volume; <file> can be any\n" 49 "\t\tfile on that volume. Defaults to the current volume.\n" 50 " Hint: '%s name=foo' will find files named \"foo\"\n", 51 kProgramName, kProgramName); 52 exit(0); 53 } 54 55 56 void 57 perform_query(BVolume &volume, const char *predicate) 58 { 59 BQuery query; 60 query.SetVolume(&volume); 61 62 if (sLocalizedAppNames) 63 query.SetPredicate("BEOS:APP_SIG=*"); 64 else 65 query.SetPredicate(predicate); 66 67 status_t status = query.Fetch(); 68 if (status == B_BAD_VALUE) { 69 // the "name=" part may be omitted in our arguments 70 BString string = "name="; 71 string << predicate; 72 73 query.SetPredicate(string.String()); 74 status = query.Fetch(); 75 } 76 if (status != B_OK) { 77 fprintf(stderr, "%s: bad query expression\n", kProgramName); 78 return; 79 } 80 81 BEntry entry; 82 BPath path; 83 while (query.GetNextEntry(&entry) == B_OK) { 84 if (sFilesOnly && !entry.IsFile()) 85 continue; 86 87 if (entry.GetPath(&path) < B_OK) { 88 fprintf(stderr, "%s: could not get path for entry\n", kProgramName); 89 continue; 90 } 91 92 BString string; 93 if (sLocalizedAppNames && predicate != NULL) { 94 entry_ref ref; 95 96 if (entry.GetRef(&ref) != B_OK || BLocaleRoster::Default() 97 ->GetLocalizedFileName(string, ref) != B_OK) 98 continue; 99 100 if (string.IFindFirst(predicate) < 0) 101 continue; 102 } 103 104 string = path.Path(); 105 if (sEscapeMetaChars) 106 string.CharacterEscape(" ()?*&\"'[]^\\~|;!<>*$\t", '\\'); 107 108 printf("%s\n", string.String()); 109 } 110 } 111 112 113 int 114 main(int argc, char **argv) 115 { 116 // Make sure we have the minimum number of arguments. 117 if (argc < 2) 118 usage(); 119 120 // Which volume do we make the query on? 121 // Default to the current volume. 122 char volumePath[B_FILE_NAME_LENGTH]; 123 strcpy(volumePath, "."); 124 125 // Parse command-line arguments. 126 int opt; 127 while ((opt = getopt(argc, argv, "efalv:")) != -1) { 128 switch(opt) { 129 case 'e': 130 sEscapeMetaChars = false; 131 break; 132 case 'f': 133 sFilesOnly = true; 134 break; 135 case 'a': 136 sAllVolumes = true; 137 break; 138 case 'l': 139 sLocalizedAppNames = true; 140 break; 141 case 'v': 142 strlcpy(volumePath, optarg, B_FILE_NAME_LENGTH); 143 break; 144 145 default: 146 usage(); 147 break; 148 } 149 } 150 151 BVolume volume; 152 153 if (!sAllVolumes) { 154 // Find the volume that the query should be performed on, 155 // and set the query to it. 156 BEntry entry(volumePath); 157 if (entry.InitCheck() != B_OK) { 158 fprintf(stderr, "%s: \"%s\" is not a valid file\n", kProgramName, volumePath); 159 exit(1); 160 } 161 162 status_t status = entry.GetVolume(&volume); 163 if (status != B_OK) { 164 fprintf(stderr, "%s: could not get volume: %s\n", kProgramName, strerror(status)); 165 exit(1); 166 } 167 168 if (!volume.KnowsQuery()) 169 fprintf(stderr, "%s: volume containing %s is not query-enabled\n", kProgramName, volumePath); 170 else 171 perform_query(volume, argv[optind]); 172 } else { 173 // Okay, we want to query all the disks -- so iterate over 174 // them, one by one, running the query. 175 BVolumeRoster volumeRoster; 176 while (volumeRoster.GetNextVolume(&volume) == B_OK) { 177 // We don't print errors here -- this will catch /pipe and 178 // other filesystems we don't care about. 179 if (volume.KnowsQuery()) 180 perform_query(volume, argv[optind]); 181 } 182 } 183 184 return 0; 185 } 186