1 /* cmd-inventory.c: file inventories
2 *
3 ****************************************************************
4 * Copyright (C) 2002, 2003 Tom Lord
5 *
6 * See the file "COPYING" for further information about
7 * the copyright and warranty status of this work.
8 */
9
10
11 #include "config-options.h"
12 #include "hackerlab/cmd/main.h"
13 #include "hackerlab/vu/safe.h"
14 #include "hackerlab/char/pika-escaping-utils.h"
15 #include "tla/libarch/project-tree.h"
16 #include "tla/libarch/invent.h"
17 #include "tla/libarch/cmd.h"
18 #include "tla/libarch/cmd-inventory.h"
19
20 #include "hackerlab/os/errno-to-string.h"
21
22
23 static t_uchar * usage = "[options] [--] [dir]*";
24 static t_uchar * version_string = (cfg__std__package " from regexps.com\n"
25 "\n"
26 "Copyright 2002 Tom Lord\n"
27 "\n"
28 "This is free software; see the source for copying conditions.\n"
29 "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n"
30 "PARTICULAR PURPOSE.\n"
31 "\n"
32 "Report bugs to " cfg__tla_bug_mail ".\n"
33 "\n"
34 cfg__std__release_id_string
35 "\n");
36
37 #define OPTS(OP) \
38 OP (opt_help_msg, "h", "help", 0, \
39 "display help") \
40 OP (opt_long_help, "H", 0, 0, \
41 "Display a verbose help message and exit.") \
42 OP (opt_version, "V", "version", 0, \
43 "display version info\n") \
44 OP (opt_source, "s", "source", 0, \
45 "list source files") \
46 OP (opt_precious, "p", "precious", 0, \
47 "list precious files") \
48 OP (opt_backups, "b", "backups", 0, \
49 "list backup files") \
50 OP (opt_junk, "j", "junk", 0, \
51 "list junk files") \
52 OP (opt_unrecognized, "u", "unrecognized", 0, \
53 "list unrecognized files") \
54 OP (opt_trees, "t", "trees", 0, \
55 "list roots of nested trees\n") \
56 OP (opt_directories, "d", "directories", 0, \
57 "list only directories") \
58 OP (opt_files, "f", "files", 0, \
59 "list only non-directories") \
60 OP (opt_both, "B", "both", 0, \
61 "list both dirs and files") \
62 OP (opt_kind, 0, "kind", 0, \
63 "indicate file kinds\n") \
64 OP (opt_all, 0, "all", 0, \
65 "include arch control files") \
66 OP (opt_nested, 0, "nested", 0, \
67 "include nested trees\n") \
68 OP (opt_ids, 0, "ids", 0, \
69 "list with ids (source files only)") \
70 OP (opt_untagged, 0, "untagged", 0, \
71 "include files that are missing ids\n") \
72 OP (opt_explicit, 0, "explicit", 0, \
73 "use explicit file ids") \
74 OP (opt_implicit, 0, "implicit", 0, \
75 "permit implicit file ids") \
76 OP (opt_tagline, 0, "tagline", 0, \
77 "permit tagline file ids") \
78 OP (opt_names, 0, "names", 0, \
79 "use name-based file ids") \
80 OP (opt_unescaped, 0, "unescaped", 0, \
81 "show filenames in unescaped form")
82
83
84 t_uchar arch_cmd_inventory_help[] = ("inventory a source tree\n"
85 "With no arguments, print a human-readable inventory report.\n"
86 "\n"
87 "With category options (--source etc) limit the report to just\n"
88 "those files. With no other options, the report includes all\n"
89 "sections and files.\n"
90 "\n"
91 "The options -d, -f, and -B cancel each other.\n"
92 "\n"
93 "If a directory is precious, junk, or unrecognized, only the\n"
94 "directory name itself is printed -- its contents are not\n"
95 "searched.\n"
96 "\n"
97 "Each command option implies the corresponding category option\n"
98 "(e.g. \"--source-command\" implies \"--source\"). The exit\n"
99 "status of the command is ignored.\n");
100
101 enum options
102 {
103 OPTS (OPT_ENUM)
104 };
105
106 static struct opt_desc opts[] =
107 {
108 OPTS (OPT_DESC)
109 {-1, 0, 0, 0, 0}
110 };
111
112
113 /* __STDC__ prototypes for static functions */
114 static void inventory_printer (const t_uchar * path,
115 struct stat * stat_buf,
116 enum arch_inventory_category category,
117 const t_uchar * id,
118 int has_source_name,
119 void * closure,
120 int escape_classes);
121
122
123
124 static int show_dirs = 0;
125 static int show_files = 1;
126 static int show_kind = 0;
127 static int show_ids;
128
129 static int n_categories = 0;
130
131 int
arch_cmd_inventory(t_uchar * program_name,int argc,char * argv[])132 arch_cmd_inventory (t_uchar * program_name, int argc, char * argv[])
133 {
134 int o;
135 struct opt_parsed * option;
136 struct arch_inventory_options inv_options;
137 int escape_classes = arch_escape_classes;
138
139 option = 0;
140 mem_set0 ((t_uchar *)&inv_options, sizeof (inv_options));
141
142 while (1)
143 {
144 o = opt_standard (lim_use_must_malloc, &option, opts, &argc, argv,
145 program_name, usage, version_string, arch_cmd_inventory_help,
146 opt_help_msg, opt_long_help, opt_version);
147 if (o == opt_none)
148 break;
149 switch (o)
150 {
151 default:
152 safe_printfmt (2, "unhandled option `%s'\n", option->opt_string);
153 panic ("internal error parsing arguments");
154
155 usage_error:
156 opt_usage (2, argv[0], program_name, usage, 1);
157 exit (1);
158
159 /* bogus_arg: */
160 safe_printfmt (2, "ill-formed argument for `%s' (`%s')\n", option->opt_string, option->arg_string);
161 goto usage_error;
162
163 case opt_source:
164 inv_options.categories |= arch_inventory_source;
165 break;
166
167 case opt_precious:
168 inv_options.categories |= arch_inventory_precious;
169 break;
170
171 case opt_backups:
172 inv_options.categories |= arch_inventory_backup;
173 break;
174
175 case opt_junk:
176 inv_options.categories |= arch_inventory_junk;
177 break;
178
179 case opt_unrecognized:
180 inv_options.categories |= arch_inventory_unrecognized;
181 break;
182
183 case opt_trees:
184 inv_options.categories |= arch_inventory_tree;
185 break;
186
187 case opt_directories:
188 show_dirs = 1;
189 show_files = 0;
190 break;
191
192 case opt_files:
193 show_dirs = 0;
194 show_files = 1;
195 break;
196
197 case opt_both:
198 show_dirs = 1;
199 show_files = 1;
200 break;
201
202 case opt_kind:
203 show_kind = 1;
204 break;
205
206 case opt_all:
207 inv_options.include_excluded = 1;
208 break;
209
210 case opt_nested:
211 inv_options.nested = 1;
212 break;
213
214 case opt_ids:
215 inv_options.want_ids = 1;
216 show_ids = 1;
217 break;
218
219 case opt_untagged:
220 inv_options.treat_unrecognized_source_as_source = 1;
221 break;
222
223 case opt_explicit:
224 inv_options.override_method = 1;
225 inv_options.method = arch_explicit_id_tagging;
226 break;
227
228 case opt_implicit:
229 inv_options.override_method = 1;
230 inv_options.method = arch_implicit_id_tagging;
231 break;
232
233 case opt_tagline:
234 inv_options.override_method = 1;
235 inv_options.method = arch_tagline_id_tagging;
236 break;
237
238 case opt_names:
239 inv_options.override_method = 1;
240 inv_options.method = arch_names_id_tagging;
241 break;
242
243 case opt_unescaped:
244 escape_classes = 0;
245 break;
246 }
247 }
248
249 n_categories = 0;
250 if (inv_options.categories & arch_inventory_source)
251 ++n_categories;
252
253 if (inv_options.categories & arch_inventory_precious)
254 ++n_categories;
255
256 if (inv_options.categories & arch_inventory_backup)
257 ++n_categories;
258
259 if (inv_options.categories & arch_inventory_junk)
260 ++n_categories;
261
262 if (inv_options.categories & arch_inventory_tree)
263 ++n_categories;
264
265 if (inv_options.categories & arch_inventory_unrecognized)
266 ++n_categories;
267
268 if (!n_categories)
269 {
270 n_categories = 6;
271 inv_options.categories = arch_inventory_source | arch_inventory_precious | arch_inventory_backup | arch_inventory_tree | arch_inventory_unrecognized;
272 }
273
274 if (argc == 1)
275 {
276 argv[1] = ".";
277 ++argc;
278 }
279
280 {
281 int x;
282 int errn;
283 int re_error;
284
285 for (x = 1; x < argc; ++x)
286 {
287 t_uchar * tree_root;
288 char * bad_file;
289 errn = 0;
290 re_error = 0;
291
292 if ( vu_access(&errn, argv[x], X_OK | F_OK ) == -1)
293 {
294 safe_printfmt (2, "inventory: Cannot access directory %s\n%s\n", argv[x], errno_to_string(errn));
295 exit (2);
296 }
297 tree_root = arch_tree_root (0, argv[x], 0);
298 arch_get_inventory_naming_conventions (&inv_options, tree_root);
299
300 bad_file = 0;
301 arch_inventory_traversal (&inv_options, argv[x], inventory_printer, 0, escape_classes);
302 arch_free_inventory_naming_conventions (&inv_options);
303 lim_free (0, tree_root);
304 }
305 }
306 return 0;
307 }
308
309
310
311 static void
inventory_printer(const t_uchar * path,struct stat * stat_buf,enum arch_inventory_category category,const t_uchar * id,int has_source_name,void * closure,int escape_classes)312 inventory_printer (const t_uchar * path,
313 struct stat * stat_buf,
314 enum arch_inventory_category category,
315 const t_uchar * id,
316 int has_source_name,
317 void * closure,
318 int escape_classes)
319 {
320 if ((category != arch_inventory_tree) && !show_dirs && S_ISDIR (stat_buf->st_mode))
321 return;
322
323 if (!show_files && !S_ISDIR (stat_buf->st_mode))
324 return;
325
326 if (n_categories > 1)
327 {
328 t_uchar * quest = (has_source_name ? "?" : " ");
329
330 switch (category)
331 {
332 case arch_inventory_source:
333 safe_printfmt (1, "S ");
334 break;
335 case arch_inventory_precious:
336 safe_printfmt (1, "P%s ", quest);
337 break;
338 case arch_inventory_backup:
339 safe_printfmt (1, "B%s ", quest);
340 break;
341 case arch_inventory_junk:
342 safe_printfmt (1, "J%s ", quest);
343 break;
344 case arch_inventory_tree:
345 safe_printfmt (1, "T%s ", quest);
346 break;
347 case arch_inventory_unrecognized:
348 safe_printfmt (1, "U%s ", quest);
349 break;
350 case arch_inventory_excludes:
351 break;
352 }
353 }
354
355 if (show_kind)
356 {
357 if (S_ISDIR (stat_buf->st_mode))
358 safe_printfmt (1, "d ");
359 else if (S_ISLNK (stat_buf->st_mode))
360 safe_printfmt (1, "> ");
361 else
362 safe_printfmt (1, "r ");
363 }
364
365 if (path[0] == '.' && path[1] == '/')
366 path += 2;
367
368 {
369 t_uchar * item;
370 item = pika_save_escape_iso8859_1 (0, 0, escape_classes, path);
371
372 safe_printfmt (1, "%s%s%s\n", item, (show_ids ? "\t" : ""), (show_ids ? (id ? (char *)id : "???") : ""));
373
374 lim_free (0, item);
375 }
376 }
377
378
379
380 /* tag: Tom Lord Wed May 14 10:52:12 2003 (srcfind.c)
381 */
382