BRL-CAD
ls.c
Go to the documentation of this file.
1 /* L S . C
2  * BRL-CAD
3  *
4  * Copyright (c) 2008-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 /** @file libged/ls.c
21  *
22  * The ls command.
23  *
24  */
25 
26 #include "common.h"
27 
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include "bu/cmd.h"
32 #include "bu/getopt.h"
33 #include "bu/sort.h"
34 
35 #include "./ged_private.h"
36 
37 
38 #define RT_TERMINAL_WIDTH 80
39 #define RT_COLUMNS ((RT_TERMINAL_WIDTH + V4_MAXNAME - 1) / V4_MAXNAME)
40 
41 
42 /**
43  * This routine walks through the directory entry list and mallocs
44  * enough space for pointers to hold the number of entries specified
45  * by the argument if > 0.
46  *
47  */
48 struct directory **
49 _ged_getspace(struct db_i *dbip,
50  size_t num_entries)
51 {
52  struct directory **dir_basep;
53 
54  if (num_entries == 0)
55  num_entries = db_directory_size(dbip);
56 
57  /* Allocate and cast num_entries worth of pointers */
58  dir_basep = (struct directory **) bu_calloc((num_entries+1), sizeof(struct directory *), "_ged_getspace *dir[]");
59  return dir_basep;
60 }
61 
62 
63 /**
64  * Given two pointers to pointers to directory entries, do a string
65  * compare on the respective names and return that value.
66  */
67 static int
68 cmpdirname(const void *a, const void *b, void *UNUSED(arg))
69 {
70  struct directory **dp1, **dp2;
71 
72  dp1 = (struct directory **)a;
73  dp2 = (struct directory **)b;
74  return bu_strcmp((*dp1)->d_namep, (*dp2)->d_namep);
75 }
76 
77 
78 /**
79  * Given a pointer to a list of pointers to names and the number of
80  * names in that list, sort and print that list in column order over
81  * four columns.
82  */
83 void
85  struct directory **list_of_names,
86  size_t num_in_list,
87  int no_decorate)
88 {
89  size_t lines, i, j, k, this_one;
90  size_t namelen;
91  size_t maxnamelen; /* longest name in list */
92  size_t cwidth; /* column width */
93  size_t numcol; /* number of columns */
94 
95  bu_sort((void *)list_of_names,
96  (unsigned)num_in_list, (unsigned)sizeof(struct directory *),
97  cmpdirname, NULL);
98 
99  /*
100  * Traverse the list of names, find the longest name and set the
101  * the column width and number of columns accordingly. If the
102  * longest name is greater than 80 characters, the number of
103  * columns will be one.
104  */
105  maxnamelen = 0;
106  for (k = 0; k < num_in_list; k++) {
107  namelen = strlen(list_of_names[k]->d_namep);
108  if (namelen > maxnamelen)
109  maxnamelen = namelen;
110  }
111 
112  if (maxnamelen <= 16)
113  maxnamelen = 16;
114  cwidth = maxnamelen + 4;
115 
116  if (cwidth > 80)
117  cwidth = 80;
118  numcol = RT_TERMINAL_WIDTH / cwidth;
119 
120  /*
121  * For the number of (full and partial) lines that will be needed,
122  * print in vertical format.
123  */
124  lines = (num_in_list + (numcol - 1)) / numcol;
125  for (i = 0; i < lines; i++) {
126  for (j = 0; j < numcol; j++) {
127  this_one = j * lines + i;
128  bu_vls_printf(vls, "%s", list_of_names[this_one]->d_namep);
129  namelen = strlen(list_of_names[this_one]->d_namep);
130 
131  /*
132  * Region and ident checks here.... Since the code has
133  * been modified to push and sort on pointers, the
134  * printing of the region and ident flags must be delayed
135  * until now. There is no way to make the decision on
136  * where to place them before now.
137  */
138  if (!no_decorate && list_of_names[this_one]->d_flags & RT_DIR_COMB) {
139  bu_vls_putc(vls, '/');
140  namelen++;
141  }
142 
143  if (!no_decorate && list_of_names[this_one]->d_flags & RT_DIR_REGION) {
144  bu_vls_putc(vls, 'R');
145  namelen++;
146  }
147 
148  /*
149  * Size check (partial lines), and line termination. Note
150  * that this will catch the end of the lines that are full
151  * too.
152  */
153  if (this_one + lines >= num_in_list) {
154  bu_vls_putc(vls, '\n');
155  break;
156  } else {
157  /*
158  * Pad to next boundary as there will be another entry
159  * to the right of this one.
160  */
161  while (namelen++ < cwidth)
162  bu_vls_putc(vls, ' ');
163  }
164  }
165  }
166 }
167 
168 
169 static void
170 vls_long_dpp(struct ged *gedp,
171  struct directory **list_of_names,
172  int num_in_list,
173  int aflag, /* print all objects */
174  int cflag, /* print combinations */
175  int rflag, /* print regions */
176  int sflag) /* print solids */
177 {
178  int i;
179  int isComb=0, isRegion=0;
180  int isSolid=0;
181  const char *type=NULL;
182  size_t max_nam_len = 0;
183  size_t max_type_len = 0;
184  struct directory *dp;
185 
186  bu_sort((void *)list_of_names,
187  (unsigned)num_in_list, (unsigned)sizeof(struct directory *),
188  cmpdirname, NULL);
189 
190  for (i = 0; i < num_in_list; i++) {
191  size_t len;
192 
193  dp = list_of_names[i];
194  len = strlen(dp->d_namep);
195  if (len > max_nam_len)
196  max_nam_len = len;
197 
198  if (dp->d_flags & RT_DIR_REGION)
199  len = 6; /* "region" */
200  else if (dp->d_flags & RT_DIR_COMB)
201  len = 4; /* "comb" */
202  else if (dp->d_flags & RT_DIR_SOLID) {
203  struct rt_db_internal intern;
204  len = 9; /* "primitive" */
205  if (rt_db_get_internal(&intern, dp, gedp->ged_wdbp->dbip, (fastf_t *)NULL, &rt_uniresource) >= 0) {
206  len = strlen(intern.idb_meth->ft_label);
207  rt_db_free_internal(&intern);
208  }
209  } else {
210  switch (list_of_names[i]->d_major_type) {
211  case DB5_MAJORTYPE_ATTRIBUTE_ONLY:
212  len = 6;
213  break;
214  case DB5_MAJORTYPE_BINARY_MIME:
215  len = strlen("binary (mime)");
216  break;
217  case DB5_MAJORTYPE_BINARY_UNIF:
218  len = strlen(binu_types[list_of_names[i]->d_minor_type]);
219  break;
220  }
221  }
222 
223  if (len > max_type_len)
224  max_type_len = len;
225  }
226 
227  /*
228  * i - tracks the list item
229  */
230  for (i = 0; i < num_in_list; ++i) {
231  dp = list_of_names[i];
232 
233  if (dp->d_flags & RT_DIR_COMB) {
234  isComb = 1;
235  isSolid = 0;
236  type = "comb";
237 
238  if (dp->d_flags & RT_DIR_REGION) {
239  isRegion = 1;
240  type = "region";
241  } else
242  isRegion = 0;
243  } else if (dp->d_flags & RT_DIR_SOLID) {
244  struct rt_db_internal intern;
245  type = "primitive";
246  if (rt_db_get_internal(&intern, dp, gedp->ged_wdbp->dbip, (fastf_t *)NULL, &rt_uniresource) >= 0) {
247  type = intern.idb_meth->ft_label;
248  rt_db_free_internal(&intern);
249  }
250  isComb = isRegion = 0;
251  isSolid = 1;
252  } else {
253  switch (dp->d_major_type) {
254  case DB5_MAJORTYPE_ATTRIBUTE_ONLY:
255  isSolid = 0;
256  type = "global";
257  break;
258  case DB5_MAJORTYPE_BINARY_MIME:
259  isSolid = 0;
260  isRegion = 0;
261  type = "binary(mime)";
262  break;
263  case DB5_MAJORTYPE_BINARY_UNIF:
264  isSolid = 0;
265  isRegion = 0;
266  type = binu_types[dp->d_minor_type];
267  break;
268  }
269  }
270 
271  /* print list item i */
272  if (aflag ||
273  (!cflag && !rflag && !sflag) ||
274  (cflag && isComb) ||
275  (rflag && isRegion) ||
276  (sflag && isSolid)) {
277  bu_vls_printf(gedp->ged_result_str, "%s", dp->d_namep);
278  bu_vls_spaces(gedp->ged_result_str, (int)(max_nam_len - strlen(dp->d_namep)));
279  bu_vls_printf(gedp->ged_result_str, " %s", type);
280  if (type)
281  bu_vls_spaces(gedp->ged_result_str, (int)(max_type_len - strlen(type)));
282  bu_vls_printf(gedp->ged_result_str, " %2d %2d %ld\n",
283  dp->d_major_type, dp->d_minor_type, (long)(dp->d_len));
284  }
285  }
286 }
287 
288 
289 /**
290  * Given a pointer to a list of pointers to names and the number of names
291  * in that list, sort and print that list on the same line.
292  */
293 static void
294 vls_line_dpp(struct ged *gedp,
295  struct directory **list_of_names,
296  int num_in_list,
297  int aflag, /* print all objects */
298  int cflag, /* print combinations */
299  int rflag, /* print regions */
300  int sflag) /* print solids */
301 {
302  int i;
303  int isComb, isRegion;
304  int isSolid;
305 
306  bu_sort((void *)list_of_names,
307  (unsigned)num_in_list, (unsigned)sizeof(struct directory *),
308  cmpdirname, NULL);
309 
310  /*
311  * i - tracks the list item
312  */
313  for (i = 0; i < num_in_list; ++i) {
314  if (list_of_names[i]->d_flags & RT_DIR_COMB) {
315  isComb = 1;
316  isSolid = 0;
317 
318  if (list_of_names[i]->d_flags & RT_DIR_REGION)
319  isRegion = 1;
320  else
321  isRegion = 0;
322  } else {
323  isComb = isRegion = 0;
324  isSolid = 1;
325  }
326 
327  /* print list item i */
328  if (aflag ||
329  (!cflag && !rflag && !sflag) ||
330  (cflag && isComb) ||
331  (rflag && isRegion) ||
332  (sflag && isSolid)) {
333  bu_vls_printf(gedp->ged_result_str, "%s ", list_of_names[i]->d_namep);
334  _ged_results_add(gedp->ged_results, list_of_names[i]->d_namep);
335  }
336  }
337 }
338 
339 
340 /**
341  * List objects in this database
342  */
343 int
344 ged_ls(struct ged *gedp, int argc, const char *argv[])
345 {
346  struct directory *dp;
347  size_t i;
348  int c;
349  int aflag = 0; /* print all objects without formatting */
350  int cflag = 0; /* print combinations */
351  int rflag = 0; /* print regions */
352  int sflag = 0; /* print solids */
353  int lflag = 0; /* use long format */
354  int qflag = 0; /* quiet flag - do a quiet lookup */
355  int attr_flag = 0; /* arguments are attribute name/value pairs */
356  int or_flag = 0; /* flag indicating that any one attribute match is sufficient
357  * default is all attributes must match.
358  */
359  struct directory **dirp;
360  struct directory **dirp0 = (struct directory **)NULL;
361  static const char *usage = "[-A name/value pairs] OR [-acrslopq] object(s)";
362 
364  GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);
365 
366  /* initialize result */
367  bu_vls_trunc(gedp->ged_result_str, 0);
369 
370  bu_optind = 1; /* re-init bu_getopt() */
371  while ((c = bu_getopt(argc, (char * const *)argv, "acrslopqA")) != -1) {
372  switch (c) {
373  case 'A':
374  attr_flag = 1;
375  break;
376  case 'o':
377  or_flag = 1;
378  break;
379  case 'a':
380  aflag = 1;
381  break;
382  case 'c':
383  cflag = 1;
384  break;
385  case 'q':
386  qflag = 1;
387  break;
388  case 'r':
389  rflag = 1;
390  break;
391  case 's':
392  case 'p':
393  sflag = 1;
394  break;
395  case 'l':
396  lflag = 1;
397  break;
398  default:
399  bu_vls_printf(gedp->ged_result_str, "Unrecognized option - %c", c);
401  return GED_ERROR;
402  }
403  }
404  /* skip options processed plus command name */
405  argc -= bu_optind;
406  argv += bu_optind;
407 
408  /* create list of selected objects from database */
409  if (attr_flag) {
410  /* select objects based on attributes */
411  struct bu_ptbl *tbl;
412  struct bu_attribute_value_set avs;
413  int dir_flags;
414  int op;
415  if ((argc < 2) || (argc%2 != 0)) {
416  /* should be even number of name/value pairs */
417  bu_log("ls -A option expects even number of 'name value' pairs\n");
418  bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage);
420  return TCL_ERROR;
421  }
422 
423  if (or_flag) {
424  op = 2;
425  } else {
426  op = 1;
427  }
428 
429  dir_flags = 0;
430  if (aflag) dir_flags = -1;
431  if (cflag) dir_flags = RT_DIR_COMB;
432  if (sflag) dir_flags = RT_DIR_SOLID;
433  if (rflag) dir_flags = RT_DIR_REGION;
434  if (!dir_flags) dir_flags = -1 ^ RT_DIR_HIDDEN;
435 
436  bu_avs_init(&avs, argc, "wdb_ls_cmd avs");
437  for (i = 0; i < (size_t)argc; i += 2) {
438  if (or_flag) {
439  bu_avs_add_nonunique(&avs, (char *)argv[i], (char *)argv[i+1]);
440  } else {
441  bu_avs_add(&avs, (char *)argv[i], (char *)argv[i+1]);
442  }
443  }
444 
445  tbl = db_lookup_by_attr(gedp->ged_wdbp->dbip, dir_flags, &avs, op);
446  bu_avs_free(&avs);
447 
448  dirp = _ged_getspace(gedp->ged_wdbp->dbip, BU_PTBL_LEN(tbl));
449  dirp0 = dirp;
450  for (i = 0; i < BU_PTBL_LEN(tbl); i++) {
451  *dirp++ = (struct directory *)BU_PTBL_GET(tbl, i);
452  }
453 
454  bu_ptbl_free(tbl);
455  bu_free((char *)tbl, "wdb_ls_cmd ptbl");
456  } else if (argc > 0) {
457  /* Just list specified names */
458  dirp = _ged_getspace(gedp->ged_wdbp->dbip, argc);
459  dirp0 = dirp;
460  /*
461  * Verify the names, and add pointers to them to the array.
462  */
463  for (i = 0; i < (size_t)argc; i++) {
464  if (qflag) {
465  dp = db_lookup(gedp->ged_wdbp->dbip, argv[i], LOOKUP_QUIET);
466  } else {
467  dp = db_lookup(gedp->ged_wdbp->dbip, argv[i], LOOKUP_NOISY);
468  }
469  if (dp == RT_DIR_NULL)
470  continue;
471  *dirp++ = dp;
472  }
473  } else {
474  /* Full table of contents */
475  dirp = _ged_getspace(gedp->ged_wdbp->dbip, 0); /* Enough for all */
476  dirp0 = dirp;
477  /*
478  * Walk the directory list adding pointers (to the directory
479  * entries) to the array.
480  */
481  for (i = 0; i < RT_DBNHASH; i++)
482  for (dp = gedp->ged_wdbp->dbip->dbi_Head[i]; dp != RT_DIR_NULL; dp = dp->d_forw) {
483  if (!aflag && (dp->d_flags & RT_DIR_HIDDEN))
484  continue;
485  *dirp++ = dp;
486  }
487  }
488 
489  if (lflag)
490  vls_long_dpp(gedp, dirp0, (int)(dirp - dirp0), aflag, cflag, rflag, sflag);
491  else if (aflag || cflag || rflag || sflag)
492  vls_line_dpp(gedp, dirp0, (int)(dirp - dirp0), aflag, cflag, rflag, sflag);
493  else {
494  _ged_vls_col_pr4v(gedp->ged_result_str, dirp0, (int)(dirp - dirp0), 0);
496  }
497 
498  bu_free((void *)dirp0, "_ged_getspace dp[]");
499 
500  return GED_OK;
501 }
502 
503 
504 /*
505  * Local Variables:
506  * tab-width: 8
507  * mode: C
508  * indent-tabs-mode: t
509  * c-file-style: "stroustrup"
510  * End:
511  * ex: shiftwidth=4 tabstop=8
512  */
void usage(struct ged *gedp)
Definition: coil.c:315
#define GED_OK
Definition: ged.h:55
char * d_namep
pointer to name string
Definition: raytrace.h:859
Definition: raytrace.h:800
unsigned char d_major_type
object major type
Definition: raytrace.h:870
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
int rt_db_get_internal(struct rt_db_internal *ip, const struct directory *dp, const struct db_i *dbip, const mat_t mat, struct resource *resp)
Definition: dir.c:76
#define RT_DBNHASH
hash table is an array of linked lists with this many array pointer elements (Memory use for 32-bit: ...
Definition: raytrace.h:755
size_t d_len
of db granules used
Definition: raytrace.h:867
struct directory ** _ged_getspace(struct db_i *dbip, size_t num_entries)
Definition: ls.c:49
Definition: ged.h:338
struct db_i * dbip
Definition: raytrace.h:1266
void _ged_vls_col_pr4v(struct bu_vls *vls, struct directory **list_of_names, size_t num_in_list, int no_decorate)
Definition: ls.c:84
int bu_avs_add(struct bu_attribute_value_set *avp, const char *attribute, const char *value)
Definition: avs.c:78
int ged_ls(struct ged *gedp, int argc, const char *argv[])
Definition: ls.c:344
void bu_vls_trunc(struct bu_vls *vp, int len)
Definition: vls.c:198
#define GED_CHECK_ARGC_GT_0(_gedp, _argc, _flags)
Definition: ged.h:202
struct directory * db_lookup(const struct db_i *, const char *name, int noisy)
Definition: db_lookup.c:153
struct rt_wdb * ged_wdbp
Definition: ged.h:340
Header file for the BRL-CAD common definitions.
int bu_optind
Definition: globals.c:89
const char * binu_types[]
Definition: globals.c:55
#define RT_DIR_REGION
region
Definition: raytrace.h:885
struct directory * d_forw
link to next dir entry
Definition: raytrace.h:864
int bu_getopt(int nargc, char *const nargv[], const char *ostr)
Definition: getopt.c:43
char ft_label[9]
Definition: raytrace.h:2044
#define GED_ERROR
Definition: ged.h:61
Definition: ptbl.h:62
unsigned char d_minor_type
object minor type
Definition: raytrace.h:871
void ged_results_clear(struct ged_results *results)
Definition: ged_util.c:82
struct resource rt_uniresource
default. Defined in librt/globals.c
Definition: globals.c:41
#define GED_CHECK_DATABASE_OPEN(_gedp, _flags)
Definition: ged.h:114
void * bu_calloc(size_t nelem, size_t elsize, const char *str)
Definition: malloc.c:321
#define RT_DIR_SOLID
this name is a solid
Definition: raytrace.h:883
#define BU_PTBL_GET(ptbl, i)
Definition: ptbl.h:108
struct bu_ptbl * db_lookup_by_attr(struct db_i *dbip, int dir_flags, struct bu_attribute_value_set *avs, int op)
Definition: db_lookup.c:386
void bu_avs_add_nonunique(struct bu_attribute_value_set *avsp, const char *attribute, const char *value)
Definition: avs.c:287
#define LOOKUP_QUIET
Definition: raytrace.h:893
const struct rt_functab * idb_meth
for ft_ifree(), etc.
Definition: raytrace.h:194
void bu_sort(void *array, size_t nummemb, size_t sizememb, int(*compare)(const void *, const void *, void *), void *context)
Definition: sort.c:110
#define RT_DIR_HIDDEN
object name is hidden
Definition: raytrace.h:886
#define UNUSED(parameter)
Definition: common.h:239
void bu_avs_init(struct bu_attribute_value_set *avp, size_t len, const char *str)
Definition: avs.c:47
char * bu_vls_addr(const struct bu_vls *vp)
Definition: vls.c:111
struct bu_vls * ged_result_str
Definition: ged.h:357
#define BU_PTBL_LEN(ptbl)
Definition: ptbl.h:107
void bu_ptbl_free(struct bu_ptbl *b)
Definition: ptbl.c:226
int bu_strcmp(const char *string1, const char *string2)
Definition: str.c:171
#define RT_DIR_COMB
combination
Definition: raytrace.h:884
struct directory * dbi_Head[RT_DBNHASH]
Definition: raytrace.h:814
int _ged_results_add(struct ged_results *results, const char *result_string)
Definition: ged_util.c:47
int cmpdirname(const void *a, const void *b)
Definition: columns.c:87
void bu_vls_printf(struct bu_vls *vls, const char *fmt,...) _BU_ATTR_PRINTF23
Definition: vls.c:694
#define RT_DIR_NULL
Definition: raytrace.h:875
#define LOOKUP_NOISY
Definition: raytrace.h:892
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
#define RT_TERMINAL_WIDTH
Definition: ls.c:38
void bu_vls_spaces(struct bu_vls *vp, size_t cnt)
Definition: vls.c:721
int d_flags
flags
Definition: raytrace.h:869
Definition: vls.h:56
double fastf_t
Definition: defines.h:300
void bu_vls_putc(struct bu_vls *vp, int c)
Definition: vls.c:666
void bu_avs_free(struct bu_attribute_value_set *avp)
Definition: avs.c:235
size_t db_directory_size(const struct db_i *dbip)
Definition: db_lookup.c:54
void rt_db_free_internal(struct rt_db_internal *ip)
Definition: dir.c:216
struct ged_results * ged_results
Definition: ged.h:358