parse.c

Go to the documentation of this file.
00001 /*                         P A R S E . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1989-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** \addtogroup parse */
00023 /*@{*/
00024 
00025 /** @file ./libbu/parse.c
00026  *
00027  * @brief routines for parsing arbitrary structures
00028  *
00029  *  Routines to assign values to elements of arbitrary structures.
00030  *  The layout of a structure to be processed is described by
00031  *  a structure of type "bu_structparse", giving element names, element
00032  *  formats, an offset from the beginning of the structure, and
00033  *  a pointer to an optional "hooked" function that is called whenever
00034  *  that structure element is changed.
00035  *
00036  *  @par There are four basic operations supported:
00037  *  @arg        print   struct elements to ASCII
00038  *  @arg        parse   ASCII to struct elements
00039  *  @arg        export  struct elements to machine-independent binary
00040  *  @arg        import  machine-independent binary to struct elements
00041  *
00042  *
00043  *
00044  *  @authors    Michael John Muuss
00045  *  @authors    Lee A. Butler
00046  *
00047  *  @par Source -
00048  *      SECAD/VLD Computing Consortium, Bldg 394
00049  * @n   The U. S. Army Ballistic Research Laboratory
00050  * @n   Aberdeen Proving Ground, Maryland  21005
00051  *
00052  */
00053 
00054 #ifndef lint
00055 static const char RCSparse[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/libbu/parse.c,v 14.13 2006/09/03 15:14:07 lbutler Exp $ (BRL)";
00056 #endif
00057 
00058 #include "common.h"
00059 
00060 #include <stdlib.h>
00061 #include <stdio.h>
00062 #include <ctype.h>
00063 #include <math.h>
00064 #ifdef HAVE_STRING_H
00065 #  include <string.h>
00066 #else
00067 #  include <strings.h>
00068 #endif
00069 
00070 #include "machine.h"
00071 #include "bu.h"
00072 
00073 
00074 #define CKMEM( _len )   {  \
00075         register int    offset; \
00076         if( (offset = (ep - cp) - (_len)) < 0 )  { \
00077                 do  { \
00078                         offset += ext->ext_nbytes;      /* decr by new growth */ \
00079                         ext->ext_nbytes <<= 1; \
00080                 } while( offset < 0 ); \
00081                 offset = cp - (char *)ext->ext_buf; \
00082                 ext->ext_buf = (genptr_t)bu_realloc( (char *) ext->ext_buf, \
00083                      ext->ext_nbytes, "bu_struct_export" ); \
00084                 ep = (char *) ext->ext_buf + ext->ext_nbytes; \
00085                 cp = (char *) ext->ext_buf + offset; \
00086         } }
00087 
00088 #define BU_GETPUT_MAGIC_1       0x15cb
00089 #define BU_GETPUT_MAGIC_2       0xbc51
00090 #define BU_INIT_GETPUT_1(_p)    { \
00091         BU_CK_EXTERNAL(_p); \
00092         ((unsigned char *) _p->ext_buf)[1] = (BU_GETPUT_MAGIC_1 & 0xFF); \
00093         ((unsigned char *) _p->ext_buf)[0] = (BU_GETPUT_MAGIC_1 >> 8) & 0xFF; \
00094         }
00095 #define BU_INIT_GETPUT_2(_p,_l) {\
00096         BU_CK_EXTERNAL(_p); \
00097         ((unsigned char *) _p->ext_buf)[_l-1] = (BU_GETPUT_MAGIC_2 & 0xFF); \
00098         ((unsigned char *) _p->ext_buf)[_l-2] = (BU_GETPUT_MAGIC_2 >> 8) & 0xFF; \
00099         }
00100 
00101 #define BU_CK_GETPUT(_p) {\
00102         register long _i; \
00103         register long _len; \
00104         BU_CK_EXTERNAL(_p); \
00105         if ( !(_p->ext_buf) ) { \
00106                 bu_log("ERROR: BU_CK_GETPUT null ext_buf, file %s, line %d\n", \
00107                     __FILE__, __LINE__); \
00108                 bu_bomb("NULL pointer"); \
00109         } \
00110         if ( _p->ext_nbytes < 6 ) { \
00111                 bu_log("ERROR: BU_CK_GETPUT buffer only %d bytes, file %s, line %d\n", \
00112                     _p->ext_nbytes, __FILE__, __LINE__); \
00113                 bu_bomb("getput buffer too small"); \
00114         } \
00115         _i = (((unsigned char *)(_p->ext_buf))[0] << 8) | \
00116               ((unsigned char *)(_p->ext_buf))[1]; \
00117         if ( _i != BU_GETPUT_MAGIC_1)  { \
00118                 bu_log("ERROR: BU_CK_GETPUT buffer x%x, magic1 s/b x%x, was %s(x%x), file %s, line %d\n", \
00119                     _p->ext_buf, BU_GETPUT_MAGIC_1, \
00120                     bu_identify_magic( _i), _i, __FILE__, __LINE__); \
00121                 bu_bomb("Bad getput buffer"); \
00122         } \
00123         _len = (((unsigned char *)(_p->ext_buf))[2] << 24) | \
00124                (((unsigned char *)(_p->ext_buf))[3] << 16) | \
00125                (((unsigned char *)(_p->ext_buf))[4] <<  8) | \
00126                 ((unsigned char *)(_p->ext_buf))[5]; \
00127         if (_len > _p->ext_nbytes) { \
00128                 bu_log("ERROR: BU_CK_GETPUT buffer x%x, expected len=%d, ext_nbytes=%d, file %s, line %d\n", \
00129                     _p->ext_buf, _len, _p->ext_nbytes, \
00130                     __FILE__, __LINE__); \
00131                 bu_bomb("Bad getput buffer"); \
00132         } \
00133         _i = (((unsigned char *)(_p->ext_buf))[_len-2] << 8) | \
00134               ((unsigned char *)(_p->ext_buf))[_len-1]; \
00135         if ( _i != BU_GETPUT_MAGIC_2) { \
00136                 bu_log("ERROR: BU_CK_GETPUT buffer x%x, magic2 s/b x%x, was %s(x%x), file %s, line %d\n", \
00137                     _p->ext_buf, BU_GETPUT_MAGIC_2, \
00138                     bu_identify_magic( _i), _i, __FILE__, __LINE__); \
00139                 bu_bomb("Bad getput buffer"); \
00140         } \
00141 }
00142 
00143 /**
00144  *                      B U _ S T R U C T _ E X P O R T
00145  */
00146 int
00147 bu_struct_export(struct bu_external *ext, const genptr_t base, const struct bu_structparse *imp)
00148 {
00149         register char   *cp;            /* current possition in buffer */
00150         char            *ep;            /* &ext->ext_buf[ext->ext_nbytes] */
00151         const struct bu_structparse *ip;        /* current imexport structure */
00152         char            *loc;           /* where host-format data is */
00153         int             len;
00154         register int    i;
00155 
00156         BU_INIT_EXTERNAL(ext);
00157 
00158         ext->ext_nbytes = 480;
00159         ext->ext_buf = (genptr_t)bu_malloc( ext->ext_nbytes,
00160             "bu_struct_export output ext->ext_buf" );
00161         BU_INIT_GETPUT_1(ext);
00162         cp = (char *) ext->ext_buf + 6; /* skip magic and length */
00163         ep = cp + ext->ext_nbytes;
00164 
00165         for( ip = imp; ip->sp_fmt[0] != '\0'; ip++ )  {
00166 
00167 #if CRAY && !__STDC__
00168                 loc = ((char *)base) + ((int)ip->sp_offset*sizeof(int));
00169 #else
00170                 loc = ((char *)base) + ip->sp_offset;
00171 #endif
00172 
00173                 switch( ip->sp_fmt[0] )  {
00174                 case 'i':
00175                         /* Indirect to another structure */
00176                         /* deferred */
00177                         bu_free( (char *) ext->ext_buf, "output ext_buf" );
00178                         return( 0 );
00179                 case '%':
00180                         /* See below */
00181                         break;
00182                 default:
00183                         /* Unknown */
00184                         bu_free( (char *) ext->ext_buf, "output ext_buf" );
00185                         return( 0 );
00186                 }
00187                 /* [0] == '%', use printf-like format char */
00188                 switch( ip->sp_fmt[1] )  {
00189                 case 'f':
00190                         /* Double-precision floating point */
00191                         len = ip->sp_count * 8;
00192                         CKMEM( len );
00193                         htond( (unsigned char *)cp, (unsigned char *)loc, ip->sp_count );
00194                         cp += len;
00195                         continue;
00196                 case 'd':
00197                         /* 32-bit network integer, from "int" */
00198                         CKMEM( ip->sp_count * 4 );
00199                         {
00200                                 register unsigned long  l;
00201                                 for( i = ip->sp_count-1; i >= 0; i-- )  {
00202                                         l = *((int *)loc);
00203                                         cp[3] = l;
00204                                         cp[2] = l >> 8;
00205                                         cp[1] = l >> 16;
00206                                         cp[0] = l >> 24;
00207                                         loc += sizeof(int);
00208                                         cp += 4;
00209                                 }
00210                         }
00211                         continue;
00212                 case 'i':
00213                         /* 16-bit integer, from "int" */
00214                         CKMEM( ip->sp_count * 2 );
00215                         {
00216                                 register unsigned short s;
00217                                 for( i = ip->sp_count-1; i >= 0; i-- )  {
00218                                         s = *((int *)loc);
00219                                         cp[1] = s;
00220                                         cp[0] = s >> 8;
00221                                         loc += sizeof(int); /* XXX */
00222                                         cp += 2;
00223                                 }
00224                         }
00225                         continue;
00226                 case 's':
00227                         {
00228                                 /* char array is transmitted as a
00229                                  * 4 byte character count, followed by a
00230                                  * null terminated, word padded char array.
00231                                  * The count includes any pad bytes,
00232                                  * but not the count itself.
00233                                  *
00234                                  * ip->sp_count == sizeof(char array)
00235                                  */
00236                                 register int lenstr;
00237 
00238                                 /* include the terminating null */
00239                                 lenstr = strlen( loc ) + 1;
00240 
00241                                 len = lenstr;
00242 
00243                                 /* output an integer number of words */
00244                                 if ((len & 0x03) != 0)
00245                                         len += 4 - (len & 0x03);
00246 
00247                                 CKMEM( len + 4 );
00248 
00249                                 /* put the length on the front
00250                                  * of the string
00251                                  */
00252                                 cp[3] = len;
00253                                 cp[2] = len >> 8;
00254                                 cp[1] = len >> 16;
00255                                 cp[0] = len >> 24;
00256 
00257                                 cp += 4;
00258 
00259                                 bcopy( loc, cp, lenstr );
00260                                 cp += lenstr;
00261                                 while (lenstr++ < len) *cp++ = '\0';
00262                         }
00263                         continue;
00264                 case 'c':
00265                         {
00266                                 CKMEM( ip->sp_count + 4 );
00267                                 cp[3] = ip->sp_count;
00268                                 cp[2] = ip->sp_count >> 8;
00269                                 cp[1] = ip->sp_count >> 16;
00270                                 cp[0] = ip->sp_count >> 24;
00271                                 cp += 4;
00272                                 bcopy( loc, cp, ip->sp_count);
00273                                 cp += ip->sp_count;
00274                         }
00275                         continue;
00276                 default:
00277                         bu_free( (char *) ext->ext_buf, "output ext_buf" );
00278                         return( 0 );
00279                 }
00280         }
00281         CKMEM( 2);      /* get room for the trailing magic number */
00282         cp += 2;
00283 
00284         i = cp - (char *)ext->ext_buf;
00285         /* Fill in length in external buffer */
00286         ((char *)ext->ext_buf)[5] = i;
00287         ((char *)ext->ext_buf)[4] = i >> 8;
00288         ((char *)ext->ext_buf)[3] = i >>16;
00289         ((char *)ext->ext_buf)[2] = i >>24;
00290         BU_INIT_GETPUT_2(ext, i);
00291         ext->ext_nbytes = i;    /* XXX this changes nbytes if i < 480 ? */
00292         return( 1 );
00293 }
00294 
00295 /**
00296  *                      B U _ S T R U C T _ I M P O R T
00297  */
00298 int
00299 bu_struct_import(genptr_t base, const struct bu_structparse *imp, const struct bu_external *ext)
00300 {
00301         register const unsigned char    *cp;    /* current possition in buffer */
00302         const struct bu_structparse     *ip;    /* current imexport structure */
00303         char            *loc;           /* where host-format data is */
00304         int             len;
00305         int             bytes_used;
00306         register int    i;
00307 
00308         BU_CK_GETPUT(ext);
00309 
00310         cp = (unsigned char *)ext->ext_buf+6;
00311         bytes_used = 0;
00312         for( ip = imp; ip->sp_fmt[0] != '\0'; ip++ )  {
00313 
00314 #if CRAY && !__STDC__
00315                 loc = ((char *)base) + ((int)ip->sp_offset*sizeof(int));
00316 #else
00317                 loc = ((char *)base) + ip->sp_offset;
00318 #endif
00319 
00320                 switch( ip->sp_fmt[0] )  {
00321                 case 'i':
00322                         /* Indirect to another structure */
00323                         /* deferred */
00324                         return( -1 );
00325                 case '%':
00326                         /* See below */
00327                         break;
00328                 default:
00329                         /* Unknown */
00330                         return( -1 );
00331                 }
00332                 /* [0] == '%', use printf-like format char */
00333                 switch( ip->sp_fmt[1] )  {
00334                 case 'f':
00335                         /* Double-precision floating point */
00336                         len = ip->sp_count * 8;
00337                         ntohd( (unsigned char *)loc, cp, ip->sp_count );
00338                         cp += len;
00339                         bytes_used += len;
00340                         break;
00341                 case 'd':
00342                         /* 32-bit network integer, from "int" */
00343                         {
00344                                 register long   l;
00345                                 for( i = ip->sp_count-1; i >= 0; i-- )  {
00346                                         l =     (cp[0] << 24) |
00347                                                 (cp[1] << 16) |
00348                                                 (cp[2] <<  8) |
00349                                                  cp[3];
00350                                         *(int *)loc = l;
00351                                         loc += sizeof(int); /* XXX */
00352                                         cp += 4;
00353                                 }
00354                                 bytes_used += ip->sp_count * 4;
00355                         }
00356                         break;
00357                 case 'i':
00358                         /* 16-bit integer, from "int" */
00359                         for( i = ip->sp_count-1; i >= 0; i-- )  {
00360                                 *(int *)loc =   (cp[0] <<  8) |
00361                                                  cp[1];
00362                                 loc += sizeof(int); /* XXX */
00363                                 cp += 2;
00364                         }
00365                         bytes_used += ip->sp_count * 2;
00366                         break;
00367                 case 's':
00368                         {       /* char array transmitted as a
00369                                  * 4 byte character count, followed by a
00370                                  * null terminated, word padded char array
00371                                  *
00372                                  * ip->sp_count == sizeof(char array)
00373                                  */
00374                                 register unsigned long lenstr;
00375 
00376                                 lenstr = (cp[0] << 24) |
00377                                          (cp[1] << 16) |
00378                                          (cp[2] <<  8) |
00379                                           cp[3];
00380 
00381                                 cp += 4;
00382 
00383                                 /* don't read more than the buffer can hold */
00384                                 if (ip->sp_count < lenstr)
00385                                         bcopy( cp, loc, ip->sp_count);
00386                                 else
00387                                         bcopy( cp, loc, lenstr );
00388 
00389                                 /* ensure proper null termination */
00390                                 loc[ip->sp_count-1] = '\0';
00391 
00392                                 cp += lenstr;
00393                                 bytes_used += lenstr;
00394                         }
00395                         break;
00396                 case 'c':
00397                         {
00398                                 register unsigned long lenarray;
00399 
00400                                 lenarray = (cp[0] << 24) |
00401                                            (cp[1] << 16) |
00402                                            (cp[2] <<  8) |
00403                                             cp[3];
00404                                 cp += 4;
00405 
00406                                 if (ip->sp_count < lenarray) {
00407                                         bcopy( cp, loc, ip->sp_count);
00408                                 } else {
00409                                         bcopy( cp, loc, lenarray );
00410                                 }
00411                                 cp += lenarray;
00412                                 bytes_used += lenarray;
00413                         }
00414                         break;
00415                 default:
00416                         return( -1 );
00417                 }
00418                 if ( ip->sp_hook ) {
00419 
00420                         ip->sp_hook (ip, ip->sp_name, base, (char *)NULL);
00421                 }
00422         }
00423 
00424         /* This number may differ from that stored as "claimed_length" */
00425         return( bytes_used );
00426 }
00427 
00428 /**
00429  *                      B U _ S T R U C T _ P U T
00430  *
00431  *  Put a structure in external form to a stdio file.
00432  *  All formatting must have been accomplished previously.
00433  */
00434 int
00435 bu_struct_put(FILE *fp, const struct bu_external *ext)
00436 {
00437         BU_CK_GETPUT(ext);
00438 
00439         return(fwrite(ext->ext_buf, 1, ext->ext_nbytes, fp));
00440 }
00441 
00442 /**
00443  *                      B U _ S T R U C T _ G E T
00444  *
00445  *  Obtain the next structure in external form from a stdio file.
00446  */
00447 int
00448 bu_struct_get(struct bu_external *ext, FILE *fp)
00449 {
00450         register long i, len;
00451 
00452         BU_INIT_EXTERNAL(ext);
00453         ext->ext_buf = (genptr_t) bu_malloc( 6, "bu_struct_get buffer head");
00454         bu_semaphore_acquire( BU_SEM_SYSCALL );         /* lock */
00455 
00456         i=fread( (char *) ext->ext_buf, 1, 6, fp);      /* res_syscall */
00457         bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00458 
00459         if (i != 6 ) {
00460                 if (i == 0) return(0);
00461                 bu_log("ERROR: bu_struct_get bad fread (%d), file %s, line %d\n",
00462                     i, __FILE__, __LINE__);
00463                 bu_bomb("Bad fread");
00464         }
00465         i = (((unsigned char *)(ext->ext_buf))[0] << 8) |
00466              ((unsigned char *)(ext->ext_buf))[1];
00467         len = (((unsigned char *)(ext->ext_buf))[2] << 24) |
00468               (((unsigned char *)(ext->ext_buf))[3] << 16) |
00469               (((unsigned char *)(ext->ext_buf))[4] <<  8) |
00470                ((unsigned char *)(ext->ext_buf))[5];
00471         if ( i != BU_GETPUT_MAGIC_1) {
00472                 bu_log("ERROR: bad getput buffer header x%x, s/b x%x, was %s(x%x), file %s, line %d\n",
00473                     ext->ext_buf, BU_GETPUT_MAGIC_1,
00474                     bu_identify_magic( i), i, __FILE__, __LINE__);
00475                 bu_bomb("bad getput buffer");
00476         }
00477         ext->ext_nbytes = len;
00478         ext->ext_buf = (genptr_t) bu_realloc((char *) ext->ext_buf, len,
00479             "bu_struct_get full buffer");
00480         bu_semaphore_acquire( BU_SEM_SYSCALL );         /* lock */
00481         i=fread((char *) ext->ext_buf + 6, 1 , len-6, fp);      /* res_syscall */
00482         bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00483         if (i != len-6) {
00484                 bu_log("ERROR: bu_struct_get bad fread (%d), file %s, line %d\n",
00485                     i, __FILE__, __LINE__);
00486                 bu_bomb("Bad fread");
00487         }
00488         i = (((unsigned char *)(ext->ext_buf))[len-2] <<8) |
00489              ((unsigned char *)(ext->ext_buf))[len-1];
00490         if ( i != BU_GETPUT_MAGIC_2) {
00491                 bu_log("ERROR: bad getput buffer x%x, s/b x%x, was %s(x%x), file %s, line %d\n",
00492                     ext->ext_buf, BU_GETPUT_MAGIC_2,
00493                     bu_identify_magic( i), i, __FILE__, __LINE__);
00494                 bu_bomb("Bad getput buffer");
00495         }
00496         return(1);
00497 }
00498 
00499 /**
00500  *                      B U _ S T R U C T _ B U F
00501  *
00502  *  Given a buffer with an external representation of a structure
00503  *  (e.g. the ext_buf portion of the output from bu_struct_export),
00504  *  check it for damage in shipment, and if it's OK,
00505  *  wrap it up in an bu_external structure, suitable for passing
00506  *  to bu_struct_import().
00507  */
00508 void
00509 bu_struct_wrap_buf(struct bu_external *ext, genptr_t buf)
00510 {
00511         register long i, len;
00512 
00513         BU_INIT_EXTERNAL(ext);
00514         ext->ext_buf = buf;
00515         i = (((unsigned char *)(ext->ext_buf))[0] << 8) |
00516              ((unsigned char *)(ext->ext_buf))[1];
00517         len = (((unsigned char *)(ext->ext_buf))[2] << 24) |
00518               (((unsigned char *)(ext->ext_buf))[3] << 16) |
00519               (((unsigned char *)(ext->ext_buf))[4] <<  8) |
00520                ((unsigned char *)(ext->ext_buf))[5];
00521         if ( i != BU_GETPUT_MAGIC_1) {
00522                 bu_log("ERROR: bad getput buffer header x%x, s/b x%x, was %s(x%x), file %s, line %d\n",
00523                     ext->ext_buf, BU_GETPUT_MAGIC_1,
00524                     bu_identify_magic( i), i, __FILE__, __LINE__);
00525                 bu_bomb("bad getput buffer");
00526         }
00527         ext->ext_nbytes = len;
00528         i = (((unsigned char *)(ext->ext_buf))[len-2] <<8) |
00529              ((unsigned char *)(ext->ext_buf))[len-1];
00530         if ( i != BU_GETPUT_MAGIC_2) {
00531                 bu_log("ERROR: bad getput buffer x%x, s/b x%x, was %s(x%x), file %s, line %s\n",
00532                     ext->ext_buf, BU_GETPUT_MAGIC_2,
00533                     bu_identify_magic( i), i, __FILE__, __LINE__);
00534                 bu_bomb("Bad getput buffer");
00535         }
00536 }
00537 
00538 
00539 
00540 
00541 
00542 
00543 
00544 
00545 
00546 
00547 /**
00548  *                      B U _ P A R S E _ D O U B L E
00549  *
00550  *  Parse an array of one or more doubles.
00551  *  Return value: 0 when successful
00552  *               <0 upon failure
00553  */
00554 HIDDEN int
00555 bu_parse_double(const char *str, long int count, double *loc)
00556 {
00557         long    i;
00558         int     dot_seen;
00559         const char      *numstart;
00560         double  tmp_double;
00561         char    buf[128];
00562         int     len;
00563 
00564         for (i=0 ; i < count && *str ; ++i){
00565                 numstart = str;
00566 
00567                 /* skip sign */
00568                 if (*str == '-' || *str == '+') str++;
00569 
00570                 /* skip matissa */
00571                 dot_seen = 0;
00572                 for ( ; *str ; str++ ) {
00573                         if (*str == '.' && !dot_seen) {
00574                                 dot_seen = 1;
00575                                 continue;
00576                         }
00577                         if (!isdigit(*str))
00578                                 break;
00579 
00580                 }
00581 
00582                 /* If no mantissa seen, then there is no float here */
00583                 if (str == (numstart + dot_seen) )
00584                         return -1;
00585 
00586                 /* there was a mantissa, so we may have an exponent */
00587                 if  (*str == 'E' || *str == 'e') {
00588                         str++;
00589 
00590                         /* skip exponent sign */
00591                         if (*str == '+' || *str == '-') str++;
00592 
00593                         while (isdigit(*str)) str++;
00594                 }
00595 
00596                 len = str - numstart;
00597                 if( len > sizeof(buf)-1 )  len = sizeof(buf)-1;
00598                 strncpy( buf, numstart, len );
00599                 buf[len] = '\0';
00600 
00601                 if( sscanf( buf, "%lf", &tmp_double ) != 1 )
00602                         return -1;
00603 
00604                 *loc++ = tmp_double;
00605 
00606                 /* skip the separator */
00607                 if (*str) str++;
00608         }
00609         return 0;
00610 }
00611 
00612 /**
00613  *                      B U _ S T R U C T _ L O O K U P
00614  *
00615  *
00616  *  @return     -2      parse error
00617  *  @return     -1      not found
00618  *  @return      0      entry found and processed
00619  */
00620 HIDDEN int
00621 bu_struct_lookup(register const struct bu_structparse *sdp, register const char *name, const char *base, const char *const value)
00622                                                 /* structure description */
00623                                                 /* struct member name */
00624                                                 /* begining of structure */
00625                                                 /* string containing value */
00626 {
00627         register char *loc;
00628         int i, retval = 0;
00629 
00630         for( ; sdp->sp_name != (char *)0; sdp++ )  {
00631 
00632                 if( strcmp( sdp->sp_name, name ) != 0   /* no name match */
00633                     && sdp->sp_fmt[0] != 'i' )          /* no include desc */
00634 
00635                     continue;
00636 
00637                 /* if we get this far, we've got a name match
00638                  * with a name in the structure description
00639                  */
00640 
00641 #if CRAY && !__STDC__
00642                 loc = (char *)(base + ((int)sdp->sp_offset*sizeof(int)));
00643 #else
00644                 loc = (char *)(base + sdp->sp_offset);
00645 #endif
00646 
00647                 if (sdp->sp_fmt[0] == 'i') {
00648                         /* Indirect to another structure */
00649                         if( bu_struct_lookup(
00650                                 (struct bu_structparse *)sdp->sp_count,
00651                                 name, base, value )
00652                             == 0 )
00653                                 return(0);      /* found */
00654                         else
00655                                 continue;
00656                 }
00657                 if (sdp->sp_fmt[0] != '%') {
00658                         bu_log("bu_struct_lookup(%s): unknown format '%s'\n",
00659                                 name, sdp->sp_fmt );
00660                         return(-1);
00661                 }
00662 
00663                 switch( sdp->sp_fmt[1] )  {
00664                 case 'c':
00665                 case 's':
00666                         {       register int i, j;
00667 
00668                                 /* copy the string, converting escaped
00669                                  * double quotes to just double quotes
00670                                  */
00671                                 for(i=j=0 ;
00672                                     j < sdp->sp_count && value[i] != '\0' ;
00673                                     loc[j++] = value[i++])
00674                                         if (value[i] == '\\' &&
00675                                             value[i+1] == '"')
00676                                                 ++i;
00677 
00678                                 /* Don't null terminate chars, only strings */
00679                                 if (sdp->sp_count > 1)  {
00680                                         /* OK, it's a string */
00681                                         if( j < sdp->sp_count-1 )
00682                                                 loc[j] = '\0';
00683                                         else
00684                                                 loc[sdp->sp_count-1] = '\0';
00685                                 }
00686                         }
00687                         break;
00688                 case 'S':
00689                         {       struct bu_vls *vls = (struct bu_vls *)loc;
00690                                 bu_vls_init_if_uninit( vls );
00691                                 bu_vls_strcpy(vls, value);
00692                         }
00693                         break;
00694                 case 'i':
00695                         {       register short *ip = (short *)loc;
00696                                 register short tmpi;
00697                                 register const char *cp;
00698                                 register const char *pv = value;
00699 
00700                                 for (i=0 ; i < sdp->sp_count && *pv ; ++i){
00701                                         tmpi = atoi( pv );
00702 
00703                                         cp = pv;
00704                                         if (*cp && (*cp == '+' || *cp == '-'))
00705                                                 cp++;
00706 
00707                                         while (*cp && isdigit(*cp) )
00708                                                 cp++;
00709 
00710                                         /* make sure we actually had an
00711                                          * integer out there
00712                                          */
00713                                         if (cp == pv ||
00714                                             (cp == pv+1 &&
00715                                             (*pv == '+' || *pv == '-'))){
00716                                             retval = -2;
00717                                             break;
00718                                         } else {
00719                                                 *(ip++) = tmpi;
00720                                                 pv = cp;
00721                                         }
00722                                         /* skip the separator */
00723                                         if (*pv) pv++;
00724                                 }
00725                         }
00726                         break;
00727                 case 'd':
00728                         {       register int *ip = (int *)loc;
00729                                 register int tmpi;
00730                                 register char const *cp;
00731                                 register const char *pv = value;
00732 
00733                                 /* Special case:  '=!' toggles a boolean */
00734                                 if( *pv == '!' )  {
00735                                         *ip = *ip ? 0 : 1;
00736                                         pv++;
00737                                         break;
00738                                 }
00739                                 /* Normal case: an integer */
00740                                 for (i=0 ; i < sdp->sp_count && *pv ; ++i){
00741                                         tmpi = atoi( pv );
00742 
00743                                         cp = pv;
00744                                         if (*cp && (*cp == '+' || *cp == '-'))
00745                                                 cp++;
00746 
00747                                         while (*cp && isdigit(*cp) )
00748                                                 cp++;
00749 
00750                                         /* make sure we actually had an
00751                                          * integer out there
00752                                          */
00753                                         if (cp == pv ||
00754                                             (cp == pv+1 &&
00755                                             (*pv == '+' || *pv == '-'))){
00756                                             retval = -2;
00757                                             break;
00758                                         } else {
00759                                                 *(ip++) = tmpi;
00760                                                 pv = cp;
00761                                         }
00762                                         /* skip the separator */
00763                                         if (*pv) pv++;
00764                                 }
00765                         }
00766                         break;
00767                 case 'f':
00768                         retval = bu_parse_double(value, sdp->sp_count,
00769                                                  (double *)loc);
00770                         break;
00771                 default:
00772                         bu_log("bu_struct_lookup(%s): unknown format '%s'\n",
00773                                 name, sdp->sp_fmt );
00774                         return(-1);
00775                 }
00776                 if( sdp->sp_hook )  {
00777                         sdp->sp_hook( sdp, name, base, value );
00778                 }
00779                 return(retval);         /* OK or parse error */
00780         }
00781         return(-1);                     /* Not found */
00782 }
00783 
00784 /**
00785  *                      B U _ S T R U C T P A R S E
00786  *
00787  *      Parse the structure element description in the vls string "vls"
00788  *      according to the structure description in "parsetab"
00789  *
00790  *
00791  *  @return     <0      failure
00792  *  @return      0      OK
00793  */
00794 int
00795 bu_struct_parse(const struct bu_vls *in_vls, const struct bu_structparse *desc, const char *base)
00796                                                 /* string to parse through */
00797                                                 /* structure description */
00798                                                 /* base addr of users struct */
00799 {
00800         struct bu_vls   vls;
00801         register char *cp;
00802         char    *name;
00803         char    *value;
00804         int retval;
00805 
00806         BU_CK_VLS(in_vls);
00807         if (desc == (struct bu_structparse *)NULL) {
00808                 bu_log( "Null \"struct bu_structparse\" pointer\n");
00809                 return(-1);
00810         }
00811 
00812         /* Duplicate the input string.  This algorithm is destructive. */
00813         bu_vls_init( &vls );
00814         bu_vls_vlscat( &vls, in_vls );
00815         cp = bu_vls_addr( &vls );
00816 
00817         while( *cp )  {
00818                 /* NAME = VALUE white-space-separator */
00819 
00820                 /* skip any leading whitespace */
00821                 while( *cp != '\0' && isascii(*cp) && isspace(*cp) )
00822                         cp++;
00823 
00824                 /* Find equal sign */
00825                 name = cp;
00826                 while ( *cp != '\0' && *cp != '=' )
00827                         cp++;
00828 
00829                 if( *cp == '\0' )  {
00830                         if( name == cp ) break;
00831 
00832                         /* end of string in middle of arg */
00833                         bu_log("bu_structparse: input keyword '%s' is not followed by '=' in '%s'\nInput must be in keyword=value format.\n",
00834                                 name, bu_vls_addr(in_vls) );
00835                         bu_vls_free( &vls );
00836                         return(-2);
00837                 }
00838 
00839                 *cp++ = '\0';
00840 
00841                 /* Find end of value. */
00842                 if (*cp == '"') {
00843                         /* strings are double-quote (") delimited
00844                          * skip leading " & find terminating "
00845                          * while skipping escaped quotes (\")
00846                          */
00847                         for (value = ++cp ; *cp != '\0' ; ++cp)
00848                                 if (*cp == '"' &&
00849                                     (cp == value || *(cp-1) != '\\') )
00850                                         break;
00851 
00852                         if (*cp != '"') {
00853                                 bu_log("bu_structparse: keyword '%s'=\" without closing \"\n",
00854                                         name);
00855                                 bu_vls_free( &vls );
00856                                 return(-3);
00857                         }
00858                 } else {
00859                         /* non-strings are white-space delimited */
00860                         value = cp;
00861                         while( *cp != '\0' && isascii(*cp) && !isspace(*cp) )
00862                                 cp++;
00863                 }
00864 
00865                 if( *cp != '\0' )
00866                         *cp++ = '\0';
00867 
00868                 /* Lookup name in desc table and modify */
00869                 retval = bu_struct_lookup( desc, name, base, value );
00870                 if( retval == -1 ) {
00871                     bu_log("bu_structparse:  '%s=%s', keyword not found in:\n",
00872                            name, value);
00873                     bu_struct_print( "troublesome one", desc, base );
00874                 } else if( retval == -2 ) {
00875                     bu_vls_free( &vls );
00876                     return -2;
00877                 }
00878 
00879         }
00880         bu_vls_free( &vls );
00881         return(0);
00882 }
00883 
00884 
00885 /**
00886  *                      B U _ M A T P R I N T
00887  *
00888  *      XXX Should this be here, or could it be with the matrix support?
00889  *      pretty-print a matrix
00890  */
00891 HIDDEN void
00892 bu_matprint(const char *name, register const double *mat)
00893 {
00894         int     delta = strlen(name)+2;
00895 
00896         /* indent the body of the matrix */
00897         bu_log_indent_delta(delta);
00898 
00899         bu_log(" %s=%12E %12E %12E %12E\n",
00900                 name, mat[0], mat[1], mat[2], mat[3]);
00901 
00902         bu_log("%12E %12E %12E %12E\n",
00903                 mat[4], mat[5], mat[6], mat[7]);
00904 
00905         bu_log("%12E %12E %12E %12E\n",
00906                 mat[8], mat[9], mat[10], mat[11]);
00907 
00908         bu_log_indent_delta(-delta);
00909 
00910         bu_log("%12E %12E %12E %12E\n",
00911                 mat[12], mat[13], mat[14], mat[15]);
00912 }
00913 
00914 /**
00915  *
00916  */
00917 HIDDEN void
00918 bu_vls_matprint(struct bu_vls           *vls,
00919                 const char              *name,
00920                 register const double   *mat)
00921 {
00922         int     delta = strlen(name)+2;
00923 
00924         /* indent the body of the matrix */
00925         bu_log_indent_delta(delta);
00926 
00927         bu_vls_printf(vls, " %s=%12E %12E %12E %12E\n",
00928                       name, mat[0], mat[1], mat[2], mat[3]);
00929         bu_log_indent_vls(vls);
00930 
00931         bu_vls_printf(vls, "%12E %12E %12E %12E\n",
00932                       mat[4], mat[5], mat[6], mat[7]);
00933         bu_log_indent_vls(vls);
00934 
00935         bu_vls_printf(vls, "%12E %12E %12E %12E\n",
00936                       mat[8], mat[9], mat[10], mat[11]);
00937         bu_log_indent_vls(vls);
00938 
00939         bu_log_indent_delta(-delta);
00940 
00941         bu_vls_printf(vls, "%12E %12E %12E %12E\n",
00942                       mat[12], mat[13], mat[14], mat[15]);
00943 }
00944 
00945 /**
00946  *
00947  *      Convert a structure element (indicated by sdp) to its ASCII
00948  *      representation in a VLS
00949  */
00950 void
00951 bu_vls_struct_item(struct bu_vls *vp, const struct bu_structparse *sdp, const char *base, int sep_char)
00952 
00953                                      /* item description */
00954                                   /* base address of users structure */
00955                                  /* value separator */
00956 {
00957     register char *loc;
00958 
00959     if (sdp == (struct bu_structparse *)NULL) {
00960         bu_log( "Null \"struct bu_structparse\" pointer\n");
00961         return;
00962     }
00963 
00964 #if CRAY && !__STDC__
00965     loc = (char *)(base + ((int)sdp->sp_offset*sizeof(int)));
00966 #else
00967     loc = (char *)(base + sdp->sp_offset);
00968 #endif
00969 
00970     if (sdp->sp_fmt[0] == 'i' )  {
00971         bu_log( "Cannot print type 'i' yet!\n" );
00972         return;
00973     }
00974 
00975     if ( sdp->sp_fmt[0] != '%')  {
00976         bu_log("bu_vls_struct_item:  %s: unknown format '%s'\n",
00977                sdp->sp_name, sdp->sp_fmt );
00978         return;
00979     }
00980 
00981     switch( sdp->sp_fmt[1] )  {
00982     case 'c':
00983     case 's':
00984         if (sdp->sp_count < 1)
00985             break;
00986         if (sdp->sp_count == 1)
00987             bu_vls_printf( vp, "%c", *loc );
00988         else
00989             bu_vls_printf( vp, "%s", (char *)loc );
00990         break;
00991     case 'S': {
00992         register struct bu_vls *vls = (struct bu_vls *)loc;
00993 
00994         bu_vls_vlscat( vp, vls ); }
00995         break;
00996     case 'i': {
00997         register int i = sdp->sp_count;
00998         register short *sp = (short *)loc;
00999 
01000         bu_vls_printf( vp, "%d", *sp++ );
01001         while( --i > 0 ) bu_vls_printf( vp, "%c%d", sep_char, *sp++ ); }
01002         break;
01003     case 'd': {
01004         register int i = sdp->sp_count;
01005         register int *dp = (int *)loc;
01006 
01007         bu_vls_printf( vp, "%d", *dp++ );
01008         while( --i > 0 ) bu_vls_printf( vp, "%c%d", sep_char, *dp++ ); }
01009         break;
01010     case 'f': {
01011         register int i = sdp->sp_count;
01012         register double *dp = (double *)loc;
01013 
01014         bu_vls_printf( vp, "%.25G", *dp++ );
01015         while( --i > 0 ) bu_vls_printf( vp, "%c%.25G", sep_char, *dp++ ); }
01016         break;
01017     case 'x': {
01018         register int i = sdp->sp_count;
01019         register int *dp = (int *)loc;
01020 
01021         bu_vls_printf( vp, "%08x", *dp++ );
01022         while( --i > 0 ) bu_vls_printf( vp, "%c%08x", sep_char, *dp++ );  }
01023         break;
01024     default:
01025         break;
01026     }
01027 }
01028 
01029 
01030 
01031 /**
01032  *      B U _ V L S _ S T R U C T _ I T E M _ N A M E D
01033  *
01034  *      Convert a structure element called "name" to an ASCII representation
01035  *      in a VLS.
01036  */
01037 int
01038 bu_vls_struct_item_named(struct bu_vls *vp, const struct bu_structparse *parsetab, const char *name, const char *base, int sep_char)
01039 {
01040     register const struct bu_structparse *sdp;
01041 
01042     for( sdp = parsetab; sdp->sp_name != NULL; sdp++ )
01043         if( strcmp(sdp->sp_name, name) == 0 ) {
01044             bu_vls_struct_item( vp, sdp, base, sep_char );
01045             return 0;
01046         }
01047 
01048     return -1;
01049 }
01050 
01051 
01052 /**
01053  *                      B U _ S T R U C T P R I N T
01054  */
01055 void
01056 bu_struct_print(const char *title, const struct bu_structparse *parsetab, const char *base)
01057 
01058                                           /* structure description */
01059                                           /* base address of users structure */
01060 {
01061         register const struct bu_structparse    *sdp;
01062         register char                   *loc;
01063         register int                    lastoff = -1;
01064 
01065         bu_log( "%s\n", title );
01066         if (parsetab == (struct bu_structparse *)NULL) {
01067                 bu_log( "Null \"struct bu_structparse\" pointer\n");
01068                 return;
01069         }
01070         for( sdp = parsetab; sdp->sp_name != (char *)0; sdp++ )  {
01071 
01072                 /* Skip alternate keywords for same value */
01073                 if( lastoff == sdp->sp_offset )
01074                         continue;
01075                 lastoff = sdp->sp_offset;
01076 
01077 #if CRAY && !__STDC__
01078                 loc = (char *)(base + ((int)sdp->sp_offset*sizeof(int)));
01079 #else
01080                 loc = (char *)(base + sdp->sp_offset);
01081 #endif
01082 
01083                 if (sdp->sp_fmt[0] == 'i' )  {
01084                         bu_struct_print( sdp->sp_name,
01085                                 (struct bu_structparse *)sdp->sp_count,
01086                                 base );
01087                         continue;
01088                 }
01089 
01090                 if ( sdp->sp_fmt[0] != '%')  {
01091                         bu_log("bu_struct_print:  %s: unknown format '%s'\n",
01092                                 sdp->sp_name, sdp->sp_fmt );
01093                         continue;
01094                 }
01095 #if 0
01096                 bu_vls_trunc( &vls, 0 );
01097                 bu_vls_struct_item( &vls, sdp, base, ',' );
01098                 bu_log( " %s=%s\n", sdp->sp_name, bu_vls_addr(&vls) );
01099 #else
01100                 switch( sdp->sp_fmt[1] )  {
01101                 case 'c':
01102                 case 's':
01103                         if (sdp->sp_count < 1)
01104                                 break;
01105                         if (sdp->sp_count == 1)
01106                                 bu_log( " %s='%c'\n", sdp->sp_name, *loc);
01107                         else
01108                                 bu_log( " %s=\"%s\"\n", sdp->sp_name,
01109                                         (char *)loc );
01110                         break;
01111                 case 'S':
01112                         {
01113                                 int delta = strlen(sdp->sp_name)+2;
01114                                 register struct bu_vls *vls =
01115                                         (struct bu_vls *)loc;
01116 
01117                                 bu_log_indent_delta(delta);
01118                                 bu_log(" %s=(vls_magic)%d (vls_offset)%d (vls_len)%d (vls_max)%d\n",
01119                                         sdp->sp_name, vls->vls_magic,
01120                                         vls->vls_offset,
01121                                         vls->vls_len, vls->vls_max);
01122                                 bu_log_indent_delta(-delta);
01123                                 bu_log("\"%s\"\n", vls->vls_str+vls->vls_offset);
01124                         }
01125                         break;
01126                 case 'i':
01127                         {       register int i = sdp->sp_count;
01128                                 register short *sp = (short *)loc;
01129 
01130                                 bu_log( " %s=%d", sdp->sp_name, *sp++ );
01131 
01132                                 while (--i > 0) bu_log( ",%d", *sp++ );
01133 
01134                                 bu_log("\n");
01135                         }
01136                         break;
01137                 case 'd':
01138                         {       register int i = sdp->sp_count;
01139                                 register int *dp = (int *)loc;
01140 
01141                                 bu_log( " %s=%d", sdp->sp_name, *dp++ );
01142 
01143                                 while (--i > 0) bu_log( ",%d", *dp++ );
01144 
01145                                 bu_log("\n");
01146                         }
01147                         break;
01148                 case 'f':
01149                         {       register int i = sdp->sp_count;
01150                                 register double *dp = (double *)loc;
01151 
01152                                 if (sdp->sp_count == 16) {
01153                                         bu_matprint(sdp->sp_name, dp);
01154                                 } else if (sdp->sp_count <= 3){
01155                                         bu_log( " %s=%.25G", sdp->sp_name, *dp++ );
01156 
01157                                         while (--i > 0)
01158                                                 bu_log( ",%.25G", *dp++ );
01159 
01160                                         bu_log("\n");
01161                                 }else  {
01162                                         int delta = strlen(sdp->sp_name)+2;
01163 
01164                                         bu_log_indent_delta(delta);
01165 
01166                                         bu_log( " %s=%.25G\n", sdp->sp_name, *dp++ );
01167 
01168                                         while (--i > 1)
01169                                                 bu_log( "%.25G\n", *dp++ );
01170 
01171                                         bu_log_indent_delta(-delta);
01172                                         bu_log( "%.25G\n", *dp );
01173                                 }
01174                         }
01175                         break;
01176                 case 'x':
01177                         {       register int i = sdp->sp_count;
01178                                 register int *dp = (int *)loc;
01179 
01180                                 bu_log( " %s=%08x", sdp->sp_name, *dp++ );
01181 
01182                                 while (--i > 0) bu_log( ",%08x", *dp++ );
01183 
01184                                 bu_log("\n");
01185                         }
01186                         break;
01187                 default:
01188                         bu_log( " bu_struct_print: Unknown format: %s=%s??\n",
01189                                 sdp->sp_name, sdp->sp_fmt );
01190                         break;
01191                 }
01192 #endif
01193         }
01194 }
01195 
01196 /**
01197  *                      B U _ V L S _ P R I N T _ D O U B L E
01198  */
01199 HIDDEN void
01200 bu_vls_print_double(struct bu_vls *vls, const char *name, register long int count, register const double *dp)
01201 {
01202         register int tmpi;
01203         register char *cp;
01204 
01205         bu_vls_extend(vls, strlen(name) + 3 + 32 * count);
01206 
01207         cp = vls->vls_str + vls->vls_offset + vls->vls_len;
01208         sprintf(cp, "%s%s=%.27G", (vls->vls_len?" ":""), name, *dp++);
01209         tmpi = strlen(cp);
01210         vls->vls_len += tmpi;
01211 
01212         while (--count > 0) {
01213                 cp += tmpi;
01214                 sprintf(cp, ",%.27G", *dp++);
01215                 tmpi = strlen(cp);
01216                 vls->vls_len += tmpi;
01217         }
01218 }
01219 
01220 /**
01221  *                      B U _ V L S _ S T R U C T P R I N T
01222  *
01223  *      This differs from bu_struct_print in that this output is less readable
01224  *      by humans, but easier to parse with the computer.
01225  */
01226 void
01227 bu_vls_struct_print(struct bu_vls *vls, register const struct bu_structparse *sdp, const char *base)
01228                                                 /* vls to print into */
01229                                                 /* structure description */
01230                                                 /* structure ponter */
01231 {
01232         register char                   *loc;
01233         register int                    lastoff = -1;
01234         register char                   *cp;
01235 
01236         BU_CK_VLS(vls);
01237 
01238         if (sdp == (struct bu_structparse *)NULL) {
01239                 bu_log( "Null \"struct bu_structparse\" pointer\n");
01240                 return;
01241         }
01242 
01243         for ( ; sdp->sp_name != (char*)NULL ; sdp++) {
01244                 /* Skip alternate keywords for same value */
01245 
01246                 if( lastoff == sdp->sp_offset )
01247                         continue;
01248                 lastoff = sdp->sp_offset;
01249 
01250 #if CRAY && !__STDC__
01251                 loc = (char *)(base + ((int)sdp->sp_offset*sizeof(int)));
01252 #else
01253                 loc = (char *)(base + sdp->sp_offset);
01254 #endif
01255 
01256                 if (sdp->sp_fmt[0] == 'i')  {
01257                         struct bu_vls sub_str;
01258 
01259                         bu_vls_init(&sub_str);
01260                         bu_vls_struct_print( &sub_str,
01261                                 (struct bu_structparse *)sdp->sp_count,
01262                                 base );
01263 
01264                         bu_vls_vlscat(vls, &sub_str);
01265                         bu_vls_free( &sub_str );
01266                         continue;
01267                 }
01268 
01269                 if ( sdp->sp_fmt[0] != '%' )  {
01270                         bu_log("bu_struct_print:  %s: unknown format '%s'\n",
01271                                 sdp->sp_name, sdp->sp_fmt );
01272                         break;
01273                 }
01274 
01275                 switch( sdp->sp_fmt[1] )  {
01276                 case 'c':
01277                 case 's':
01278                         if (sdp->sp_count < 1)
01279                                 break;
01280                         if (sdp->sp_count == 1) {
01281                                 bu_vls_extend(vls, strlen(sdp->sp_name)+6);
01282                                 cp = vls->vls_str + vls->vls_offset + vls->vls_len;
01283                                 if (*loc == '"')
01284                                         sprintf(cp, "%s%s=\"%s\"",
01285                                                 (vls->vls_len?" ":""),
01286                                                 sdp->sp_name, "\\\"");
01287                                 else
01288                                         sprintf(cp, "%s%s=\"%c\"",
01289                                                 (vls->vls_len?" ":""),
01290                                                 sdp->sp_name,
01291                                                 *loc);
01292                         } else {
01293                                 register char *p;
01294                                 register int count=0;
01295 
01296                                 /* count the quote characters */
01297                                 p = loc;
01298                                 while ((p=strchr(p, '"')) != (char *)NULL) {
01299                                         ++p;
01300                                         ++count;
01301                                 }
01302                                 bu_vls_extend(vls, strlen(sdp->sp_name)+
01303                                         strlen(loc)+5+count);
01304 
01305                                 cp = vls->vls_str + vls->vls_offset + vls->vls_len;
01306                                 if (vls->vls_len) (void)strcat(cp, " ");
01307                                 (void)strcat(cp, sdp->sp_name);
01308                                 (void)strcat(cp, "=\"");
01309 
01310                                 /* copy the string, escaping all the internal
01311                                  * double quote (") characters
01312                                  */
01313                                 p = &cp[strlen(cp)];
01314                                 while (*loc) {
01315                                         if (*loc == '"') {
01316                                                 *p++ = '\\';
01317                                         }
01318                                         *p++ = *loc++;
01319                                 }
01320                                 *p++ = '"';
01321                                 *p = '\0';
01322                         }
01323                         vls->vls_len += strlen(cp);
01324                         break;
01325                 case 'S':
01326                         {       register struct bu_vls *vls_p =
01327                                         (struct bu_vls *)loc;
01328 
01329                                 bu_vls_extend(vls, bu_vls_strlen(vls_p) + 5 +
01330                                         strlen(sdp->sp_name) );
01331 
01332                                 cp = vls->vls_str + vls->vls_offset + vls->vls_len;
01333                                 sprintf(cp, "%s%s=\"%s\"",
01334                                         (vls->vls_len?" ":""),
01335                                         sdp->sp_name,
01336                                         bu_vls_addr(vls_p) );
01337                                 vls->vls_len += strlen(cp);
01338                         }
01339                         break;
01340                 case 'i':
01341                         {       register int i = sdp->sp_count;
01342                                 register short *sp = (short *)loc;
01343                                 register int tmpi;
01344 
01345                                 bu_vls_extend(vls,
01346                                         64 * i + strlen(sdp->sp_name) + 3 );
01347 
01348                                 cp = vls->vls_str + vls->vls_offset + vls->vls_len;
01349                                 sprintf(cp, "%s%s=%d",
01350                                                 (vls->vls_len?" ":""),
01351                                                  sdp->sp_name, *sp++);
01352                                 tmpi = strlen(cp);
01353                                 vls->vls_len += tmpi;
01354 
01355                                 while (--i > 0) {
01356                                         cp += tmpi;
01357                                         sprintf(cp, ",%d", *sp++);
01358                                         tmpi = strlen(cp);
01359                                         vls->vls_len += tmpi;
01360                                 }
01361                         }
01362                         break;
01363                 case 'd':
01364                         {       register int i = sdp->sp_count;
01365                                 register int *dp = (int *)loc;
01366                                 register int tmpi;
01367 
01368                                 bu_vls_extend(vls,
01369                                         64 * i + strlen(sdp->sp_name) + 3 );
01370 
01371                                 cp = vls->vls_str + vls->vls_offset + vls->vls_len;
01372                                 sprintf(cp, "%s%s=%d",
01373                                         (vls->vls_len?" ":""),
01374                                         sdp->sp_name, *dp++);
01375                                 tmpi = strlen(cp);
01376                                 vls->vls_len += tmpi;
01377 
01378                                 while (--i > 0) {
01379                                         cp += tmpi;
01380                                         sprintf(cp, ",%d", *dp++);
01381                                         tmpi = strlen(cp);
01382                                         vls->vls_len += tmpi;
01383                                 }
01384                         }
01385                         break;
01386                 case 'f':
01387                         bu_vls_print_double(vls, sdp->sp_name, sdp->sp_count,
01388                                 (double *)loc);
01389                         break;
01390                 default:
01391                         bu_log( " %s=%s??\n", sdp->sp_name, sdp->sp_fmt );
01392                         bu_bomb("unexpected case encountered in bu_vls_struct_print\n");
01393                         break;
01394                 }
01395         }
01396 }
01397 
01398 
01399 /**
01400  *                      B U _ V L S _ S T R U C T P R I N T 2
01401  *
01402  *      This differs from bu_struct_print in that it prints to a vls.
01403  */
01404 void
01405 bu_vls_struct_print2(struct bu_vls                      *vls_out,
01406                      const char                         *title,
01407                      const struct bu_structparse        *parsetab,      /* structure description */
01408                      const char                         *base)          /* base address of users structure */
01409 {
01410         register const struct bu_structparse    *sdp;
01411         register char                   *loc;
01412         register int                    lastoff = -1;
01413 
01414         bu_vls_printf(vls_out, "%s\n", title);
01415         if (parsetab == (struct bu_structparse *)NULL) {
01416                 bu_vls_printf(vls_out, "Null \"struct bu_structparse\" pointer\n");
01417                 return;
01418         }
01419 
01420         for (sdp = parsetab; sdp->sp_name != (char *)0; sdp++) {
01421 
01422                 /* Skip alternate keywords for same value */
01423                 if (lastoff == sdp->sp_offset)
01424                         continue;
01425                 lastoff = sdp->sp_offset;
01426 
01427 #if CRAY && !__STDC__
01428                 loc = (char *)(base + ((int)sdp->sp_offset*sizeof(int)));
01429 #else
01430                 loc = (char *)(base + sdp->sp_offset);
01431 #endif
01432 
01433                 if (sdp->sp_fmt[0] == 'i' )  {
01434                         bu_vls_struct_print2(vls_out, sdp->sp_name,
01435                                              (struct bu_structparse *)sdp->sp_count,
01436                                              base);
01437                         continue;
01438                 }
01439 
01440                 if (sdp->sp_fmt[0] != '%') {
01441                         bu_vls_printf(vls_out, "bu_vls_struct_print:  %s: unknown format '%s'\n",
01442                                sdp->sp_name, sdp->sp_fmt );
01443                         continue;
01444                 }
01445 
01446                 switch( sdp->sp_fmt[1] )  {
01447                 case 'c':
01448                 case 's':
01449                         if (sdp->sp_count < 1)
01450                                 break;
01451                         if (sdp->sp_count == 1)
01452                                 bu_vls_printf(vls_out, " %s='%c'\n", sdp->sp_name, *loc);
01453                         else
01454                                 bu_vls_printf(vls_out, " %s=\"%s\"\n", sdp->sp_name,
01455                                         (char *)loc );
01456                         break;
01457                 case 'S':
01458                         {
01459                                 int delta = strlen(sdp->sp_name)+2;
01460                                 register struct bu_vls *vls =
01461                                         (struct bu_vls *)loc;
01462 
01463                                 bu_log_indent_delta(delta);
01464                                 bu_vls_printf(vls_out, " %s=(vls_magic)%ld (vls_offset)%d (vls_len)%d (vls_max)%d\n",
01465                                         sdp->sp_name, vls->vls_magic,
01466                                         vls->vls_offset,
01467                                         vls->vls_len, vls->vls_max);
01468                                 bu_log_indent_vls(vls_out);
01469                                 bu_log_indent_delta(-delta);
01470                                 bu_vls_printf(vls_out, "\"%s\"\n", vls->vls_str+vls->vls_offset);
01471                         }
01472                         break;
01473                 case 'i':
01474                         {       register int i = sdp->sp_count;
01475                                 register short *sp = (short *)loc;
01476 
01477                                 bu_vls_printf(vls_out, " %s=%d", sdp->sp_name, *sp++ );
01478 
01479                                 while (--i > 0)
01480                                         bu_vls_printf(vls_out, ",%d", *sp++ );
01481 
01482                                 bu_vls_printf(vls_out, "\n");
01483                         }
01484                         break;
01485                 case 'd':
01486                         {       register int i = sdp->sp_count;
01487                                 register int *dp = (int *)loc;
01488 
01489                                 bu_vls_printf(vls_out, " %s=%d", sdp->sp_name, *dp++ );
01490 
01491                                 while (--i > 0)
01492                                         bu_vls_printf(vls_out, ",%d", *dp++ );
01493 
01494                                 bu_vls_printf(vls_out, "\n");
01495                         }
01496                         break;
01497                 case 'f':
01498                         {       register int i = sdp->sp_count;
01499                                 register double *dp = (double *)loc;
01500 
01501                                 if (sdp->sp_count == 16) {
01502                                         bu_vls_matprint(vls_out, sdp->sp_name, dp);
01503                                 } else if (sdp->sp_count <= 3){
01504                                         bu_vls_printf(vls_out, " %s=%.25G", sdp->sp_name, *dp++ );
01505 
01506                                         while (--i > 0)
01507                                                 bu_vls_printf(vls_out, ",%.25G", *dp++ );
01508 
01509                                         bu_vls_printf(vls_out, "\n");
01510                                 }else  {
01511                                         int delta = strlen(sdp->sp_name)+2;
01512 
01513                                         bu_log_indent_delta(delta);
01514                                         bu_vls_printf(vls_out, " %s=%.25G\n", sdp->sp_name, *dp++ );
01515                                         bu_log_indent_vls(vls_out);
01516 
01517                                         while (--i > 1) {
01518                                                 bu_vls_printf(vls_out, "%.25G\n", *dp++ );
01519                                                 bu_log_indent_vls(vls_out);
01520                                         }
01521 
01522                                         bu_log_indent_delta(-delta);
01523                                         bu_vls_printf(vls_out, "%.25G\n", *dp );
01524                                 }
01525                         }
01526                         break;
01527                 case 'x':
01528                         {       register int i = sdp->sp_count;
01529                                 register int *dp = (int *)loc;
01530 
01531                                 bu_vls_printf(vls_out, " %s=%08x", sdp->sp_name, *dp++ );
01532 
01533                                 while (--i > 0)
01534                                         bu_vls_printf(vls_out, ",%08x", *dp++ );
01535 
01536                                 bu_vls_printf(vls_out, "\n");
01537                         }
01538                         break;
01539                 default:
01540                         bu_vls_printf(vls_out, " bu_vls_struct_print2: Unknown format: %s=%s??\n",
01541                                 sdp->sp_name, sdp->sp_fmt );
01542                         break;
01543                 }
01544         }
01545 }
01546 
01547 
01548 /**
01549  * This allows us to specify the "size" parameter as values like ".5m"
01550  * or "27in" rather than using mm all the time.
01551  */
01552 void
01553 bu_parse_mm(register const struct bu_structparse *sdp, register const char *name, char *base, const char *value)
01554                                                 /* structure description */
01555                                                 /* struct member name */
01556                                                 /* begining of structure */
01557                                                 /* string containing value */
01558 {
01559         double *p = (double *)(base+sdp->sp_offset);
01560 
01561         /* reconvert with optional units */
01562         *p = bu_mm_value(value);
01563 }
01564 
01565 #define STATE_UNKNOWN           0
01566 #define STATE_IN_KEYWORD        1
01567 #define STATE_IN_VALUE          2
01568 #define STATE_IN_QUOTED_VALUE   3
01569 
01570 /**
01571  *
01572  */
01573 int
01574 bu_key_eq_to_key_val(char *in, char **next, struct bu_vls *vls)
01575 {
01576         char *iptr=in;
01577         char *start;
01578         int state=STATE_IN_KEYWORD;
01579 
01580         BU_CK_VLS( vls );
01581 
01582         *next = NULL;
01583 
01584         while ( *iptr )
01585         {
01586                 char *prev='\0';
01587 
01588                 switch( state )
01589                 {
01590                         case STATE_IN_KEYWORD:
01591                                 /* skip leading white space */
01592                                 while( isspace( *iptr ) )
01593                                         iptr++;
01594 
01595                                 if( !(*iptr) )
01596                                         break;
01597 
01598                                 if( *iptr == ';' )
01599                                 {
01600                                         /* found end of a stack element */
01601                                         *next = iptr+1;
01602                                         return( 0 );
01603                                 }
01604 
01605                                 /* copy keyword up to '=' */
01606                                 start = iptr;
01607                                 while( *iptr && *iptr != '=' )
01608                                         iptr++;
01609 
01610                                 bu_vls_strncat( vls, start, iptr - start );
01611 
01612                                 /* add a single space after keyword */
01613                                 bu_vls_putc( vls, ' ' );
01614 
01615                                 if( !*iptr )
01616                                         break;
01617 
01618                                 /* skip over '=' in input */
01619                                 iptr++;
01620 
01621                                 /* switch to value state */
01622                                 state = STATE_IN_VALUE;
01623 
01624                                 break;
01625                         case STATE_IN_VALUE:
01626                                 /* skip excess white space */
01627                                 while( isspace( *iptr ) )
01628                                         iptr++;
01629 
01630                                 /* check for quoted value */
01631                                 if( *iptr == '"' )
01632                                 {
01633                                         /* switch to quoted value state */
01634                                         state = STATE_IN_QUOTED_VALUE;
01635 
01636                                         /* skip over '"' */
01637                                         iptr++;
01638 
01639                                         break;
01640                                 }
01641 
01642                                 /* copy value up to next white space or end of string */
01643                                 start = iptr;
01644                                 while( *iptr && *iptr != ';' && !isspace( *iptr ) )
01645                                         iptr++;
01646 
01647                                 bu_vls_strncat( vls, start, iptr - start );
01648 
01649                                 if( *iptr ) /* more to come */
01650                                 {
01651                                         bu_vls_putc( vls, ' ' );
01652 
01653                                         /* switch back to keyword state */
01654                                         state = STATE_IN_KEYWORD;
01655                                 }
01656 
01657                                 break;
01658                         case STATE_IN_QUOTED_VALUE:
01659                                 /* copy byte-for-byte to end quote (watch out for escaped quote)
01660                                  * replace quotes with '{' '}' */
01661 
01662                                 bu_vls_strcat( vls, " {" );
01663                                 while( 1 )
01664                                 {
01665                                         if( *iptr == '"' && *prev != '\\' )
01666                                         {
01667                                                 bu_vls_putc( vls, '}' );
01668                                                 iptr++;
01669                                                 break;
01670                                         }
01671                                         bu_vls_putc( vls, *iptr );
01672                                         prev = iptr++;
01673                                 }
01674 
01675                                 if( *iptr && *iptr != ';' ) /* more to come */
01676                                         bu_vls_putc( vls, ' ' );
01677 
01678                                 /* switch back to keyword state */
01679                                 state = STATE_IN_KEYWORD;
01680 
01681                                 break;
01682                 }
01683         }
01684         return( 0 );
01685 }
01686 
01687 /**
01688  *                      B U _ S H A D E R _ T O _ T C L _ L I S T
01689  *
01690  *  Take an old v4 shader specification of the form
01691  *
01692  *      shadername arg1=value1 arg2=value2 color=1/2/3
01693  *
01694  *  and convert it into the v5 Tcl-list form
01695  *
01696  *      shadername {arg1 value1 arg2 value2 color 1/2/3}
01697  *
01698  *  Note -- the input string is smashed with nulls.
01699  *
01700  *  Note -- the v5 version is used everywhere internally, and in v5
01701  *  databases.
01702  *
01703  *
01704  *  @return     1       error
01705  *  @return     0       OK
01706  */
01707 int
01708 bu_shader_to_tcl_list(char *in, struct bu_vls *vls)
01709 {
01710         char *iptr;
01711         char *next=in;
01712         char *shader;
01713         int shader_name_len=0;
01714         int is_stack=0;
01715         int len;
01716 
01717 
01718         BU_CK_VLS( vls );
01719 
01720         while( next )
01721         {
01722                 iptr = next;
01723 
01724                 /* skip over white space */
01725                 while( isspace( *iptr ) )
01726                         iptr++;
01727 
01728                 /* this is start of shader name */
01729                 shader = iptr;
01730 
01731                 /* find end of shader name */
01732                 while( *iptr && !isspace( *iptr ) && *iptr != ';' )
01733                         iptr++;
01734                 shader_name_len = iptr - shader;
01735 
01736                 if( !strncmp( shader, "stack", 5 ) )
01737                 {
01738                         /* stack shader, loop through all shaders in stack */
01739                         int done=0;
01740 
01741                         bu_vls_strcat( vls, "stack {" );
01742 
01743                         while( !done )
01744                         {
01745                                 char *shade1;
01746 
01747                                 while( isspace( *iptr ) )
01748                                         iptr++;
01749                                 if( *iptr == '\0' )
01750                                         break;
01751                                 shade1 = iptr;
01752                                 while( *iptr && *iptr != ';' )
01753                                         iptr++;
01754                                 if( *iptr == '\0' )
01755                                         done = 1;
01756                                 *iptr = '\0';
01757 
01758                                 bu_vls_putc( vls, '{' );
01759 
01760                                 if( bu_shader_to_tcl_list( shade1, vls ) )
01761                                         return( 1 );
01762 
01763                                 bu_vls_strcat( vls, "} " );
01764 
01765                                 if( !done )
01766                                         iptr++;
01767                         }
01768                         bu_vls_putc( vls, '}' );
01769                         return( 0 );
01770                 }
01771                 else if( !strncmp( shader, "envmap", 6 ) )
01772                 {
01773                         bu_vls_strcat( vls, "envmap {" );
01774                         if( bu_shader_to_tcl_list( iptr, vls ) )
01775                                 return( 1 );
01776                         bu_vls_putc( vls, '}' );
01777                         return( 0 );
01778                 }
01779 
01780                 if( is_stack )
01781                         bu_vls_strcat( vls, " {" );
01782 
01783                 bu_vls_strncat( vls, shader, shader_name_len );
01784 
01785                 /* skip more white space */
01786                 while( *iptr && isspace( *iptr ) )
01787                         iptr++;
01788 
01789                 /* iptr now points at start of parameters, if any */
01790                 if( *iptr && *iptr != ';' )
01791                 {
01792                         bu_vls_strcat( vls, " {" );
01793                         len = bu_vls_strlen( vls );
01794                         if( bu_key_eq_to_key_val( iptr, &next, vls ) )
01795                                 return( 1 );
01796                         if( bu_vls_strlen( vls ) > len )
01797                                 bu_vls_putc( vls, '}' );
01798                         else
01799                                 bu_vls_trunc( vls, len-2 );
01800                 }
01801                 else if( *iptr && *iptr == ';' )
01802                         next = ++iptr;
01803                 else
01804                         next = (char *)NULL;
01805 
01806                 if( is_stack )
01807                         bu_vls_putc( vls, '}' );
01808         }
01809 
01810         if( is_stack )
01811                 bu_vls_putc( vls, '}' );
01812 
01813         return( 0 );
01814 }
01815 
01816 /**
01817  *                      B U _ L I S T _ E L E M
01818  *
01819  *  Given a Tcl list, return a copy of the 'index'th entry,
01820  *  which may itself be a list.
01821  *
01822  *
01823  *  Note -- the caller is responsible for freeing the returned string.
01824  */
01825 char *
01826 bu_list_elem( const char *in, int index )
01827 {
01828         int depth=0;
01829         int count=0;
01830         int len=0;
01831         const char *ptr=in;
01832         const char *prev=NULL;
01833         const char *start=NULL;
01834         const char *end=NULL;
01835         char *out=NULL;
01836 
01837         while( *ptr )
01838         {
01839                 /* skip leading white space */
01840                 while( *ptr && isspace( *ptr ) )
01841                 {
01842                         prev = ptr;
01843                         ptr++;
01844                 }
01845 
01846                 if( !*ptr )
01847                         break;
01848 
01849                 if( depth == 0 && count == index )
01850                         start = ptr;
01851 
01852                 if( *ptr == '{' )
01853                 {
01854                         depth++;
01855                         prev = ptr;
01856                         ptr++;
01857                 }
01858                 else if( *ptr == '}' )
01859                 {
01860                         depth--;
01861                         if( depth == 0 )
01862                                 count++;
01863                         if( start && depth == 0 )
01864                         {
01865                                 end = ptr;
01866                                 break;
01867                         }
01868                         prev = ptr;
01869                         ptr++;
01870                 }
01871                 else
01872                 {
01873                         while( *ptr &&
01874                                 (!isspace( *ptr ) || *prev == '\\') &&
01875                                 (*ptr != '}' || *prev == '\\') &&
01876                                 (*ptr != '{' || *prev == '\\') )
01877                         {
01878                                 prev = ptr;
01879                                 ptr++;
01880                         }
01881                         if( depth == 0 )
01882                                 count++;
01883 
01884                         if( start && depth == 0 )
01885                         {
01886                                 end = ptr-1;
01887                                 break;
01888                         }
01889                 }
01890         }
01891 
01892         if( !start )
01893                 return( (char *)NULL );
01894 
01895         if( *start == '{' )
01896         {
01897                 if( !end || *end != '}' )
01898                 {
01899                         bu_log( "Error in list (uneven braces?): %s\n", in );
01900                         return( (char *)NULL );
01901                 }
01902 
01903                 /* remove enclosing braces */
01904                 start++;
01905                 while( start < end && isspace( *start ) )
01906                         start++;
01907 
01908                 end--;
01909                 while( end > start && isspace( *end ) && *(end-1) != '\\' )
01910                         end--;
01911 
01912                 if( start == end )
01913                         return( (char *)NULL );
01914         }
01915 
01916         len = end - start + 1;
01917         out = bu_malloc( len+1, "bu_list_elem:out" );
01918         strncpy( out, start, len );
01919         *(out + len) = '\0';
01920 
01921         return( out );
01922 }
01923 
01924 /**
01925  *                      B U _ T C L _ L I S T _ L E N G T H
01926  *
01927  *  Return number of items in a string, interpreted as a Tcl list.
01928  */
01929 int
01930 bu_tcl_list_length( const char *in )
01931 {
01932         int count=0;
01933         int depth=0;
01934         const char *ptr=in;
01935         const char *prev=NULL;
01936 
01937         while( *ptr )
01938         {
01939                 /* skip leading white space */
01940                 while( *ptr && isspace( *ptr ) )
01941                 {
01942                         prev = ptr;
01943                         ptr++;
01944                 }
01945 
01946                 if( !*ptr )
01947                         break;
01948 
01949                 if( *ptr == '{' )
01950                 {
01951                         if( depth == 0 )
01952                                 count++;
01953                         depth++;
01954                         prev = ptr;
01955                         ptr++;
01956                 }
01957                 else if( *ptr == '}' )
01958                 {
01959                         depth--;
01960                         prev = ptr;
01961                         ptr++;
01962                 }
01963                 else
01964                 {
01965                         if( depth == 0 )
01966                                 count++;
01967 
01968                         while( *ptr &&
01969                                 (!isspace( *ptr ) || *prev == '\\') &&
01970                                 (*ptr != '}' || *prev == '\\') &&
01971                                 (*ptr != '{' || *prev == '\\') )
01972                         {
01973                                 prev = ptr;
01974                                 ptr++;
01975                         }
01976                 }
01977         }
01978 
01979         return( count );
01980 }
01981 
01982 /**
01983  *
01984  */
01985 int
01986 bu_key_val_to_vls(struct bu_vls *vls, char *params)
01987 {
01988         int len;
01989         int j;
01990 
01991         len = bu_tcl_list_length( params );
01992 
01993         if( len == 1 )
01994         {
01995                 bu_vls_putc( vls, ' ' );
01996                 bu_vls_strcat( vls, params );
01997                 return( 0 );
01998         }
01999 
02000         if( len%2 )
02001         {
02002                 bu_log( "bu_key_val_to_vls: Error: shader parameters must be even numbered!!\n\t%s\n", params );
02003                 return( 1 );
02004         }
02005 
02006         for( j=0 ; j<len ; j += 2 )
02007         {
02008                 char *keyword;
02009                 char *value;
02010 
02011                 keyword = bu_list_elem( params, j );
02012                 value = bu_list_elem( params, j+1 );
02013 
02014                 bu_vls_putc( vls, ' ' );
02015                 bu_vls_strcat( vls, keyword );
02016                 bu_vls_putc( vls, '=' );
02017                 if( bu_tcl_list_length( value ) > 1  )
02018                 {
02019                         bu_vls_putc( vls, '"' );
02020                         bu_vls_strcat( vls, value );
02021                         bu_vls_putc( vls, '"' );
02022                 }
02023                 else
02024                         bu_vls_strcat( vls, value );
02025 
02026                 bu_free( keyword, "bu_key_val_to_vls() keyword");
02027                 bu_free( value, "bu_key_val_to_vls() value");
02028 
02029         }
02030         return( 0 );
02031 }
02032 
02033 /**
02034  *                      B U _ S H A D E R _ T O _ K E Y _ E Q
02035  */
02036 int
02037 bu_shader_to_key_eq(char *in, struct bu_vls *vls)
02038 {
02039         int len;
02040         int ret=0;
02041         char *shader;
02042         char *params;
02043 
02044         BU_CK_VLS( vls );
02045 
02046         len = bu_tcl_list_length( in );
02047 
02048         if( len == 0 )
02049                 return( 0 );
02050 
02051         if( len == 1 )
02052         {
02053                 /* shader with no parameters */
02054                 if( bu_vls_strlen( vls ) )
02055                         bu_vls_putc( vls, ' ' );
02056                 bu_vls_strcat( vls, in );
02057                 return( 0 );
02058         }
02059 
02060         if( len != 2 )
02061         {
02062                 bu_log( "bu_shader_to_key_eq: Error: shader must have two elements (not %d)!!\n\t%s\n", len, in );
02063                 return 1;
02064         }
02065 
02066         shader = bu_list_elem( in, 0 );
02067         params = bu_list_elem( in, 1 );
02068 
02069         if( !strcmp( shader, "envmap" ) )
02070         {
02071                 /* environment map */
02072 
02073                 if( bu_vls_strlen( vls ) )
02074                         bu_vls_putc( vls, ' ' );
02075                 bu_vls_strcat( vls, "envmap" );
02076 
02077                 bu_shader_to_key_eq( params, vls );
02078         }
02079         else if( !strcmp( shader, "stack" ) )
02080         {
02081                 /* stacked shaders */
02082 
02083                 int i;
02084 
02085                 if( bu_vls_strlen( vls ) )
02086                         bu_vls_putc( vls, ' ' );
02087                 bu_vls_strcat( vls, "stack" );
02088 
02089                 /* get number of shaders in the stack */
02090                 len = bu_tcl_list_length( params );
02091 
02092                 /* process each shader in the stack */
02093                 for( i=0 ; i<len ; i++ )
02094                 {
02095                         char *shader1;
02096 
02097                         /* each parameter must be a shader specification in itself */
02098                         shader1 = bu_list_elem( params, i );
02099 
02100                         if( i > 0 )
02101                                 bu_vls_putc( vls, ';' );
02102                         bu_shader_to_key_eq( shader1, vls );
02103                         bu_free( shader1, "shader1" );
02104                 }
02105         }
02106         else
02107         {
02108                 if( bu_vls_strlen( vls ) )
02109                         bu_vls_putc( vls, ' ' );
02110                 bu_vls_strcat( vls, shader );
02111                 ret = bu_key_val_to_vls( vls, params );
02112         }
02113 
02114         bu_free( shader, "shader" );
02115         bu_free( params, "params" );
02116 
02117         return( ret );
02118 }
02119 
02120 /**
02121  *
02122  *                      B U _ F W R I T E _ E X T E R N A L
02123  *
02124  *  Take a block of memory, and write it into a file.
02125  *
02126  *  Caller is responsible for freeing memory of external representation,
02127  *  using bu_free_external().
02128  *
02129  *
02130  *  @return     <0      error
02131  *  @return     0       OK
02132  */
02133 int
02134 bu_fwrite_external( FILE *fp, const struct bu_external *ep )
02135 {
02136         size_t  got;
02137 
02138         BU_CK_EXTERNAL(ep);
02139 
02140         if( (got = fwrite( ep->ext_buf, 1, ep->ext_nbytes, fp )) != ep->ext_nbytes )  {
02141                 perror("fwrite");
02142                 bu_log("bu_fwrite_external() attempted to write %ld, got %ld\n", (long)ep->ext_nbytes, (long)got );
02143                 return -1;
02144         }
02145         return 0;
02146 }
02147 
02148 /**
02149  *                      B U _ H E X D U M P _ E X T E R N A L
02150  */
02151 void
02152 bu_hexdump_external( FILE *fp, const struct bu_external *ep, const char *str)
02153 {
02154         const unsigned char     *cp;
02155         const unsigned char     *endp;
02156         int i, j, k;
02157 
02158         BU_CK_EXTERNAL(ep);
02159 
02160         fprintf(fp, "%s:\n", str);
02161         if( ep->ext_nbytes <= 0 )  fprintf(fp, "\tWarning: 0 length external buffer\n");
02162 
02163         cp = ep->ext_buf;
02164         endp = cp + ep->ext_nbytes;
02165         for( i=0; i < ep->ext_nbytes; i += 16 )  {
02166                 const unsigned char     *sp = cp;
02167 
02168                 for( j=0; j < 4; j++ )  {
02169                         for( k=0; k < 4; k++ )  {
02170                                 if( cp >= endp )
02171                                         fprintf(fp, "   ");
02172                                 else
02173                                         fprintf(fp, "%2.2x ", *cp++ );
02174                         }
02175                         fprintf(fp, " ");
02176                 }
02177                 fprintf(fp, " |");
02178 
02179                 for( j=0; j < 16; j++,sp++ )  {
02180                         if( sp >= endp )  break;
02181                         if( isprint(*sp) )
02182                                 putc(*sp, fp);
02183                         else
02184                                 putc('.', fp);
02185                 }
02186 
02187                 fprintf(fp, "|\n");
02188         }
02189 }
02190 
02191 /**
02192  *                      B U _ F R E E _ E X T E R N A L
02193  */
02194 void
02195 bu_free_external( register struct bu_external *ep)
02196 {
02197         BU_CK_EXTERNAL(ep);
02198         if( ep->ext_buf )  {
02199                 bu_free( ep->ext_buf, "bu_external ext_buf" );
02200                 ep->ext_buf = GENPTR_NULL;
02201         }
02202 }
02203 
02204 /**
02205  *                      B U _ C O P Y _ E X T E R N A L
02206  */
02207 void
02208 bu_copy_external(struct bu_external *op, const struct bu_external *ip)
02209 {
02210         BU_CK_EXTERNAL(ip);
02211         BU_INIT_EXTERNAL(op);
02212 
02213         if( op == ip )  return;
02214 
02215         op->ext_nbytes = ip->ext_nbytes;
02216         op->ext_buf = bu_malloc( ip->ext_nbytes, "bu_copy_external" );
02217         bcopy( ip->ext_buf, op->ext_buf, ip->ext_nbytes );
02218 }
02219 
02220 /**
02221  *                      B U _ N E X T _ T O K E N
02222  *
02223  *  Advance pointer through string over current token,
02224  *  across white space, to beginning of next token.
02225  */
02226 char *
02227 bu_next_token( char *str )
02228 {
02229   char *ret;
02230 
02231   ret = str;
02232   while( !isspace( *ret ) && *ret !='\0' )
02233     ret++;
02234   while( isspace( *ret ) )
02235     ret++;
02236 
02237   return( ret );
02238 }
02239 /*@}*/
02240 /*
02241  * Local Variables:
02242  * mode: C
02243  * tab-width: 8
02244  * c-basic-offset: 4
02245  * indent-tabs-mode: t
02246  * End:
02247  * ex: shiftwidth=4 tabstop=8
02248  */

Generated on Mon Sep 18 01:24:48 2006 for BRL-CAD by  doxygen 1.4.6