BRL-CAD
exists.c
Go to the documentation of this file.
1 /* E X I S T 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/exists.c
21  *
22  * The exist command.
23  *
24  * Based on public domein code from:
25  * NetBSD: test.c, v 1.38 2011/08/29 14:51:19 joerg
26  *
27  * test(1); version 7-like -- author Erik Baalbergen
28  * modified by Eric Gisin to be used as built-in.
29  * modified by Arnold Robbins to add SVR3 compatibility
30  * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
31  * modified by J.T. Conklin for NetBSD.
32  *
33  */
34 
35 /* exists accepts the following grammar:
36  oexpr ::= aexpr | aexpr "-o" oexpr ;
37  aexpr ::= nexpr | nexpr "-a" aexpr ;
38  nexpr ::= primary | "!" primary
39  primary ::= unary-operator operand
40  | operand binary-operator operand
41  | operand
42  | "(" oexpr ")"
43  ;
44  unary-operator ::= "-c"|"-e"|"-n"|"-p"|"-v";
45 
46  binary-operator ::= "="|"!="|"-beq"|"-bne"|"-bge"|"-bgt"|"-ble"|"-blt";
47  operand ::= <any legal BRL-CAD object name>
48 */
49 
50 #include "common.h"
51 
52 #include <stdlib.h>
53 #include <string.h>
54 
55 #include "bu/cmd.h"
56 
57 #include "./ged_private.h"
58 
59 #ifndef __arraycount
60 # define __arraycount(__x) (sizeof(__x) / sizeof(__x[0]))
61 #endif
62 
63 /* expression handling logic */
64 
65 enum token {
66  EOI,
85  BOR,
89 };
90 
91 
98 };
99 
100 
101 struct t_op {
102  const char *op_text;
103  short op_num, op_type;
104 };
105 
106 
107 /* The following option structures need to be kept in sorted order for
108  * bsearch - be sure any new entries are in the right numerical order
109  * per bu_strcmp (or the ASCII character values, in the single char
110  * case.
111  */
112 static const struct t_op cop[] = {
113  {"!", UNOT, BUNOP},
114  {"(", LPAREN, PAREN},
115  {")", RPAREN, PAREN},
116  {"<", EXTLT, BINOP},
117  {"=", EXTEQ, BINOP},
118  {">", EXTGT, BINOP},
119 };
120 
121 
122 static const struct t_op cop2[] = {
123  {"!=", EXTNE, BINOP},
124 };
125 
126 
127 static const struct t_op mop4[] = {
128  {"beq", BVOLEQ, BINOP},
129  {"bge", BVOLGE, BINOP},
130  {"bgt", BVOLGT, BINOP},
131  {"ble", BVOLLE, BINOP},
132  {"blt", BVOLLT, BINOP},
133  {"bne", BVOLNE, BINOP},
134 };
135 
136 
137 static const struct t_op mop2[] = {
138  {"N", ONNULL, UNOP},
139  {"a", BAND, BBINOP},
140  {"c", OCOMB, UNOP},
141  {"e", OEXIST, UNOP},
142  {"n", ONULL, UNOP},
143  {"o", BOR, BBINOP},
144  {"p", OPRIM, UNOP},
145  {"v", OBVOL, UNOP},
146 };
147 
148 
149 struct exists_data {
150  char **t_wp;
151  struct t_op const *t_wp_op;
152  struct bu_vls *message;
153  struct ged *gedp;
154  int no_op;
155 };
156 #define EXISTS_DATA_INIT_ZERO {NULL, NULL, NULL, NULL, 0}
157 
158 static int oexpr(enum token, struct exists_data *);
159 static int aexpr(enum token, struct exists_data *);
160 static int nexpr(enum token, struct exists_data *);
161 static int primary(enum token, struct exists_data *);
162 static int binop(struct exists_data *);
163 static int isoperand(struct exists_data *);
164 
165 int db_object_exists(struct exists_data *);
167 
168 #define VTOC(x) (const unsigned char *)((const struct t_op *)x)->op_text
169 
170 static int
171 compare1(const void *va, const void *vb)
172 {
173  const unsigned char *a = (unsigned char *)va;
174  const unsigned char *b = VTOC(vb);
175 
176  return a[0] - b[0];
177 }
178 
179 
180 static int
181 compare3(const void *va, const void *vb)
182 {
183  const char *a = (const char *)va;
184  const char *b = (const char *)VTOC(vb);
185  return bu_strcmp(a, b);
186 }
187 
188 
189 static const struct t_op *
190 findop(const char *s)
191 {
192  if (s[0] == '-') {
193  if (s[1] == '\0')
194  return NULL;
195  if (s[2] == '\0')
196  return (const struct t_op *)bsearch(s + 1, mop2, __arraycount(mop2), sizeof(*mop2), compare1);
197  else if (s[4] != '\0')
198  return NULL;
199  else
200  return (const struct t_op *)bsearch(s + 1, mop4, __arraycount(mop4), sizeof(*mop4), compare3);
201  } else {
202  if (s[1] == '\0')
203  return (const struct t_op *)bsearch(s, cop, __arraycount(cop), sizeof(*cop), compare1);
204  else if (BU_STR_EQUAL(s, cop2[0].op_text))
205  return cop2;
206  else
207  return NULL;
208  }
209 }
210 
211 
212 static enum token
213 t_lex(char *s, struct exists_data *ed)
214 {
215  struct t_op const *op;
216 
217  ed->no_op = 0;
218  if (s == NULL) {
219  ed->t_wp_op = NULL;
220  return EOI;
221  }
222 
223  if ((op = findop(s)) != NULL) {
224  if (!((op->op_type == UNOP && isoperand(ed)) ||
225  (op->op_num == LPAREN && *(ed->t_wp+1) == 0))) {
226  ed->t_wp_op = op;
227  return (enum token)op->op_num;
228  }
229  }
230  if (strlen(*(ed->t_wp)) > 0 && !op && !ed->t_wp_op) {
231  ed->t_wp_op = findop("-N");
232  ed->no_op = 1;
233  return (enum token)ed->t_wp_op->op_num;
234  } else {
235  ed->t_wp_op = NULL;
236  }
237  return OPERAND;
238 }
239 
240 
241 static int
242 oexpr(enum token n, struct exists_data *ed)
243 {
244  int res;
245 
246  res = aexpr(n, ed);
247  if (*(ed->t_wp) == NULL)
248  return res;
249  if (t_lex(*++(ed->t_wp), ed) == BOR) {
250  ed->t_wp_op = NULL;
251  return oexpr(t_lex(*++(ed->t_wp), ed), ed) || res;
252  }
253  (ed->t_wp)--;
254  return res;
255 }
256 
257 
258 static int
259 aexpr(enum token n, struct exists_data *ed)
260 {
261  int res;
262 
263  res = nexpr(n, ed);
264  if (*(ed->t_wp) == NULL)
265  return res;
266  if (t_lex(*++(ed->t_wp), ed) == BAND) {
267  ed->t_wp_op = NULL;
268  return aexpr(t_lex(*++(ed->t_wp), ed), ed) && res;
269  }
270  (ed->t_wp)--;
271  return res;
272 }
273 
274 
275 static int
276 nexpr(enum token n, struct exists_data *ed)
277 {
278 
279  if (n == UNOT)
280  return !nexpr(t_lex(*++(ed->t_wp), ed), ed);
281  return primary(n, ed);
282 }
283 
284 
285 static int
286 isoperand(struct exists_data *ed)
287 {
288  struct t_op const *op;
289  char *s, *t;
290 
291  if ((s = *((ed->t_wp)+1)) == 0)
292  return 1;
293  if ((t = *((ed->t_wp)+2)) == 0)
294  return 0;
295  if ((op = findop(s)) != NULL)
296  return op->op_type == BINOP && (t[0] != ')' || t[1] != '\0');
297  return 0;
298 }
299 
300 
301 /* The code below starts the part that still needs reworking for the
302  * new geometry based tokens/logic */
303 static int
304 primary(enum token n, struct exists_data *ed)
305 {
306  enum token nn;
307  int res;
308 
309  if (n == EOI)
310  return 0; /* missing expression */
311  if (n == LPAREN) {
312  ed->t_wp_op = NULL;
313  if ((nn = t_lex(*++(ed->t_wp), ed)) == RPAREN)
314  return 0; /* missing expression */
315  res = oexpr(nn, ed);
316  if (t_lex(*++(ed->t_wp), ed) != RPAREN) {
317  bu_vls_printf(ed->message , "closing paren expected");
318  return 0;
319  }
320  return res;
321  }
322  if (ed->t_wp_op && ed->t_wp_op->op_type == UNOP) {
323  /* unary expression */
324  if (!ed->no_op) {
325  if (*++(ed->t_wp) == NULL) {
326  bu_vls_printf(ed->message , "argument expected");
327  return 0;
328  }
329  }
330  switch (n) {
331  case OCOMB:
332  bu_log("comb case");
333  /*return is_comb();*/
334  case OEXIST:
335  return db_object_exists(ed);
336  /*return db_lookup();*/
337  case ONULL:
338  bu_log("null case");
339  /*return is_null();*/
340  case ONNULL:
341  /* default case */
343  case OPRIM:
344  bu_log("primitive case");
345  /*return is_prim();*/
346  case OBVOL:
347  bu_log("bounding volume case");
348  /*return has_vol();*/
349  default:
350  /* not reached */
351  return 0;
352  }
353  }
354 
355  if (t_lex(ed->t_wp[1], ed), ed->t_wp_op && ed->t_wp_op->op_type == BINOP) {
356  return binop(ed);
357  }
358 
359  return 0;
360 }
361 
362 
363 static int
364 binop(struct exists_data *ed)
365 {
366  const char /**opnd1, */*opnd2;
367  struct t_op const *op;
368 
369  /* opnd1 = *(ed->t_wp); */
370  (void) t_lex(*++(ed->t_wp), ed);
371  op = ed->t_wp_op;
372 
373  if ((opnd2 = *++(ed->t_wp)) == NULL) {
374  bu_vls_printf(ed->message , "argument expected");
375  return 0;
376  }
377 
378  switch (op->op_num) {
379  case EXTEQ:
380  bu_log("extern eq case");
381  /*bu_extern compare*/
382  case EXTNE:
383  bu_log("extern neq case");
384  /*bu_extern compare*/
385  case EXTLT:
386  bu_log("extern lt case");
387  /*bu_extern compare*/
388  case EXTGT:
389  bu_log("extern gt case");
390  /*bu_extern compare*/
391  case BVOLEQ:
392  bu_log("vol eq case");
393  /*return bbox_vol(opnd1) == bbox_vol(opnd2);*/
394  case BVOLNE:
395  bu_log("vol neq case");
396  /*return bbox_vol(opnd1) != bbox_vol(opnd2);*/
397  case BVOLGE:
398  bu_log("vol geq case");
399  /*return bbox_vol(opnd1) >= bbox_vol(opnd2);*/
400  case BVOLGT:
401  bu_log("vol gt case");
402  /*return bbox_vol(opnd1) > bbox_vol(opnd2);*/
403  case BVOLLE:
404  bu_log("vol leq case");
405  /*return bbox_vol(opnd1) <= bbox_vol(opnd2);*/
406  case BVOLLT:
407  bu_log("vol lt case");
408  /*return bbox_vol(opnd1) < bbox_vol(opnd2);*/
409  default:
410  return 0;
411  /* NOTREACHED */
412  }
413 }
414 
415 
416 /* test functions */
418 {
419  struct directory *dp = NULL;
420  dp = db_lookup(ed->gedp->ged_wdbp->dbip, *(ed->t_wp), LOOKUP_QUIET);
421  if (dp) return 1;
422  return 0;
423 }
424 
425 
427 {
428  int result;
429  result = db_object_exists(ed);
430  if (result) {
431  /* db_lookup passes: todo - check for null database object */
432  return result;
433  } else {
434  /* db_lookup fails - no go */
435  return result;
436  }
437 }
438 
439 
440 /**
441  * Checks for the existence of a specified object.
442  */
443 int
444 ged_exists(struct ged *gedp, int argc, const char *argv_orig[])
445 {
446 /* struct directory *dp;*/
447  static const char *usage = "object";
449  struct bu_vls message = BU_VLS_INIT_ZERO;
450  int result;
451  char **argv = bu_dup_argv(argc, argv_orig);
452 
454  GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);
455 
456  /* initialize result */
457  bu_vls_trunc(gedp->ged_result_str, 0);
458 
459  /* must be wanting help */
460  if (argc == 1) {
461  bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv_orig[0], usage);
462  return GED_HELP;
463  }
464  /*
465  if (argc != 2) {
466  bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv_orig[0], usage);
467  return GED_ERROR;
468  }
469  */
470 
471  ed.t_wp = &argv[1];
472  ed.gedp = gedp;
473  ed.t_wp_op = NULL;
474  ed.message = &message;
475  result = oexpr(t_lex(*(ed.t_wp), &ed), &ed);
476 
477  if (result)
478  bu_vls_printf(gedp->ged_result_str, "1");
479  else
480  bu_vls_printf(gedp->ged_result_str, "0");
481 
482  if (bu_vls_strlen(ed.message) > 0) {
484  bu_vls_free(&message);
485  return GED_ERROR;
486  }
487 
488  bu_vls_free(&message);
489  if (*(ed.t_wp) != NULL && *++(ed.t_wp) != NULL) {
490  return GED_ERROR;
491  } else {
492  return GED_OK;
493  }
494 }
495 
496 
497 /*
498  * Local Variables:
499  * tab-width: 8
500  * mode: C
501  * indent-tabs-mode: t
502  * c-file-style: "stroustrup"
503  * End:
504  * ex: shiftwidth=4 tabstop=8
505  */
void usage(struct ged *gedp)
Definition: coil.c:315
Definition: exists.c:79
#define GED_OK
Definition: ged.h:55
#define __arraycount(__x)
Definition: exists.c:60
Definition: exists.c:76
short op_num
Definition: exists.c:103
int ged_exists(struct ged *gedp, int argc, const char *argv_orig[])
Definition: exists.c:444
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
Definition: exists.c:86
Definition: ged.h:338
int db_object_exists(struct exists_data *)
Definition: exists.c:417
struct db_i * dbip
Definition: raytrace.h:1266
if lu s
Definition: nmg_mod.c:3860
const char * op_text
Definition: exists.c:102
Definition: exists.c:95
void bu_vls_trunc(struct bu_vls *vp, int len)
Definition: vls.c:198
Definition: exists.c:72
#define GED_CHECK_ARGC_GT_0(_gedp, _argc, _flags)
Definition: ged.h:202
Definition: exists.c:83
struct directory * db_lookup(const struct db_i *, const char *name, int noisy)
Definition: db_lookup.c:153
struct ged * gedp
Definition: exists.c:153
Definition: exists.c:80
struct rt_wdb * ged_wdbp
Definition: ged.h:340
Header file for the BRL-CAD common definitions.
Definition: exists.c:87
Definition: exists.c:101
Definition: exists.c:74
Definition: exists.c:81
Definition: exists.c:67
#define GED_ERROR
Definition: ged.h:61
Definition: exists.c:73
struct t_op const * t_wp_op
Definition: exists.c:151
token
Definition: exists.c:65
Definition: exists.c:70
Definition: exists.c:66
void bu_vls_free(struct bu_vls *vp)
Definition: vls.c:248
Definition: exists.c:84
char ** t_wp
Definition: exists.c:150
#define GED_CHECK_DATABASE_OPEN(_gedp, _flags)
Definition: ged.h:114
Definition: exists.c:78
Definition: exists.c:75
#define LOOKUP_QUIET
Definition: raytrace.h:893
Definition: exists.c:93
Definition: exists.c:85
#define VTOC(x)
Definition: exists.c:168
size_t bu_vls_strlen(const struct bu_vls *vp)
Definition: vls.c:189
token_types
Definition: exists.c:92
Definition: exists.c:96
char * bu_vls_addr(const struct bu_vls *vp)
Definition: vls.c:111
struct bu_vls * ged_result_str
Definition: ged.h:357
int no_op
Definition: exists.c:154
Definition: exists.c:69
Definition: exists.c:68
Definition: exists.c:97
int bu_strcmp(const char *string1, const char *string2)
Definition: str.c:171
Definition: exists.c:94
Definition: exists.c:88
Definition: exists.c:82
void bu_vls_printf(struct bu_vls *vls, const char *fmt,...) _BU_ATTR_PRINTF23
Definition: vls.c:694
char ** bu_dup_argv(int argc, const char *argv[])
Definition: argv.c:207
#define GED_HELP
Definition: ged.h:62
Definition: exists.c:77
Definition: exists.c:71
#define BU_VLS_INIT_ZERO
Definition: vls.h:84
int db_object_exists_and_non_null(struct exists_data *)
Definition: exists.c:426
Definition: vls.h:56
#define EXISTS_DATA_INIT_ZERO
Definition: exists.c:156
struct bu_vls * message
Definition: exists.c:152
short op_type
Definition: exists.c:103
#define BU_STR_EQUAL(s1, s2)
Definition: str.h:126