db_scan.c

Go to the documentation of this file.
00001 /*                       D B _ S C A N . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1994-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 db4 */
00023 
00024 /*@{*/
00025 /** @file db_scan.c
00026  *
00027  * Functions -
00028  *      db_scan         Sequentially read database, send objects to handler()
00029  *      db_ident        Update database IDENT record
00030  *      db_conversions  Update unit conversion factors
00031  *
00032  *
00033  *  Author -
00034  *      Michael John Muuss
00035  *
00036  *  Source -
00037  *      The U. S. Army Research Laboratory
00038  *      Aberdeen Proving Ground, Maryland  21005-5068  USA
00039  */
00040 
00041 #ifndef lint
00042 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/db_scan.c,v 14.12 2006/09/16 02:04:24 lbutler Exp $ (ARL)";
00043 #endif
00044 
00045 #include "common.h"
00046 
00047 
00048 
00049 #include <stdio.h>
00050 #ifdef HAVE_STRING_H
00051 #include <string.h>
00052 #else
00053 #include <strings.h>
00054 #endif
00055 
00056 #include "machine.h"
00057 #include "vmath.h"
00058 #include "db.h"
00059 #include "raytrace.h"
00060 
00061 #include "./debug.h"
00062 
00063 #define DEBUG_PR(aaa, rrr)      {\
00064         if(RT_G_DEBUG&DEBUG_DB) bu_log("db_scan x%x %c (0%o)\n", \
00065                 aaa,rrr.u_id,rrr.u_id ); }
00066 
00067 /**
00068  *                      D B _ S C A N
00069  *
00070  *  This routine sequentially reads through the model database file and
00071  *  builds a directory of the object names, to allow rapid
00072  *  named access to objects.
00073  *
00074  *  Note that some multi-record database items include length fields.
00075  *  These length fields are not used here.
00076  *  Instead, the sizes of multi-record items are determined by
00077  *  reading ahead and computing the actual size.
00078  *  This prevents difficulties arising from external "adjustment" of
00079  *  the number of records without corresponding adjustment of the length fields.
00080  *  In the future, these length fields will be phased out.
00081  *
00082  *  The handler will be called with a variety of args.
00083  *  The handler is responsible for handling name strings of exactly
00084  *  NAMESIZE chars.
00085  *  The most common example of such a function is db_diradd().
00086  *
00087  *  Note that the handler may do I/O, including repositioning the
00088  *  file pointer, so this must be taken into account.
00089  *
00090  * Returns -
00091  *       0      Success
00092  *      -1      Fatal Error
00093  */
00094 int
00095 db_scan(register struct db_i *dbip, int (*handler) (struct db_i *, const char *, long int, int, int, genptr_t), int do_old_matter, genptr_t client_data)
00096 
00097 
00098 
00099                                         /* argument for handler */
00100 {
00101         union record    record;         /* Initial record, holds name */
00102         union record    rec2;           /* additional record(s) */
00103         register long   addr;           /* start of current rec */
00104         register long   here;           /* intermediate positions */
00105         register long   next;           /* start of next rec */
00106         register int    nrec;           /* # records for this solid */
00107         register int    totrec;         /* # records for database */
00108         register int    j;
00109 
00110         RT_CK_DBI(dbip);
00111         if(RT_G_DEBUG&DEBUG_DB) bu_log("db_scan( x%x, x%x )\n", dbip, handler);
00112 
00113         /* XXXX Note that this ignores dbip->dbi_inmem */
00114         /* In a portable way, read the header (even if not rewound) */
00115         rewind( dbip->dbi_fp );
00116         if( fread( (char *)&record, sizeof record, 1, dbip->dbi_fp ) != 1  ||
00117             record.u_id != ID_IDENT )  {
00118                 bu_log("db_scan ERROR:  File is lacking a proper MGED database header\n");
00119                 return(-1);
00120         }
00121         rewind( dbip->dbi_fp );
00122         next = ftell(dbip->dbi_fp);
00123 
00124         here = addr = -1L;
00125         totrec = 0;
00126         while(1)  {
00127                 nrec = 0;
00128                 if( fseek(dbip->dbi_fp, next, 0) != 0 )  {
00129                         bu_log("db_scan:  fseek(offset=%d) failure\n", next);
00130                         return(-1);
00131                 }
00132                 addr = next;
00133 
00134                 if( fread( (char *)&record, sizeof record, 1, dbip->dbi_fp ) != 1
00135                     || feof(dbip->dbi_fp) )
00136                         break;
00137                 next = ftell(dbip->dbi_fp);
00138                 DEBUG_PR( addr, record );
00139 
00140                 nrec++;
00141                 switch( record.u_id )  {
00142                 case ID_IDENT:
00143                         if( strcmp( record.i.i_version, ID_VERSION) != 0 )  {
00144                                 bu_log("db_scan WARNING: File is Version %s, Program is version %s\n",
00145                                         record.i.i_version, ID_VERSION );
00146                         }
00147                         /* Record first IDENT records title string */
00148                         if( dbip->dbi_title == (char *)0 )  {
00149                                 dbip->dbi_title = bu_strdup( record.i.i_title );
00150                                 db_conversions( dbip, record.i.i_units );
00151                         }
00152                         break;
00153                 case ID_FREE:
00154                         /* Inform db manager of avail. space */
00155                         rt_memfree( &(dbip->dbi_freep), (unsigned)1,
00156                                 addr/sizeof(union record) );
00157                         break;
00158                 case ID_ARS_A:
00159                         while(1) {
00160                                 here = ftell( dbip->dbi_fp );
00161                                 if( fread( (char *)&rec2, sizeof(rec2),
00162                                     1, dbip->dbi_fp ) != 1 )
00163                                         break;
00164                                 DEBUG_PR( here, rec2 );
00165                                 if( rec2.u_id != ID_ARS_B )  {
00166                                         fseek( dbip->dbi_fp, here, 0 );
00167                                         break;
00168                                 }
00169                                 nrec++;
00170                         }
00171                         next = ftell(dbip->dbi_fp);
00172                         handler( dbip, record.a.a_name, addr, nrec,
00173                                 DIR_SOLID, client_data );
00174                         break;
00175                 case ID_ARS_B:
00176                         bu_log("db_scan ERROR: Unattached ARS 'B' record\n");
00177                         break;
00178                 case ID_SOLID:
00179                         handler( dbip, record.s.s_name, addr, nrec,
00180                                 DIR_SOLID, client_data );
00181                         break;
00182                 case DBID_STRSOL:
00183                         for( ; nrec < DB_SS_NGRAN; nrec++ )  {
00184                                 if( fread( (char *)&rec2, sizeof(rec2),
00185                                     1, dbip->dbi_fp ) != 1 )
00186                                         break;
00187                         }
00188                         next = ftell(dbip->dbi_fp);
00189                         handler( dbip, record.ss.ss_name, addr, nrec,
00190                                 DIR_SOLID, client_data );
00191                         break;
00192                 case ID_MATERIAL:
00193                         if( do_old_matter ) {
00194                                 /* This is common to RT and MGED */
00195                                 rt_color_addrec(
00196                                         record.md.md_low,
00197                                         record.md.md_hi,
00198                                         record.md.md_r,
00199                                         record.md.md_g,
00200                                         record.md.md_b,
00201                                         addr );
00202                         }
00203                         break;
00204                 case ID_P_HEAD:
00205                         while(1) {
00206                                 here = ftell( dbip->dbi_fp );
00207                                 if( fread( (char *)&rec2, sizeof(rec2),
00208                                     1, dbip->dbi_fp ) != 1 )
00209                                         break;
00210                                 DEBUG_PR( here, rec2 );
00211                                 if( rec2.u_id != ID_P_DATA )  {
00212                                         fseek( dbip->dbi_fp, here, 0 );
00213                                         break;
00214                                 }
00215                                 nrec++;
00216                         }
00217                         next = ftell(dbip->dbi_fp);
00218                         handler( dbip, record.p.p_name, addr, nrec,
00219                                 DIR_SOLID, client_data );
00220                         break;
00221                 case ID_P_DATA:
00222                         bu_log("db_scan ERROR: Unattached P_DATA record\n");
00223                         break;
00224                 case ID_BSOLID:
00225                         while(1) {
00226                                 /* Find and skip subsequent BSURFs */
00227                                 here = ftell( dbip->dbi_fp );
00228                                 if( fread( (char *)&rec2, sizeof(rec2),
00229                                     1, dbip->dbi_fp ) != 1 )
00230                                         break;
00231                                 DEBUG_PR( here, rec2 );
00232                                 if( rec2.u_id != ID_BSURF )  {
00233                                         fseek( dbip->dbi_fp, here, 0 );
00234                                         break;
00235                                 }
00236 
00237                                 /* Just skip over knots and control mesh */
00238                                 j = (rec2.d.d_nknots + rec2.d.d_nctls);
00239                                 nrec += j+1;
00240                                 while( j-- > 0 )
00241                                         fread( (char *)&rec2, sizeof(rec2), 1, dbip->dbi_fp );
00242                                 next = ftell(dbip->dbi_fp);
00243                         }
00244                         handler( dbip, record.B.B_name, addr, nrec,
00245                                 DIR_SOLID, client_data );
00246                         break;
00247                 case ID_BSURF:
00248                         bu_log("db_scan ERROR: Unattached B-spline surface record\n");
00249 
00250                         /* Just skip over knots and control mesh */
00251                         j = (record.d.d_nknots + record.d.d_nctls);
00252                         nrec += j;
00253                         while( j-- > 0 )
00254                                 fread( (char *)&rec2, sizeof(rec2), 1, dbip->dbi_fp );
00255                         break;
00256                 case DBID_ARBN:
00257                         j = bu_glong(record.n.n_grans);
00258                         nrec += j;
00259                         while( j-- > 0 )
00260                                 fread( (char *)&rec2, sizeof(rec2), 1, dbip->dbi_fp );
00261                         next = ftell(dbip->dbi_fp);
00262                         handler( dbip, record.n.n_name, addr, nrec,
00263                                 DIR_SOLID, client_data );
00264                         break;
00265                 case DBID_PARTICLE:
00266                         handler( dbip, record.part.p_name, addr, nrec,
00267                                 DIR_SOLID, client_data );
00268                         break;
00269                 case DBID_PIPE:
00270                         j = bu_glong(record.pwr.pwr_count);
00271                         nrec += j;
00272                         while( j-- > 0 )
00273                                 fread( (char *)&rec2, sizeof(rec2), 1, dbip->dbi_fp );
00274                         next = ftell(dbip->dbi_fp);
00275                         handler( dbip, record.pwr.pwr_name, addr, nrec,
00276                                 DIR_SOLID, client_data );
00277                         break;
00278                 case DBID_NMG:
00279                         j = bu_glong(record.nmg.N_count);
00280                         nrec += j;
00281                         while( j-- > 0 )
00282                                 (void)fread( (char *)&rec2, sizeof(rec2), 1, dbip->dbi_fp );
00283                         next = ftell(dbip->dbi_fp);
00284                         handler( dbip, record.nmg.N_name, addr, nrec,
00285                                 DIR_SOLID, client_data );
00286                         break;
00287                 case DBID_SKETCH:
00288                         j = bu_glong(record.skt.skt_count);
00289                         nrec += j;
00290                         while( j-- > 0 )
00291                                 (void)fread( (char *)&rec2, sizeof(rec2), 1, dbip->dbi_fp );
00292                         next = ftell(dbip->dbi_fp);
00293                         handler( dbip, record.skt.skt_name, addr, nrec,
00294                                 DIR_SOLID, client_data );
00295                         break;
00296                 case DBID_EXTR:
00297                         j = bu_glong(record.extr.ex_count);
00298                         nrec += j;
00299                         while( j-- > 0 )
00300                                 (void)fread( (char *)&rec2, sizeof(rec2), 1, dbip->dbi_fp );
00301                         next = ftell(dbip->dbi_fp);
00302                         handler( dbip, record.extr.ex_name, addr, nrec,
00303                                 DIR_SOLID, client_data );
00304                         break;
00305                 case DBID_CLINE:
00306                         handler( dbip, record.s.s_name, addr, nrec,
00307                                 DIR_SOLID, client_data );
00308                         break;
00309                 case DBID_BOT:
00310                         j = bu_glong( record.bot.bot_nrec );
00311                         nrec += j;
00312                         while( j-- > 0 )
00313                                 (void)fread( (char *)&rec2, sizeof(rec2), 1, dbip->dbi_fp );
00314                         next = ftell(dbip->dbi_fp);
00315                         handler( dbip, record.s.s_name, addr, nrec,
00316                                 DIR_SOLID, client_data );
00317                         break;
00318                 case ID_MEMB:
00319                         bu_log("db_scan ERROR: Unattached combination MEMBER record\n");
00320                         break;
00321                 case ID_COMB:
00322                         while(1) {
00323                                 here = ftell( dbip->dbi_fp );
00324                                 if( fread( (char *)&rec2, sizeof(rec2),
00325                                     1, dbip->dbi_fp ) != 1 )
00326                                         break;
00327                                 DEBUG_PR( here, rec2 );
00328                                 if( rec2.u_id != ID_MEMB )  {
00329                                         fseek( dbip->dbi_fp, here, 0 );
00330                                         break;
00331                                 }
00332                                 nrec++;
00333                         }
00334                         next = ftell(dbip->dbi_fp);
00335                         switch(record.c.c_flags)  {
00336                         default:
00337                         case DBV4_NON_REGION:
00338                                 j = DIR_COMB;
00339                                 break;
00340                         case DBV4_REGION:
00341                         case DBV4_REGION_FASTGEN_PLATE:
00342                         case DBV4_REGION_FASTGEN_VOLUME:
00343                                 j = DIR_COMB|DIR_REGION;
00344                                 break;
00345                         }
00346                         handler( dbip, record.c.c_name, addr, nrec, j,
00347                                 client_data );
00348                         break;
00349                 default:
00350                         bu_log("db_scan ERROR:  bad record %c (0%o), addr=x%x\n",
00351                                 record.u_id, record.u_id, addr );
00352                         /* skip this record */
00353                         break;
00354                 }
00355                 totrec += nrec;
00356         }
00357         dbip->dbi_nrec = totrec;
00358         dbip->dbi_eof = ftell( dbip->dbi_fp );
00359         rewind( dbip->dbi_fp );
00360 
00361         return( 0 );                    /* OK */
00362 }
00363 
00364 /**
00365  *                      D B _ U P D A T E _ I D E N T
00366  *
00367  *  Update the existing v4 IDENT record with new title and units.
00368  *  To permit using db_get and db_put, a custom directory entry is crafted.
00369  *
00370  *  Note:  Special care is required, because the "title" arg may actually
00371  *  be passed in as dbip->dbi_title.
00372  */
00373 int
00374 db_update_ident( struct db_i *dbip, const char *new_title, double local2mm )
00375 {
00376         struct directory        dir;
00377         union record            rec;
00378         char                    *old_title;
00379         int                     v4units;
00380 
00381         RT_CK_DBI(dbip);
00382         if(RT_G_DEBUG&DEBUG_DB) bu_log("db_update_ident( x%x, '%s', %g )\n",
00383                 dbip, new_title, local2mm );
00384 
00385         BU_ASSERT_LONG( dbip->dbi_version, >, 0 );
00386 
00387         if( dbip->dbi_read_only )
00388                 return(-1);
00389 
00390         if( dbip->dbi_version > 4 )  return db5_update_ident( dbip, new_title, local2mm );
00391 
00392         RT_DIR_SET_NAMEP(&dir, "/IDENT/");
00393         dir.d_addr = 0L;
00394         dir.d_len = 1;
00395         dir.d_magic = RT_DIR_MAGIC;
00396         dir.d_flags = 0;
00397         if( db_get( dbip, &dir, &rec, 0, 1 ) < 0 ||
00398             rec.u_id != ID_IDENT )  {
00399                 bu_log("db_update_ident() corrupted database header!\n");
00400                 dbip->dbi_read_only = 1;
00401                 return(-1);
00402         }
00403 
00404         rec.i.i_title[0] = '\0';
00405         (void)strncpy(rec.i.i_title, new_title, sizeof(rec.i.i_title)-1 );
00406 
00407         old_title = dbip->dbi_title;
00408         dbip->dbi_title = bu_strdup( new_title );
00409 
00410         if( (v4units = db_v4_get_units_code(bu_units_string(local2mm))) < 0 )  {
00411                 bu_log("db_update_ident(): \
00412 Due to a restriction in previous versions of the BRL-CAD database format, your\n\
00413 editing units %g will not be remembered on your next editing session.\n\
00414 This will not harm the integrity of your database.\n\
00415 You may wish to consider upgrading your database using \"dbupgrade\".\n",
00416                         local2mm);
00417                 v4units = ID_MM_UNIT;
00418         }
00419         rec.i.i_units = v4units;
00420 
00421         if( old_title )
00422                 bu_free( old_title, "old dbi_title" );
00423 
00424         return( db_put( dbip, &dir, &rec, 0, 1 ) );
00425 
00426 }
00427 
00428 /**
00429  *                      D B _ F W R I T E _ I D E N T
00430  *
00431  *  Fwrite an IDENT record with given title and editing scale.
00432  *  Attempts to map the editing scale into a v4 database unit
00433  *  as best it can.  No harm done if it doesn't map.
00434  *
00435  *  This should be called by db_create() only.
00436  *  All others should call db_update_ident().
00437  *
00438  * Returns -
00439  *       0      Success
00440  *      -1      Fatal Error
00441  */
00442 int
00443 db_fwrite_ident( FILE *fp, const char *title, double local2mm )
00444 {
00445         union record            rec;
00446         int                     code;
00447 
00448         code = db_v4_get_units_code(bu_units_string(local2mm));
00449 
00450         if(RT_G_DEBUG&DEBUG_DB) bu_log("db_fwrite_ident( x%x, '%s', %g ) code=%d\n",
00451                 fp, title, local2mm, code );
00452 
00453         bzero( (char *)&rec, sizeof(rec) );
00454         rec.i.i_id = ID_IDENT;
00455         rec.i.i_units = code;
00456         (void)strncpy( rec.i.i_version, ID_VERSION, sizeof(rec.i.i_version) );
00457         (void)strncpy(rec.i.i_title, title, sizeof(rec.i.i_title)-1 );
00458 
00459         if( fwrite( (char *)&rec, sizeof(rec), 1, fp ) != 1 )
00460                 return -1;
00461         return 0;
00462 }
00463 
00464 /**
00465  *                      D B _ C O N V E R S I O N S
00466  *
00467  *      Initialize conversion factors given the v4 database unit
00468  */
00469 void
00470 db_conversions(struct db_i *dbip, int local)
00471 
00472                                                 /* one of ID_??_UNIT */
00473 {
00474         RT_CK_DBI(dbip);
00475 
00476         /* Base unit is MM */
00477         switch( local ) {
00478 
00479         case ID_NO_UNIT:
00480                 /* no local unit specified ... use the base unit */
00481                 dbip->dbi_local2base = 1.0;
00482                 break;
00483 
00484         case ID_UM_UNIT:
00485                 /* local unit is um */
00486                 dbip->dbi_local2base = 0.001;           /* UM to MM */
00487                 break;
00488 
00489         case ID_MM_UNIT:
00490                 /* local unit is mm */
00491                 dbip->dbi_local2base = 1.0;
00492                 break;
00493 
00494         case ID_CM_UNIT:
00495                 /* local unit is cm */
00496                 dbip->dbi_local2base = 10.0;            /* CM to MM */
00497                 break;
00498 
00499         case ID_M_UNIT:
00500                 /* local unit is meters */
00501                 dbip->dbi_local2base = 1000.0;          /* M to MM */
00502                 break;
00503 
00504         case ID_KM_UNIT:
00505                 /* local unit is km */
00506                 dbip->dbi_local2base = 1000000.0;       /* KM to MM */
00507                 break;
00508 
00509         case ID_IN_UNIT:
00510                 /* local unit is inches */
00511                 dbip->dbi_local2base = 25.4;            /* IN to MM */
00512                 break;
00513 
00514         case ID_FT_UNIT:
00515                 /* local unit is feet */
00516                 dbip->dbi_local2base = 304.8;           /* FT to MM */
00517                 break;
00518 
00519         case ID_YD_UNIT:
00520                 /* local unit is yards */
00521                 dbip->dbi_local2base = 914.4;           /* YD to MM */
00522                 break;
00523 
00524         case ID_MI_UNIT:
00525                 /* local unit is miles */
00526                 dbip->dbi_local2base = 1609344;         /* MI to MM */
00527                 break;
00528 
00529         default:
00530                 dbip->dbi_local2base = 1.0;
00531                 break;
00532         }
00533         dbip->dbi_base2local = 1.0 / dbip->dbi_local2base;
00534 }
00535 
00536 /**
00537  *                      D B _ V 4 _ G E T _ U N I T S _ C O D E
00538  *
00539  *  Given a string, return the V4 database code representing
00540  *  the user's preferred editing units.
00541  *  The v4 database format does not have many choices.
00542  *
00543  *  Returns -
00544  *      -1      Not a legal V4 database code
00545  *      #       The V4 database code number
00546  */
00547 int
00548 db_v4_get_units_code( const char *str )
00549 {
00550         if( !str )  return ID_NO_UNIT;  /* no units specified */
00551 
00552         if( strcmp(str, "mm") == 0 || strcmp(str, "millimeters") == 0 )
00553                 return ID_MM_UNIT;
00554         if( strcmp(str, "um") == 0 || strcmp(str, "micrometers") == 0)
00555                 return ID_UM_UNIT;
00556         if( strcmp(str, "cm") == 0 || strcmp(str, "centimeters") == 0)
00557                 return ID_CM_UNIT;
00558         if( strcmp(str,"m")==0 || strcmp(str,"meters")==0 )
00559                 return ID_M_UNIT;
00560         if( strcmp(str, "km") == 0 || strcmp(str, "kilometers") == 0)
00561                 return ID_KM_UNIT;
00562         if( strcmp(str,"in")==0 || strcmp(str,"inches")==0 || strcmp(str,"inch")==0 )
00563                 return ID_IN_UNIT;
00564         if( strcmp(str,"ft")==0 || strcmp(str,"feet")==0 || strcmp(str,"foot")==0 )
00565                 return ID_FT_UNIT;
00566         if( strcmp(str,"yd")==0 || strcmp(str,"yards")==0 || strcmp(str,"yard")==0 )
00567                 return ID_YD_UNIT;
00568         if( strcmp(str,"mi")==0 || strcmp(str,"miles")==0 || strcmp(str,"mile")==0 )
00569                 return ID_MI_UNIT;
00570 
00571         return -1;              /* error */
00572 }
00573 
00574 /*@}*/
00575 /*
00576  * Local Variables:
00577  * mode: C
00578  * tab-width: 8
00579  * c-basic-offset: 4
00580  * indent-tabs-mode: t
00581  * End:
00582  * ex: shiftwidth=4 tabstop=8
00583  */

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