BRL-CAD
parse.c
Go to the documentation of this file.
1 /* P A R S E . C
2  * BRL-CAD
3  *
4  * Copyright (c) 1989-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 
21 #include "common.h"
22 
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <math.h>
27 #include <string.h>
28 #include <assert.h>
29 
30 #include "bu/cv.h"
31 #include "bu/log.h"
32 #include "bu/malloc.h"
33 #include "bu/parallel.h"
34 #include "bu/parse.h"
35 #include "bu/str.h"
36 #include "bu/units.h"
37 
38 
39 /* Note: struct parsing requires no space after the commas. take care
40  * when formatting this file. if the compile breaks here, it means
41  * that spaces got inserted incorrectly.
42  */
43 #define COMMA ','
44 
45 #define CKMEM(_len) { \
46  register ssize_t offset; \
47  if ((offset = (ep - cp) - (_len)) < 0) { \
48  do { \
49  offset += ext->ext_nbytes; /* decr by new growth */ \
50  ext->ext_nbytes <<= 1; \
51  } while (offset < 0); \
52  offset = cp - (char *)ext->ext_buf; \
53  ext->ext_buf = (uint8_t *)bu_realloc((char *) ext->ext_buf, \
54  ext->ext_nbytes, "bu_struct_export"); \
55  ep = (char *)ext->ext_buf + ext->ext_nbytes; \
56  cp = (char *)ext->ext_buf + offset; \
57  } \
58  }
59 
60 
61 #define PARSE_MAGIC_1 0x15cb
62 #define PARSE_MAGIC_2 0xbc51
63 #define PARSE_INIT_GETPUT_1(_p) { \
64  BU_CK_EXTERNAL(_p); \
65  ((unsigned char *) _p->ext_buf)[1] = (PARSE_MAGIC_1 & 0xFF); \
66  ((unsigned char *) _p->ext_buf)[0] = (PARSE_MAGIC_1 >> 8) & 0xFF; \
67  }
68 #define PARSE_INIT_GETPUT_2(_p, _l) { \
69  BU_CK_EXTERNAL(_p); \
70  ((unsigned char *) _p->ext_buf)[_l-1] = (PARSE_MAGIC_2 & 0xFF); \
71  ((unsigned char *) _p->ext_buf)[_l-2] = (PARSE_MAGIC_2 >> 8) & 0xFF; \
72  }
73 
74 
75 #define PARSE_CK_GETPUT(_p) { \
76  register unsigned long _i; \
77  register size_t _len; \
78  BU_CK_EXTERNAL(_p); \
79  if (UNLIKELY(!(_p->ext_buf))) { \
80  bu_log("ERROR: PARSE_CK_GETPUT null ext_buf, file %s, line %d\n", \
81  __FILE__, __LINE__); \
82  bu_bomb("NULL pointer"); \
83  } \
84  if (UNLIKELY(_p->ext_nbytes < 6)) { \
85  bu_log("ERROR: PARSE_CK_GETPUT buffer only %zu bytes, file %s, line %d\n", \
86  _p->ext_nbytes, __FILE__, __LINE__); \
87  bu_bomb("getput buffer too small"); \
88  } \
89  _i = (((unsigned char *)(_p->ext_buf))[0] << 8) | \
90  ((unsigned char *)(_p->ext_buf))[1]; \
91  if (UNLIKELY(_i != PARSE_MAGIC_1)) { \
92  bu_log("ERROR: PARSE_CK_GETPUT buffer %p, magic1 s/b %x, was %s(0x%lx), file %s, line %d\n", \
93  (void *)_p->ext_buf, PARSE_MAGIC_1, \
94  bu_identify_magic(_i), _i, __FILE__, __LINE__); \
95  bu_bomb("Bad getput buffer"); \
96  } \
97  _len = \
98  ((size_t)((unsigned char *)(_p->ext_buf))[2] << 24) | \
99  ((size_t)((unsigned char *)(_p->ext_buf))[3] << 16) | \
100  ((size_t)((unsigned char *)(_p->ext_buf))[4] << 8) | \
101  (size_t)((unsigned char *)(_p->ext_buf))[5]; \
102  if (UNLIKELY(_len > _p->ext_nbytes)) { \
103  bu_log("ERROR: PARSE_CK_GETPUT buffer %p, expected len=%zu, ext_nbytes=%zu, file %s, line %d\n", \
104  (void *)_p->ext_buf, (size_t)_len, _p->ext_nbytes, \
105  __FILE__, __LINE__); \
106  bu_bomb("Bad getput buffer"); \
107  } \
108  _i = (((unsigned char *)(_p->ext_buf))[_len-2] << 8) | \
109  ((unsigned char *)(_p->ext_buf))[_len-1]; \
110  if (UNLIKELY(_i != PARSE_MAGIC_2)) { \
111  bu_log("ERROR: PARSE_CK_GETPUT buffer %p, magic2 s/b %x, was %s(0x%lx), file %s, line %d\n", \
112  (void *)_p->ext_buf, PARSE_MAGIC_2, \
113  bu_identify_magic(_i), _i, __FILE__, __LINE__); \
114  bu_bomb("Bad getput buffer"); \
115  } \
116  }
117 
118 
119 int
120 bu_struct_export(struct bu_external *ext, const void *base, const struct bu_structparse *imp)
121 {
122  register char *cp; /* current position in buffer */
123  char *ep; /* &ext->ext_buf[ext->ext_nbytes] */
124  const struct bu_structparse *ip; /* current imexport structure */
125  char *loc; /* where host-format data is */
126  size_t len;
127  register size_t i;
128 
129  BU_EXTERNAL_INIT(ext);
130 
131  if (UNLIKELY(base == ((void *)0) || !ext))
132  return 0;
133 
134  ext->ext_nbytes = 480;
135  ext->ext_buf = (uint8_t *)bu_malloc(ext->ext_nbytes, "bu_struct_export output ext->ext_buf");
136  PARSE_INIT_GETPUT_1(ext);
137  cp = (char *) ext->ext_buf + 6; /* skip magic and length */
138  ep = cp + ext->ext_nbytes;
139 
140  for (ip = imp; ip && ip->sp_fmt[0] != '\0'; ip++) {
141 
142  loc = ((char *)base) + ip->sp_offset;
143 
144  switch (ip->sp_fmt[0]) {
145  case 'i':
146  {
147  /* DEPRECATED: use %p instead. */
148  static int warned = 0;
149  if (!warned) {
150  bu_log("DEVELOPER DEPRECATION NOTICE: Use of \"i\" is replaced by \"%%p\" for chained bu_structparse tables.\n");
151  warned++;
152  }
153  }
154  continue;
155  case '%':
156  /* See below */
157  break;
158  default:
159  /* Unknown */
160  bu_free((char *) ext->ext_buf, "output ext_buf");
161  return 0;
162  }
163  /* [0] == '%', use printf-like format char */
164  switch (ip->sp_fmt[1]) {
165  case 'f':
166  /* Variable-precision "fastf_t" floating point */
167  len = ip->sp_count * sizeof(fastf_t);
168  CKMEM(len);
169  switch (sizeof(fastf_t)) {
170  case sizeof(float):
171  bu_cv_htonf((unsigned char *)cp, (unsigned char *)loc, ip->sp_count);
172  break;
173  case sizeof(double):
174  default:
175  bu_cv_htond((unsigned char *)cp, (unsigned char *)loc, ip->sp_count);
176  break;
177  }
178  cp += len;
179  continue;
180  case 'g':
181  /* Double-precision floating point */
182  len = ip->sp_count * sizeof(double);
183  CKMEM(len);
184  bu_cv_htond((unsigned char *)cp, (unsigned char *)loc, ip->sp_count);
185  cp += len;
186  continue;
187  case 'd':
188  /* 32-bit network integer, from "int" */
189  CKMEM(ip->sp_count * sizeof(int));
190  {
191  register unsigned long l;
192  for (i = ip->sp_count; i > 0; i--) {
193  l = *((long int *)loc);
194  cp[3] = l;
195  cp[2] = l >> 8;
196  cp[1] = l >> 16;
197  cp[0] = l >> 24;
198  loc += sizeof(int);
199  cp += 4;
200  }
201  }
202  continue;
203  case 'i':
204  /* 16-bit integer, from "short int" */
205  CKMEM(ip->sp_count * 2);
206  {
207  register unsigned short s;
208  for (i = ip->sp_count; i > 0; i--) {
209  s = *((short int *)loc);
210  cp[1] = s;
211  cp[0] = s >> 8;
212  loc += sizeof(short int);
213  cp += 2;
214  }
215  }
216  continue;
217  case 's':
218  {
219  /* char array is transmitted as a 4 byte character
220  * count, followed by a null terminated, word
221  * padded char array. The count includes any pad
222  * bytes, but not the count itself.
223  *
224  * ip->sp_count == sizeof(char array)
225  */
226  register size_t lenstr;
227 
228  /* include the terminating null */
229  lenstr = strlen(loc) + 1;
230 
231  len = lenstr;
232 
233  /* output an integer number of words */
234  if ((len & 0x03) != 0)
235  len += 4 - (len & 0x03);
236 
237  CKMEM(len + 4);
238 
239  /* put the length on the front of the string
240  */
241  cp[3] = (char)len;
242  cp[2] = (char)(len >> 8);
243  cp[1] = (char)(len >> 16);
244  cp[0] = (char)(len >> 24);
245 
246  cp += 4;
247 
248  memcpy(cp, loc, lenstr);
249  cp += lenstr;
250  while (lenstr++ < len) *cp++ = '\0';
251  }
252  continue;
253  case 'c':
254  {
255  CKMEM(ip->sp_count + 4);
256  cp[3] = (char)ip->sp_count;
257  cp[2] = (char)(ip->sp_count >> 8);
258  cp[1] = (char)(ip->sp_count >> 16);
259  cp[0] = (char)(ip->sp_count >> 24);
260  cp += 4;
261  memcpy(cp, loc, ip->sp_count);
262  cp += ip->sp_count;
263  }
264  continue;
265  case 'p':
266  {
267  BU_ASSERT(ip->sp_count == 1);
268 
269  /* Indirect to another structure */
270  /* FIXME: unimplemented */
271  bu_log("INTERNAL ERROR: attempt to indirectly export bu_structparse table, unimplemented\n");
272  }
273  continue;
274  default:
275  bu_free((char *) ext->ext_buf, "output ext_buf");
276  return 0;
277  }
278  }
279  CKMEM(2); /* get room for the trailing magic number */
280  cp += 2;
281 
282  i = cp - (char *)ext->ext_buf;
283  /* Fill in length in external buffer */
284  ((char *)ext->ext_buf)[5] = (char)i;
285  ((char *)ext->ext_buf)[4] = (char)(i >> 8);
286  ((char *)ext->ext_buf)[3] = (char)(i >>16);
287  ((char *)ext->ext_buf)[2] = (char)(i >>24);
288  PARSE_INIT_GETPUT_2(ext, i);
289  ext->ext_nbytes = i; /* XXX this changes nbytes if i < 480 ? */
290  return 1;
291 }
292 
293 
294 int
295 bu_struct_import(void *base, const struct bu_structparse *imp, const struct bu_external *ext, void *data)
296 {
297  register const unsigned char *cp; /* current position in buffer */
298  const struct bu_structparse *ip; /* current imexport structure */
299  char *loc; /* where host-format data is */
300  size_t len;
301  size_t bytes_used;
302  register size_t i;
303 
304  if (UNLIKELY(base == ((void *)0) || !ext))
305  return -1;
306 
307  PARSE_CK_GETPUT(ext);
308 
309  cp = (unsigned char *)ext->ext_buf+6;
310  bytes_used = 0;
311  for (ip = imp; ip && ip->sp_fmt[0] != '\0'; ip++) {
312 
313  loc = ((char *)base) + ip->sp_offset;
314 
315  switch (ip->sp_fmt[0]) {
316  case 'i':
317  {
318  /* DEPRECATED: use %p instead. */
319  static int warned = 0;
320  if (!warned) {
321  bu_log("DEVELOPER DEPRECATION NOTICE: Use of \"i\" is replaced by \"%%p\" for chained bu_structparse tables.\n");
322  warned++;
323  }
324  }
325  continue;
326  case '%':
327  /* See below */
328  break;
329  default:
330  /* Unknown */
331  return -1;
332  }
333  /* [0] == '%', use printf-like format char */
334  switch (ip->sp_fmt[1]) {
335  case 'f':
336  /* Variable-precision fastf_t floating point */
337  len = ip->sp_count * sizeof(fastf_t);
338  switch (sizeof(fastf_t)) {
339  case sizeof(float):
340  bu_cv_ntohf((unsigned char *)loc, cp, ip->sp_count);
341  break;
342  case sizeof(double):
343  default:
344  bu_cv_ntohd((unsigned char *)loc, cp, ip->sp_count);
345  break;
346  }
347  cp += len;
348  bytes_used += len;
349  break;
350  case 'g':
351  /* Double-precision floating point */
352  len = ip->sp_count * sizeof(double);
353  bu_cv_ntohd((unsigned char *)loc, cp, ip->sp_count);
354  cp += len;
355  bytes_used += len;
356  break;
357  case 'd':
358  /* 32-bit network integer, from "int" */
359  {
360  register long l;
361  for (i = ip->sp_count; i > 0; i--) {
362  l =
363  ((long)cp[0] << 24) |
364  ((long)cp[1] << 16) |
365  ((long)cp[2] << 8) |
366  (long)cp[3];
367  *(int *)loc = l;
368  loc += sizeof(int);
369  cp += 4;
370  }
371  bytes_used += ip->sp_count * 4;
372  }
373  break;
374  case 'i':
375  /* 16-bit integer, from "short int" */
376  for (i = ip->sp_count; i > 0; i--) {
377  *(short int *)loc = (cp[0] << 8) |
378  cp[1];
379  loc += sizeof(short int);
380  cp += 2;
381  }
382  bytes_used += ip->sp_count * 2;
383  break;
384  case 's':
385  {
386  /* char array transmitted as a 4 byte character
387  * count, followed by a null terminated, word
388  * padded char array
389  *
390  * ip->sp_count == sizeof(char array)
391  */
392  register unsigned long lenstr;
393 
394  lenstr =
395  ((unsigned long)cp[0] << 24) |
396  ((unsigned long)cp[1] << 16) |
397  ((unsigned long)cp[2] << 8) |
398  ((unsigned long)cp[3]);
399 
400  cp += 4;
401 
402  /* don't read more than the buffer can hold */
403  if ((unsigned long)ip->sp_count < lenstr)
404  memcpy(loc, cp, ip->sp_count);
405  else
406  memcpy(loc, cp, lenstr);
407 
408  /* ensure proper null termination */
409  loc[ip->sp_count-1] = '\0';
410 
411  cp += lenstr;
412  bytes_used += lenstr;
413  }
414  break;
415  case 'c':
416  {
417  register unsigned long lenarray;
418 
419  lenarray =
420  ((unsigned long)cp[0] << 24) |
421  ((unsigned long)cp[1] << 16) |
422  ((unsigned long)cp[2] << 8) |
423  ((unsigned long)cp[3]);
424  cp += 4;
425 
426  if ((unsigned long)ip->sp_count < lenarray) {
427  memcpy(loc, cp, ip->sp_count);
428  } else {
429  memcpy(loc, cp, lenarray);
430  }
431  cp += lenarray;
432  bytes_used += lenarray;
433  }
434  break;
435  case 'p':
436  BU_ASSERT(ip->sp_count == 1);
437 
438  /* Indirect to another structure */
439  /* FIXME: unimplemented */
440  bu_log("INTERNAL ERROR: attempt to indirectly import bu_structparse table, unimplemented\n");
441  break;
442  default:
443  return -1;
444  }
445  if (ip->sp_hook) {
446  ip->sp_hook(ip, ip->sp_name, base, NULL, data);
447  }
448  }
449 
450  /* This number may differ from that stored as "claimed_length" */
451  BU_ASSERT_LONG(bytes_used, <, INT_MAX);
452  return (int)bytes_used;
453 }
454 
455 
456 size_t
457 bu_struct_put(FILE *fp, const struct bu_external *ext)
458 {
459  if (UNLIKELY(!fp || !ext))
460  return 0;
461 
462  PARSE_CK_GETPUT(ext);
463 
464  return fwrite(ext->ext_buf, 1, ext->ext_nbytes, fp);
465 }
466 
467 
468 size_t
469 bu_struct_get(struct bu_external *ext, FILE *fp)
470 {
471  size_t i;
472  uint32_t len;
473 
474  if (UNLIKELY(!ext || !fp))
475  return 0;
476 
477  BU_EXTERNAL_INIT(ext);
478  ext->ext_buf = (uint8_t *)bu_malloc(6, "bu_struct_get buffer head");
480 
481  i = fread((char *)ext->ext_buf, 1, 6, fp); /* res_syscall */
482  bu_semaphore_release(BU_SEM_SYSCALL); /* unlock */
483 
484  if (i != 6) {
485  if (i == 0)
486  return 0;
487 
488  perror("fread");
489  bu_log("ERROR: bu_struct_get bad fread (%zu), file %s, line %d\n",
490  i, __FILE__, __LINE__);
491  return 0;
492  }
493 
494  i = (((unsigned char *)(ext->ext_buf))[0] << 8)
495  | ((unsigned char *)(ext->ext_buf))[1];
496 
497  len = (((unsigned char *)(ext->ext_buf))[2] << 24)
498  | (((unsigned char *)(ext->ext_buf))[3] << 16)
499  | (((unsigned char *)(ext->ext_buf))[4] << 8)
500  | (((unsigned char *)(ext->ext_buf))[5]);
501 
502  if (UNLIKELY(i != PARSE_MAGIC_1)) {
503  bu_log("ERROR: bad getput buffer header %p, s/b %x, was %s(0x%lx), file %s, line %d\n",
504  (void *)ext->ext_buf, PARSE_MAGIC_1,
505  bu_identify_magic(i), (long int)i, __FILE__, __LINE__);
506  bu_bomb("bad getput buffer");
507  }
508  ext->ext_nbytes = len;
509  ext->ext_buf = (uint8_t *)bu_realloc((char *) ext->ext_buf, len,
510  "bu_struct_get full buffer");
512  i = fread((char *)ext->ext_buf + 6, 1, len-6, fp); /* res_syscall */
513  bu_semaphore_release(BU_SEM_SYSCALL); /* unlock */
514 
515  if (UNLIKELY(i != len-6)) {
516  bu_log("ERROR: bu_struct_get bad fread (%zu), file %s, line %d\n",
517  i, __FILE__, __LINE__);
518  ext->ext_nbytes = 0;
519  bu_free(ext->ext_buf, "bu_struct_get full buffer");
520  ext->ext_buf = NULL;
521  return 0;
522  }
523 
524  i = (((unsigned char *)(ext->ext_buf))[len-2] << 8)
525  | ((unsigned char *)(ext->ext_buf))[len-1];
526 
527  if (UNLIKELY(i != PARSE_MAGIC_2)) {
528  bu_log("ERROR: bad getput buffer %p, s/b %x, was %s(0x%lx), file %s, line %d\n",
529  (void *)ext->ext_buf, PARSE_MAGIC_2,
530  bu_identify_magic(i), (long int)i, __FILE__, __LINE__);
531  ext->ext_nbytes = 0;
532  bu_free(ext->ext_buf, "bu_struct_get full buffer");
533  ext->ext_buf = NULL;
534  return 0;
535  }
536 
537  return (size_t)len;
538 }
539 
540 
541 void
542 bu_struct_wrap_buf(struct bu_external *ext, void *buf)
543 {
544  register long i, len;
545 
546  if (UNLIKELY(!ext || buf == ((void *)0)))
547  return;
548 
549  BU_EXTERNAL_INIT(ext);
550  ext->ext_buf = (uint8_t *)buf;
551  i = ((long)((unsigned char *)(ext->ext_buf))[0] << 8) |
552  ((long)((unsigned char *)(ext->ext_buf))[1]);
553  len =
554  ((long)((unsigned char *)(ext->ext_buf))[2] << 24) |
555  ((long)((unsigned char *)(ext->ext_buf))[3] << 16) |
556  ((long)((unsigned char *)(ext->ext_buf))[4] << 8) |
557  ((long)((unsigned char *)(ext->ext_buf))[5]);
558  if (UNLIKELY(i != PARSE_MAGIC_1)) {
559  bu_log("ERROR: bad getput buffer header %p, s/b %x, was %s(0x%lx), file %s, line %d\n",
560  (void *)ext->ext_buf, PARSE_MAGIC_1,
561  bu_identify_magic(i), i, __FILE__, __LINE__);
562  bu_bomb("bad getput buffer");
563  }
564  ext->ext_nbytes = len;
565  i = (((unsigned char *)(ext->ext_buf))[len-2] <<8) |
566  ((unsigned char *)(ext->ext_buf))[len-1];
567  if (UNLIKELY(i != PARSE_MAGIC_2)) {
568  bu_log("ERROR: bad getput buffer %p, s/b %x, was %s(0x%lx), file %s, line %d\n",
569  (void *)ext->ext_buf, PARSE_MAGIC_2,
570  bu_identify_magic(i), i, __FILE__, __LINE__);
571  bu_bomb("Bad getput buffer");
572  }
573 }
574 
575 
576 /**
577  * Parse an array of one or more floating point values.
578  *
579  * Returns: 0 when successful
580  * <0 upon failure
581  */
582 HIDDEN int
583 parse_floating(const char *str, size_t count, fastf_t *floc, double *dloc)
584 {
585  size_t i;
586  int dot_seen;
587  const char *numstart;
588  double tmp_double;
589  struct bu_vls buf = BU_VLS_INIT_ZERO;
590  int len;
591 
592  if (UNLIKELY(str == NULL))
593  return -1;
594 
595  for (i = 0; i < count && *str; ++i) {
596  numstart = str;
597 
598  /* skip sign */
599  if (*str == '-' || *str == '+')
600  str++;
601 
602  /* skip matissa */
603  dot_seen = 0;
604  for (; *str; str++) {
605  if (*str == '.' && !dot_seen) {
606  dot_seen = 1;
607  continue;
608  }
609  if (!isdigit((int)(*str)))
610  break;
611  }
612 
613  /* If no mantissa seen, then there is no float here */
614  if (str == (numstart + dot_seen))
615  return -1;
616 
617  /* there was a mantissa, so we may have an exponent */
618  if (*str == 'E' || *str == 'e') {
619  str++;
620 
621  /* skip exponent sign */
622  if (*str == '+' || *str == '-')
623  str++;
624 
625  while (isdigit((int)(*str)))
626  str++;
627  }
628 
629  len = str - numstart;
630  bu_vls_strncpy(&buf, numstart, len);
631 
632  if (UNLIKELY(sscanf(bu_vls_addr(&buf), "%lf", &tmp_double) != 1)) {
633  bu_vls_free(&buf);
634  return -1;
635  }
636 
637  if (floc)
638  *floc++ = (fastf_t)tmp_double;
639  if (dloc)
640  *dloc++ = tmp_double;
641 
642  /* skip any whitespace before separator */
643  while (*str && isspace((int)(*str)))
644  str++;
645 
646  /* skip the separator */
647  if (*str && !isdigit((int)(*str)) && *str != '-' && *str != '+' && *str != '.')
648  str++;
649 
650  /* skip any whitespace after separator */
651  while (*str && isspace((int)(*str)))
652  str++;
653  }
654 
655  bu_vls_free(&buf);
656  return 0;
657 }
658 
659 
660 /**
661  *
662  * @return -2 parse error
663  * @return -1 not found
664  * @return 0 entry found and processed
665  */
666 HIDDEN int
667 parse_struct_lookup(register const struct bu_structparse *sdp, register const char *name, const char *base, const char *const value, void *data)
668 /* structure description */
669 /* struct member name */
670 /* beginning of structure */
671 /* string containing value */
672 {
673  register char *loc;
674  size_t i;
675  int retval = 0;
676 
677  /* sanity */
678  if (UNLIKELY(!sdp || !name))
679  return -1;
680 
681  /* iterate over all structure entries and look for a match */
682  for (; sdp->sp_name != (char *)0; sdp++) {
683 
684  loc = (char *)(base + sdp->sp_offset);
685 
686  if (UNLIKELY(loc == NULL)) {
687  bu_log("Structure inconsistency detected parsing '%s'\n", sdp->sp_name ? sdp->sp_name : "NULL");
688  bu_bomb("INTERNAL ERROR: encountered NULL address.\n");
689  }
690 
691  if (!BU_STR_EQUAL(sdp->sp_name, name) /* no name match */
692  && sdp->sp_fmt[0] != 'i'
693  && sdp->sp_fmt[1] != 'p') /* no include desc */
694 
695  continue;
696 
697  /* if we get this far, we've got a name match with a name in
698  * the structure description
699  */
700 
701  if (UNLIKELY(sdp->sp_fmt[0] == 'i')) {
702  static int warned = 0;
703  if (!warned) {
704  bu_log("DEVELOPER DEPRECATION NOTICE: Use of \"i\" is replaced by \"%%p\" for chained bu_structparse tables.\n");
705  warned++;
706  }
707  /* Indirect to another structure */
708  if (parse_struct_lookup((struct bu_structparse *)sdp->sp_count, name, base, value, data) == 0)
709  return 0; /* found */
710  else
711  continue;
712  }
713  if (sdp->sp_fmt[0] != '%') {
714  bu_log("parse_struct_lookup(%s): unknown format '%s'\n",
715  name, sdp->sp_fmt);
716  return -1;
717  }
718 
719  switch (sdp->sp_fmt[1]) {
720  case 'c':
721  case 's':
722  {
723  register size_t j;
724 
725  /* copy the string, converting escaped double
726  * quotes to just double quotes
727  */
728  for (i = j = 0;
729  j < sdp->sp_count && value[i] != '\0';
730  loc[j++] = value[i++])
731  if (value[i] == '\\' &&
732  value[i+1] == '"')
733  ++i;
734 
735  /* Don't null terminate chars, only strings */
736  if (sdp->sp_count > 1) {
737  /* OK, it's a string */
738  if (j < sdp->sp_count-1)
739  loc[j] = '\0';
740  else
741  loc[sdp->sp_count-1] = '\0';
742  }
743  }
744  break;
745  case 'V':
746  {
747  struct bu_vls *vls = (struct bu_vls *)loc;
748  bu_vls_strcpy(vls, value);
749  }
750  break;
751  case 'i':
752  {
753  register short *ip = (short *)loc;
754  register short tmpi;
755  register const char *cp;
756  register const char *pv = value;
757 
758  for (i = 0; i < sdp->sp_count && *pv; ++i) {
759  tmpi = atoi(pv);
760 
761  cp = pv;
762  if (*cp && (*cp == '+' || *cp == '-'))
763  cp++;
764 
765  while (*cp && isdigit((int)(*cp)))
766  cp++;
767 
768  /* make sure we actually had an
769  * integer out there
770  */
771  if (cp == pv ||
772  (cp == pv+1 &&
773  (*pv == '+' || *pv == '-'))) {
774  retval = -2;
775  break;
776  } else {
777  *(ip++) = tmpi;
778  pv = cp;
779  }
780 
781  /* skip any whitespace before separator */
782  while (*pv && isspace((int)(*pv)))
783  pv++;
784 
785  /* skip the separator */
786  if (*pv && !isdigit((int)(*pv)) && *pv != '+' && *pv != '-')
787  pv++;
788 
789  /* skip any whitespace after separator */
790  while (*pv && isspace((int)(*pv)))
791  pv++;
792  }
793  }
794  break;
795  case 'd':
796  {
797  register int *ip = (int *)loc;
798  register int tmpi;
799  register char const *cp;
800  register const char *pv = value;
801 
802  /* Special case: '=!' toggles a boolean */
803  if (*pv == '!') {
804  *ip = *ip ? 0 : 1;
805  pv++;
806  break;
807  }
808  /* Normal case: an integer */
809  for (i = 0; i < sdp->sp_count && *pv; ++i) {
810  tmpi = atoi(pv);
811 
812  cp = pv;
813  if (*cp && (*cp == '+' || *cp == '-'))
814  cp++;
815 
816  while (*cp && isdigit((int)(*cp)))
817  cp++;
818 
819  /* make sure we actually had an
820  * integer out there
821  */
822  if (cp == pv ||
823  (cp == pv+1 &&
824  (*pv == '+' || *pv == '-'))) {
825  retval = -2;
826  break;
827  } else {
828  *(ip++) = tmpi;
829  pv = cp;
830  }
831 
832  /* skip any whitespace before separator */
833  while (*pv && isspace((int)(*pv)))
834  pv++;
835 
836  /* skip the separator */
837  if (*pv && !isdigit((int)(*pv)) && *pv != '+' && *pv != '-')
838  pv++;
839 
840  /* skip any whitespace after separator */
841  while (*pv && isspace((int)(*pv)))
842  pv++;
843  }
844  }
845  break;
846  case 'f':
847  retval = parse_floating(value, sdp->sp_count, (fastf_t *)loc, NULL);
848  break;
849  case 'g':
850  retval = parse_floating(value, sdp->sp_count, NULL, (double *)loc);
851  break;
852  case 'p': {
853  struct bu_structparse *tbl = (struct bu_structparse *)sdp->sp_offset;
854 
855  BU_ASSERT(sdp->sp_count == 1);
856 
857  retval = parse_struct_lookup(tbl, name, base, value, data);
858  if (retval == 0) {
859  return 0; /* found */
860  }
861  continue;
862  }
863  default:
864  bu_log("parse_struct_lookup(%s): unknown format '%s'\n",
865  name, sdp->sp_fmt);
866  return -1;
867  }
868  if (sdp->sp_hook) {
869  sdp->sp_hook(sdp, name, (void *)base, value, data);
870  }
871  return retval; /* OK or parse error */
872  }
873  return -1; /* Not found */
874 }
875 
876 
877 int
878 bu_struct_parse(const struct bu_vls *in_vls, const struct bu_structparse *desc, const char *base, void *data)
879 /* string to parse through */
880 /* structure description */
881 /* base addr of users struct */
882 {
883  struct bu_vls vls = BU_VLS_INIT_ZERO;
884  register char *cp;
885  char *name;
886  char *value;
887  int retval;
888 
889  BU_CK_VLS(in_vls);
890  if (UNLIKELY(desc == (struct bu_structparse *)NULL)) {
891  bu_log("NULL \"struct bu_structparse\" pointer\n");
892  return -1;
893  }
894 
895  /* Duplicate the input string. This algorithm is destructive. */
896  bu_vls_vlscat(&vls, in_vls);
897  cp = bu_vls_addr(&vls);
898 
899  while (*cp) {
900  /* NAME = VALUE white-space-separator */
901 
902  /* skip any leading whitespace */
903  while (*cp != '\0' && isspace((int)(*cp)))
904  cp++;
905 
906  /* Find equal sign */
907  name = cp;
908  while (*cp != '\0' && *cp != '=')
909  cp++;
910 
911  if (*cp == '\0') {
912  if (name == cp)
913  break;
914 
915  /* end of string in middle of arg */
916  bu_log("bu_structparse: input keyword '%s' is not followed by '=' in '%s'\nInput must be in keyword=value format.\n",
917  name, bu_vls_addr(in_vls));
918  bu_vls_free(&vls);
919  return -2;
920  }
921 
922  *cp++ = '\0';
923 
924  /* Find end of value. */
925  if (*cp == '"') {
926  /* strings are double-quote (") delimited skip leading " &
927  * find terminating " while skipping escaped quotes (\")
928  */
929  for (value = ++cp; *cp != '\0'; ++cp)
930  if (*cp == '"' &&
931  (cp == value || *(cp-1) != '\\'))
932  break;
933 
934  if (*cp != '"') {
935  bu_log("bu_structparse: keyword '%s'=\" without closing \"\n",
936  name);
937  bu_vls_free(&vls);
938  return -3;
939  }
940  } else {
941  /* non-strings are white-space delimited */
942  value = cp;
943  while (*cp != '\0' && !isspace((int)(*cp)))
944  cp++;
945  }
946 
947  if (*cp != '\0')
948  *cp++ = '\0';
949 
950  /* Lookup name in desc table and modify */
951  retval = parse_struct_lookup(desc, name, base, value, data);
952  if (retval == -1) {
953  bu_log("WARNING: Keyword '%s=%s' not recognized.\n",
954  name, value);
955  bu_struct_print("Current key values:", desc, base);
956  } else if (retval == -2) {
957  bu_vls_free(&vls);
958  return -2;
959  }
960 
961  }
962  bu_vls_free(&vls);
963  return 0;
964 }
965 
966 
967 /* XXX Should this be here, or could it be with the matrix support?
968  * pretty-print a matrix
969  */
970 HIDDEN void
971 parse_matprint(const char *name, register const fastf_t *mat)
972 {
973  int delta;
974 
975  if (UNLIKELY(!name || !mat))
976  return;
977 
978  delta = (int)strlen(name)+2;
979 
980  /* indent the body of the matrix */
981  bu_log_indent_delta(delta);
982 
983  bu_log(" %s=%12E %12E %12E %12E\n",
984  name, mat[0], mat[1], mat[2], mat[3]);
985 
986  bu_log("%12E %12E %12E %12E\n",
987  mat[4], mat[5], mat[6], mat[7]);
988 
989  bu_log("%12E %12E %12E %12E\n",
990  mat[8], mat[9], mat[10], mat[11]);
991 
992  bu_log_indent_delta(-delta);
993 
994  bu_log("%12E %12E %12E %12E\n",
995  mat[12], mat[13], mat[14], mat[15]);
996 }
997 
998 
999 HIDDEN void
1000 parse_dmatprint(const char *name, register const double *mat)
1001 {
1002  int delta;
1003 
1004  if (UNLIKELY(!name || !mat))
1005  return;
1006 
1007  delta = (int)strlen(name)+2;
1008 
1009  /* indent the body of the matrix */
1010  bu_log_indent_delta(delta);
1011 
1012  bu_log(" %s=%12E %12E %12E %12E\n",
1013  name, mat[0], mat[1], mat[2], mat[3]);
1014 
1015  bu_log("%12E %12E %12E %12E\n",
1016  mat[4], mat[5], mat[6], mat[7]);
1017 
1018  bu_log("%12E %12E %12E %12E\n",
1019  mat[8], mat[9], mat[10], mat[11]);
1020 
1021  bu_log_indent_delta(-delta);
1022 
1023  bu_log("%12E %12E %12E %12E\n",
1024  mat[12], mat[13], mat[14], mat[15]);
1025 }
1026 
1027 
1028 HIDDEN void
1030  const char *name,
1031  register const fastf_t *mat)
1032 {
1033  int delta;
1034 
1035  if (UNLIKELY(!vls || !name || !mat))
1036  return;
1037 
1038  delta = (int)strlen(name)+2;
1039 
1040  /* indent the body of the matrix */
1041  bu_log_indent_delta(delta);
1042 
1043  bu_vls_printf(vls, " %s=%12E %12E %12E %12E\n",
1044  name, mat[0], mat[1], mat[2], mat[3]);
1045  bu_log_indent_vls(vls);
1046 
1047  bu_vls_printf(vls, "%12E %12E %12E %12E\n",
1048  mat[4], mat[5], mat[6], mat[7]);
1049  bu_log_indent_vls(vls);
1050 
1051  bu_vls_printf(vls, "%12E %12E %12E %12E\n",
1052  mat[8], mat[9], mat[10], mat[11]);
1053  bu_log_indent_vls(vls);
1054 
1055  bu_log_indent_delta(-delta);
1056 
1057  bu_vls_printf(vls, "%12E %12E %12E %12E\n",
1058  mat[12], mat[13], mat[14], mat[15]);
1059 }
1060 
1061 
1062 HIDDEN void
1064  const char *name,
1065  register const double *mat)
1066 {
1067  int delta;
1068 
1069  if (UNLIKELY(!vls || !name || !mat))
1070  return;
1071 
1072  delta = (int)strlen(name)+2;
1073 
1074  /* indent the body of the matrix */
1075  bu_log_indent_delta(delta);
1076 
1077  bu_vls_printf(vls, " %s=%12E %12E %12E %12E\n",
1078  name, mat[0], mat[1], mat[2], mat[3]);
1079  bu_log_indent_vls(vls);
1080 
1081  bu_vls_printf(vls, "%12E %12E %12E %12E\n",
1082  mat[4], mat[5], mat[6], mat[7]);
1083  bu_log_indent_vls(vls);
1084 
1085  bu_vls_printf(vls, "%12E %12E %12E %12E\n",
1086  mat[8], mat[9], mat[10], mat[11]);
1087  bu_log_indent_vls(vls);
1088 
1089  bu_log_indent_delta(-delta);
1090 
1091  bu_vls_printf(vls, "%12E %12E %12E %12E\n",
1092  mat[12], mat[13], mat[14], mat[15]);
1093 }
1094 
1095 
1096 void
1097 bu_vls_struct_item(struct bu_vls *vp, const struct bu_structparse *sdp, const char *base, int sep_char)
1098 
1099 /* item description */
1100 /* base address of users structure */
1101 /* value separator */
1102 {
1103  register char *loc;
1104 
1105  if (UNLIKELY(!vp || !base))
1106  return;
1107 
1108  if (UNLIKELY(sdp == (struct bu_structparse *)NULL)) {
1109  bu_log("NULL \"struct bu_structparse\" pointer\n");
1110  return;
1111  }
1112 
1113  loc = (char *)(base + sdp->sp_offset);
1114 
1115  if (UNLIKELY(sdp->sp_fmt[0] == 'i')) {
1116  bu_log("Cannot print type 'i' yet!\n");
1117  return;
1118  }
1119 
1120  if (UNLIKELY(sdp->sp_fmt[0] != '%')) {
1121  bu_log("bu_vls_struct_item: %s: unknown format '%s'\n",
1122  sdp->sp_name, sdp->sp_fmt);
1123  return;
1124  }
1125 
1126  switch (sdp->sp_fmt[1]) {
1127  case 'c':
1128  case 's':
1129  if (sdp->sp_count < 1)
1130  break;
1131  if (sdp->sp_count == 1)
1132  bu_vls_printf(vp, "%c", *loc);
1133  else
1134  bu_vls_printf(vp, "%s", (char *)loc);
1135  break;
1136  case 'V':
1137  {
1138  struct bu_vls *vls = (struct bu_vls *)loc;
1139  bu_vls_vlscat(vp, vls);
1140  }
1141  break;
1142  case 'i':
1143  {
1144  register size_t i = sdp->sp_count;
1145  register short *sp = (short *)loc;
1146 
1147  bu_vls_printf(vp, "%d", *sp++);
1148  while (--i > 0) bu_vls_printf(vp, "%c%d", sep_char, *sp++);
1149  }
1150  break;
1151  case 'd':
1152  {
1153  register size_t i = sdp->sp_count;
1154  register int *dp = (int *)loc;
1155 
1156  bu_vls_printf(vp, "%d", *dp++);
1157  while (--i > 0) bu_vls_printf(vp, "%c%d", sep_char, *dp++);
1158  }
1159  break;
1160  case 'f':
1161  {
1162  register size_t i = sdp->sp_count;
1163  register fastf_t *fp = (fastf_t *)loc;
1164 
1165  bu_vls_printf(vp, "%.25G", *fp++);
1166  while (--i > 0) bu_vls_printf(vp, "%c%.25G", sep_char, *fp++);
1167  }
1168  break;
1169  case 'g':
1170  {
1171  register size_t i = sdp->sp_count;
1172  register double *dp = (double *)loc;
1173 
1174  bu_vls_printf(vp, "%.25G", *dp++);
1175  while (--i > 0) bu_vls_printf(vp, "%c%.25G", sep_char, *dp++);
1176  }
1177  break;
1178  case 'x':
1179  {
1180  register size_t i = sdp->sp_count;
1181  register int *dp = (int *)loc;
1182 
1183  bu_vls_printf(vp, "%08x", *dp++);
1184  while (--i > 0) bu_vls_printf(vp, "%c%08x", sep_char, *dp++);
1185  }
1186  break;
1187  case 'p':
1188  {
1189  BU_ASSERT(sdp->sp_count == 1);
1190 
1191  /* Indirect to another structure */
1192  /* FIXME: unimplemented */
1193  bu_log("INTERNAL ERROR: Cannot print type '%%p' yet!\n");
1194  }
1195  break;
1196  default:
1197  break;
1198  }
1199 }
1200 
1201 
1202 int
1203 bu_vls_struct_item_named(struct bu_vls *vp, const struct bu_structparse *parsetab, const char *name, const char *base, int sep_char)
1204 {
1205  register const struct bu_structparse *sdp;
1206 
1207  if (UNLIKELY(!vp || !parsetab))
1208  return -1;
1209 
1210  for (sdp = parsetab; sdp->sp_name != NULL; sdp++)
1211  if (BU_STR_EQUAL(sdp->sp_name, name)) {
1212  bu_vls_struct_item(vp, sdp, base, sep_char);
1213  return 0;
1214  }
1215 
1216  return -1;
1217 }
1218 
1219 
1220 void
1221 bu_struct_print(const char *title, const struct bu_structparse *parsetab, const char *base)
1222 
1223 /* structure description */
1224 /* base address of users structure */
1225 {
1226  register const struct bu_structparse *sdp;
1227  register char *loc;
1228  register int lastoff = -1;
1229  register size_t i = 0;
1230 
1231  if (title)
1232  bu_log("%s\n", title);
1233 
1234  if (UNLIKELY(parsetab == (struct bu_structparse *)NULL)) {
1235  bu_log("NULL \"struct bu_structparse\" pointer\n");
1236  return;
1237  }
1238 
1239  if (UNLIKELY(base == NULL))
1240  return;
1241 
1242  for (sdp = parsetab; sdp->sp_name != (char *)0; sdp++) {
1243 
1244  /* Skip alternate keywords for same value */
1245  if (lastoff == (int)sdp->sp_offset)
1246  continue;
1247  lastoff = (int)sdp->sp_offset;
1248 
1249  loc = (char *)(base + sdp->sp_offset);
1250 
1251  if (sdp->sp_fmt[0] == 'i') {
1252  /* DEPRECATED: use %p instead. */
1253  static int warned = 0;
1254  if (!warned) {
1255  bu_log("DEVELOPER DEPRECATION NOTICE: Use of \"i\" is replaced by \"%%p\" for chained bu_structparse tables.\n");
1256  warned++;
1257  }
1258  bu_struct_print(sdp->sp_name, (struct bu_structparse *)sdp->sp_offset, base);
1259  continue;
1260  }
1261 
1262  if (sdp->sp_fmt[0] != '%') {
1263  bu_log("bu_struct_print: %s: unknown format '%s'\n",
1264  sdp->sp_name, sdp->sp_fmt);
1265  continue;
1266  }
1267 
1268  switch (sdp->sp_fmt[1]) {
1269  case 'c':
1270  case 's':
1271  if (sdp->sp_count < 1)
1272  break;
1273  if (sdp->sp_count == 1)
1274  bu_log("\t%s='%c'\n", sdp->sp_name, *loc);
1275  else
1276  bu_log("\t%s=\"%s\"\n", sdp->sp_name,
1277  (char *)loc);
1278  break;
1279  case 'V':
1280  {
1281  struct bu_vls *vls = (struct bu_vls *)loc;
1282 
1283  bu_log("\t%s=\"%s\"\n", sdp->sp_name, bu_vls_addr(vls));
1284  bu_log("\t\t(vls_magic)0x%lx (vls_offset)%zu (vls_len)%zu (vls_max)%zu\n",
1285  (long unsigned int)vls->vls_magic, vls->vls_offset, vls->vls_len, vls->vls_max);
1286  }
1287  break;
1288  case 'i':
1289  {
1290  register short *sp = (short *)loc;
1291 
1292  bu_log("\t%s=%d", sdp->sp_name, *sp++);
1293 
1294  for (i = 1; i < sdp->sp_count; i++) {
1295  bu_log("%c%d", COMMA, *sp++);
1296  }
1297 
1298  bu_log("\n");
1299  }
1300  break;
1301  case 'd':
1302  {
1303  register int *dp = (int *)loc;
1304 
1305  bu_log("\t%s=%d", sdp->sp_name, *dp++);
1306 
1307  for (i = 1; i < sdp->sp_count; i++) {
1308  bu_log("%c%d", COMMA, *dp++);
1309  }
1310 
1311  bu_log("\n");
1312  }
1313  break;
1314  case 'f':
1315  {
1316  register fastf_t *dp = (fastf_t *)loc;
1317 
1318  if (sdp->sp_count == 16) {
1319  parse_matprint(sdp->sp_name, dp);
1320  } else if (sdp->sp_count <= 3) {
1321  bu_log("\t%s=%.25G", sdp->sp_name, *dp++);
1322 
1323  for (i = 1; i < sdp->sp_count; i++) {
1324  bu_log("%c%.25G", COMMA, *dp++);
1325  }
1326 
1327  bu_log("\n");
1328  } else {
1329  int delta = (int)strlen(sdp->sp_name)+2;
1330 
1331  bu_log_indent_delta(delta);
1332 
1333  bu_log("\t%s=%.25G\n", sdp->sp_name, *dp++);
1334 
1335  /* print first and last value individually, so
1336  * don't iterate over them.
1337  */
1338  for (i = 1; i < sdp->sp_count-1; i++) {
1339  bu_log("%.25G\n", *dp++);
1340  }
1341 
1342  bu_log_indent_delta(-delta);
1343  bu_log("%.25G\n", *dp);
1344  }
1345  }
1346  break;
1347  case 'g':
1348  {
1349  register double *dp = (double *)loc;
1350 
1351  if (sdp->sp_count == 16) {
1352  parse_dmatprint(sdp->sp_name, dp);
1353  } else if (sdp->sp_count <= 3) {
1354  bu_log("\t%s=%.25G", sdp->sp_name, *dp++);
1355 
1356  for (i = 1; i < sdp->sp_count; i++) {
1357  bu_log("%c%.25G", COMMA, *dp++);
1358  }
1359 
1360  bu_log("\n");
1361  } else {
1362  int delta = (int)strlen(sdp->sp_name)+2;
1363 
1364  bu_log_indent_delta(delta);
1365 
1366  bu_log("\t%s=%.25G\n", sdp->sp_name, *dp++);
1367 
1368  /* print first and last value individually, so
1369  * don't iterate over them.
1370  */
1371  for (i = 1; i < sdp->sp_count-1; i++) {
1372  bu_log("%.25G\n", *dp++);
1373  }
1374 
1375  bu_log_indent_delta(-delta);
1376  bu_log("%.25G\n", *dp);
1377  }
1378  }
1379  break;
1380  case 'x':
1381  {
1382  register int *dp = (int *)loc;
1383 
1384  bu_log("\t%s=%08x", sdp->sp_name, *dp++);
1385 
1386  for (i = 1; i < sdp->sp_count; i++) {
1387  bu_log("%c%08x", COMMA, *dp++);
1388  }
1389 
1390  bu_log("\n");
1391  }
1392  break;
1393  case 'p':
1394  {
1395  struct bu_structparse *tbl = (struct bu_structparse *)sdp->sp_offset;
1396 
1397  BU_ASSERT(sdp->sp_count == 1);
1398 
1399  bu_struct_print(sdp->sp_name, tbl, base);
1400  break;
1401  }
1402  default:
1403  bu_log("bu_struct_print: Unknown format: %s=%s ??\n", sdp->sp_name, sdp->sp_fmt);
1404  break;
1405  }
1406  }
1407 }
1408 
1409 
1410 HIDDEN void
1411 parse_vls_print_floating(struct bu_vls *vls, const char *name, size_t count, const fastf_t *fp, const double *dp)
1412 {
1413  register size_t tmpi;
1414  register char *cp;
1415 
1416  size_t increase;
1417 
1418  if (UNLIKELY(!vls || !name))
1419  return;
1420 
1421  increase = strlen(name) + 3 + 32 * count;
1422  bu_vls_extend(vls, (unsigned int)increase);
1423 
1424 
1425  /* FIXME: should not directly access the bu_vls members */
1426  cp = vls->vls_str + vls->vls_offset + vls->vls_len;
1427  if (fp) {
1428  snprintf(cp, increase, "%s%s=%.27G", (vls->vls_len?" ":""), name, *fp++);
1429  }
1430  if (dp) {
1431  snprintf(cp, increase, "%s%s=%.27G", (vls->vls_len?" ":""), name, *dp++);
1432  }
1433  tmpi = strlen(cp);
1434  vls->vls_len += tmpi;
1435 
1436  while (--count > 0) {
1437  cp += tmpi;
1438  if (fp) {
1439  sprintf(cp, "%c%.27G", COMMA, *fp++);
1440  }
1441  if (dp) {
1442  sprintf(cp, "%c%.27G", COMMA, *dp++);
1443  }
1444  tmpi = strlen(cp);
1445  vls->vls_len += tmpi;
1446  }
1447 }
1448 
1449 
1450 void
1451 bu_vls_struct_print(struct bu_vls *vls, register const struct bu_structparse *sdp, const char *base)
1452 /* vls to print into */
1453 /* structure description */
1454 /* structure pointer */
1455 {
1456  register char *loc;
1457  register int lastoff = -1;
1458  register char *cp;
1459  size_t increase;
1460 
1461  BU_CK_VLS(vls);
1462 
1463  if (UNLIKELY(sdp == (struct bu_structparse *)NULL)) {
1464  bu_log("NULL \"struct bu_structparse\" pointer\n");
1465  return;
1466  }
1467  if (UNLIKELY(base == NULL))
1468  return;
1469 
1470  for (; sdp->sp_name != (char*)NULL; sdp++) {
1471  /* Skip alternate keywords for same value */
1472 
1473  if (lastoff == (int)sdp->sp_offset)
1474  continue;
1475  lastoff = (int)sdp->sp_offset;
1476 
1477  loc = (char *)(base + sdp->sp_offset);
1478 
1479  if (sdp->sp_fmt[0] == 'i') {
1480  struct bu_vls sub_str = BU_VLS_INIT_ZERO;
1481 
1482  /* DEPRECATED: use %p instead. */
1483  static int warned = 0;
1484  if (!warned) {
1485  bu_log("DEVELOPER DEPRECATION NOTICE: Use of \"i\" is replaced by \"%%p\" for chained bu_structparse tables.\n");
1486  warned++;
1487  }
1488 
1489  bu_vls_struct_print(&sub_str, (struct bu_structparse *)sdp->sp_offset, base);
1490  bu_vls_vlscat(vls, &sub_str);
1491  bu_vls_free(&sub_str);
1492  continue;
1493  }
1494 
1495  if (sdp->sp_fmt[0] != '%') {
1496  bu_log("bu_struct_print: %s: unknown format '%s'\n",
1497  sdp->sp_name, sdp->sp_fmt);
1498  break;
1499  }
1500 
1501  switch (sdp->sp_fmt[1]) {
1502  case 'c':
1503  case 's':
1504  if (sdp->sp_count < 1)
1505  break;
1506  if (sdp->sp_count == 1) {
1507  increase = strlen(sdp->sp_name)+6;
1508  bu_vls_extend(vls, (unsigned int)increase);
1509  cp = vls->vls_str + vls->vls_offset + vls->vls_len;
1510  if (*loc == '"')
1511  snprintf(cp, increase, "%s%s=\"%s\"",
1512  (vls->vls_len?" ":""),
1513  sdp->sp_name, "\\\"");
1514  else
1515  snprintf(cp, increase, "%s%s=\"%c\"",
1516  (vls->vls_len?" ":""),
1517  sdp->sp_name,
1518  *loc);
1519  vls->vls_len += (int)strlen(cp);
1520  } else {
1521  struct bu_vls tmpstr = BU_VLS_INIT_ZERO;
1522 
1523  /* quote the quote characters */
1524  while (*loc) {
1525  if (*loc == '"') {
1526  bu_vls_putc(&tmpstr, '\\');
1527  }
1528  bu_vls_putc(&tmpstr, *loc);
1529  loc++;
1530  }
1531  bu_vls_printf(vls, "%s=\"%s\"", sdp->sp_name, bu_vls_addr(&tmpstr));
1532  bu_vls_free(&tmpstr);
1533  }
1534  break;
1535  case 'V':
1536  {
1537  struct bu_vls *vls_p = (struct bu_vls *)loc;
1538  bu_vls_printf(vls, "%s=\"%s\"", sdp->sp_name, bu_vls_addr(vls_p));
1539  }
1540  break;
1541  case 'i':
1542  {
1543  register size_t i = sdp->sp_count;
1544  register short *sp = (short *)loc;
1545  register int tmpi;
1546 
1547  increase = 64 * i + strlen(sdp->sp_name) + 3;
1548  bu_vls_extend(vls, (unsigned int)increase);
1549 
1550 
1551  cp = vls->vls_str + vls->vls_offset + vls->vls_len;
1552  snprintf(cp, increase, "%s%s=%d",
1553  (vls->vls_len?" ":""),
1554  sdp->sp_name, *sp++);
1555  tmpi = (int)strlen(cp);
1556  vls->vls_len += tmpi;
1557 
1558  while (--i > 0) {
1559  cp += tmpi;
1560  sprintf(cp, "%c%d", COMMA, *sp++);
1561  tmpi = (int)strlen(cp);
1562  vls->vls_len += tmpi;
1563  }
1564  }
1565  break;
1566  case 'd':
1567  {
1568  register size_t i = sdp->sp_count;
1569  register int *dp = (int *)loc;
1570 
1571  bu_vls_printf(vls, "%s%s=%d", " ", sdp->sp_name, *dp++);
1572 
1573  while (--i > 0) {
1574  bu_vls_printf(vls, "%c%d", COMMA, *dp++);
1575  }
1576  }
1577  break;
1578  case 'f':
1579  parse_vls_print_floating(vls, sdp->sp_name, sdp->sp_count, (fastf_t *)loc, NULL);
1580  break;
1581  case 'g':
1582  parse_vls_print_floating(vls, sdp->sp_name, sdp->sp_count, NULL, (double *)loc);
1583  break;
1584  case 'p':
1585  {
1586  struct bu_vls sub_str = BU_VLS_INIT_ZERO;
1587 
1588  BU_ASSERT(sdp->sp_count == 1);
1589 
1590  bu_vls_struct_print(&sub_str, (struct bu_structparse *)sdp->sp_offset, base);
1591  bu_vls_vlscat(vls, &sub_str);
1592  bu_vls_free(&sub_str);
1593  continue;
1594  }
1595 
1596  default:
1597  bu_log("\t%s=%s ??\n", sdp->sp_name, sdp->sp_fmt);
1598  bu_bomb("unexpected case encountered in bu_vls_struct_print\n");
1599  break;
1600  }
1601  }
1602 }
1603 
1604 
1605 void
1607  const char *title,
1608  const struct bu_structparse *parsetab, /* structure description */
1609  const char *base) /* base address of users structure */
1610 {
1611  register const struct bu_structparse *sdp;
1612  register char *loc;
1613  register int lastoff = -1;
1614 
1615  if (UNLIKELY(!vls_out || !base))
1616  return;
1617 
1618  if (title)
1619  bu_vls_printf(vls_out, "%s\n", title);
1620 
1621  if (UNLIKELY(parsetab == (struct bu_structparse *)NULL)) {
1622  bu_vls_printf(vls_out, "NULL \"struct bu_structparse\" pointer\n");
1623  return;
1624  }
1625 
1626  for (sdp = parsetab; sdp->sp_name != (char *)0; sdp++) {
1627 
1628  /* Skip alternate keywords for same value */
1629  if (lastoff == (int)sdp->sp_offset)
1630  continue;
1631  lastoff = (int)sdp->sp_offset;
1632 
1633  loc = (char *)(base + sdp->sp_offset);
1634 
1635  if (sdp->sp_fmt[0] == 'i') {
1636  /* DEPRECATED: use %p instead. */
1637  static int warned = 0;
1638  if (!warned) {
1639  bu_log("DEVELOPER DEPRECATION NOTICE: Use of \"i\" is replaced by \"%%p\" for chained bu_structparse tables.\n");
1640  warned++;
1641  }
1642  bu_vls_struct_print2(vls_out, sdp->sp_name, (struct bu_structparse *)sdp->sp_count, base);
1643  continue;
1644  }
1645 
1646  if (sdp->sp_fmt[0] != '%') {
1647  bu_vls_printf(vls_out, "bu_vls_struct_print: %s: unknown format '%s'\n",
1648  sdp->sp_name, sdp->sp_fmt);
1649  continue;
1650  }
1651 
1652  switch (sdp->sp_fmt[1]) {
1653  case 'c':
1654  case 's':
1655  if (sdp->sp_count < 1)
1656  break;
1657  if (sdp->sp_count == 1)
1658  bu_vls_printf(vls_out, "\t%s='%c'\n", sdp->sp_name, *loc);
1659  else
1660  bu_vls_printf(vls_out, "\t%s=\"%s\"\n", sdp->sp_name,
1661  (char *)loc);
1662  break;
1663  case 'V':
1664  {
1665  struct bu_vls *vls = (struct bu_vls *)loc;
1666 
1667  bu_vls_printf(vls_out, "\t%s=\"%s\"\n", sdp->sp_name, bu_vls_addr(vls));
1668  bu_vls_printf(vls_out, "\t\t(vls_magic)%ld (vls_offset)%zu (vls_len)%zu (vls_max)%zu\n",
1669  (long unsigned int)vls->vls_magic, vls->vls_offset, vls->vls_len, vls->vls_max);
1670  }
1671  break;
1672  case 'i':
1673  {
1674  register size_t i = sdp->sp_count;
1675  register short *sp = (short *)loc;
1676 
1677  bu_vls_printf(vls_out, "\t%s=%d", sdp->sp_name, *sp++);
1678 
1679  while (--i > 0)
1680  bu_vls_printf(vls_out, "%c%d", COMMA, *sp++);
1681 
1682  bu_vls_printf(vls_out, "\n");
1683  }
1684  break;
1685  case 'd':
1686  {
1687  register size_t i = sdp->sp_count;
1688  register int *dp = (int *)loc;
1689 
1690  bu_vls_printf(vls_out, "\t%s=%d", sdp->sp_name, *dp++);
1691 
1692  while (--i > 0)
1693  bu_vls_printf(vls_out, "%c%d", COMMA, *dp++);
1694 
1695  bu_vls_printf(vls_out, "\n");
1696  }
1697  break;
1698  case 'f':
1699  {
1700  register size_t i = sdp->sp_count;
1701  register fastf_t *dp = (fastf_t *)loc;
1702 
1703  if (sdp->sp_count == 16) {
1704  parse_vls_matprint(vls_out, sdp->sp_name, dp);
1705  } else if (sdp->sp_count <= 3) {
1706  bu_vls_printf(vls_out, "\t%s=%.25G", sdp->sp_name, *dp++);
1707 
1708  while (--i > 0)
1709  bu_vls_printf(vls_out, "%c%.25G", COMMA, *dp++);
1710 
1711  bu_vls_printf(vls_out, "\n");
1712  } else {
1713  int delta = (int)strlen(sdp->sp_name)+2;
1714 
1715  bu_log_indent_delta(delta);
1716  bu_vls_printf(vls_out, "\t%s=%.25G\n", sdp->sp_name, *dp++);
1717  bu_log_indent_vls(vls_out);
1718 
1719  /* print first and last value individually, so
1720  * don't iterate over them.
1721  */
1722  while (--i > 1) {
1723  bu_vls_printf(vls_out, "%.25G\n", *dp++);
1724  bu_log_indent_vls(vls_out);
1725  }
1726 
1727  bu_log_indent_delta(-delta);
1728  bu_vls_printf(vls_out, "%.25G\n", *dp);
1729  }
1730  }
1731  break;
1732  case 'g':
1733  {
1734  register size_t i = sdp->sp_count;
1735  register double *dp = (double *)loc;
1736 
1737  if (sdp->sp_count == 16) {
1738  parse_vls_dmatprint(vls_out, sdp->sp_name, dp);
1739  } else if (sdp->sp_count <= 3) {
1740  bu_vls_printf(vls_out, "\t%s=%.25G", sdp->sp_name, *dp++);
1741 
1742  while (--i > 0)
1743  bu_vls_printf(vls_out, "%c%.25G", COMMA, *dp++);
1744 
1745  bu_vls_printf(vls_out, "\n");
1746  } else {
1747  int delta = (int)strlen(sdp->sp_name)+2;
1748 
1749  bu_log_indent_delta(delta);
1750  bu_vls_printf(vls_out, "\t%s=%.25G\n", sdp->sp_name, *dp++);
1751  bu_log_indent_vls(vls_out);
1752 
1753  /* print first and last value individually, so
1754  * don't iterate over them.
1755  */
1756  while (--i > 1) {
1757  bu_vls_printf(vls_out, "%.25G\n", *dp++);
1758  bu_log_indent_vls(vls_out);
1759  }
1760 
1761  bu_log_indent_delta(-delta);
1762  bu_vls_printf(vls_out, "%.25G\n", *dp);
1763  }
1764  }
1765  break;
1766  case 'x':
1767  {
1768  register size_t i = sdp->sp_count;
1769  register int *dp = (int *)loc;
1770 
1771  bu_vls_printf(vls_out, "\t%s=%08x", sdp->sp_name, *dp++);
1772 
1773  while (--i > 0)
1774  bu_vls_printf(vls_out, "%c%08x", COMMA, *dp++);
1775 
1776  bu_vls_printf(vls_out, "\n");
1777  }
1778  break;
1779  case 'p':
1780  BU_ASSERT(sdp->sp_count == 1);
1781 
1782  bu_vls_struct_print2(vls_out, sdp->sp_name, (struct bu_structparse *)sdp->sp_offset, base);
1783  break;
1784  default:
1785  bu_vls_printf(vls_out, " bu_vls_struct_print2: Unknown format: %s=%s ??\n",
1786  sdp->sp_name, sdp->sp_fmt);
1787  break;
1788  }
1789  }
1790 }
1791 
1792 
1793 void
1794 bu_parse_mm(const struct bu_structparse *sdp, const char *name, char *base, const char *value)
1795 /* structure description */
1796 /* struct member name */
1797 /* beginning of structure */
1798 /* string containing value */
1799 {
1800  double *p;
1801 
1802  if (UNLIKELY(!sdp || !base || !value))
1803  return;
1804 
1805  p = (double *)(base+sdp->sp_offset);
1806 
1807  /* reconvert with optional units, name if-statement just to quell unused warning */
1808  if (name)
1809  *p = bu_mm_value(value);
1810  else
1811  *p = bu_mm_value(value);
1812 }
1813 
1814 
1815 #define STATE_UNKNOWN 0
1816 #define STATE_IN_KEYWORD 1
1817 #define STATE_IN_VALUE 2
1818 #define STATE_IN_QUOTED_VALUE 3
1819 
1820 int
1821 bu_key_eq_to_key_val(const char *in, const char **next, struct bu_vls *vls)
1822 {
1823  const char *iptr=in;
1824  const char *start;
1825  int state=STATE_IN_KEYWORD;
1826 
1827  BU_CK_VLS(vls);
1828 
1829  if (UNLIKELY(!next || !vls))
1830  return -1;
1831 
1832  *next = NULL;
1833 
1834  while (iptr && *iptr) {
1835  const char *prev = NULL;
1836 
1837  switch (state) {
1838  case STATE_IN_KEYWORD:
1839  /* skip leading white space */
1840  while (isspace((int)(*iptr)))
1841  iptr++;
1842 
1843  if (!(*iptr))
1844  break;
1845 
1846  if (*iptr == ';') {
1847  /* found end of a stack element */
1848  *next = iptr+1;
1849  return 0;
1850  }
1851 
1852  /* copy keyword up to '=' */
1853  start = iptr;
1854  while (*iptr && *iptr != '=')
1855  iptr++;
1856 
1857  bu_vls_strncat(vls, start, iptr - start);
1858 
1859  /* add a single space after keyword */
1860  bu_vls_putc(vls, ' ');
1861 
1862  if (!*iptr)
1863  break;
1864 
1865  /* skip over '=' in input */
1866  iptr++;
1867 
1868  /* switch to value state */
1869  state = STATE_IN_VALUE;
1870 
1871  break;
1872  case STATE_IN_VALUE:
1873  /* skip excess white space */
1874  while (isspace((int)(*iptr)))
1875  iptr++;
1876 
1877  /* check for quoted value */
1878  if (*iptr == '"') {
1879  /* switch to quoted value state */
1880  state = STATE_IN_QUOTED_VALUE;
1881 
1882  /* skip over '"' */
1883  iptr++;
1884 
1885  break;
1886  }
1887 
1888  /* copy value up to next white space or end of string */
1889  start = iptr;
1890  while (*iptr && *iptr != ';' && !isspace((int)(*iptr)))
1891  iptr++;
1892 
1893  bu_vls_strncat(vls, start, iptr - start);
1894 
1895  if (*iptr) {
1896  /* more to come */
1897  bu_vls_putc(vls, ' ');
1898 
1899  /* switch back to keyword state */
1900  state = STATE_IN_KEYWORD;
1901  }
1902 
1903  break;
1904  case STATE_IN_QUOTED_VALUE:
1905  /* copy byte-for-byte to end quote (watch out for escaped quote)
1906  * replace quotes with '{' '}' */
1907 
1908  bu_vls_strcat(vls, " {");
1909  while (1) {
1910  if (*iptr == '"' && *prev != '\\') {
1911  bu_vls_putc(vls, '}');
1912  iptr++;
1913  break;
1914  }
1915  bu_vls_putc(vls, *iptr);
1916  prev = iptr++;
1917  }
1918 
1919  if (*iptr && *iptr != ';') /* more to come */
1920  bu_vls_putc(vls, ' ');
1921 
1922  /* switch back to keyword state */
1923  state = STATE_IN_KEYWORD;
1924 
1925  break;
1926  }
1927  }
1928  return 0;
1929 }
1930 
1931 
1932 int
1933 bu_shader_to_list(const char *in, struct bu_vls *vls)
1934 {
1935  size_t len;
1936  size_t shader_name_len = 0;
1937  char *iptr;
1938  const char *shader;
1939  char *copy;
1940  char *next;
1941 
1942  if (UNLIKELY(in == NULL))
1943  in = "";
1944 
1945  copy = bu_strdup(in);
1946  next = copy;
1947 
1948  BU_CK_VLS(vls);
1949 
1950  while (next) {
1951  iptr = next;
1952 
1953  /* find start of shader name */
1954  while (isspace((int)(*iptr)))
1955  iptr++;
1956 
1957  shader = iptr;
1958 
1959  /* find end of shader name */
1960  while (*iptr && !isspace((int)(*iptr)) && *iptr != ';')
1961  iptr++;
1962 
1963  shader_name_len = iptr - shader;
1964 
1965  if (shader_name_len == 5 && !bu_strncasecmp(shader, "stack", 5)) {
1966 
1967  /* stack shader, loop through all shaders in stack */
1968  int done = 0;
1969 
1970  bu_vls_strcat(vls, "stack {");
1971 
1972  while (!done) {
1973  const char *shade1;
1974 
1975  /* find start of shader */
1976  while (isspace((int)(*iptr)))
1977  iptr++;
1978 
1979  if (*iptr == '\0')
1980  break;
1981 
1982  shade1 = iptr;
1983 
1984  /* find end of shader */
1985  while (*iptr && *iptr != ';')
1986  iptr++;
1987 
1988  if (*iptr == '\0')
1989  done = 1;
1990 
1991  *iptr = '\0';
1992 
1993  bu_vls_putc(vls, '{');
1994 
1995  if (bu_shader_to_list(shade1, vls)) {
1996  bu_free(copy, BU_FLSTR);
1997  return 1;
1998  }
1999 
2000  bu_vls_strcat(vls, "} ");
2001 
2002  if (!done)
2003  iptr++;
2004  }
2005  bu_vls_putc(vls, '}');
2006  bu_free(copy, BU_FLSTR);
2007  return 0;
2008  }
2009 
2010  if (shader_name_len == 6 && !bu_strncasecmp(shader, "envmap", 6)) {
2011  bu_vls_strcat(vls, "envmap {");
2012  if (bu_shader_to_list(iptr, vls)) {
2013  bu_free(copy, BU_FLSTR);
2014  return 1;
2015  }
2016  bu_vls_putc(vls, '}');
2017  bu_free(copy, BU_FLSTR);
2018  return 0;
2019  }
2020 
2021  bu_vls_strncat(vls, shader, shader_name_len);
2022 
2023  /* skip more white space */
2024  while (*iptr && isspace((int)(*iptr)))
2025  iptr++;
2026 
2027  /* iptr now points at start of parameters, if any */
2028  if (*iptr && *iptr != ';') {
2029  int needClosingBrace = 0;
2030 
2031  bu_vls_strcat(vls, " {");
2032 
2033  if (*iptr == '{') {
2034  /* if parameter set begins with open brace then
2035  * it should already have a closing brace
2036  */
2037  iptr++;
2038  } else {
2039  /* otherwise we'll need to add it */
2040  needClosingBrace = 1;
2041  }
2042 
2043  /* append next set of parameters (if any) to vls */
2044  len = bu_vls_strlen(vls);
2045  if (bu_key_eq_to_key_val(iptr, (const char **)&next, vls)) {
2046  bu_free(copy, BU_FLSTR);
2047  return 1;
2048  }
2049 
2050  if (needClosingBrace) {
2051  /* Add closing brace unless we didn't actually append any
2052  * parameters, in which case we need to delete the " {"
2053  * appended earlier.
2054  */
2055  if (bu_vls_strlen(vls) > len) {
2056  bu_vls_putc(vls, '}');
2057  } else {
2058  bu_vls_trunc(vls, len - 2);
2059  }
2060  }
2061  } else if (*iptr && *iptr == ';') {
2062  next = ++iptr;
2063  } else {
2064  next = (char *)NULL;
2065  }
2066  }
2067 
2068  bu_free(copy, BU_FLSTR);
2069  return 0;
2070 }
2071 
2072 
2073 /**
2074  * Given a list in "{1}, {2}, {3}" form, return a copy of the
2075  * 'index'th entry, which may itself be a list.
2076  *
2077  * Note: caller is responsible for freeing the returned string.
2078  */
2079 HIDDEN char *
2080 parse_list_elem(const char *in, int idx)
2081 {
2082  int depth = 0;
2083  int count = 0;
2084  int len = 0;
2085  const char *ptr = in;
2086  const char *prev = NULL;
2087  const char *start = NULL;
2088  const char *end = NULL;
2089 
2090  struct bu_vls out = BU_VLS_INIT_ZERO;
2091  char *ret = NULL;
2092 
2093  while (ptr && *ptr) {
2094  /* skip leading white space */
2095  while (*ptr && isspace((int)(*ptr))) {
2096  prev = ptr;
2097  ptr++;
2098  }
2099 
2100  if (!*ptr)
2101  break;
2102 
2103  if (depth == 0 && count == idx)
2104  start = ptr;
2105 
2106  if (*ptr == '{') {
2107  depth++;
2108  prev = ptr;
2109  ptr++;
2110  } else if (*ptr == '}') {
2111  depth--;
2112  if (depth == 0)
2113  count++;
2114  if (start && depth == 0) {
2115  end = ptr;
2116  break;
2117  }
2118  prev = ptr;
2119  ptr++;
2120  } else {
2121  while (*ptr &&
2122  (!isspace((int)(*ptr)) || *prev == '\\') &&
2123  (*ptr != '}' || *prev == '\\') &&
2124  (*ptr != '{' || *prev == '\\'))
2125  {
2126  prev = ptr;
2127  ptr++;
2128  }
2129  if (depth == 0)
2130  count++;
2131 
2132  if (start && depth == 0) {
2133  end = ptr-1;
2134  break;
2135  }
2136  }
2137  }
2138 
2139  if (!start)
2140  return (char *)NULL;
2141 
2142  if (*start == '{') {
2143  if (!end || *end != '}') {
2144  bu_log("Error in list (uneven braces?): %s\n", in);
2145  return (char *)NULL;
2146  }
2147 
2148  /* remove enclosing braces */
2149  start++;
2150  while (start < end && isspace((int)(*start)))
2151  start++;
2152 
2153  end--;
2154  while (end > start && isspace((int)(*end)) && *(end-1) != '\\')
2155  end--;
2156 
2157  if (start == end)
2158  return (char *)NULL;
2159  }
2160 
2161  len = end - start + 1;
2162  bu_vls_strncpy(&out, start, len);
2163 
2164  ret = bu_vls_strdup(&out);
2165  bu_vls_free(&out);
2166 
2167  return ret;
2168 }
2169 
2170 
2171 /**
2172  * Return number of items in a string, interpreted as a Tcl list.
2173  */
2174 HIDDEN int
2175 parse_list_length(const char *in)
2176 {
2177  int count = 0;
2178  int depth = 0;
2179  const char *ptr = in;
2180  const char *prev = NULL;
2181 
2182  if (UNLIKELY(in == NULL))
2183  return 0;
2184 
2185  while (ptr && *ptr) {
2186  /* skip leading white space */
2187  while (*ptr && isspace((int)(*ptr))) {
2188  prev = ptr;
2189  ptr++;
2190  }
2191 
2192  if (!*ptr)
2193  break;
2194 
2195  if (*ptr == '{') {
2196  if (depth == 0)
2197  count++;
2198  depth++;
2199  prev = ptr;
2200  ptr++;
2201  } else if (*ptr == '}') {
2202  depth--;
2203  prev = ptr;
2204  ptr++;
2205  } else {
2206  if (depth == 0)
2207  count++;
2208 
2209  while (*ptr &&
2210  (!isspace((int)(*ptr)) || *prev == '\\') &&
2211  (*ptr != '}' || *prev == '\\') &&
2212  (*ptr != '{' || *prev == '\\'))
2213  {
2214  prev = ptr;
2215  ptr++;
2216  }
2217  }
2218  }
2219 
2220  return count;
2221 }
2222 
2223 
2224 HIDDEN int
2225 parse_key_val_to_vls(struct bu_vls *vls, char *params)
2226 {
2227  int len;
2228  int j;
2229 
2230  if (UNLIKELY(!params || strlen(params) == 0))
2231  return 0;
2232 
2233  len = parse_list_length(params);
2234 
2235  if (len == 0) {
2236  return 0;
2237  } else if (len == 1) {
2238  bu_vls_putc(vls, ' ');
2239  bu_vls_strcat(vls, params);
2240  return 0;
2241  } else if (len%2) {
2242  bu_log("ERROR: shader parameters must be even numbered! (key value pairings)\n\t%s\n", params);
2243  return 1;
2244  }
2245 
2246  for (j = 0; j < len; j += 2) {
2247  char *keyword;
2248  char *value;
2249 
2250  keyword = parse_list_elem(params, j);
2251  if (!keyword)
2252  continue;
2253  value = parse_list_elem(params, j+1);
2254  if (!value) {
2255  bu_free(keyword, "parse_key_val_to_vls() keyword");
2256  continue;
2257  }
2258 
2259  bu_vls_putc(vls, ' ');
2260  bu_vls_strcat(vls, keyword);
2261  bu_vls_putc(vls, '=');
2262  if (parse_list_length(value) > 1) {
2263  bu_vls_putc(vls, '"');
2264  bu_vls_strcat(vls, value);
2265  bu_vls_putc(vls, '"');
2266  } else {
2267  bu_vls_strcat(vls, value);
2268  }
2269 
2270  bu_free(keyword, "parse_key_val_to_vls() keyword");
2271  bu_free(value, "parse_key_val_to_vls() value");
2272 
2273  }
2274  return 0;
2275 }
2276 
2277 
2278 int
2279 bu_shader_to_key_eq(const char *in, struct bu_vls *vls)
2280 {
2281  int len;
2282  int ret = 0;
2283  char *shader;
2284  char *params;
2285 
2286  BU_CK_VLS(vls);
2287 
2288  if (UNLIKELY(in == NULL))
2289  return 0;
2290 
2291  len = parse_list_length(in);
2292 
2293  if (len == 0) {
2294  return 0;
2295  } else if (len == 1) {
2296  /* shader with no parameters */
2297  if (bu_vls_strlen(vls))
2298  bu_vls_putc(vls, ' ');
2299  bu_vls_strcat(vls, in);
2300  return 0;
2301  } else if (len != 2) {
2302  bu_log("ERROR: expecting exactly two shader parameters (not %d)!!\n\t%s\n", len, in);
2303  return 1;
2304  }
2305 
2306  shader = parse_list_elem(in, 0);
2307  if (!shader) {
2308  bu_log("ERROR: failed to parse valid shader name\n");
2309  return 1;
2310  }
2311  params = parse_list_elem(in, 1);
2312  if (!params) {
2313  bu_free(shader, "shader");
2314  bu_log("ERROR: failed to parse valid shader parameters\n");
2315  return 1;
2316  }
2317 
2318  /* FIXME: should not be aware of specific shader names here.
2319  * breaks encapsulation and just sucks.
2320  */
2321  if (BU_STR_EQUAL(shader, "envmap")) {
2322  /* environment map */
2323 
2324  if (bu_vls_strlen(vls))
2325  bu_vls_putc(vls, ' ');
2326  bu_vls_strcat(vls, "envmap");
2327 
2328  bu_shader_to_key_eq(params, vls);
2329  } else if (BU_STR_EQUAL(shader, "stack")) {
2330  /* stacked shaders */
2331 
2332  int i;
2333 
2334  if (bu_vls_strlen(vls))
2335  bu_vls_putc(vls, ' ');
2336  bu_vls_strcat(vls, "stack");
2337 
2338  /* get number of shaders in the stack */
2339  len = parse_list_length(params);
2340 
2341  /* process each shader in the stack */
2342  for (i = 0; i < len; i++) {
2343  char *shader1;
2344 
2345  /* each parameter must be a shader specification in itself */
2346  shader1 = parse_list_elem(params, i);
2347 
2348  if (i > 0)
2349  bu_vls_putc(vls, ';');
2350  bu_shader_to_key_eq(shader1, vls);
2351  bu_free(shader1, "shader1");
2352  }
2353  } else {
2354  if (bu_vls_strlen(vls))
2355  bu_vls_putc(vls, ' ');
2356  bu_vls_strcat(vls, shader);
2357  ret = parse_key_val_to_vls(vls, params);
2358  }
2359 
2360  bu_free(shader, "shader");
2361  bu_free(params, "params");
2362 
2363  return ret;
2364 }
2365 
2366 
2367 int
2368 bu_fwrite_external(FILE *fp, const struct bu_external *ep)
2369 {
2370  size_t got;
2371 
2372  if (UNLIKELY(fp == NULL)) {
2373  bu_log("INTERNAL ERROR: NULL file pointer encountered in %s:%d\n", __FILE__, __LINE__);
2374  return -1;
2375  }
2376 
2377  BU_CK_EXTERNAL(ep);
2378 
2379  got = fwrite(ep->ext_buf, 1, ep->ext_nbytes, fp);
2380  if (UNLIKELY(got != (size_t)ep->ext_nbytes)) {
2381  perror("fwrite");
2382  bu_log("ERROR: attempted to write %ld, only wrote %ld\n", (long)ep->ext_nbytes, (long)got);
2383  return -1;
2384  }
2385  return 0;
2386 }
2387 
2388 
2389 void
2390 bu_hexdump_external(FILE *fp, const struct bu_external *ep, const char *str)
2391 {
2392  const unsigned char *cp;
2393  const unsigned char *endp;
2394  size_t i, j, k;
2395 
2396  if (UNLIKELY(fp == NULL)) {
2397  bu_log("INTERNAL ERROR: NULL file pointer encountered in %s:%d\n", __FILE__, __LINE__);
2398  return;
2399  }
2400 
2401  BU_CK_EXTERNAL(ep);
2402 
2403  if (UNLIKELY(str == NULL))
2404  return;
2405 
2406  fprintf(fp, "%s:\n", str);
2407 
2408  if (UNLIKELY(ep->ext_nbytes <= 0))
2409  fprintf(fp, "\tWarning: 0 length external buffer\n");
2410 
2411  cp = (const unsigned char *)ep->ext_buf;
2412  endp = cp + ep->ext_nbytes;
2413  for (i = 0; i < ep->ext_nbytes; i += 16) {
2414  const unsigned char *sp = cp;
2415 
2416  for (j = 0; j < 4; j++) {
2417  for (k = 0; k < 4; k++) {
2418  if (cp >= endp)
2419  fprintf(fp, " ");
2420  else
2421  fprintf(fp, "%2.2x ", *cp++);
2422  }
2423  fprintf(fp, " ");
2424  }
2425  fprintf(fp, " |");
2426 
2427  for (j = 0; j < 16; j++, sp++) {
2428  if (sp >= endp) break;
2429  if (isprint(*sp))
2430  putc(*sp, fp);
2431  else
2432  putc('.', fp);
2433  }
2434 
2435  fprintf(fp, "|\n");
2436  }
2437 }
2438 
2439 
2440 void
2441 bu_free_external(register struct bu_external *ep)
2442 {
2443  BU_CK_EXTERNAL(ep);
2444 
2445  if (UNLIKELY(ep->ext_buf == NULL))
2446  return;
2447 
2448  bu_free(ep->ext_buf, "bu_external ext_buf");
2449  ep->ext_buf = NULL;
2450 }
2451 
2452 
2453 void
2454 bu_copy_external(struct bu_external *op, const struct bu_external *ip)
2455 {
2456  BU_CK_EXTERNAL(ip);
2457  BU_EXTERNAL_INIT(op);
2458 
2459  if (UNLIKELY(op == ip))
2460  return;
2461 
2462  op->ext_nbytes = ip->ext_nbytes;
2463  op->ext_buf = (uint8_t *)bu_malloc(ip->ext_nbytes, "bu_copy_external");
2464  memcpy(op->ext_buf, ip->ext_buf, ip->ext_nbytes);
2465 }
2466 
2467 
2468 char *
2469 bu_next_token(char *str)
2470 {
2471  char *ret = str;
2472 
2473  while (ret && !isspace((int)(*ret)) && *ret !='\0')
2474  ret++;
2475  while (ret && isspace((int)(*ret)))
2476  ret++;
2477 
2478  return ret;
2479 }
2480 
2481 
2482 void
2483 bu_structparse_get_terse_form(struct bu_vls *logstr, const struct bu_structparse *sp)
2484 {
2485  struct bu_vls str = BU_VLS_INIT_ZERO;
2486  size_t i;
2487 
2488  if (UNLIKELY(!logstr || !sp))
2489  return;
2490 
2491  while (sp->sp_name != NULL) {
2492  bu_vls_printf(logstr, "%s ", sp->sp_name);
2493  /* These types are specified by lengths, e.g. %80s */
2494  if (BU_STR_EQUAL(sp->sp_fmt, "%c") ||
2495  BU_STR_EQUAL(sp->sp_fmt, "%s") ||
2496  BU_STR_EQUAL(sp->sp_fmt, "%V")) {
2497  if (sp->sp_count > 1) {
2498  /* Make them all look like %###s */
2499  bu_vls_printf(logstr, "%%%zus", sp->sp_count);
2500  } else {
2501  /* Singletons are specified by their actual character */
2502  bu_vls_printf(logstr, "%%c");
2503  }
2504  } else {
2505  if (sp->sp_count < 2) {
2506  bu_vls_printf(logstr, "%s ", sp->sp_fmt);
2507  } else {
2508  /* Vectors are specified by repetition, e.g. {%f %f %f} */
2509  bu_vls_printf(logstr, "{%s", sp->sp_fmt);
2510  for (i = 1; i < sp->sp_count; i++)
2511  bu_vls_printf(logstr, " %s", sp->sp_fmt);
2512  bu_vls_printf(logstr, "} ");
2513  }
2514  }
2515  ++sp;
2516  }
2517  bu_vls_free(&str);
2518 }
2519 
2520 
2521 int
2523  int argc,
2524  const char **argv,
2525  const struct bu_structparse *desc,
2526  char *base,
2527  void *data)
2528 {
2529  register const struct bu_structparse *sdp = NULL;
2530  register size_t j;
2531  register size_t ii;
2532  const char *cp = NULL;
2533  char *loc = NULL;
2534  struct bu_vls str = BU_VLS_INIT_ZERO;
2535 
2536  if (UNLIKELY(!logstr || !argv))
2537  return BRLCAD_OK;
2538 
2539  if (UNLIKELY(desc == (struct bu_structparse *)NULL)) {
2540  bu_vls_printf(logstr, "bu_structparse_argv: NULL desc pointer\n");
2541  return BRLCAD_ERROR;
2542  }
2543 
2544  /* Run through each of the attributes and their arguments. */
2545 
2546  while (argc > 0) {
2547  /* Find the attribute which matches this argument. */
2548  for (sdp = desc; sdp->sp_name != NULL; sdp++) {
2549  if (!BU_STR_EQUAL(sdp->sp_name, *argv))
2550  continue;
2551 
2552  /* if we get this far, we've got a name match
2553  * with a name in the structure description
2554  */
2555  loc = (char *)(base+((int)sdp->sp_offset));
2556  if (sdp->sp_fmt[0] != '%') {
2557  bu_vls_printf(logstr, "bu_structparse_argv: unknown format\n");
2558  return BRLCAD_ERROR;
2559  }
2560 
2561  --argc;
2562  ++argv;
2563 
2564  switch (sdp->sp_fmt[1]) {
2565  case 'c':
2566  case 's':
2567  /* copy the string to an array of length
2568  * sdp->sp_count, converting escaped double quotes
2569  * to just double quotes
2570  */
2571  if (argc < 1) {
2572  bu_vls_printf(logstr,
2573  "not enough values for \"%s\" argument: should be %zu",
2574  sdp->sp_name,
2575  sdp->sp_count);
2576  return BRLCAD_ERROR;
2577  }
2578  for (ii = j = 0;
2579  j < sdp->sp_count && argv[0][ii] != '\0';
2580  loc[j++] = argv[0][ii++])
2581  ;
2582  if (ii < sdp->sp_count)
2583  loc[ii] = '\0';
2584  if (sdp->sp_count > 1) {
2585  loc[sdp->sp_count-1] = '\0';
2586  bu_vls_printf(logstr, "%s %s ", sdp->sp_name, loc);
2587  } else {
2588  bu_vls_printf(logstr, "%s %c ", sdp->sp_name, *loc);
2589  }
2590  break;
2591  case 'V':
2592  {
2593  /* copy the string to a bu_vls (string of
2594  * variable length provided by libbu)
2595  */
2596  struct bu_vls *vls = (struct bu_vls *)loc;
2597 
2598  /* argv[0] contains the string. i.e., we have
2599  * exactly one value
2600  */
2601  BU_ASSERT(sdp->sp_count == 1);
2602 
2603  if (argc < 1) {
2604  bu_vls_printf(logstr,
2605  "not enough values for \"%s\" argument: should be %zu",
2606  sdp->sp_name,
2607  sdp->sp_count);
2608  return BRLCAD_ERROR;
2609  }
2610 
2611  bu_vls_printf(logstr, "%s ", sdp->sp_name);
2612 
2613  bu_vls_strcpy(vls, argv[0]);
2614 
2615  bu_vls_printf(logstr, "%s ", argv[0]);
2616  break;
2617  }
2618  case 'i': {
2619  register short *sh = (short *)loc;
2620  register int tmpi;
2621 
2622  if (argc < 1) {
2623  bu_vls_printf(logstr,
2624  "not enough values for \"%s\" argument: should have %zu",
2625  sdp->sp_name,
2626  sdp->sp_count);
2627  return BRLCAD_ERROR;
2628  }
2629 
2630  bu_vls_printf(logstr, "%s ", sdp->sp_name);
2631 
2632  /* Special case: '=!' toggles a boolean */
2633  if (argv[0][0] == '!') {
2634  *sh = *sh ? 0 : 1;
2635  bu_vls_printf(logstr, "%hd ", *sh);
2636  break;
2637  }
2638  /* Normal case: an integer */
2639  cp = *argv;
2640  for (ii = 0; ii < sdp->sp_count; ++ii) {
2641  if (*cp == '\0') {
2642  bu_vls_printf(logstr,
2643  "not enough values for \"%s\" argument: should have %zu",
2644  sdp->sp_name,
2645  sdp->sp_count);
2646  return BRLCAD_ERROR;
2647  }
2648 
2649  BU_SP_SKIP_SEP(cp);
2650  tmpi = atoi(cp);
2651  if (*cp && (*cp == '+' || *cp == '-'))
2652  cp++;
2653  while (*cp && isdigit((int)(*cp)))
2654  cp++;
2655  /* make sure we actually had an
2656  * integer out there
2657  */
2658 
2659  if (cp == *argv ||
2660  (cp == *argv+1 &&
2661  (argv[0][0] == '+' ||
2662  argv[0][0] == '-'))) {
2663  bu_vls_printf(logstr,
2664  "value \"%s\" to argument %s isn't an integer",
2665  argv[0],
2666  sdp->sp_name);
2667  return BRLCAD_ERROR;
2668  } else {
2669  *(sh++) = tmpi;
2670  }
2671  BU_SP_SKIP_SEP(cp);
2672  }
2673 
2674  if (sdp->sp_count > 1)
2675  bu_vls_printf(logstr, "{%s} ", argv[0]);
2676  else
2677  bu_vls_printf(logstr, "%s ", argv[0]);
2678  break;
2679  }
2680  case 'd': {
2681  register int *ip = (int *)loc;
2682  register int tmpi;
2683 
2684  if (argc < 1) {
2685  /* XXX - when was ii defined */
2686  bu_vls_printf(logstr,
2687  "not enough values for \"%s\" argument: should have %zu",
2688  sdp->sp_name,
2689  sdp->sp_count);
2690  return BRLCAD_ERROR;
2691  }
2692 
2693  bu_vls_printf(logstr, "%s ", sdp->sp_name);
2694 
2695  /* Special case: '=!' toggles a boolean */
2696  if (argv[0][0] == '!') {
2697  *ip = *ip ? 0 : 1;
2698  bu_vls_printf(logstr, "%d ", *ip);
2699  break;
2700  }
2701  /* Normal case: an integer */
2702  cp = *argv;
2703  for (ii = 0; ii < sdp->sp_count; ++ii) {
2704  if (*cp == '\0') {
2705  bu_vls_printf(logstr,
2706  "not enough values for \"%s\" argument: should have %zu",
2707  sdp->sp_name,
2708  sdp->sp_count);
2709  return BRLCAD_ERROR;
2710  }
2711 
2712  BU_SP_SKIP_SEP(cp);
2713  tmpi = atoi(cp);
2714  if (*cp && (*cp == '+' || *cp == '-'))
2715  cp++;
2716  while (*cp && isdigit((int)(*cp)))
2717  cp++;
2718  /* make sure we actually had an
2719  * integer out there
2720  */
2721 
2722  if (cp == *argv ||
2723  (cp == *argv+1 &&
2724  (argv[0][0] == '+' ||
2725  argv[0][0] == '-'))) {
2726  bu_vls_printf(logstr,
2727  "value \"%s\" to argument %s isn't an integer",
2728  argv[0],
2729  sdp->sp_name);
2730  return BRLCAD_ERROR;
2731  } else {
2732  *(ip++) = tmpi;
2733  }
2734  BU_SP_SKIP_SEP(cp);
2735  }
2736  if (sdp->sp_count > 1)
2737  bu_vls_printf(logstr, "{%s} ", argv[0]);
2738  else
2739  bu_vls_printf(logstr, "%s ", argv[0]);
2740  break;
2741  }
2742  case 'g':
2743  case 'f': {
2744  int ret;
2745  int dot_seen;
2746  const char *numstart;
2747  double tmp_double;
2748 
2749  double *dp = (double *)loc;
2750  fastf_t *fp = (fastf_t *)loc;
2751 
2752  if (argc < 1) {
2753  bu_vls_printf(&str,
2754  "not enough values for \"%s\" argument: should have %zu, only %d given",
2755  sdp->sp_name,
2756  sdp->sp_count, argc);
2757  return BRLCAD_ERROR;
2758  }
2759 
2760  bu_vls_printf(logstr, "%s ", sdp->sp_name);
2761 
2762  cp = *argv;
2763  for (ii = 0; ii < sdp->sp_count; ii++) {
2764  if (*cp == '\0') {
2765  bu_vls_printf(logstr,
2766  "not enough values for \"%s\" argument: should have %zu, only %zu given",
2767  sdp->sp_name,
2768  sdp->sp_count,
2769  ii);
2770  return BRLCAD_ERROR;
2771  }
2772 
2773  BU_SP_SKIP_SEP(cp);
2774  numstart = cp;
2775  if (*cp == '-' || *cp == '+') cp++;
2776 
2777  /* skip matissa */
2778  dot_seen = 0;
2779  for (; *cp; cp++) {
2780  if (*cp == '.' && !dot_seen) {
2781  dot_seen = 1;
2782  continue;
2783  }
2784  if (!isdigit((int)(*cp)))
2785  break;
2786  }
2787 
2788  /* If no mantissa seen, then there is no float
2789  * here.
2790  */
2791  if (cp == (numstart + dot_seen)) {
2792  bu_vls_printf(logstr,
2793  "value \"%s\" to argument %s isn't a float",
2794  argv[0],
2795  sdp->sp_name);
2796  return BRLCAD_ERROR;
2797  }
2798 
2799  /* there was a mantissa, so we may have an
2800  * exponent.
2801  */
2802  if (*cp == 'E' || *cp == 'e') {
2803  cp++;
2804 
2805  /* skip exponent sign */
2806  if (*cp == '+' || *cp == '-')
2807  cp++;
2808  while (isdigit((int)(*cp)))
2809  cp++;
2810  }
2811 
2812  bu_vls_trunc(&str, 0);
2813  bu_vls_strcpy(&str, numstart);
2814  bu_vls_trunc(&str, cp-numstart);
2815 
2816  ret = sscanf(bu_vls_addr(&str), "%lf", &tmp_double);
2817  if (ret != 1) {
2818  bu_vls_printf(logstr,
2819  "value \"%s\" to argument %s isn't a float",
2820  numstart,
2821  sdp->sp_name);
2822  bu_vls_free(&str);
2823  return BRLCAD_ERROR;
2824  }
2825  bu_vls_free(&str);
2826 
2827  if (sdp->sp_fmt[1] == 'f') {
2828  *fp++ = (fastf_t)tmp_double;
2829  } else {
2830  *dp++ = tmp_double;
2831  }
2832 
2833  BU_SP_SKIP_SEP(cp);
2834  }
2835  if (sdp->sp_count > 1)
2836  bu_vls_printf(logstr, "{%s} ", argv[0]);
2837  else
2838  bu_vls_printf(logstr, "%s ", argv[0]);
2839  break;
2840  }
2841  case 'p':
2842  BU_ASSERT(sdp->sp_count == 1);
2843 
2844  /* Indirect to another structure */
2845  /* FIXME: unimplemented */
2846  bu_log("INTERNAL ERROR: referencing indirect bu_structparse table, unimplemented\n");
2847  break;
2848  default:
2849  bu_vls_printf(logstr,
2850  "%s line:%d Parse error, unknown format: '%s' for element \"%s\"",
2851  __FILE__, __LINE__, sdp->sp_fmt,
2852  sdp->sp_name);
2853 
2854  return BRLCAD_ERROR;
2855  }
2856 
2857  if (sdp->sp_hook) {
2858  sdp->sp_hook(sdp, sdp->sp_name, base, *argv, data);
2859  }
2860  --argc;
2861  ++argv;
2862 
2863 
2864  break;
2865  }
2866 
2867 
2868  if (sdp->sp_name == NULL) {
2869  bu_vls_printf(logstr, "invalid attribute %s\n", argv[0]);
2870  return BRLCAD_ERROR;
2871  }
2872  }
2873 
2874  return BRLCAD_OK;
2875 }
2876 
2877 
2878 /*
2879  * Local Variables:
2880  * mode: C
2881  * tab-width: 8
2882  * indent-tabs-mode: t
2883  * c-file-style: "stroustrup"
2884  * End:
2885  * ex: shiftwidth=4 tabstop=8
2886  */
int bu_struct_import(void *base, const struct bu_structparse *imp, const struct bu_external *ext, void *data)
Definition: parse.c:295
void bu_vls_struct_print2(struct bu_vls *vls_out, const char *title, const struct bu_structparse *parsetab, const char *base)
Definition: parse.c:1606
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
#define STATE_IN_VALUE
Definition: parse.c:1817
const char * sp_name
Definition: parse.h:140
void bu_vls_strncat(struct bu_vls *vp, const char *s, size_t n)
Definition: vls.c:390
int bu_shader_to_list(const char *in, struct bu_vls *vls)
Definition: parse.c:1933
uint32_t vls_magic
Definition: vls.h:57
HIDDEN int parse_struct_lookup(register const struct bu_structparse *sdp, register const char *name, const char *base, const char *const value, void *data)
Definition: parse.c:667
HIDDEN void parse_dmatprint(const char *name, register const double *mat)
Definition: parse.c:1000
if lu s
Definition: nmg_mod.c:3860
Definition: clone.c:90
void bu_vls_strcat(struct bu_vls *vp, const char *s)
Definition: vls.c:368
void bu_semaphore_acquire(unsigned int i)
Definition: semaphore.c:180
void bu_parse_mm(const struct bu_structparse *sdp, const char *name, char *base, const char *value)
Definition: parse.c:1794
void bu_vls_trunc(struct bu_vls *vp, int len)
Definition: vls.c:198
int bu_fwrite_external(FILE *fp, const struct bu_external *ep)
Definition: parse.c:2368
HIDDEN int parse_list_length(const char *in)
Definition: parse.c:2175
#define BU_ASSERT_LONG(_lhs, _relation, _rhs)
Definition: defines.h:240
void bu_vls_strncpy(struct bu_vls *vp, const char *s, size_t n)
Definition: vls.c:339
void bu_log_indent_vls(struct bu_vls *v)
Definition: log.c:62
Header file for the BRL-CAD common definitions.
size_t vls_len
Definition: vls.h:60
#define PARSE_CK_GETPUT(_p)
Definition: parse.c:75
#define COMMA
Definition: parse.c:43
#define BU_ASSERT(_equation)
Definition: defines.h:216
void bu_cv_htond(unsigned char *out, const unsigned char *in, size_t count)
void bu_log_indent_delta(int delta)
Definition: log.c:54
double bu_mm_value(const char *s)
Definition: units.c:355
void bu_hexdump_external(FILE *fp, const struct bu_external *ep, const char *str)
Definition: parse.c:2390
#define HIDDEN
Definition: common.h:86
void bu_struct_print(const char *title, const struct bu_structparse *parsetab, const char *base)
Definition: parse.c:1221
void * bu_malloc(size_t siz, const char *str)
Definition: malloc.c:314
void(* sp_hook)(const struct bu_structparse *, const char *, void *, const char *, void *)
Definition: parse.h:142
int bu_key_eq_to_key_val(const char *in, const char **next, struct bu_vls *vls)
Definition: parse.c:1821
HIDDEN void parse_matprint(const char *name, register const fastf_t *mat)
Definition: parse.c:971
void bu_vls_free(struct bu_vls *vp)
Definition: vls.c:248
const char sp_fmt[4]
Definition: parse.h:138
COMPLEX data[64]
Definition: fftest.c:34
#define PARSE_MAGIC_2
Definition: parse.c:62
int bu_strncasecmp(const char *string1, const char *string2, size_t n)
Definition: str.c:239
#define BU_CK_VLS(_vp)
Definition: vls.h:69
HIDDEN char * parse_list_elem(const char *in, int idx)
Definition: parse.c:2080
int bu_vls_struct_item_named(struct bu_vls *vp, const struct bu_structparse *parsetab, const char *name, const char *base, int sep_char)
Definition: parse.c:1203
HIDDEN int parse_floating(const char *str, size_t count, fastf_t *floc, double *dloc)
Definition: parse.c:583
int bu_struct_export(struct bu_external *ext, const void *base, const struct bu_structparse *imp)
Definition: parse.c:120
#define BRLCAD_OK
Definition: defines.h:71
uint8_t * ext_buf
Definition: parse.h:216
void bu_vls_struct_print(struct bu_vls *vls, register const struct bu_structparse *sdp, const char *base)
Definition: parse.c:1451
#define STATE_IN_QUOTED_VALUE
Definition: parse.c:1818
#define PARSE_INIT_GETPUT_1(_p)
Definition: parse.c:63
#define BU_FLSTR
Definition: defines.h:142
size_t bu_vls_strlen(const struct bu_vls *vp)
Definition: vls.c:189
void * bu_realloc(void *ptr, size_t siz, const char *str)
char * bu_next_token(char *str)
Definition: parse.c:2469
char * bu_vls_strdup(const struct bu_vls *vp)
Definition: vls.c:274
size_t sp_offset
Definition: parse.h:141
char * bu_vls_addr(const struct bu_vls *vp)
Definition: vls.c:111
size_t vls_offset
Definition: vls.h:59
void bu_semaphore_release(unsigned int i)
Definition: semaphore.c:218
void bu_free_external(register struct bu_external *ep)
Definition: parse.c:2441
int bu_structparse_argv(struct bu_vls *logstr, int argc, const char **argv, const struct bu_structparse *desc, char *base, void *data)
Definition: parse.c:2522
void bu_cv_ntohf(unsigned char *out, const unsigned char *in, size_t count)
#define PARSE_INIT_GETPUT_2(_p, _l)
Definition: parse.c:68
void bu_vls_struct_item(struct bu_vls *vp, const struct bu_structparse *sdp, const char *base, int sep_char)
Definition: parse.c:1097
void bu_cv_ntohd(unsigned char *out, const unsigned char *in, size_t count)
#define PARSE_MAGIC_1
Definition: parse.c:61
#define BU_SEM_SYSCALL
Definition: parallel.h:178
size_t sp_count
Definition: parse.h:139
int bu_struct_parse(const struct bu_vls *in_vls, const struct bu_structparse *desc, const char *base, void *data)
Definition: parse.c:878
void bu_structparse_get_terse_form(struct bu_vls *logstr, const struct bu_structparse *sp)
Definition: parse.c:2483
void bu_vls_printf(struct bu_vls *vls, const char *fmt,...) _BU_ATTR_PRINTF23
Definition: vls.c:694
void bu_struct_wrap_buf(struct bu_external *ext, void *buf)
Definition: parse.c:542
#define BU_EXTERNAL_INIT(_p)
Definition: parse.h:229
void bu_vls_extend(struct bu_vls *vp, size_t extra)
Definition: vls.c:136
char * vls_str
Definition: vls.h:58
int bu_shader_to_key_eq(const char *in, struct bu_vls *vls)
Definition: parse.c:2279
void bu_cv_htonf(unsigned char *out, const unsigned char *in, size_t count)
#define BU_SP_SKIP_SEP(_cp)
Definition: parse.h:457
void bu_vls_strcpy(struct bu_vls *vp, const char *s)
Definition: vls.c:310
HIDDEN int parse_key_val_to_vls(struct bu_vls *vls, char *params)
Definition: parse.c:2225
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
HIDDEN void parse_vls_matprint(struct bu_vls *vls, const char *name, register const fastf_t *mat)
Definition: parse.c:1029
#define BU_CK_EXTERNAL(_p)
Definition: parse.h:224
ustring shader
size_t bu_struct_put(FILE *fp, const struct bu_external *ext)
Definition: parse.c:457
#define BU_VLS_INIT_ZERO
Definition: vls.h:84
size_t ext_nbytes
Definition: parse.h:210
void bu_vls_vlscat(struct bu_vls *dest, const struct bu_vls *src)
Definition: vls.c:415
HIDDEN void parse_vls_dmatprint(struct bu_vls *vls, const char *name, register const double *mat)
Definition: parse.c:1063
size_t vls_max
Definition: vls.h:61
#define CKMEM(_len)
Definition: parse.c:45
#define STATE_IN_KEYWORD
Definition: parse.c:1816
Definition: vls.h:56
#define BRLCAD_ERROR
Definition: defines.h:72
void bu_bomb(const char *str) _BU_ATTR_NORETURN
Definition: bomb.c:91
HIDDEN const point_t delta
Definition: sh_prj.c:618
double fastf_t
Definition: defines.h:300
const char * bu_identify_magic(uint32_t magic)
void bu_vls_putc(struct bu_vls *vp, int c)
Definition: vls.c:666
void bu_copy_external(struct bu_external *op, const struct bu_external *ip)
Definition: parse.c:2454
HIDDEN void parse_vls_print_floating(struct bu_vls *vls, const char *name, size_t count, const fastf_t *fp, const double *dp)
Definition: parse.c:1411
#define bu_strdup(s)
Definition: str.h:71
#define UNLIKELY(expression)
Definition: common.h:282
size_t bu_struct_get(struct bu_external *ext, FILE *fp)
Definition: parse.c:469
#define BU_STR_EQUAL(s1, s2)
Definition: str.h:126