BRL-CAD
red.c
Go to the documentation of this file.
1 /* R E D . 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/red.c
21  *
22  * The red command.
23  *
24  */
25 
26 #include "common.h"
27 
28 #include <stdlib.h>
29 #include <ctype.h>
30 #include <string.h>
31 #include <regex.h>
32 
33 #include "bu/getopt.h"
34 #include "db.h"
35 #include "raytrace.h"
36 
37 #include "./ged_private.h"
38 
39 /* also accessed by put_comb.c */
40 char _ged_tmpfil[MAXPATHLEN] = {0};
41 
42 static const char combseparator[] = "---------- Combination Tree ----------\n";
43 static const char *combtree_header = "---*[[:space:]]*Combination Tree[[:space:]]*---*\r?\n";
44 
45 
46 static int
47 get_attr_val_pair(char *line, struct bu_vls *attr, struct bu_vls *val)
48 {
49  char *ptr1;
50 
51  if (!line) return 0;
52 
53  /* find the '=' */
54  ptr1 = strchr(&line[0], '=');
55  if (!ptr1)
56  return 0;
57 
58  /* Everything from the beginning to the = is the attribute name*/
59  bu_vls_strncpy(attr, line, ptr1 - &line[0]);
60  bu_vls_trimspace(attr);
61  if (bu_vls_strlen(attr) == 0) return 0;
62 
63  ++ptr1;
64 
65  /* Grab the attribute value */
66  bu_vls_strcpy(val, ptr1);
67  bu_vls_trimspace(val);
68 
69  return 1;
70 }
71 
72 
73 void
74 _ged_print_matrix(FILE *fp, matp_t matrix)
75 {
76  int k;
77  char buf[64];
78  fastf_t tmp;
79 
80  if (!matrix)
81  return;
82 
83  for (k = 0; k < 16; k++) {
84  sprintf(buf, "%g", matrix[k]);
85  tmp = atof(buf);
86  if (ZERO(tmp - matrix[k]))
87  fprintf(fp, " %g", matrix[k]);
88  else
89  fprintf(fp, " %.12e", matrix[k]);
90  if ((k&3)==3) fputc(' ', fp);
91  }
92 }
93 
94 
95 int
96 _ged_find_matrix(struct ged *gedp, const char *currptr, int strlength, matp_t *matrix, int *name_end)
97 {
98  int ret = 1;
99  regex_t matrix_entry, full_matrix, nonwhitespace_regex;
100  regmatch_t *float_locations;
101  struct bu_vls current_substring = BU_VLS_INIT_ZERO;
102  struct bu_vls matrix_substring = BU_VLS_INIT_ZERO;
103  int floatcnt, tail_start;
104  const char *floatptr;
105  const char *float_string = "[+-]?[0-9]*[.]?[0-9]+([eE][+-]?[0-9]+)?";
106 
107  bu_vls_sprintf(&current_substring, "(%s[[:space:]]+)", float_string);
108  regcomp(&matrix_entry, bu_vls_addr(&current_substring), REG_EXTENDED);
109  bu_vls_sprintf(&current_substring,
110  /* broken into two strings so auto-formatting
111  * doesn't inject space between ')' and '{'
112  */
113  "[[:space:]]+(%s[[:space:]]+)"
114  "{15}(%s)", float_string, float_string);
115  regcomp(&full_matrix, bu_vls_addr(&current_substring), REG_EXTENDED);
116  regcomp(&nonwhitespace_regex, "([^[:space:]])", REG_EXTENDED);
117 
118  float_locations = (regmatch_t *)bu_calloc(full_matrix.re_nsub, sizeof(regmatch_t), "array to hold answers from regex");
119 
120  floatcnt = 0;
121  float_locations[0].rm_so = 0;
122  float_locations[0].rm_eo = strlength;
123  while (floatcnt < 16 && floatcnt >= 0) {
124  if (regexec(&matrix_entry, currptr, matrix_entry.re_nsub, float_locations, REG_STARTEND) == 0) {
125  /* matched */
126  floatcnt++;
127  float_locations[0].rm_so = float_locations[0].rm_eo;
128  float_locations[0].rm_eo = strlength;
129  } else {
130  floatcnt = -1 * floatcnt - 1;
131  }
132  }
133  if (floatcnt >= 16) {
134  /* Possible matrix - use matrix regex to locate it */
135  float_locations[0].rm_so = 0;
136  float_locations[0].rm_eo = strlength;
137  if (regexec(&full_matrix, currptr, full_matrix.re_nsub, float_locations, REG_STARTEND) == 0) {
138  /* matched */
139  bu_vls_trunc(&matrix_substring, 0);
140  bu_vls_strncpy(&matrix_substring, currptr + float_locations[0].rm_so, float_locations[0].rm_eo - float_locations[0].rm_so);
141  *name_end = float_locations[0].rm_so;
142  tail_start = float_locations[0].rm_eo;
143  (*matrix) = (matp_t)bu_calloc(16, sizeof(fastf_t), "red: matrix");
144  floatptr = bu_vls_addr(&matrix_substring);
145  floatcnt = 0;
146  float_locations[0].rm_so = 0;
147  float_locations[0].rm_eo = bu_vls_strlen(&matrix_substring);
148  while (floatcnt < 16) {
149  if (regexec(&matrix_entry, floatptr, matrix_entry.re_nsub, float_locations, REG_STARTEND) == 0) {
150  /* matched */
151  bu_vls_trunc(&current_substring, 0);
152  bu_vls_strncpy(&current_substring, currptr + float_locations[0].rm_so, float_locations[0].rm_eo - float_locations[0].rm_so);
153  (*matrix)[floatcnt] = atof(floatptr);
154  floatptr = floatptr + float_locations[0].rm_eo;
155  float_locations[0].rm_so = 0;
156  float_locations[0].rm_eo = strlen(floatptr);
157  floatcnt++;
158  } else {
159  bu_vls_sprintf(&current_substring, "%s", floatptr);
160  (*matrix)[floatcnt] = atof(bu_vls_addr(&current_substring));
161  floatcnt++;
162  }
163  }
164  bu_vls_free(&matrix_substring);
165  bu_vls_trunc(&current_substring, 0);
166  bu_vls_strncpy(&current_substring, currptr + tail_start, strlength - tail_start - 1);
167  /* Need to check for non-whitespace in the distance-from-end zone */
168  if (regexec(&nonwhitespace_regex, bu_vls_addr(&current_substring), nonwhitespace_regex.re_nsub, float_locations, 0) == 0) {
169  /* matched */
170  bu_vls_printf(gedp->ged_result_str, "Saw something other than whitespace after matrix - error!\n");
171  ret = -1;
172  } else {
173  ret = 0;
174  }
175  } else {
176  bu_vls_printf(gedp->ged_result_str, "Yikes! Found 16 or more float matches in a comb string but no valid matrix!!\n");
177  ret = -1;
178  }
179  }
180 
181  if (floatcnt < -1 && (floatcnt + 1) < -4) {
182  bu_vls_printf(gedp->ged_result_str, "More than 4 floats found without a matrix present - possible invalid matrix?\n");
183  ret = -1;
184  }
185 
186  /* cleanup */
187  bu_free(float_locations, "free float_locations");
188  bu_vls_free(&current_substring);
189  regfree(&matrix_entry);
190  regfree(&full_matrix);
191  regfree(&nonwhitespace_regex);
192 
193  return ret;
194 }
195 
196 
197 HIDDEN int
198 build_comb(struct ged *gedp, struct directory *dp, struct bu_vls *target_name)
199 {
200  struct rt_comb_internal *comb;
201  size_t node_count=0;
202  int nonsubs=0;
203  union tree *tp;
204  int tree_index=0;
205  struct rt_db_internal intern;
207  const char *currptr;
208  regex_t nonwhitespace_regex, attr_regex, combtree_regex, combtree_op_regex;
209  regmatch_t *result_locations;
210  struct bu_vls current_substring = BU_VLS_INIT_ZERO;
211  struct bu_vls attr_vls = BU_VLS_INIT_ZERO;
212  struct bu_vls val_vls = BU_VLS_INIT_ZERO;
213  struct bu_vls curr_op_vls = BU_VLS_INIT_ZERO;
214  struct bu_vls next_op_vls = BU_VLS_INIT_ZERO;
215  struct bu_mapped_file *redtmpfile;
216  int attrstart, attrend, attrcumulative, name_end;
217  int ret, reti, gedret, combtagstart, combtagend;
218  struct bu_attribute_value_set avs;
219  matp_t matrix = {0};
220 
221  bu_vls_init(target_name);
222 
223  rt_tree_array = (struct rt_tree_array *)NULL;
224 
225  /* Standard sanity checks */
226  if (gedp->ged_wdbp->dbip == DBI_NULL)
227  return GED_ERROR;
228 
229  GED_DB_GET_INTERNAL(gedp, &intern, dp, (fastf_t *)NULL, &rt_uniresource, GED_ERROR);
230  comb = (struct rt_comb_internal *)intern.idb_ptr;
231 
232  if (comb) {
233  RT_CK_COMB(comb);
234  RT_CK_DIR(dp);
235  }
236 
237  /* Map the temp file for reading */
238  redtmpfile = bu_open_mapped_file(_ged_tmpfil, (char *)NULL);
239  if (!redtmpfile) {
240  bu_vls_printf(gedp->ged_result_str, "Cannot open temporary file %s\n", _ged_tmpfil);
241  return GED_ERROR;
242  }
243 
244  /* Set up the regular expressions */
245  reti = 0;
246  reti |= regcomp(&nonwhitespace_regex, "([^[:space:]])", REG_EXTENDED);
247  reti |= regcomp(&attr_regex, "(.+[[:space:]]+=.*)", REG_EXTENDED|REG_NEWLINE);
248  bu_vls_sprintf(&current_substring, "(%s)", combtree_header);
249  reti |= regcomp(&combtree_regex, bu_vls_addr(&current_substring), REG_EXTENDED);
250  reti |= regcomp(&combtree_op_regex, "([[:blank:]]+[[.-.][.+.]u][[:blank:]]+)", REG_EXTENDED);
251 
252  if (reti) {
253  bu_vls_printf(gedp->ged_result_str, "Unable to compile regular expression.\n");
254  return GED_ERROR;
255  }
256 
257  /* Need somewhere to hold the results - initially, size according to attribute regex */
258  result_locations = (regmatch_t *)bu_calloc(attr_regex.re_nsub, sizeof(regmatch_t), "array to hold answers from regex");
259 
260  /* First thing, find the beginning of the tree definition. Without that, file is invalid. Even an empty comb must
261  * include this header.
262  */
263  currptr = (const char *)(redtmpfile->buf);
264  ret = regexec(&combtree_regex, currptr, combtree_regex.re_nsub , result_locations, 0);
265  if (ret == 0) {
266  /* matched */
267 
268  combtagstart = result_locations[0].rm_so;
269  combtagend = result_locations[0].rm_eo;
270  attrcumulative = 0;
271  if (regexec(&combtree_regex, currptr + combtagend, combtree_regex.re_nsub, result_locations, 0) == 0) {
272  /* matched */
273 
274  bu_vls_printf(gedp->ged_result_str, "ERROR - multiple instances of comb tree header \"%s\" in temp file!", combtree_header);
275  bu_vls_printf(gedp->ged_result_str, "cannot locate comb tree, aborting\n");
276  bu_vls_free(&current_substring);
277  regfree(&nonwhitespace_regex);
278  regfree(&attr_regex);
279  regfree(&combtree_regex);
280  regfree(&combtree_op_regex);
281  bu_free(result_locations, "free regex results array\n");
282  bu_close_mapped_file(redtmpfile);
283 
284  return GED_ERROR;
285  }
286  } else {
287  bu_vls_printf(gedp->ged_result_str, "cannot locate comb tree, aborting\n");
288  bu_vls_free(&current_substring);
289  regfree(&nonwhitespace_regex);
290  regfree(&attr_regex);
291  regfree(&combtree_regex);
292  regfree(&combtree_op_regex);
293  bu_free(result_locations, "free regex results array\n");
294  bu_close_mapped_file(redtmpfile);
295 
296  return GED_ERROR;
297  }
298 
299  /* Parsing the file is handled in two stages - attributes and combination tree. Start with attributes */
300  bu_avs_init_empty(&avs);
301  while (attrcumulative < combtagstart - 1) {
302  /* If attributes are present, the first line must match the attr regex - mult-line attribute names are not supported. */
303  if (regexec(&attr_regex, currptr, attr_regex.re_nsub , result_locations, 0) != 0) {
304  /* did NOT match */
305 
306  bu_vls_printf(gedp->ged_result_str, "invalid attribute line\n");
307  bu_vls_free(&current_substring);
308  bu_vls_free(&attr_vls);
309  bu_vls_free(&val_vls);
310  regfree(&nonwhitespace_regex);
311  regfree(&attr_regex);
312  regfree(&combtree_regex);
313  regfree(&combtree_op_regex);
314  bu_avs_free(&avs);
315  bu_free(result_locations, "free regex results array\n");
316  bu_close_mapped_file(redtmpfile);
317 
318  return GED_ERROR;
319  } else {
320  /* matched */
321 
322  /* If an attribute line is found, set the attr pointers and look for the next attribute, if any. Multi-line attribute values
323  * are supported, but only if the line does not itself match the format for an attribute (i.e. no equal sign
324  * surrounded by spaces or tabs.
325  */
326  attrstart = result_locations[0].rm_so;
327  attrend = result_locations[0].rm_eo;
328  attrcumulative += attrend;
329  if (regexec(&attr_regex, (const char *)(redtmpfile->buf) + attrcumulative, attr_regex.re_nsub , result_locations, 0) == 0) {
330  /* matched */
331 
332  if (attrcumulative + result_locations[0].rm_eo < combtagstart) {
333  attrend += result_locations[0].rm_so - 1;
334  attrcumulative += result_locations[0].rm_so - 1;
335  } else {
336  attrend = attrend + (combtagstart - attrcumulative);
337  attrcumulative = combtagstart;
338  }
339  } else {
340  attrend = attrend + (combtagstart - attrcumulative);
341  attrcumulative = combtagstart;
342  }
343  bu_vls_trunc(&current_substring, 0);
344  bu_vls_strncpy(&current_substring, currptr + attrstart, attrend - attrstart);
345  if (get_attr_val_pair(bu_vls_addr(&current_substring), &attr_vls, &val_vls)) {
346  if (BU_STR_EQUAL(bu_vls_addr(&attr_vls), "name")) {
347  bu_vls_sprintf(target_name, "%s", bu_vls_addr(&val_vls));
348  }
349  if (!BU_STR_EQUAL(bu_vls_addr(&val_vls), "") && !BU_STR_EQUAL(bu_vls_addr(&attr_vls), "name"))
350  (void)bu_avs_add(&avs, bu_vls_addr(&attr_vls), bu_vls_addr(&val_vls));
351  }
352  currptr = currptr + attrend;
353  }
354  }
355 
356  db5_standardize_avs(&avs);
357 
358  bu_vls_free(&attr_vls);
359  bu_vls_free(&val_vls);
360 
361  /* Now, the comb tree. First, count the number of operators - without at least one, the comb tree is empty
362  * and we need to know how many there are before allocating rt_tree_array memory. */
363  currptr = (const char *)(redtmpfile->buf) + combtagend;
364  node_count = 0;
365  ret = regexec(&combtree_op_regex, currptr, combtree_op_regex.re_nsub , result_locations, 0);
366  while (ret == 0) {
367  currptr = currptr + result_locations[0].rm_eo;
368  ret = regexec(&combtree_op_regex, currptr, combtree_op_regex.re_nsub , result_locations, 0);
369  node_count++;
370  }
371  currptr = (const char *)(redtmpfile->buf) + combtagend + 1;
372  name_end = 0;
373 
374  ret = regexec(&combtree_op_regex, currptr, combtree_op_regex.re_nsub , result_locations, 0);
375  if (ret == 0) {
376  /* matched */
377 
378  /* Check for non-whitespace garbage between first operator and start of comb tree definition */
379  result_locations[0].rm_eo = result_locations[0].rm_so;
380  result_locations[0].rm_so = 0;
381  if (regexec(&nonwhitespace_regex, currptr, nonwhitespace_regex.re_nsub, result_locations, REG_STARTEND) == 0) {
382  /* matched */
383 
384  bu_vls_printf(gedp->ged_result_str, "Saw something other than comb tree entries after comb tree tag - error!\n");
385  bu_vls_free(&current_substring);
386  bu_vls_free(&curr_op_vls);
387  bu_vls_free(&next_op_vls);
388  regfree(&nonwhitespace_regex);
389  regfree(&attr_regex);
390  regfree(&combtree_regex);
391  regfree(&combtree_op_regex);
392  bu_avs_free(&avs);
393  bu_free(result_locations, "free regex results array\n");
394  bu_close_mapped_file(redtmpfile);
395 
396  return GED_ERROR;
397  }
398  ret = regexec(&combtree_op_regex, currptr, combtree_op_regex.re_nsub , result_locations, 0);
399  bu_vls_trunc(&next_op_vls, 0);
400  bu_vls_strncpy(&next_op_vls, currptr + result_locations[0].rm_so, result_locations[0].rm_eo - result_locations[0].rm_so);
401  bu_vls_trimspace(&next_op_vls);
402  currptr = currptr + result_locations[0].rm_eo;
403  rt_tree_array = (struct rt_tree_array *)bu_calloc(node_count, sizeof(struct rt_tree_array), "tree list");
404  /* As long as we have operators ahead of us in the tree, we have comb entries to handle */
405  while (ret == 0) {
406  db_op_t op;
407 
408  ret = regexec(&combtree_op_regex, currptr, combtree_op_regex.re_nsub , result_locations, 0);
409  bu_vls_sprintf(&curr_op_vls, "%s", bu_vls_addr(&next_op_vls));
410  if (ret == 0) {
411  /* matched */
412  bu_vls_trunc(&next_op_vls, 0);
413  bu_vls_strncpy(&next_op_vls, currptr + result_locations[0].rm_so, result_locations[0].rm_eo - result_locations[0].rm_so);
414  bu_vls_trimspace(&next_op_vls);
415  name_end = result_locations[0].rm_so;
416  } else {
417  name_end = strlen(currptr);
418  }
419  bu_vls_trunc(&current_substring, 0);
420  bu_vls_strncpy(&current_substring, currptr, name_end);
421  if (!bu_vls_strlen(&current_substring)) {
422  bu_vls_printf(gedp->ged_result_str, "Zero length substring\n");
423  bu_vls_free(&current_substring);
424  bu_vls_free(&curr_op_vls);
425  bu_vls_free(&next_op_vls);
426  regfree(&nonwhitespace_regex);
427  regfree(&attr_regex);
428  regfree(&combtree_regex);
429  regfree(&combtree_op_regex);
430  bu_avs_free(&avs);
431  bu_free(result_locations, "free regex results array\n");
432  bu_close_mapped_file(redtmpfile);
433 
434  return GED_ERROR;
435 
436  }
437  /* We have a string - now check for a matrix and build it if present
438  * Otherwise, set matrix to NULL */
439  gedret = _ged_find_matrix(gedp, currptr, name_end, &matrix, &name_end);
440  if (gedret) {
441  matrix = (matp_t)NULL;
442  if (gedret == -1) {
443  bu_vls_printf(gedp->ged_result_str, "Problem parsing Matrix\n");
444  bu_vls_free(&current_substring);
445  bu_vls_free(&curr_op_vls);
446  bu_vls_free(&next_op_vls);
447  regfree(&nonwhitespace_regex);
448  regfree(&attr_regex);
449  regfree(&combtree_regex);
450  regfree(&combtree_op_regex);
451  bu_avs_free(&avs);
452  bu_free(result_locations, "free regex results array\n");
453  bu_close_mapped_file(redtmpfile);
454  return GED_ERROR;
455  }
456  }
457  bu_vls_trunc(&current_substring, 0);
458  bu_vls_strncpy(&current_substring, currptr, name_end);
459  bu_vls_trimspace(&current_substring);
460  currptr = currptr + result_locations[0].rm_eo;
461  if (bu_vls_addr(&curr_op_vls)[0] != '-')
462  nonsubs++;
463 
464  op = db_str2op(bu_vls_addr(&curr_op_vls));
465 
466  /* Add it to the combination */
467  switch (op) {
468  case DB_OP_INTERSECT:
469  rt_tree_array[tree_index].tl_op = OP_INTERSECT;
470  break;
471  case DB_OP_SUBTRACT:
472  rt_tree_array[tree_index].tl_op = OP_SUBTRACT;
473  break;
474  default:
475  bu_vls_printf(gedp->ged_result_str, "build_comb: unrecognized relation %c (assume UNION)\n", bu_vls_addr(&curr_op_vls)[0]);
476  /* fall through */
477  case DB_OP_UNION:
478  rt_tree_array[tree_index].tl_op = OP_UNION;
479  break;
480  }
481  BU_ALLOC(tp, union tree);
482  RT_TREE_INIT(tp);
483  rt_tree_array[tree_index].tl_tree = tp;
484  tp->tr_l.tl_op = OP_DB_LEAF;
485  tp->tr_l.tl_name = bu_strdup(bu_vls_addr(&current_substring));
486  tp->tr_l.tl_mat = matrix;
487  tree_index++;
488 
489  }
490  } else {
491  /* Empty tree, ok as long as there is no garbage after the comb tree indicator */
492  bu_vls_sprintf(&current_substring, "%s", currptr);
493  if (regexec(&nonwhitespace_regex, bu_vls_addr(&current_substring), nonwhitespace_regex.re_nsub, result_locations, 0) == 0) {
494  /* matched */
495 
496  bu_vls_printf(gedp->ged_result_str, "Saw something other than comb tree entries after comb tree tag - error!\n");
497  bu_vls_free(&current_substring);
498  bu_vls_free(&curr_op_vls);
499  bu_vls_free(&next_op_vls);
500  regfree(&nonwhitespace_regex);
501  regfree(&attr_regex);
502  regfree(&combtree_regex);
503  regfree(&combtree_op_regex);
504  bu_avs_free(&avs);
505  bu_free(result_locations, "free regex results array\n");
506  bu_close_mapped_file(redtmpfile);
507 
508  return GED_ERROR;
509  }
510  }
511  bu_vls_free(&current_substring);
512  bu_vls_free(&curr_op_vls);
513  bu_vls_free(&next_op_vls);
514  regfree(&nonwhitespace_regex);
515  regfree(&attr_regex);
516  regfree(&combtree_regex);
517  regfree(&combtree_op_regex);
518 
519  bu_free(result_locations, "free regex results array\n");
520  bu_close_mapped_file(redtmpfile);
521 
522  if (nonsubs == 0 && node_count) {
523  bu_vls_printf(gedp->ged_result_str, "Cannot create a combination with all subtraction operators\n");
524  bu_avs_free(&avs);
525  return GED_ERROR;
526  }
527 
528  if (tree_index)
529  tp = (union tree *)db_mkgift_tree(rt_tree_array, node_count, &rt_uniresource);
530  else
531  tp = (union tree *)NULL;
532 
533  if (comb) {
535  comb->tree = NULL;
536  }
537  comb->tree = tp;
538 
539  db5_standardize_avs(&avs);
540  db5_sync_attr_to_comb(comb, &avs, dp);
541  db5_sync_comb_to_attr(&avs, comb);
542 
543  if (rt_db_put_internal(dp, gedp->ged_wdbp->dbip, &intern, &rt_uniresource) < 0) {
544  bu_vls_printf(gedp->ged_result_str, "build_comb %s: Cannot apply tree\n", dp->d_namep);
545  bu_avs_free(&avs);
546  return GED_ERROR;
547  }
548 
549  if (db5_replace_attributes(dp, &avs, gedp->ged_wdbp->dbip))
550  bu_vls_printf(gedp->ged_result_str, "build_comb %s: Failed to update attributes\n", dp->d_namep);
551 
552  bu_avs_free(&avs);
553  return GED_OK;
554 }
555 
556 
557 HIDDEN int
558 write_comb(struct ged *gedp, struct rt_comb_internal *comb, const char *name)
559 {
560  /* Writes the file for later editing */
562  struct bu_attribute_value_set avs;
563  struct bu_attribute_value_pair *avpp;
564  struct directory *dp;
565  FILE *fp;
566  size_t i, j, maxlength;
567  int hasattr;
568  size_t node_count;
569  size_t actual_count;
570  struct bu_vls spacer = BU_VLS_INIT_ZERO;
571  const char *attr;
572 
573  bu_avs_init_empty(&avs);
574 
575  dp = db_lookup(gedp->ged_wdbp->dbip, name, LOOKUP_QUIET);
576  if (dp == RT_DIR_NULL) {
577  bu_vls_free(&spacer);
578  return GED_ERROR;
579  }
580 
581  if (comb)
582  RT_CK_COMB(comb);
583 
584  /* open the file */
585  if ((fp=fopen(_ged_tmpfil, "w")) == NULL) {
586  perror("fopen");
587  bu_vls_printf(gedp->ged_result_str, "ERROR: Cannot open temporary file [%s] for writing\n", _ged_tmpfil);
588  bu_vls_free(&spacer);
589  return GED_ERROR;
590  }
591 
592  maxlength = 0;
593  for (i = 0; (attr = db5_standard_attribute(i)) != NULL; i++) {
594  if (strlen(attr) > maxlength)
595  maxlength = strlen(attr);
596  }
597 
598  if (!comb) {
599  bu_vls_trunc(&spacer, 0);
600  for (j = 0; j < maxlength - 4 + 1; j++) {
601  bu_vls_printf(&spacer, " ");
602  }
603  fprintf(fp, "name%s= %s\n", bu_vls_addr(&spacer), name);
604  for (i = 0; (attr = db5_standard_attribute(i)) != NULL; i++) {
605  bu_vls_trunc(&spacer, 0);
606  for (j = 0; j < maxlength - strlen(attr); j++) {
607  bu_vls_printf(&spacer, " ");
608  }
609  fprintf(fp, "%s%s = \n", attr, bu_vls_addr(&spacer));
610  }
611  fprintf(fp, "%s\n", combseparator);
612  fclose(fp);
613  bu_vls_free(&spacer);
614  return GED_OK;
615  }
616 
617  if (comb->tree && db_ck_v4gift_tree(comb->tree) < 0) {
619  if (db_ck_v4gift_tree(comb->tree) < 0) {
620  bu_vls_printf(gedp->ged_result_str, "ERROR: Cannot prepare tree for editing\n");
621  bu_vls_free(&spacer);
622  fclose(fp);
623  return GED_ERROR;
624  }
625  }
626  node_count = db_tree_nleaves(comb->tree);
627  if (node_count > 0) {
628  rt_tree_array = (struct rt_tree_array *)bu_calloc(node_count, sizeof(struct rt_tree_array), "tree list");
629  actual_count = (struct rt_tree_array *)db_flatten_tree(rt_tree_array, comb->tree, OP_UNION, 0, &rt_uniresource) - rt_tree_array;
630  BU_ASSERT_SIZE_T(actual_count, ==, node_count);
631  } else {
632  rt_tree_array = (struct rt_tree_array *)NULL;
633  actual_count = 0;
634  }
635 
636  hasattr = db5_get_attributes(gedp->ged_wdbp->dbip, &avs, dp);
637  db5_standardize_avs(&avs);
638  db5_sync_comb_to_attr(&avs, comb);
639 
640  if (!hasattr) {
641  avpp = avs.avp;
642  for (i = 0; i < avs.count; i++, avpp++) {
643  if (strlen(avpp->name) > maxlength)
644  maxlength = strlen(avpp->name);
645  }
646  bu_vls_trunc(&spacer, 0);
647  for (j = 0; j < maxlength - 4 + 1; j++) {
648  bu_vls_printf(&spacer, " ");
649  }
650  fprintf(fp, "name%s= %s\n", bu_vls_addr(&spacer), name);
651  for (i = 0; (attr = db5_standard_attribute(i)) != NULL; i++) {
652  bu_vls_trunc(&spacer, 0);
653  for (j = 0; j < maxlength - strlen(attr) + 1; j++) {
654  bu_vls_printf(&spacer, " ");
655  }
656  if (bu_avs_get(&avs, attr)) {
657  fprintf(fp, "%s%s= %s\n", attr, bu_vls_addr(&spacer), bu_avs_get(&avs, attr));
658  } else {
659  fprintf(fp, "%s%s= \n", attr, bu_vls_addr(&spacer));
660  }
661  }
662  avpp = avs.avp;
663  for (i = 0; i < avs.count; i++, avpp++) {
664  if (!db5_is_standard_attribute(avpp->name)) {
665  bu_vls_trunc(&spacer, 0);
666  for (j = 0; j < maxlength - strlen(avpp->name) + 1; j++) {
667  bu_vls_printf(&spacer, " ");
668  }
669  fprintf(fp, "%s%s= %s\n", avpp->name, bu_vls_addr(&spacer), avpp->value);
670  }
671  }
672  }
673  bu_vls_free(&spacer);
674 
675  fprintf(fp, "%s\n", combseparator);
676 
677  for (i = 0; i<actual_count; i++) {
678  char op;
679 
680  switch (rt_tree_array[i].tl_op) {
681  case OP_UNION:
682  op = DB_OP_UNION;
683  break;
684  case OP_INTERSECT:
685  op = DB_OP_INTERSECT;
686  break;
687  case OP_SUBTRACT:
688  op = DB_OP_SUBTRACT;
689  break;
690  default:
691  bu_vls_printf(gedp->ged_result_str, "ERROR: Encountered illegal op code in tree\n");
692  fclose(fp);
693  bu_avs_free(&avs);
694  return GED_ERROR;
695  }
696  if (fprintf(fp, " %c %s", op, rt_tree_array[i].tl_tree->tr_l.tl_name) <= 0) {
697  bu_vls_printf(gedp->ged_result_str, "ERROR: Cannot write to temporary file [%s].\nAborting edit.\n",
698  _ged_tmpfil);
699  fclose(fp);
700  bu_avs_free(&avs);
701  return GED_ERROR;
702  }
703  _ged_print_matrix(fp, rt_tree_array[i].tl_tree->tr_l.tl_mat);
704  fprintf(fp, "\n");
705  }
706  fclose(fp);
707  bu_avs_free(&avs);
708  return GED_OK;
709 }
710 
711 
712 int
713 ged_red(struct ged *gedp, int argc, const char **argv)
714 {
715  FILE *fp;
716  int c, counter;
717  int ret = GED_ERROR; /* needs to be error */
718  int have_tmp_name = 0;
719  struct directory *dp, *tmp_dp;
720  struct rt_db_internal intern;
721  struct rt_comb_internal *comb;
722  static const char *usage = "{combination}";
723  const char *editstring = NULL;
724  const char *av[3];
725  struct bu_vls comb_name = BU_VLS_INIT_ZERO;
726  struct bu_vls temp_name = BU_VLS_INIT_ZERO;
727  struct bu_vls final_name = BU_VLS_INIT_ZERO;
728  struct bu_vls tmp_ged_result_str = BU_VLS_INIT_ZERO;
729  int force_flag = 0;
730 
732  GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);
733 
734  /* initialize result */
735  bu_vls_trunc(gedp->ged_result_str, 0);
736 
737  /* must be wanting help */
738  if (argc < 2) {
739  bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", "red", usage);
740  return GED_HELP;
741  }
742 
743  if (argc > 4) {
744  bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", "red", usage);
745  return GED_ERROR;
746  }
747 
748  bu_optind = 1;
749  /* First, grab the editstring off of the argv list */
750  while ((c = bu_getopt(argc, (char **)argv, "E:")) != -1) {
751  switch (c) {
752  case 'E' :
753  editstring = bu_optarg;
754  break;
755  case 'f' :
756  force_flag = 1;
757  default :
758  break;
759  }
760  }
761 
762  argc -= bu_optind - 1;
763  argv += bu_optind - 1;
764 
765  dp = db_lookup(gedp->ged_wdbp->dbip, argv[1], LOOKUP_QUIET);
766 
767  /* Now, sanity check to make sure a comb is listed instead of a
768  * primitive, and either write out existing contents for an
769  * existing comb or a blank template for a new comb.
770  */
771  if (dp != RT_DIR_NULL) {
772 
773  /* Stash original primitive name and find appropriate temp name */
774  bu_vls_sprintf(&comb_name, "%s", dp->d_namep);
775 
776  counter = 0;
777  have_tmp_name = 0;
778  while (!have_tmp_name) {
779  /* FIXME: need a general routine for selecting temporary
780  * object names.
781  */
782  bu_vls_sprintf(&temp_name, "%s_red%d", dp->d_namep, counter);
783  if (db_lookup(gedp->ged_wdbp->dbip, bu_vls_addr(&temp_name), LOOKUP_QUIET) == RT_DIR_NULL) {
784  have_tmp_name = 1;
785  } else {
786  counter++;
787  }
788  }
789  if (!(dp->d_flags & RT_DIR_COMB)) {
790  bu_vls_printf(gedp->ged_result_str, "%s must be a combination\n", argv[1]);
791  bu_vls_free(&comb_name);
792  bu_vls_free(&temp_name);
793  return GED_ERROR;
794  }
795 
796  GED_DB_GET_INTERNAL(gedp, &intern, dp, (fastf_t *)NULL, &rt_uniresource, GED_ERROR);
797  comb = (struct rt_comb_internal *)intern.idb_ptr;
798 
799  } else {
800  bu_vls_sprintf(&comb_name, "%s", argv[1]);
801  bu_vls_sprintf(&temp_name, "%s", argv[1]);
802 
803  comb = (struct rt_comb_internal *)NULL;
804  }
805 
806  /* Make a file for the text editor, stash name in _ged_tmpfil */
808  if (fp == (FILE *)0) {
809  bu_vls_printf(gedp->ged_result_str, "Unable to edit %s\n", argv[1]);
810  bu_vls_printf(gedp->ged_result_str, "Unable to create %s\n", _ged_tmpfil);
811  bu_vls_free(&comb_name);
812  bu_vls_free(&temp_name);
813  return GED_ERROR;
814  }
815 
816  /* Close the temp file since 'write_comb' opens it. */
817  (void)fclose(fp);
818 
819  /* Write the combination components to the file */
820  if (write_comb(gedp, comb, argv[1])) {
821  bu_vls_printf(gedp->ged_result_str, "Unable to edit %s\n", argv[1]);
822  goto cleanup;
823  }
824 
825  /* Edit the file */
826  if (_ged_editit(editstring, _ged_tmpfil)) {
827 
828  /* specifically avoid CHECK_READ_ONLY; above so that we can
829  * delay checking if the geometry is read-only until here so
830  * that red may be used to view objects.
831  */
832 
833  if (gedp->ged_wdbp->dbip->dbi_read_only) {
834  bu_vls_printf(gedp->ged_result_str, "Database is READ-ONLY.\nNo changes were made.\n");
835  goto cleanup;
836  }
837 
838  /* comb is to be changed. All changes will first be made to
839  * the temporary copy of the comb - if that succeeds, the
840  * result will be copied over the original comb. If we have
841  * an existing comb copy its contents to the temporary, else
842  * create a new empty comb from scratch.
843  */
844 
845  if (dp) {
846  if (rt_db_get_internal(&intern, dp, gedp->ged_wdbp->dbip, (fastf_t *)NULL, &rt_uniresource) < 0) {
847  bu_vls_printf(gedp->ged_result_str, "Database read error, aborting\n");
848  goto cleanup;
849  }
850 
851  if ((tmp_dp = db_diradd(gedp->ged_wdbp->dbip, bu_vls_addr(&temp_name), RT_DIR_PHONY_ADDR, 0, dp->d_flags, (void *)&intern.idb_type)) == RT_DIR_NULL) {
852  bu_vls_printf(gedp->ged_result_str, "Cannot save copy of %s, no changed made\n", bu_vls_addr(&temp_name));
853  goto cleanup;
854  }
855 
856  if (rt_db_put_internal(tmp_dp, gedp->ged_wdbp->dbip, &intern, &rt_uniresource) < 0) {
857  bu_vls_printf(gedp->ged_result_str, "Cannot save copy of %s, no changed made\n", bu_vls_addr(&temp_name));
858  goto cleanup;
859  }
860  } else {
861  RT_DB_INTERNAL_INIT(&intern);
862  intern.idb_major_type = DB5_MAJORTYPE_BRLCAD;
863  intern.idb_type = ID_COMBINATION;
864  intern.idb_meth = &OBJ[ID_COMBINATION];
865 
866  GED_DB_DIRADD(gedp, tmp_dp, bu_vls_addr(&temp_name), -1, 0, RT_DIR_COMB, (void *)&intern.idb_type, 0);
867 
868  BU_ALLOC(comb, struct rt_comb_internal);
869  RT_COMB_INTERNAL_INIT(comb);
870 
871  intern.idb_ptr = (void *)comb;
872 
873  GED_DB_PUT_INTERNAL(gedp, tmp_dp, &intern, &rt_uniresource, 0);
874  }
875 
876  /* reconstitute the new combination */
877  if ((ret = build_comb(gedp, tmp_dp, &final_name)) != GED_OK) {
878 
879  /* Something went wrong - kill the temporary comb */
880 
881  bu_vls_printf(gedp->ged_result_str, "Problem in edited region, no changes made\n");
882 
883  /* save ged_result_str */
884  bu_vls_sprintf(&tmp_ged_result_str, "%s", bu_vls_addr(gedp->ged_result_str));
885 
886  av[0] = "kill";
887  av[1] = bu_vls_addr(&temp_name);
888  av[2] = NULL;
889  (void)ged_kill(gedp, 2, (const char **)av);
890 
891  /* restore ged_result_str */
892  bu_vls_printf(gedp->ged_result_str, "%s", bu_vls_addr(&tmp_ged_result_str));
893 
894  goto cleanup;
895  }
896 
897  /* if we got a final_name from build_comb and it isn't
898  * identical to comb_name, check to ensure an object with the
899  * new name doesn't already exist - red will not overwrite a
900  * pre-existing comb (unless the -f force flag is set).
901  */
902  if (bu_vls_strlen(&final_name) > 0) {
903  if (!BU_STR_EQUAL(bu_vls_addr(&comb_name), bu_vls_addr(&final_name))) {
904  if (db_lookup(gedp->ged_wdbp->dbip, bu_vls_addr(&final_name), LOOKUP_QUIET) != RT_DIR_NULL) {
905  if (force_flag) {
906  av[0] = "kill";
907  av[1] = bu_vls_addr(&final_name);
908  av[2] = NULL;
909 
910  /* save ged_result_str */
911  bu_vls_sprintf(&tmp_ged_result_str, "%s", bu_vls_addr(gedp->ged_result_str));
912 
913  (void)ged_kill(gedp, 2, (const char **)av);
914 
915  /* restore ged_result_str */
916  bu_vls_printf(gedp->ged_result_str, "%s", bu_vls_addr(&tmp_ged_result_str));
917 
918  } else {
919  /* not forced, can't overwrite destination, can't proceed */
920  bu_vls_printf(gedp->ged_result_str, "%s already exists\n", bu_vls_addr(&final_name));
921  goto cleanup;
922  }
923  }
924  }
925  }
926 
927  /* if we ended up with an empty final name, print an error message and head for cleanup */
928  if (strlen(bu_vls_addr(&final_name)) == 0) {
929  bu_vls_printf(gedp->ged_result_str, "Problem reading target name\n");
930  goto cleanup;
931  }
932 
933  /* it worked - kill the original and put the updated copy in
934  * its place if a pre-existing comb was being edited -
935  * otherwise just move temp_name to final_name.
936  */
937  if (!BU_STR_EQUAL(bu_vls_addr(&comb_name), bu_vls_addr(&temp_name))) {
938  if (BU_STR_EQUAL(bu_vls_addr(&comb_name), bu_vls_addr(&final_name))) {
939  av[0] = "kill";
940  av[1] = bu_vls_addr(&comb_name);
941  av[2] = NULL;
942 
943  /* save ged_result_str */
944  bu_vls_sprintf(&tmp_ged_result_str, "%s", bu_vls_addr(gedp->ged_result_str));
945 
946  (void)ged_kill(gedp, 2, (const char **)av);
947 
948  /* restore ged_result_str */
949  bu_vls_printf(gedp->ged_result_str, "%s", bu_vls_addr(&tmp_ged_result_str));
950  }
951  }
952  av[0] = "mv";
953  av[1] = bu_vls_addr(&temp_name);
954  av[2] = bu_vls_addr(&final_name);
955 
956  /* save ged_result_str */
957  bu_vls_sprintf(&tmp_ged_result_str, "%s", bu_vls_addr(gedp->ged_result_str));
958 
959  (void)ged_move(gedp, 3, (const char **)av);
960 
961  /* restore ged_result_str */
962  bu_vls_printf(gedp->ged_result_str, "%s", bu_vls_addr(&tmp_ged_result_str));
963  }
964  /* if we have reached cleanup by now, everything was fine */
965  ret = GED_OK;
966 
967 cleanup:
969 
970  bu_vls_free(&final_name);
971  bu_vls_free(&comb_name);
972  bu_vls_free(&temp_name);
973  bu_vls_free(&tmp_ged_result_str);
974 
975  return ret;
976 }
977 
978 
979 /*
980  * Local Variables:
981  * tab-width: 8
982  * mode: C
983  * indent-tabs-mode: t
984  * c-file-style: "stroustrup"
985  * End:
986  * ex: shiftwidth=4 tabstop=8
987  */
Definition: db_flip.c:35
void usage(struct ged *gedp)
Definition: coil.c:315
char _ged_tmpfil[MAXPATHLEN]
Definition: red.c:40
#define GED_DB_DIRADD(_gedp, _dp, _name, _laddr, _len, _dirflags, _ptr, _flags)
Definition: ged.h:213
void bu_vls_init(struct bu_vls *vp)
Definition: vls.c:56
#define GED_OK
Definition: ged.h:55
char * d_namep
pointer to name string
Definition: raytrace.h:859
const char * db5_standard_attribute(int idx)
Definition: db5_attr.c:129
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
size_t db5_standardize_avs(struct bu_attribute_value_set *avs)
Definition: db5_attr.c:223
void bu_avs_init_empty(struct bu_attribute_value_set *avp)
Definition: avs.c:36
int rt_db_put_internal(struct directory *dp, struct db_i *dbip, struct rt_db_internal *ip, struct resource *resp)
Definition: dir.c:136
size_t db_tree_nleaves(const union tree *tp)
Definition: db_comb.c:99
Definition: ged.h:338
struct db_i * dbip
Definition: raytrace.h:1266
Definition: clone.c:90
int bu_avs_add(struct bu_attribute_value_set *avp, const char *attribute, const char *value)
Definition: avs.c:78
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
#define RT_CK_COMB(_p)
Definition: raytrace.h:955
union tree * tl_tree
Definition: raytrace.h:1247
void bu_vls_strncpy(struct bu_vls *vp, const char *s, size_t n)
Definition: vls.c:339
struct rt_wdb * ged_wdbp
Definition: ged.h:340
char * bu_optarg
Definition: globals.c:91
Header file for the BRL-CAD common definitions.
int bu_optind
Definition: globals.c:89
db_op_t db_str2op(const char *str)
Definition: op.c:31
const char * value
Definition: avs.h:62
int ged_red(struct ged *gedp, int argc, const char **argv)
Definition: red.c:713
union tree * db_mkgift_tree(struct rt_tree_array *trees, size_t subtreecount, struct resource *resp)
Definition: db_comb.c:1016
HIDDEN int write_comb(struct ged *gedp, struct rt_comb_internal *comb, const char *name)
Definition: red.c:558
#define ID_COMBINATION
Combination Record.
Definition: raytrace.h:499
int bu_getopt(int nargc, char *const nargv[], const char *ostr)
Definition: getopt.c:43
#define GED_ERROR
Definition: ged.h:61
#define HIDDEN
Definition: common.h:86
#define RT_TREE_INIT(_p)
Definition: raytrace.h:1189
const char * bu_avs_get(const struct bu_attribute_value_set *avp, const char *attribute)
Definition: avs.c:172
size_t counter[MAX_PSW]
Definition: bu_parallel.c:42
#define GED_DB_PUT_INTERNAL(_gedp, _dp, _intern, _resource, _flags)
Definition: ged.h:243
struct rt_tree_array * db_flatten_tree(struct rt_tree_array *rt_tree_array, union tree *tp, int op, int avail, struct resource *resp)
Definition: db_comb.c:138
if(share_geom)
Definition: nmg_mod.c:3829
char * strchr(const char *sp, int c)
int idb_major_type
Definition: raytrace.h:192
void bu_vls_free(struct bu_vls *vp)
Definition: vls.c:248
#define OP_SUBTRACT
Binary: L subtract R.
Definition: raytrace.h:1129
void db_non_union_push(union tree *tp, struct resource *resp)
Definition: db_tree.c:1426
void db5_sync_attr_to_comb(struct rt_comb_internal *comb, const struct bu_attribute_value_set *avs, struct directory *dp)
Definition: db5_attr.c:303
#define OP_INTERSECT
Binary: L intersect R.
Definition: raytrace.h:1128
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
db_op_t
Definition: op.h:33
#define OP_DB_LEAF
Leaf of combination, db fmt.
Definition: raytrace.h:1139
struct bu_attribute_value_pair * avp
Definition: avs.h:89
#define BU_ALLOC(_ptr, _type)
Definition: malloc.h:223
void * bu_calloc(size_t nelem, size_t elsize, const char *str)
Definition: malloc.c:321
#define RT_CK_DIR(_dp)
Definition: raytrace.h:876
#define RT_DB_INTERNAL_INIT(_p)
Definition: raytrace.h:199
void bu_vls_sprintf(struct bu_vls *vls, const char *fmt,...) _BU_ATTR_PRINTF23
Definition: vls.c:707
#define LOOKUP_QUIET
Definition: raytrace.h:893
const struct rt_functab * idb_meth
for ft_ifree(), etc.
Definition: raytrace.h:194
FILE * bu_temp_file(char *filepath, size_t len)
Definition: temp.c:180
void db_free_tree(union tree *tp, struct resource *resp)
Definition: db_tree.c:1296
int ged_kill(struct ged *gedp, int argc, const char *argv[])
Definition: kill.c:37
matp_t tl_mat
xform matp, NULL ==> identity
Definition: raytrace.h:1173
#define RT_DIR_PHONY_ADDR
Special marker for d_addr field.
Definition: raytrace.h:879
int db5_replace_attributes(struct directory *dp, struct bu_attribute_value_set *avsp, struct db_i *dbip)
Definition: attributes.c:223
size_t bu_vls_strlen(const struct bu_vls *vp)
Definition: vls.c:189
char * tl_name
Name of this leaf (bu_strdup'ed)
Definition: raytrace.h:1174
HIDDEN int build_comb(struct ged *gedp, struct directory *dp, struct bu_vls *target_name)
Definition: red.c:198
struct bu_mapped_file * bu_open_mapped_file(const char *name, const char *appl)
Definition: mappedfile.c:56
char * bu_vls_addr(const struct bu_vls *vp)
Definition: vls.c:111
struct bu_vls * ged_result_str
Definition: ged.h:357
int ged_move(struct ged *gedp, int argc, const char *argv[])
Definition: move.c:37
int dbi_read_only
!0 => read only file
Definition: raytrace.h:806
struct directory * db_diradd(struct db_i *, const char *name, off_t laddr, size_t len, int flags, void *ptr)
Definition: db_lookup.c:190
void db5_sync_comb_to_attr(struct bu_attribute_value_set *avs, const struct rt_comb_internal *comb)
Definition: db5_attr.c:447
struct tree::tree_db_leaf tr_l
#define ZERO(val)
Definition: units.c:38
int _ged_editit(char *editstring, const char *filename)
Definition: editit.c:49
void * idb_ptr
Definition: raytrace.h:195
#define RT_DIR_COMB
combination
Definition: raytrace.h:884
const struct rt_functab OBJ[]
Definition: table.c:159
Definition: op.h:35
#define DBI_NULL
Definition: raytrace.h:827
int _ged_find_matrix(struct ged *gedp, const char *currptr, int strlength, matp_t *matrix, int *name_end)
Definition: red.c:96
#define RT_COMB_INTERNAL_INIT(_p)
Definition: raytrace.h:960
union tree * tree
Leading to tree_db_leaf leaves.
Definition: raytrace.h:938
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
void bu_close_mapped_file(struct bu_mapped_file *mp)
Definition: mappedfile.c:339
#define GED_HELP
Definition: ged.h:62
#define GED_DB_GET_INTERNAL(_gedp, _intern, _dp, _mat, _resource, _flags)
Definition: ged.h:233
void bu_vls_trimspace(struct bu_vls *vp)
Definition: vls.c:678
#define BU_ASSERT_SIZE_T(_lhs, _relation, _rhs)
Definition: defines.h:253
void bu_vls_strcpy(struct bu_vls *vp, const char *s)
Definition: vls.c:310
const char * name
Definition: avs.h:61
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
#define BU_VLS_INIT_ZERO
Definition: vls.h:84
int tl_op
leaf, OP_DB_LEAF
Definition: raytrace.h:1172
int db5_get_attributes(const struct db_i *dbip, struct bu_attribute_value_set *avs, const struct directory *dp)
Definition: db5_io.c:1027
int d_flags
flags
Definition: raytrace.h:869
Definition: vls.h:56
double fastf_t
Definition: defines.h:300
#define OP_UNION
Binary: L union R.
Definition: raytrace.h:1127
int db_ck_v4gift_tree(const union tree *tp)
Definition: db_comb.c:927
void bu_avs_free(struct bu_attribute_value_set *avp)
Definition: avs.c:235
#define bu_strdup(s)
Definition: str.h:71
void _ged_print_matrix(FILE *fp, matp_t matrix)
Definition: red.c:74
int bu_file_delete(const char *path)
Definition: file.c:278
#define BU_STR_EQUAL(s1, s2)
Definition: str.h:126
#define MAXPATHLEN
Definition: defines.h:113
int db5_is_standard_attribute(const char *attr_want)
Definition: db5_attr.c:136