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