(root)/
libredwg-0.13/
programs/
dwggrep.c
       1  /*****************************************************************************/
       2  /*  LibreDWG - free implementation of the DWG file format                    */
       3  /*                                                                           */
       4  /*  Copyright (C) 2018-2020 Free Software Foundation, Inc.                   */
       5  /*                                                                           */
       6  /*  This library is free software, licensed under the terms of the GNU       */
       7  /*  General Public License as published by the Free Software Foundation,     */
       8  /*  either version 3 of the License, or (at your option) any later version.  */
       9  /*  You should have received a copy of the GNU General Public License        */
      10  /*  along with this program.  If not, see <http://www.gnu.org/licenses/>.    */
      11  /*****************************************************************************/
      12  
      13  /*
      14   * dwggrep.c: search a string in all text values in a DWG
      15   * TODO scan the dwg.spec for all text DXF codes, per object.
      16   *
      17   * written by Reini Urban
      18   */
      19  
      20  #define _GNU_SOURCE
      21  #include "../src/config.h"
      22  #include <stdio.h>
      23  #include <stdlib.h>
      24  #ifdef HAVE_STRCASESTR
      25  #  undef __DARWIN_C_LEVEL
      26  #  define __DARWIN_C_LEVEL __DARWIN_C_FULL
      27  #  ifndef __USE_GNU
      28  #    define __USE_GNU
      29  #  endif
      30  #  ifndef __BSD_VISIBLE
      31  #    define __BSD_VISIBLE 1
      32  #  endif
      33  #  include <string.h>
      34  #else
      35  #  include <string.h>
      36  #  include <ctype.h>
      37  #endif
      38  #include "my_getopt.h"
      39  #ifdef HAVE_PCRE2_H
      40  // use both, 8 and 16 (r2007+)
      41  #  define PCRE2_CODE_UNIT_WIDTH 0
      42  #  include <pcre2.h>
      43  #endif
      44  
      45  static const int verbose = 0;
      46  
      47  #include "dwg.h"
      48  #include "logging.h"
      49  #include "dwg_api.h"
      50  #include "common.h"
      51  #include "bits.h"
      52  
      53  #ifndef HAVE_PCRE2_H
      54  #  define PCRE2_MULTILINE 1
      55  #  define PCRE2_CASELESS 2
      56  #  define PCRE2_EXTENDED 3
      57  #  define PCRE2_NO_AUTO_CAPTURE 4
      58  #  define PCRE2_NO_DOTSTAR_ANCHOR 5
      59  #else
      60  #  define PCRE2_JIT_MATCH_OPTIONS                                             \
      61      (PCRE2_NO_UTF_CHECK | PCRE2_NOTBOL | PCRE2_NOTEOL | PCRE2_NOTEMPTY        \
      62       | PCRE2_NOTEMPTY_ATSTART)
      63  #  define PCRE2_JIT_COMPILE_OPTIONS (PCRE2_JIT_COMPLETE)
      64  #endif
      65  
      66  char *pattern;
      67  char buf[4096];
      68  // partial to find substrings, not only complete matches
      69  int options
      70      = PCRE2_MULTILINE | PCRE2_NO_AUTO_CAPTURE | PCRE2_NO_DOTSTAR_ANCHOR;
      71  int opt_count = 0;
      72  int opt_text = 0;
      73  int opt_blocks = 0;
      74  int opt_tables = 0;
      75  int opt_filename = 1;
      76  short numdxf = 0;
      77  short numtype = 0;
      78  static short dxf[10];  // ensure zero-fill
      79  static char *type[10]; // ensure zero-fill
      80  
      81  /* the current version per spec block */
      82  static unsigned int cur_ver = 0;
      83  
      84  #ifdef HAVE_PCRE2_H
      85  #  undef USE_MATCH_CONTEXT
      86  /* pcre2_compile */
      87  static pcre2_code_8 *ri8;
      88  static pcre2_match_data_8 *match_data8;
      89  static pcre2_match_context_8 *match_context8 = NULL;
      90  #  ifdef HAVE_PCRE2_16
      91  static pcre2_code_16 *ri16;
      92  static pcre2_match_data_16 *match_data16;
      93  static pcre2_match_context_16 *match_context16 = NULL;
      94  #  endif
      95  
      96  #  ifdef USE_MATCH_CONTEXT
      97  static pcre2_jit_stack_8 *jit_stack8 = NULL;
      98  static pcre2_compile_context_8 *compile_context8 = NULL;
      99  #    ifdef HAVE_PCRE2_16
     100  static pcre2_jit_stack_16 *jit_stack16 = NULL;
     101  static pcre2_compile_context_16 *compile_context16 = NULL;
     102  #    endif
     103  #  endif
     104  #endif
     105  
     106  static int
     107  usage (void)
     108  {
     109    printf ("\nUsage: dwggrep [-cRr] pattern *.dwg\n");
     110    return 1;
     111  }
     112  static int
     113  opt_version (void)
     114  {
     115    printf ("dwggrep %s\n", PACKAGE_VERSION);
     116    return 0;
     117  }
     118  static int
     119  help (void)
     120  {
     121    printf ("\nUsage: dwggrep [OPTIONS]... pattern files\n");
     122  #ifdef HAVE_PCRE2_H
     123    printf ("Search regex pattern in a list of DWGs.\n\n");
     124  #else
     125    printf ("Search string (no regex) in a list of DWGs.\n\n");
     126  #endif
     127    printf ("  -i                        Case-insensitive pattern\n");
     128  #ifdef HAVE_PCRE2_H
     129    printf ("  -x                        Extended regex pattern\n");
     130  #endif
     131    printf ("  -c, --count               Print only the count of matched "
     132            "elements.\n");
     133    printf ("  -h, --no-filename         Print no filename.\n");
     134  #if 0
     135    printf("  -R, -r, --recursive       Recursively search subdirectories listed.\n");
     136  #endif
     137    printf (
     138        "  -y, --type NAME           Search only NAME entities or objects.\n");
     139    printf ("  -d, --dxf NUM             Search only DXF group NUM fields.\n");
     140    printf ("  -t, --text                Search only in TEXT-like entities.\n");
     141    printf (
     142        "  -b, --blocks              Search also in all block definitions.\n");
     143    printf ("       --tables              Search only in table names.\n");
     144  #ifdef HAVE_GETOPT_LONG
     145    printf ("      --help                Display this help and exit\n");
     146    printf ("      --version             Output version information and exit\n"
     147            "\n");
     148  #else
     149    printf ("  -u                        Display this help and exit\n");
     150    printf ("  -v                        Output version information and exit\n"
     151            "\n");
     152  #endif
     153    printf ("GNU LibreDWG online manual: "
     154            "<https://www.gnu.org/software/libredwg/>\n");
     155    return 0;
     156  }
     157  
     158  static void
     159  print_match (const int is16, const char *restrict filename,
     160               const char *restrict entity, const int dxfgroup,
     161               char *restrict text)
     162  {
     163    if (is16)
     164      text = bit_convert_TU ((BITCODE_TU)text);
     165    printf ("%s %s %d: %s\n", opt_filename ? filename : "", entity, dxfgroup,
     166            text);
     167    if (is16)
     168      free (text);
     169  }
     170  
     171  static int
     172  do_match (const int is16, const char *restrict filename,
     173            const char *restrict entity, const int dxfgroup, char *restrict text)
     174  {
     175  #ifdef HAVE_PCRE2_H
     176    int rc;
     177  #  ifdef HAVE_PCRE2_16
     178    if (is16)
     179      rc = pcre2_match_16 (ri16, (PCRE2_SPTR16)text, PCRE2_ZERO_TERMINATED, 0,
     180                           PCRE2_JIT_MATCH_OPTIONS,
     181                           match_data16,     /* block for storing the result */
     182                           match_context16); /* disabled */
     183    else
     184  #  endif
     185      // already converted to UTF-8 before
     186      rc = pcre2_match_8 (ri8, (PCRE2_SPTR8)text, PCRE2_ZERO_TERMINATED, 0,
     187                          PCRE2_JIT_MATCH_OPTIONS,
     188                          match_data8,     /* block for storing the result */
     189                          match_context8); /* disabled */
     190    if (rc >= 0)
     191      {
     192        if (!opt_count)
     193          print_match (is16, filename, entity, dxfgroup, text);
     194        return 1;
     195      }
     196    else if (rc < -2)
     197      { // not PCRE2_ERROR_NOMATCH nor PCRE2_ERROR_PARTIAL
     198        pcre2_get_error_message_8 (rc, (PCRE2_UCHAR8 *)buf, 4096);
     199        LOG_WARN ("pcre2 match error %s with %s", buf, pattern);
     200      }
     201    return 0;
     202  
     203  #else
     204  
     205    if (options & PCRE2_CASELESS)
     206      {
     207  #  ifndef HAVE_STRCASESTR
     208        size_t i, len;
     209        size_t dmax;
     210        char *dest = text;
     211        size_t dlen = dmax = strlen (text);
     212        char *src = pattern;
     213        size_t slen = strlen (pattern);
     214  
     215        while (*dest && dmax)
     216          {
     217            i = 0;
     218            len = slen;
     219            dlen = dmax;
     220            while (dest[i] && dlen)
     221              {
     222                if (toupper ((unsigned char)dest[i])
     223                    != toupper ((unsigned char)src[i]))
     224                  {
     225                    break;
     226                  }
     227                /* move to the next char */
     228                i++;
     229                len--;
     230                dlen--;
     231  
     232                if (src[i] == '\0' || !len)
     233                  {
     234                    if (!opt_count)
     235                      print_match (0, filename, entity, dxfgroup, text);
     236                    return 1;
     237                  }
     238              }
     239            dest++;
     240            dmax--;
     241          }
     242  #  else
     243        if (strcasestr (text, pattern))
     244          {
     245            if (!opt_count)
     246              print_match (0, filename, entity, dxfgroup, text);
     247            return 1;
     248          }
     249  #  endif
     250      }
     251    else
     252      {
     253        if (strstr (text, pattern))
     254          {
     255            if (!opt_count)
     256              print_match (0, filename, entity, dxfgroup, text);
     257            return 1;
     258          }
     259      }
     260    return 0;
     261  #endif
     262  }
     263  
     264  // check matching dxfgroup first to avoid costly utf8 conversions
     265  #define MATCH_DXF(type, ENTITY, text_field, dxfgroup)                         \
     266    if (numdxf)                                                                 \
     267      {                                                                         \
     268        int dxfok = 0;                                                          \
     269        for (int _i = 0; _i < numdxf; _i++)                                     \
     270          {                                                                     \
     271            if (dxf[_i] == dxfgroup)                                            \
     272              {                                                                 \
     273                dxfok = 1;                                                      \
     274                break;                                                          \
     275              }                                                                 \
     276          }                                                                     \
     277        if (dxfok)                                                              \
     278          {                                                                     \
     279            MATCH_TYPE (type, ENTITY, text_field, dxfgroup);                    \
     280          }                                                                     \
     281      }                                                                         \
     282    else                                                                        \
     283      {                                                                         \
     284        MATCH_TYPE (type, ENTITY, text_field, dxfgroup);                        \
     285      }
     286  
     287  // 8bit only
     288  #define MATCH_NO16(type, ENTITY, text_field, dxfgroup)                        \
     289    text = (char *)obj->tio.type->tio.ENTITY->text_field;                       \
     290    if (text && numdxf)                                                         \
     291      {                                                                         \
     292        int dxfok = 0;                                                          \
     293        for (int i = 0; i < numdxf; i++)                                        \
     294          {                                                                     \
     295            if (dxf[i] == dxfgroup)                                             \
     296              {                                                                 \
     297                dxfok = 1;                                                      \
     298                break;                                                          \
     299              }                                                                 \
     300          }                                                                     \
     301        if (dxfok)                                                              \
     302          {                                                                     \
     303            found += do_match (0, filename, #ENTITY, dxfgroup, text);           \
     304          }                                                                     \
     305      }                                                                         \
     306    else if (text)                                                              \
     307      {                                                                         \
     308        found += do_match (0, filename, #ENTITY, dxfgroup, text);               \
     309      }
     310  
     311  #ifdef HAVE_PCRE2_16
     312  #  define MATCH_TYPE(type, ENTITY, text_field, dxfgroup)                      \
     313      text = (char *)obj->tio.type->tio.ENTITY->text_field;                     \
     314      if (text)                                                                 \
     315      found += do_match (obj->parent->header.version >= R_2007, filename,       \
     316                         #ENTITY, dxfgroup, text)
     317  #else
     318  #  define MATCH_TYPE(type, ENTITY, text_field, dxfgroup)                      \
     319      text = (char *)obj->tio.type->tio.ENTITY->text_field;                     \
     320      if (text)                                                                 \
     321        {                                                                       \
     322          if (obj->parent->header.version >= R_2007)                            \
     323            text = bit_convert_TU ((BITCODE_TU)text);                           \
     324          found += do_match (obj->parent->header.version >= R_2007, filename,   \
     325                             #ENTITY, dxfgroup, text);                          \
     326          if (obj->parent->header.version >= R_2007)                            \
     327            free (text);                                                        \
     328        }
     329  #endif
     330  
     331  #define MATCH_ENTITY(ENTITY, text_field, dxf)                                 \
     332    MATCH_DXF (entity, ENTITY, text_field, dxf)
     333  #define MATCH_OBJECT(ENTITY, text_field, dxf)                                 \
     334    MATCH_DXF (object, ENTITY, text_field, dxf)
     335  #define MATCH_TABLE(ENTITY, handle, TABLE, dxf)                               \
     336    {                                                                           \
     337    }
     338  
     339  static int
     340  match_TEXT (const char *restrict filename, const Dwg_Object *restrict obj)
     341  {
     342    char *text;
     343    int found = 0;
     344    MATCH_ENTITY (TEXT, text_value, 1);
     345    if (!opt_text)
     346      {
     347        MATCH_TABLE (TEXT, style, STYLE, 7);
     348      }
     349    return found;
     350  }
     351  
     352  static int
     353  match_ARCALIGNEDTEXT (const char *restrict filename,
     354                        const Dwg_Object *restrict obj)
     355  {
     356    char *text;
     357    int found = 0;
     358    MATCH_ENTITY (ARCALIGNEDTEXT, text_value, 1);
     359    if (!opt_text)
     360      {
     361        // ignore the various sizes stored as text
     362        MATCH_ENTITY (ARCALIGNEDTEXT, style, 7);
     363      }
     364    return found;
     365  }
     366  
     367  static int
     368  match_ATTRIB (const char *restrict filename, const Dwg_Object *restrict obj)
     369  {
     370    char *text;
     371    int found = 0;
     372    // printf("--ATTRIB %lX %s\n", obj->handle.value, filename);
     373    MATCH_ENTITY (ATTRIB, text_value, 1);
     374    MATCH_ENTITY (ATTRIB, tag, 2);
     375    if (!opt_text)
     376      {
     377        MATCH_TABLE (ATTRIB, style, STYLE, 7);
     378      }
     379    return found;
     380  }
     381  
     382  static int
     383  match_ATTDEF (const char *restrict filename, const Dwg_Object *restrict obj)
     384  {
     385    char *text;
     386    int found = 0;
     387    MATCH_ENTITY (ATTDEF, default_value, 1);
     388    MATCH_ENTITY (ATTDEF, tag, 2);
     389    MATCH_ENTITY (ATTDEF, prompt, 3);
     390    return found;
     391  }
     392  
     393  static int
     394  match_MTEXT (const char *restrict filename, const Dwg_Object *restrict obj)
     395  {
     396    char *text;
     397    int found = 0;
     398    MATCH_ENTITY (MTEXT, text, 1);
     399    return found;
     400  }
     401  
     402  static int
     403  match_BLOCK (const char *restrict filename, const Dwg_Object *restrict obj)
     404  {
     405    char *text;
     406    int found = 0;
     407    MATCH_ENTITY (BLOCK, name, 2);
     408    return found;
     409  }
     410  
     411  static int
     412  match_DIMENSION (const char *restrict filename, const Dwg_Object *restrict obj)
     413  {
     414    char *text;
     415    int found = 0;
     416    // int is16 = obj->parent->header.version >= R_2007;
     417  
     418    text = obj->tio.entity->tio.DIMENSION_ORDINATE->user_text;
     419    if (text)
     420      found += do_match (0, filename, "DIMENSION", 1, text);
     421    return found;
     422  }
     423  
     424  static int
     425  match_VIEWPORT (const char *restrict filename, const Dwg_Object *restrict obj)
     426  {
     427    char *text;
     428    int found = 0;
     429    MATCH_ENTITY (VIEWPORT, style_sheet, 1);
     430    return found;
     431  }
     432  static int
     433  match_LEADER (const char *restrict filename, const Dwg_Object *restrict obj)
     434  {
     435    char *text;
     436    int found = 0;
     437    // MATCH_ENTITY (LEADER, text, 1);
     438    return found;
     439  }
     440  static int
     441  match_MULTILEADER (const char *restrict filename,
     442                     const Dwg_Object *restrict obj)
     443  {
     444    char *text;
     445    int found = 0;
     446    const Dwg_Entity_MULTILEADER *_obj = obj->tio.entity->tio.MULTILEADER;
     447    if (_obj->ctx.has_content_txt)
     448      {
     449        MATCH_ENTITY (MULTILEADER, ctx.content.txt.default_text, 304);
     450      }
     451    // SUB_FIELD_T (blocklabels[rcount1],label_text, 302);
     452    return found;
     453  }
     454  
     455  static int
     456  match_3DSOLID (const char *restrict filename, const Dwg_Object *restrict obj)
     457  {
     458    char *text = NULL;
     459    int found = 0;
     460    BITCODE_BL j;
     461    Dwg_Entity_3DSOLID *_obj;
     462  
     463    if (!obj || !obj->tio.entity)
     464      return 0;
     465    _obj = obj->tio.entity->tio._3DSOLID;
     466    if (!_obj)
     467      return 0;
     468    if (_obj->acis_data)
     469      {
     470        MATCH_NO16 (entity, _3DSOLID, acis_data, 1);
     471        // MATCH_ENTITY (_3DSOLID, acis_data, 1);
     472        // found += do_match(0, filename, "3DSOLID", 1, (char*)_obj->acis_data);
     473      }
     474    /*
     475    if (!_obj->encr_sat_data) return 0;
     476    for (j=0; j<_obj->num_blocks; j++)
     477      {
     478        //text = _obj->encr_sat_data[j];
     479        //if (text)
     480        //  found += do_match(0, filename, "3DSOLID", 301, text);
     481        MATCH_NO16 (entity, _3DSOLID, encr_sat_data[j], 301);
     482      }
     483    */
     484    return found;
     485  }
     486  
     487  static int
     488  match_DICTIONARY (const char *restrict filename,
     489                    const Dwg_Object *restrict obj)
     490  {
     491    char *text;
     492    int found = 0;
     493    BITCODE_BL i;
     494    Dwg_Object_DICTIONARY *_obj = obj->tio.object->tio.DICTIONARY;
     495  
     496    for (i = 0; i < _obj->numitems; i++)
     497      {
     498        MATCH_OBJECT (DICTIONARY, texts[i], 3);
     499      }
     500    return found;
     501  }
     502  
     503  static int
     504  match_STYLE (const char *restrict filename, const Dwg_Object *restrict obj)
     505  {
     506    char *text;
     507    int found = 0;
     508    MATCH_OBJECT (STYLE, name, 2);
     509    if (!opt_tables)
     510      {
     511        MATCH_OBJECT (STYLE, font_file, 3);
     512        MATCH_OBJECT (STYLE, bigfont_file, 4);
     513      }
     514    return found;
     515  }
     516  
     517  static int
     518  match_LTYPE (const char *restrict filename, const Dwg_Object *restrict obj)
     519  {
     520    char *text;
     521    int found = 0;
     522    MATCH_OBJECT (LTYPE, name, 2);
     523    MATCH_OBJECT (LTYPE, description, 3);
     524    if (!opt_tables)
     525      {
     526        MATCH_OBJECT (LTYPE, strings_area, 3);
     527      }
     528    return found;
     529  }
     530  static int
     531  match_LAYER (const char *restrict filename, const Dwg_Object *restrict obj)
     532  {
     533    char *text;
     534    int found = 0;
     535    MATCH_OBJECT (LAYER, name, 2);
     536    return found;
     537  }
     538  static int
     539  match_VIEW (const char *restrict filename, const Dwg_Object *restrict obj)
     540  {
     541    char *text;
     542    int found = 0;
     543    MATCH_OBJECT (VIEW, name, 2);
     544    return found;
     545  }
     546  static int
     547  match_VPORT (const char *restrict filename, const Dwg_Object *restrict obj)
     548  {
     549    char *text;
     550    int found = 0;
     551    MATCH_OBJECT (VPORT, name, 2);
     552    return found;
     553  }
     554  static int
     555  match_UCS (const char *restrict filename, const Dwg_Object *restrict obj)
     556  {
     557    char *text;
     558    int found = 0;
     559    MATCH_OBJECT (UCS, name, 2);
     560    return found;
     561  }
     562  static int
     563  match_VX_TABLE_RECORD (const char *restrict filename,
     564                         const Dwg_Object *restrict obj)
     565  {
     566    char *text;
     567    int found = 0;
     568    MATCH_OBJECT (VX_TABLE_RECORD, name, 2);
     569    return found;
     570  }
     571  
     572  static int
     573  match_DIMSTYLE (const char *restrict filename, const Dwg_Object *restrict obj)
     574  {
     575    char *text;
     576    int found = 0;
     577    MATCH_OBJECT (DIMSTYLE, name, 2);
     578    if (!opt_tables)
     579      {
     580        MATCH_OBJECT (DIMSTYLE, DIMPOST, 3);
     581        MATCH_OBJECT (DIMSTYLE, DIMAPOST, 4);
     582        MATCH_OBJECT (DIMSTYLE, DIMBLK_T, 5);
     583        MATCH_OBJECT (DIMSTYLE, DIMBLK1_T, 6);
     584        MATCH_OBJECT (DIMSTYLE, DIMBLK2_T, 7);
     585        MATCH_OBJECT (DIMSTYLE, DIMMZS, 0);
     586        MATCH_OBJECT (DIMSTYLE, DIMALTMZS, 0);
     587      }
     588    return found;
     589  }
     590  
     591  static int
     592  match_GROUP (const char *restrict filename, const Dwg_Object *restrict obj)
     593  {
     594    char *text;
     595    int found = 0;
     596    MATCH_OBJECT (GROUP, name, 3);
     597    return found;
     598  }
     599  
     600  static int
     601  match_MLINESTYLE (const char *restrict filename,
     602                    const Dwg_Object *restrict obj)
     603  {
     604    char *text;
     605    int found = 0;
     606    MATCH_OBJECT (MLINESTYLE, name, 2);
     607    MATCH_OBJECT (MLINESTYLE, description, 3);
     608    return found;
     609  }
     610  
     611  static int
     612  match_DICTIONARYVAR (const char *restrict filename,
     613                       const Dwg_Object *restrict obj)
     614  {
     615    char *text;
     616    int found = 0;
     617    MATCH_OBJECT (DICTIONARYVAR, strvalue, 1);
     618    return found;
     619  }
     620  
     621  static int
     622  match_HATCH (const char *restrict filename, const Dwg_Object *restrict obj)
     623  {
     624    char *text;
     625    int found = 0;
     626    MATCH_ENTITY (HATCH, name, 2);
     627    MATCH_ENTITY (HATCH, gradient_name, 470);
     628    return found;
     629  }
     630  static int
     631  match_TOLERANCE (const char *restrict filename, const Dwg_Object *restrict obj)
     632  {
     633    char *text;
     634    int found = 0;
     635    MATCH_ENTITY (TOLERANCE, text_value, 1);
     636    return found;
     637  }
     638  
     639  static int
     640  match_IMAGEDEF (const char *restrict filename, const Dwg_Object *restrict obj)
     641  {
     642    char *text;
     643    int found = 0;
     644    MATCH_OBJECT (IMAGEDEF, file_path, 1);
     645    return found;
     646  }
     647  
     648  static int
     649  match_SCALE (const char *restrict filename, const Dwg_Object *restrict obj)
     650  {
     651    char *text;
     652    int found = 0, i;
     653    // const Dwg_Object_SCALE *_obj = obj->tio.object->tio.SCALE;
     654    MATCH_OBJECT (SCALE, name, 1);
     655    return found;
     656  }
     657  
     658  static int
     659  match_LAYER_INDEX (const char *restrict filename,
     660                     const Dwg_Object *restrict obj)
     661  {
     662    char *text;
     663    int found = 0;
     664    BITCODE_BL i;
     665    const Dwg_Object_LAYER_INDEX *_obj = obj->tio.object->tio.LAYER_INDEX;
     666    for (i = 0; i < _obj->num_entries; i++)
     667      {
     668        MATCH_OBJECT (LAYER_INDEX, entries[i].name, 8);
     669      }
     670    return found;
     671  }
     672  
     673  static int
     674  match_LAYOUT (const char *restrict filename, const Dwg_Object *restrict obj)
     675  {
     676    char *text;
     677    int found = 0;
     678    BITCODE_BL i;
     679    const Dwg_Object_LAYOUT *_obj = obj->tio.object->tio.LAYOUT;
     680  
     681    MATCH_OBJECT (LAYOUT, plotsettings.printer_cfg_file, 1);
     682    MATCH_OBJECT (LAYOUT, plotsettings.paper_size, 2);
     683    MATCH_OBJECT (LAYOUT, plotsettings.canonical_media_name, 4);
     684    MATCH_TABLE (LAYOUT, plotsettings.plotview, VIEW, 6);
     685    MATCH_OBJECT (LAYOUT, plotsettings.plotview_name, 6);
     686    MATCH_OBJECT (LAYOUT, plotsettings.stylesheet, 7);
     687  
     688    MATCH_OBJECT (LAYOUT, layout_name, 1);
     689    MATCH_TABLE (LAYOUT, block_header, BLOCK, 330);
     690    MATCH_TABLE (LAYOUT, active_viewport, VIEWPORT, 331);
     691    MATCH_TABLE (LAYOUT, shadeplot, VISUALSTYLE, 333);
     692    MATCH_TABLE (LAYOUT, base_ucs, UCS, 346);
     693    MATCH_TABLE (LAYOUT, named_ucs, UCS, 345);
     694    for (i = 0; i < _obj->num_viewports; i++)
     695      {
     696        MATCH_TABLE (LAYOUT, viewports[i], VPORT, 0);
     697      }
     698    return found;
     699  }
     700  
     701  static int
     702  match_FIELD (const char *restrict filename, const Dwg_Object *restrict obj)
     703  {
     704    char *text;
     705    int found = 0;
     706    BITCODE_BL i;
     707    const Dwg_Object_FIELD *_obj = obj->tio.object->tio.FIELD;
     708  
     709    MATCH_OBJECT (FIELD, format, 4);
     710    MATCH_OBJECT (FIELD, evaluation_error_msg, 300);
     711    MATCH_OBJECT (FIELD, value.format_string, 300);
     712    MATCH_OBJECT (FIELD, value.value_string, 300);
     713    MATCH_OBJECT (FIELD, value_string, 301);
     714    for (i = 0; i < _obj->num_childval; i++)
     715      {
     716        MATCH_OBJECT (FIELD, childval[i].key, 6);
     717        MATCH_OBJECT (FIELD, childval[i].value.format_string, 300);
     718        MATCH_OBJECT (FIELD, childval[i].value.value_string, 302);
     719      }
     720    return found;
     721  }
     722  
     723  static int
     724  match_TABLE (const char *restrict filename, const Dwg_Object *restrict obj)
     725  {
     726    char *text;
     727    int found = 0;
     728    BITCODE_BL i, j;
     729    const Dwg_Entity_TABLE *_obj = obj->tio.entity->tio.TABLE;
     730  
     731    for (i = 0; i < _obj->num_cells; i++)
     732      {
     733        if (_obj->cells[i].type == 1)
     734          {
     735            MATCH_ENTITY (TABLE, cells[i].text_value, 1);
     736          }
     737        else if (_obj->cells[i].type == 2
     738                 && _obj->cells[i].additional_data_flag == 1
     739                 && _obj->cells[i].num_attr_defs)
     740          {
     741            for (j = 0; j < _obj->cells[i].num_attr_defs; j++)
     742              {
     743                MATCH_ENTITY (TABLE, cells[i].attr_defs[j].text, 300);
     744              }
     745          }
     746      }
     747    return found;
     748  }
     749  
     750  static int
     751  match_TABLECONTENT (const char *restrict filename,
     752                      const Dwg_Object *restrict obj)
     753  {
     754    char *text;
     755    int found = 0;
     756    BITCODE_BL i, j, k;
     757    const Dwg_Object_TABLECONTENT *_obj = obj->tio.object->tio.TABLECONTENT;
     758  
     759    MATCH_OBJECT (TABLECONTENT, ldata.name, 1);
     760    MATCH_OBJECT (TABLECONTENT, ldata.description, 300);
     761    for (i = 0; i < _obj->tdata.num_cols; i++)
     762      {
     763        MATCH_OBJECT (TABLECONTENT, tdata.cols[i].name, 300);
     764      }
     765    for (i = 0; i < _obj->tdata.num_rows; i++)
     766      {
     767        for (j = 0; j < _obj->tdata.rows[i].num_cells; j++)
     768          {
     769            MATCH_OBJECT (TABLECONTENT, tdata.rows[i].cells[j].tooltip, 300);
     770            for (k = 0; k < _obj->tdata.rows[i].cells[j].num_customdata_items;
     771                 k++)
     772              {
     773  #define _custom tdata.rows[i].cells[j].customdata_items[k]
     774                MATCH_OBJECT (TABLECONTENT, _custom.name, 300);
     775                if (_obj->_custom.value.data_type == 4)
     776                  {
     777                    MATCH_OBJECT (TABLECONTENT, _custom.value.data_string, 302);
     778                  }
     779  #undef _custom
     780              }
     781            for (k = 0; k < _obj->tdata.rows[i].cells[j].num_cell_contents; k++)
     782              {
     783  #define _content tdata.rows[i].cells[j].cell_contents[k]
     784                if (_obj->_content.type == 1
     785                    && _obj->_content.value.data_type == 4)
     786                  {
     787                    MATCH_OBJECT (TABLECONTENT, _content.value.data_string, 302);
     788                  }
     789  #undef _content
     790              }
     791          }
     792      }
     793    return found;
     794  }
     795  
     796  static int
     797  match_GEODATA (const char *restrict filename, const Dwg_Object *restrict obj)
     798  {
     799    char *text;
     800    int found = 0;
     801    // const Dwg_Object_GEODATA *_obj = obj->tio.object->tio.GEODATA;
     802  
     803    MATCH_OBJECT (GEODATA, coord_system_def, 0);
     804    MATCH_OBJECT (GEODATA, geo_rss_tag, 302);
     805    MATCH_OBJECT (GEODATA, observation_from_tag, 305);
     806    MATCH_OBJECT (GEODATA, observation_to_tag, 306);
     807    MATCH_OBJECT (GEODATA, observation_coverage_tag, 0);
     808    // obsolete
     809    MATCH_OBJECT (GEODATA, coord_system_datum, 0);
     810    MATCH_OBJECT (GEODATA, coord_system_wkt, 0);
     811    return found;
     812  }
     813  
     814  static int
     815  match_GEOPOSITIONMARKER (const char *restrict filename,
     816                           const Dwg_Object *restrict obj)
     817  {
     818    char *text;
     819    int found = 0;
     820    // const Dwg_Entity_GEOPOSITIONMARKER *_obj =
     821    // obj->tio.entity->tio.GEOPOSITIONMARKER;
     822  
     823    MATCH_ENTITY (GEOPOSITIONMARKER, notes, 1);
     824    // if enabled
     825    // MATCH_ENTITY (GEOPOSITIONMARKER, mtext->tio.entity->tio.MTEXT->text, 3);
     826    return found;
     827  }
     828  
     829  static int
     830  match_UNDERLAYDEFINITION (const char *restrict filename,
     831                            const Dwg_Object *restrict obj)
     832  {
     833    char *text;
     834    int found = 0;
     835    // const Dwg_Object_PDFDEFINITION *_obj = obj->tio.object->tio.PDFDEFINITION;
     836  
     837    MATCH_OBJECT (PDFDEFINITION, filename, 1);
     838    MATCH_OBJECT (PDFDEFINITION, name, 2);
     839    return found;
     840  }
     841  
     842  static int
     843  match_VISUALSTYLE (const char *restrict filename,
     844                     const Dwg_Object *restrict obj)
     845  {
     846    char *text;
     847    int found = 0, i;
     848    // const Dwg_Object_VISUALSTYLE *_obj = obj->tio.object->tio.VISUALSTYLE;
     849    MATCH_OBJECT (VISUALSTYLE, description, 1);
     850    return found;
     851  }
     852  
     853  static int
     854  match_TABLESTYLE (const char *restrict filename,
     855                    const Dwg_Object *restrict obj)
     856  {
     857    char *text;
     858    int found = 0, i;
     859    // const Dwg_Object_TABLESTYLE *_obj = obj->tio.object->tio.TABLESTYLE;
     860    MATCH_OBJECT (TABLESTYLE, name, 2);
     861    return found;
     862  }
     863  static int
     864  match_LIGHT (const char *restrict filename, const Dwg_Object *restrict obj)
     865  {
     866    char *text;
     867    int found = 0;
     868    // const Dwg_Entity_LIGHT *_obj = obj->tio.entity->tio.LIGHT;
     869    MATCH_ENTITY (LIGHT, name, 1);
     870    // MATCH_ENTITY (LIGHT, web_file, 1);
     871    return found;
     872  }
     873  
     874  static int
     875  match_SUNSTUDY (const char *restrict filename, const Dwg_Object *restrict obj)
     876  {
     877    char *text;
     878    int found = 0;
     879    // const Dwg_Object_SUNSTUDY *_obj = obj->tio.object->tio.SUNSTUDY;
     880    MATCH_OBJECT (SUNSTUDY, setup_name, 1);
     881    MATCH_OBJECT (SUNSTUDY, description, 2);
     882    MATCH_OBJECT (SUNSTUDY, sheet_set_name, 3);
     883    return found;
     884  }
     885  
     886  static int
     887  match_LIGHTLIST (const char *restrict filename, const Dwg_Object *restrict obj)
     888  {
     889    char *text;
     890    int found = 0;
     891    const Dwg_Object_LIGHTLIST *_obj = obj->tio.object->tio.LIGHTLIST;
     892  
     893    for (BITCODE_BL i = 0; i < _obj->num_lights; i++)
     894      {
     895        MATCH_OBJECT (LIGHTLIST, lights[i].name, 1);
     896      }
     897    return found;
     898  }
     899  
     900  static int
     901  match_DBCOLOR (const char *restrict filename, const Dwg_Object *restrict obj)
     902  {
     903    char *text;
     904    int found = 0;
     905    // const Dwg_Object_DBCOLOR *_obj = obj->tio.object->tio.DBCOLOR;
     906    MATCH_OBJECT (DBCOLOR, color.name, 430);
     907    MATCH_OBJECT (DBCOLOR, color.book_name, 430);
     908    return found;
     909  }
     910  
     911  static int
     912  match_MATERIAL (const char *restrict filename, const Dwg_Object *restrict obj)
     913  {
     914    char *text;
     915    int found = 0;
     916    // const Dwg_Object_MATERIAL *_obj = obj->tio.object->tio.MATERIAL;
     917    MATCH_OBJECT (MATERIAL, name, 1);
     918    MATCH_OBJECT (MATERIAL, description, 2);
     919    MATCH_OBJECT (MATERIAL, diffusemap.filename, 3);
     920    MATCH_OBJECT (MATERIAL, specularmap.filename, 4);
     921    MATCH_OBJECT (MATERIAL, reflectionmap.filename, 6);
     922    MATCH_OBJECT (MATERIAL, opacitymap.filename, 7);
     923    MATCH_OBJECT (MATERIAL, bumpmap.filename, 8);
     924    MATCH_OBJECT (MATERIAL, refractionmap.filename, 9);
     925    // MATCH_OBJECT (MATERIAL, normalmap.filename, 3);
     926    // MATCH_OBJECT (MATERIAL, genprocname, 300);
     927    // MATCH_OBJECT (MATERIAL, genprocvaltext, 301);
     928    // MATCH_OBJECT (MATERIAL, genprocvalcolorname, 430);
     929    return found;
     930  }
     931  
     932  static int
     933  match_PLOTSETTINGS (const char *restrict filename,
     934                      const Dwg_Object *restrict obj)
     935  {
     936    char *text;
     937    int found = 0;
     938    // const Dwg_Object_PLOTSETTINGS *_obj = obj->tio.object->tio.PLOTSETTINGS;
     939    MATCH_OBJECT (PLOTSETTINGS, printer_cfg_file, 1);
     940    MATCH_OBJECT (PLOTSETTINGS, paper_size, 2);
     941    MATCH_OBJECT (PLOTSETTINGS, canonical_media_name, 4);
     942    MATCH_OBJECT (PLOTSETTINGS, plotview_name, 6);
     943    MATCH_TABLE (PLOTSETTINGS, VIEW, plotview, 6);
     944    MATCH_OBJECT (PLOTSETTINGS, stylesheet, 7);
     945    MATCH_TABLE (PLOTSETTINGS, VISUALSTYLE, shadeplot, 333);
     946    return found;
     947  }
     948  static int
     949  match_DIMASSOC (const char *restrict filename, const Dwg_Object *restrict obj)
     950  {
     951    char *text;
     952    int found = 0;
     953    const Dwg_Object_DIMASSOC *_obj = obj->tio.object->tio.DIMASSOC;
     954    for (BITCODE_BL i = 0; i < 4; i++)
     955      {
     956        if (_obj->ref[i].classname)
     957          {
     958            MATCH_OBJECT (DIMASSOC, ref[i].classname, 0);
     959          }
     960      }
     961    return found;
     962  }
     963  
     964  static int
     965  match_ASSOCOSNAPPOINTREFACTIONPARAM (const char *restrict filename,
     966                                       const Dwg_Object *restrict obj)
     967  {
     968    char *text;
     969    int found = 0;
     970    MATCH_OBJECT (ASSOCOSNAPPOINTREFACTIONPARAM, name, 1);
     971    return found;
     972  }
     973  static int
     974  match_ASSOCACTIONPARAM (const char *restrict filename,
     975                          const Dwg_Object *restrict obj)
     976  {
     977    char *text;
     978    int found = 0;
     979    MATCH_OBJECT (ASSOCACTIONPARAM, name, 1);
     980    return found;
     981  }
     982  static int
     983  match_ASSOCEDGEACTIONPARAM (const char *restrict filename,
     984                              const Dwg_Object *restrict obj)
     985  {
     986    char *text;
     987    int found = 0;
     988    MATCH_OBJECT (ASSOCEDGEACTIONPARAM, name, 1);
     989    return found;
     990  }
     991  static int
     992  match_ASSOCFACEACTIONPARAM (const char *restrict filename,
     993                              const Dwg_Object *restrict obj)
     994  {
     995    char *text;
     996    int found = 0;
     997    MATCH_OBJECT (ASSOCFACEACTIONPARAM, name, 1);
     998    return found;
     999  }
    1000  static int
    1001  match_ASSOCOBJECTACTIONPARAM (const char *restrict filename,
    1002                                const Dwg_Object *restrict obj)
    1003  {
    1004    char *text;
    1005    int found = 0;
    1006    MATCH_OBJECT (ASSOCOBJECTACTIONPARAM, name, 1);
    1007    return found;
    1008  }
    1009  static int
    1010  match_ASSOCPATHACTIONPARAM (const char *restrict filename,
    1011                              const Dwg_Object *restrict obj)
    1012  {
    1013    char *text;
    1014    int found = 0;
    1015    MATCH_OBJECT (ASSOCPATHACTIONPARAM, name, 1);
    1016    return found;
    1017  }
    1018  static int
    1019  match_ASSOCVERTEXACTIONPARAM (const char *restrict filename,
    1020                                const Dwg_Object *restrict obj)
    1021  {
    1022    char *text;
    1023    int found = 0;
    1024    MATCH_OBJECT (ASSOCVERTEXACTIONPARAM, name, 1);
    1025    return found;
    1026  }
    1027  
    1028  // TODO match on its subclasses which holds the text:
    1029  //  ASSOCVARIABLE, EvalVariant
    1030  
    1031  #define MATCH_AcDbAssocParamBasedActionBody(_type)                            \
    1032    for (unsigned i = 0; i < _obj->pab.num_values; i++)                         \
    1033      {                                                                         \
    1034        MATCH_OBJECT (_type, pab.values[i].name, 1);                            \
    1035        for (unsigned j = 0; j < _obj->pab.values[i].num_vars; j++)             \
    1036          {                                                                     \
    1037            int _dxf = _obj->pab.values[i].vars[j].value.code;                  \
    1038            if (dwg_resbuf_value_type (_dxf) == DWG_VT_STRING)                  \
    1039              {                                                                 \
    1040                MATCH_OBJECT (_type, pab.values[i].vars[j].value.u.text, _dxf); \
    1041              }                                                                 \
    1042          }                                                                     \
    1043      }
    1044  
    1045  static int
    1046  match_ASSOCMLEADERACTIONBODY (const char *restrict filename,
    1047                                const Dwg_Object *restrict obj)
    1048  {
    1049    char *text;
    1050    int found = 0;
    1051    const Dwg_Object_ASSOCMLEADERACTIONBODY *_obj
    1052        = obj->tio.object->tio.ASSOCMLEADERACTIONBODY;
    1053    MATCH_AcDbAssocParamBasedActionBody (ASSOCMLEADERACTIONBODY) return found;
    1054  }
    1055  static int
    1056  match_ASSOC3POINTANGULARDIMACTIONBODY (const char *restrict filename,
    1057                                         const Dwg_Object *restrict obj)
    1058  {
    1059    char *text;
    1060    int found = 0;
    1061    const Dwg_Object_ASSOC3POINTANGULARDIMACTIONBODY *_obj
    1062        = obj->tio.object->tio.ASSOC3POINTANGULARDIMACTIONBODY;
    1063    MATCH_AcDbAssocParamBasedActionBody (
    1064        ASSOC3POINTANGULARDIMACTIONBODY) return found;
    1065  }
    1066  static int
    1067  match_ASSOCALIGNEDDIMACTIONBODY (const char *restrict filename,
    1068                                   const Dwg_Object *restrict obj)
    1069  {
    1070    char *text;
    1071    int found = 0;
    1072    const Dwg_Object_ASSOCALIGNEDDIMACTIONBODY *_obj
    1073        = obj->tio.object->tio.ASSOCALIGNEDDIMACTIONBODY;
    1074    MATCH_AcDbAssocParamBasedActionBody (ASSOCALIGNEDDIMACTIONBODY) return found;
    1075  }
    1076  
    1077  static int
    1078  match_ASSOCORDINATEDIMACTIONBODY (const char *restrict filename,
    1079                                    const Dwg_Object *restrict obj)
    1080  {
    1081    char *text;
    1082    int found = 0;
    1083    const Dwg_Object_ASSOCORDINATEDIMACTIONBODY *_obj
    1084        = obj->tio.object->tio.ASSOCORDINATEDIMACTIONBODY;
    1085    MATCH_AcDbAssocParamBasedActionBody (
    1086        ASSOCORDINATEDIMACTIONBODY) return found;
    1087  }
    1088  
    1089  static int
    1090  match_ASSOCROTATEDDIMACTIONBODY (const char *restrict filename,
    1091                                   const Dwg_Object *restrict obj)
    1092  {
    1093    char *text;
    1094    int found = 0;
    1095    const Dwg_Object_ASSOCROTATEDDIMACTIONBODY *_obj
    1096        = obj->tio.object->tio.ASSOCROTATEDDIMACTIONBODY;
    1097    MATCH_AcDbAssocParamBasedActionBody (ASSOCROTATEDDIMACTIONBODY) return found;
    1098  }
    1099  
    1100  static int
    1101  match_ASSOCPATCHSURFACEACTIONBODY (const char *restrict filename,
    1102                                     const Dwg_Object *restrict obj)
    1103  {
    1104    char *text;
    1105    int found = 0;
    1106    const Dwg_Object_ASSOCPATCHSURFACEACTIONBODY *_obj
    1107        = obj->tio.object->tio.ASSOCPATCHSURFACEACTIONBODY;
    1108    MATCH_AcDbAssocParamBasedActionBody (
    1109        ASSOCPATCHSURFACEACTIONBODY) return found;
    1110  }
    1111  static int
    1112  match_ASSOCPLANESURFACEACTIONBODY (const char *restrict filename,
    1113                                     const Dwg_Object *restrict obj)
    1114  {
    1115    char *text;
    1116    int found = 0;
    1117    const Dwg_Object_ASSOCPLANESURFACEACTIONBODY *_obj
    1118        = obj->tio.object->tio.ASSOCPLANESURFACEACTIONBODY;
    1119    MATCH_AcDbAssocParamBasedActionBody (
    1120        ASSOCPLANESURFACEACTIONBODY) return found;
    1121  }
    1122  static int
    1123  match_ASSOCEXTENDSURFACEACTIONBODY (const char *restrict filename,
    1124                                      const Dwg_Object *restrict obj)
    1125  {
    1126    char *text;
    1127    int found = 0;
    1128    const Dwg_Object_ASSOCEXTENDSURFACEACTIONBODY *_obj
    1129        = obj->tio.object->tio.ASSOCEXTENDSURFACEACTIONBODY;
    1130    MATCH_AcDbAssocParamBasedActionBody (
    1131        ASSOCEXTENDSURFACEACTIONBODY) return found;
    1132  }
    1133  static int
    1134  match_ASSOCEXTRUDEDSURFACEACTIONBODY (const char *restrict filename,
    1135                                        const Dwg_Object *restrict obj)
    1136  {
    1137    char *text;
    1138    int found = 0;
    1139    const Dwg_Object_ASSOCEXTRUDEDSURFACEACTIONBODY *_obj
    1140        = obj->tio.object->tio.ASSOCEXTRUDEDSURFACEACTIONBODY;
    1141    MATCH_AcDbAssocParamBasedActionBody (
    1142        ASSOCEXTRUDEDSURFACEACTIONBODY) return found;
    1143  }
    1144  static int
    1145  match_ASSOCFILLETSURFACEACTIONBODY (const char *restrict filename,
    1146                                      const Dwg_Object *restrict obj)
    1147  {
    1148    char *text;
    1149    int found = 0;
    1150    const Dwg_Object_ASSOCFILLETSURFACEACTIONBODY *_obj
    1151        = obj->tio.object->tio.ASSOCFILLETSURFACEACTIONBODY;
    1152    MATCH_AcDbAssocParamBasedActionBody (
    1153        ASSOCFILLETSURFACEACTIONBODY) return found;
    1154  }
    1155  static int
    1156  match_ASSOCLOFTEDSURFACEACTIONBODY (const char *restrict filename,
    1157                                      const Dwg_Object *restrict obj)
    1158  {
    1159    char *text;
    1160    int found = 0;
    1161    const Dwg_Object_ASSOCLOFTEDSURFACEACTIONBODY *_obj
    1162        = obj->tio.object->tio.ASSOCLOFTEDSURFACEACTIONBODY;
    1163    MATCH_AcDbAssocParamBasedActionBody (
    1164        ASSOCLOFTEDSURFACEACTIONBODY) return found;
    1165  }
    1166  static int
    1167  match_ASSOCNETWORKSURFACEACTIONBODY (const char *restrict filename,
    1168                                       const Dwg_Object *restrict obj)
    1169  {
    1170    char *text;
    1171    int found = 0;
    1172    const Dwg_Object_ASSOCNETWORKSURFACEACTIONBODY *_obj
    1173        = obj->tio.object->tio.ASSOCNETWORKSURFACEACTIONBODY;
    1174    MATCH_AcDbAssocParamBasedActionBody (
    1175        ASSOCNETWORKSURFACEACTIONBODY) return found;
    1176  }
    1177  static int
    1178  match_ASSOCOFFSETSURFACEACTIONBODY (const char *restrict filename,
    1179                                      const Dwg_Object *restrict obj)
    1180  {
    1181    char *text;
    1182    int found = 0;
    1183    const Dwg_Object_ASSOCOFFSETSURFACEACTIONBODY *_obj
    1184        = obj->tio.object->tio.ASSOCOFFSETSURFACEACTIONBODY;
    1185    MATCH_AcDbAssocParamBasedActionBody (
    1186        ASSOCOFFSETSURFACEACTIONBODY) return found;
    1187  }
    1188  static int
    1189  match_ASSOCREVOLVEDSURFACEACTIONBODY (const char *restrict filename,
    1190                                        const Dwg_Object *restrict obj)
    1191  {
    1192    char *text;
    1193    int found = 0;
    1194    const Dwg_Object_ASSOCREVOLVEDSURFACEACTIONBODY *_obj
    1195        = obj->tio.object->tio.ASSOCREVOLVEDSURFACEACTIONBODY;
    1196    MATCH_AcDbAssocParamBasedActionBody (
    1197        ASSOCREVOLVEDSURFACEACTIONBODY) return found;
    1198  }
    1199  static int
    1200  match_ASSOCSWEPTSURFACEACTIONBODY (const char *restrict filename,
    1201                                     const Dwg_Object *restrict obj)
    1202  {
    1203    char *text;
    1204    int found = 0;
    1205    const Dwg_Object_ASSOCSWEPTSURFACEACTIONBODY *_obj
    1206        = obj->tio.object->tio.ASSOCSWEPTSURFACEACTIONBODY;
    1207    MATCH_AcDbAssocParamBasedActionBody (
    1208        ASSOCSWEPTSURFACEACTIONBODY) return found;
    1209  }
    1210  static int
    1211  match_ASSOCTRIMSURFACEACTIONBODY (const char *restrict filename,
    1212                                    const Dwg_Object *restrict obj)
    1213  {
    1214    char *text;
    1215    int found = 0;
    1216    const Dwg_Object_ASSOCTRIMSURFACEACTIONBODY *_obj
    1217        = obj->tio.object->tio.ASSOCTRIMSURFACEACTIONBODY;
    1218    MATCH_AcDbAssocParamBasedActionBody (
    1219        ASSOCTRIMSURFACEACTIONBODY) return found;
    1220  }
    1221  
    1222  static int
    1223  match_BLOCKPARAMDEPENDENCYBODY (const char *restrict filename,
    1224                                  const Dwg_Object *restrict obj)
    1225  {
    1226    char *text;
    1227    int found = 0;
    1228    MATCH_OBJECT (BLOCKPARAMDEPENDENCYBODY, name, 1);
    1229    return found;
    1230  }
    1231  static int
    1232  match_BLOCKMOVEACTION (const char *restrict filename,
    1233                         const Dwg_Object *restrict obj)
    1234  {
    1235    char *text;
    1236    int found = 0;
    1237    MATCH_OBJECT (BLOCKMOVEACTION, conn_pts[0].name, 301);
    1238    MATCH_OBJECT (BLOCKMOVEACTION, conn_pts[1].name, 302);
    1239    return found;
    1240  }
    1241  static int
    1242  match_BLOCKSTRETCHACTION (const char *restrict filename,
    1243                            const Dwg_Object *restrict obj)
    1244  {
    1245    char *text;
    1246    int found = 0;
    1247    MATCH_OBJECT (BLOCKSTRETCHACTION, conn_pts[0].name, 301);
    1248    MATCH_OBJECT (BLOCKSTRETCHACTION, conn_pts[1].name, 302);
    1249    return found;
    1250  }
    1251  static int
    1252  match_BLOCKROTATEACTION (const char *restrict filename,
    1253                           const Dwg_Object *restrict obj)
    1254  {
    1255    char *text;
    1256    int found = 0;
    1257    MATCH_OBJECT (BLOCKROTATEACTION, conn_pts[0].name, 301);
    1258    MATCH_OBJECT (BLOCKROTATEACTION, conn_pts[1].name, 302);
    1259    MATCH_OBJECT (BLOCKROTATEACTION, conn_pts[2].name, 303);
    1260    return found;
    1261  }
    1262  static int
    1263  match_BLOCKVISIBILITYGRIP (const char *restrict filename,
    1264                             const Dwg_Object *restrict obj)
    1265  {
    1266    char *text;
    1267    int found = 0;
    1268    Dwg_Object_BLOCKVISIBILITYGRIP *_obj
    1269        = obj->tio.object->tio.BLOCKVISIBILITYGRIP;
    1270  
    1271    if (_obj->evalexpr.value_code == 1)
    1272      {
    1273        MATCH_OBJECT (BLOCKVISIBILITYGRIP, evalexpr.value.text1, 1);
    1274      }
    1275    MATCH_OBJECT (BLOCKVISIBILITYGRIP, name, 1);
    1276    return found;
    1277  }
    1278  static int
    1279  match_BLOCKGRIPLOCATIONCOMPONENT (const char *restrict filename,
    1280                                    const Dwg_Object *restrict obj)
    1281  {
    1282    char *text;
    1283    int found = 0;
    1284    Dwg_Object_BLOCKGRIPLOCATIONCOMPONENT *_obj
    1285        = obj->tio.object->tio.BLOCKGRIPLOCATIONCOMPONENT;
    1286  
    1287    if (_obj->evalexpr.value_code == 1)
    1288      {
    1289        MATCH_OBJECT (BLOCKGRIPLOCATIONCOMPONENT, evalexpr.value.text1, 1);
    1290      }
    1291    MATCH_OBJECT (BLOCKGRIPLOCATIONCOMPONENT, grip_expr, 91);
    1292    return found;
    1293  }
    1294  static int
    1295  match_BLOCKBASEPOINTPARAMETER (const char *restrict filename,
    1296                                 const Dwg_Object *restrict obj)
    1297  {
    1298    char *text;
    1299    int found = 0;
    1300    Dwg_Object_BLOCKBASEPOINTPARAMETER *_obj
    1301        = obj->tio.object->tio.BLOCKBASEPOINTPARAMETER;
    1302  
    1303    if (_obj->evalexpr.value_code == 1)
    1304      {
    1305        MATCH_OBJECT (BLOCKBASEPOINTPARAMETER, evalexpr.value.text1, 1);
    1306      }
    1307    MATCH_OBJECT (BLOCKBASEPOINTPARAMETER, name, 1);
    1308    for (unsigned i = 0; i < _obj->prop1.num_connections; i++)
    1309      {
    1310        MATCH_OBJECT (BLOCKROTATIONPARAMETER, prop1.connections[i].name, 301);
    1311      }
    1312    for (unsigned i = 0; i < _obj->prop2.num_connections; i++)
    1313      {
    1314        MATCH_OBJECT (BLOCKROTATIONPARAMETER, prop2.connections[i].name, 302);
    1315      }
    1316    return found;
    1317  }
    1318  static int
    1319  match_BLOCKLINEARPARAMETER (const char *restrict filename,
    1320                              const Dwg_Object *restrict obj)
    1321  {
    1322    char *text;
    1323    int found = 0;
    1324    Dwg_Object_BLOCKLINEARPARAMETER *_obj
    1325        = obj->tio.object->tio.BLOCKLINEARPARAMETER;
    1326  
    1327    if (_obj->evalexpr.value_code == 1)
    1328      {
    1329        MATCH_OBJECT (BLOCKLINEARPARAMETER, evalexpr.value.text1, 1);
    1330      }
    1331    MATCH_OBJECT (BLOCKLINEARPARAMETER, name, 1);
    1332    for (unsigned i = 0; i < _obj->prop1.num_connections; i++)
    1333      {
    1334        MATCH_OBJECT (BLOCKLINEARPARAMETER, prop1.connections[i].name, 301);
    1335      }
    1336    for (unsigned i = 0; i < _obj->prop2.num_connections; i++)
    1337      {
    1338        MATCH_OBJECT (BLOCKLINEARPARAMETER, prop2.connections[i].name, 302);
    1339      }
    1340    for (unsigned i = 0; i < _obj->prop3.num_connections; i++)
    1341      {
    1342        MATCH_OBJECT (BLOCKLINEARPARAMETER, prop3.connections[i].name, 303);
    1343      }
    1344    for (unsigned i = 0; i < _obj->prop4.num_connections; i++)
    1345      {
    1346        MATCH_OBJECT (BLOCKLINEARPARAMETER, prop4.connections[i].name, 304);
    1347      }
    1348    MATCH_OBJECT (BLOCKLINEARPARAMETER, distance_name, 305);
    1349    MATCH_OBJECT (BLOCKLINEARPARAMETER, distance_desc, 306);
    1350    MATCH_OBJECT (BLOCKLINEARPARAMETER, value_set.desc, 307);
    1351    return found;
    1352  }
    1353  static int
    1354  match_BLOCKFLIPPARAMETER (const char *restrict filename,
    1355                            const Dwg_Object *restrict obj)
    1356  {
    1357    char *text;
    1358    int found = 0;
    1359    Dwg_Object_BLOCKFLIPPARAMETER *_obj
    1360        = obj->tio.object->tio.BLOCKFLIPPARAMETER;
    1361  
    1362    if (_obj->evalexpr.value_code == 1)
    1363      {
    1364        MATCH_OBJECT (BLOCKFLIPPARAMETER, evalexpr.value.text1, 1);
    1365      }
    1366    MATCH_OBJECT (BLOCKFLIPPARAMETER, name, 1);
    1367    for (unsigned i = 0; i < _obj->prop1.num_connections; i++)
    1368      {
    1369        MATCH_OBJECT (BLOCKFLIPPARAMETER, prop1.connections[i].name, 301);
    1370      }
    1371    for (unsigned i = 0; i < _obj->prop2.num_connections; i++)
    1372      {
    1373        MATCH_OBJECT (BLOCKFLIPPARAMETER, prop2.connections[i].name, 302);
    1374      }
    1375    for (unsigned i = 0; i < _obj->prop3.num_connections; i++)
    1376      {
    1377        MATCH_OBJECT (BLOCKFLIPPARAMETER, prop3.connections[i].name, 303);
    1378      }
    1379    for (unsigned i = 0; i < _obj->prop4.num_connections; i++)
    1380      {
    1381        MATCH_OBJECT (BLOCKFLIPPARAMETER, prop4.connections[i].name, 304);
    1382      }
    1383    MATCH_OBJECT (BLOCKFLIPPARAMETER, flip_label, 305);
    1384    MATCH_OBJECT (BLOCKFLIPPARAMETER, flip_label_desc, 306);
    1385    MATCH_OBJECT (BLOCKFLIPPARAMETER, base_state_label, 307);
    1386    MATCH_OBJECT (BLOCKFLIPPARAMETER, flipped_state_label, 308);
    1387    MATCH_OBJECT (BLOCKFLIPPARAMETER, tooltip, 309);
    1388    return found;
    1389  }
    1390  static int
    1391  match_BLOCKROTATIONPARAMETER (const char *restrict filename,
    1392                                const Dwg_Object *restrict obj)
    1393  {
    1394    char *text;
    1395    int found = 0;
    1396    Dwg_Object_BLOCKROTATIONPARAMETER *_obj
    1397        = obj->tio.object->tio.BLOCKROTATIONPARAMETER;
    1398  
    1399    if (_obj->evalexpr.value_code == 1)
    1400      {
    1401        MATCH_OBJECT (BLOCKROTATIONPARAMETER, evalexpr.value.text1, 1);
    1402      }
    1403    MATCH_OBJECT (BLOCKROTATIONPARAMETER, name, 1);
    1404    for (unsigned i = 0; i < _obj->prop1.num_connections; i++)
    1405      {
    1406        MATCH_OBJECT (BLOCKROTATIONPARAMETER, prop1.connections[i].name, 301);
    1407      }
    1408    for (unsigned i = 0; i < _obj->prop2.num_connections; i++)
    1409      {
    1410        MATCH_OBJECT (BLOCKROTATIONPARAMETER, prop2.connections[i].name, 302);
    1411      }
    1412    for (unsigned i = 0; i < _obj->prop3.num_connections; i++)
    1413      {
    1414        MATCH_OBJECT (BLOCKROTATIONPARAMETER, prop3.connections[i].name, 303);
    1415      }
    1416    for (unsigned i = 0; i < _obj->prop4.num_connections; i++)
    1417      {
    1418        MATCH_OBJECT (BLOCKROTATIONPARAMETER, prop4.connections[i].name, 304);
    1419      }
    1420    MATCH_OBJECT (BLOCKROTATIONPARAMETER, angle_name, 305);
    1421    MATCH_OBJECT (BLOCKROTATIONPARAMETER, angle_desc, 306);
    1422    MATCH_OBJECT (BLOCKROTATIONPARAMETER, angle_value_set.desc, 307);
    1423    return found;
    1424  }
    1425  static int
    1426  match_BLOCKXYPARAMETER (const char *restrict filename,
    1427                          const Dwg_Object *restrict obj)
    1428  {
    1429    char *text;
    1430    int found = 0;
    1431    Dwg_Object_BLOCKXYPARAMETER *_obj = obj->tio.object->tio.BLOCKXYPARAMETER;
    1432  
    1433    if (_obj->evalexpr.value_code == 1)
    1434      {
    1435        MATCH_OBJECT (BLOCKXYPARAMETER, evalexpr.value.text1, 1);
    1436      }
    1437    MATCH_OBJECT (BLOCKXYPARAMETER, name, 1);
    1438    for (unsigned i = 0; i < _obj->prop1.num_connections; i++)
    1439      {
    1440        MATCH_OBJECT (BLOCKXYPARAMETER, prop1.connections[i].name, 301);
    1441      }
    1442    for (unsigned i = 0; i < _obj->prop2.num_connections; i++)
    1443      {
    1444        MATCH_OBJECT (BLOCKXYPARAMETER, prop2.connections[i].name, 302);
    1445      }
    1446    for (unsigned i = 0; i < _obj->prop3.num_connections; i++)
    1447      {
    1448        MATCH_OBJECT (BLOCKXYPARAMETER, prop3.connections[i].name, 303);
    1449      }
    1450    for (unsigned i = 0; i < _obj->prop4.num_connections; i++)
    1451      {
    1452        MATCH_OBJECT (BLOCKXYPARAMETER, prop4.connections[i].name, 304);
    1453      }
    1454    MATCH_OBJECT (BLOCKXYPARAMETER, x_label, 305);
    1455    MATCH_OBJECT (BLOCKXYPARAMETER, x_label_desc, 306);
    1456    MATCH_OBJECT (BLOCKXYPARAMETER, y_label, 307);
    1457    MATCH_OBJECT (BLOCKXYPARAMETER, y_label_desc, 308);
    1458    MATCH_OBJECT (BLOCKXYPARAMETER, x_value_set.desc, 410);
    1459    MATCH_OBJECT (BLOCKXYPARAMETER, y_value_set.desc, 309);
    1460    return found;
    1461  }
    1462  static int
    1463  match_BLOCKVISIBILITYPARAMETER (const char *restrict filename,
    1464                                  const Dwg_Object *restrict obj)
    1465  {
    1466    char *text;
    1467    int found = 0;
    1468    Dwg_Object_BLOCKVISIBILITYPARAMETER *_obj
    1469        = obj->tio.object->tio.BLOCKVISIBILITYPARAMETER;
    1470  
    1471    if (_obj->evalexpr.value_code == 1)
    1472      {
    1473        MATCH_OBJECT (BLOCKVISIBILITYPARAMETER, evalexpr.value.text1, 1);
    1474      }
    1475    MATCH_OBJECT (BLOCKVISIBILITYPARAMETER, name, 1);
    1476    for (unsigned i = 0; i < _obj->prop1.num_connections; i++)
    1477      {
    1478        MATCH_OBJECT (BLOCKVISIBILITYPARAMETER, prop1.connections[i].name, 301);
    1479      }
    1480    for (unsigned i = 0; i < _obj->prop2.num_connections; i++)
    1481      {
    1482        MATCH_OBJECT (BLOCKVISIBILITYPARAMETER, prop2.connections[i].name, 302);
    1483      }
    1484    MATCH_OBJECT (BLOCKVISIBILITYPARAMETER, blockvisi_name, 301);
    1485    MATCH_OBJECT (BLOCKVISIBILITYPARAMETER, blockvisi_desc, 302);
    1486    for (unsigned i = 0; i < _obj->num_states; i++)
    1487      {
    1488        MATCH_OBJECT (BLOCKVISIBILITYPARAMETER, states[i].name, 303);
    1489      }
    1490    return found;
    1491  }
    1492  static int
    1493  match_NAVISWORKSMODELDEF (const char *restrict filename,
    1494                            const Dwg_Object *restrict obj)
    1495  {
    1496    char *text;
    1497    int found = 0;
    1498    MATCH_OBJECT (NAVISWORKSMODELDEF, path, 1);
    1499    return found;
    1500  }
    1501  
    1502  static int
    1503  match_OBJECTS (const char *restrict filename, Dwg_Data *restrict dwg)
    1504  {
    1505    int found = 0;
    1506    char *text;
    1507  
    1508    if (!dwg)
    1509      return 0;
    1510    for (BITCODE_BL i = 0; i < dwg->num_objects; i++)
    1511      {
    1512        const Dwg_Object *obj = &dwg->object[i];
    1513        if (obj->supertype != DWG_SUPERTYPE_OBJECT)
    1514          continue;
    1515        // processed later, --tables finds BLOCK
    1516        if (obj->fixedtype == DWG_TYPE_BLOCK_HEADER)
    1517          continue;
    1518        if (numtype) // search for allowed --type and skip if not
    1519          {
    1520            int typeok = 0;
    1521            for (int j = 0; j < numtype; j++)
    1522              {
    1523                if (obj->dxfname && !strcmp (type[j], obj->dxfname))
    1524                  {
    1525                    typeok = 1;
    1526                    break;
    1527                  }
    1528              }
    1529            if (!typeok) // next obj
    1530              continue;
    1531          }
    1532  
    1533  #define ELSEMATCH(OBJECT)                                                     \
    1534    else if (obj->fixedtype == DWG_TYPE_##OBJECT) found                         \
    1535        += match_##OBJECT (filename, obj);
    1536  
    1537        if (obj->fixedtype == DWG_TYPE_LAYER)
    1538          found += match_LAYER (filename, obj);
    1539        ELSEMATCH (LTYPE)
    1540        ELSEMATCH (STYLE)
    1541        ELSEMATCH (VIEW)
    1542        ELSEMATCH (VPORT)
    1543        ELSEMATCH (DIMSTYLE)
    1544        ELSEMATCH (UCS)
    1545        ELSEMATCH (VX_TABLE_RECORD)
    1546        if (opt_tables)
    1547          continue;
    1548  
    1549        if (obj->fixedtype == DWG_TYPE_DICTIONARY
    1550            || obj->fixedtype == DWG_TYPE_DICTIONARYWDFLT)
    1551          found += match_DICTIONARY (filename, obj);
    1552        ELSEMATCH (GROUP)
    1553        ELSEMATCH (MLINESTYLE)
    1554        ELSEMATCH (DICTIONARYVAR)
    1555        ELSEMATCH (IMAGEDEF)
    1556        ELSEMATCH (LAYER_INDEX)
    1557        ELSEMATCH (LAYOUT)
    1558        ELSEMATCH (PLOTSETTINGS)
    1559        ELSEMATCH (SCALE)
    1560        ELSEMATCH (FIELD)
    1561        ELSEMATCH (TABLECONTENT)
    1562        ELSEMATCH (GEODATA)
    1563        else if (obj->fixedtype == DWG_TYPE_PDFDEFINITION) found
    1564            += match_UNDERLAYDEFINITION (filename, obj);
    1565        else if (obj->fixedtype == DWG_TYPE_DGNDEFINITION) found
    1566            += match_UNDERLAYDEFINITION (filename, obj);
    1567        else if (obj->fixedtype == DWG_TYPE_DWFDEFINITION) found
    1568            += match_UNDERLAYDEFINITION (filename, obj);
    1569        ELSEMATCH (VISUALSTYLE)
    1570        ELSEMATCH (TABLESTYLE)
    1571        ELSEMATCH (SUNSTUDY)
    1572        ELSEMATCH (LIGHTLIST)
    1573        ELSEMATCH (DBCOLOR)
    1574        ELSEMATCH (MATERIAL)
    1575        ELSEMATCH (DIMASSOC)
    1576        ELSEMATCH (ASSOCOSNAPPOINTREFACTIONPARAM)
    1577        ELSEMATCH (ASSOCACTIONPARAM)
    1578        ELSEMATCH (ASSOCEDGEACTIONPARAM)
    1579        ELSEMATCH (ASSOCFACEACTIONPARAM)
    1580        ELSEMATCH (ASSOCOBJECTACTIONPARAM)
    1581        ELSEMATCH (ASSOCPATHACTIONPARAM)
    1582        ELSEMATCH (ASSOCVERTEXACTIONPARAM)
    1583        ELSEMATCH (ASSOCPATCHSURFACEACTIONBODY)
    1584        ELSEMATCH (ASSOCPLANESURFACEACTIONBODY)
    1585        ELSEMATCH (ASSOCEXTENDSURFACEACTIONBODY)
    1586        ELSEMATCH (ASSOCEXTRUDEDSURFACEACTIONBODY)
    1587        ELSEMATCH (ASSOCFILLETSURFACEACTIONBODY)
    1588        ELSEMATCH (ASSOCLOFTEDSURFACEACTIONBODY)
    1589        ELSEMATCH (ASSOCNETWORKSURFACEACTIONBODY)
    1590        ELSEMATCH (ASSOCOFFSETSURFACEACTIONBODY)
    1591        ELSEMATCH (ASSOCREVOLVEDSURFACEACTIONBODY)
    1592        ELSEMATCH (ASSOCSWEPTSURFACEACTIONBODY)
    1593        ELSEMATCH (ASSOCTRIMSURFACEACTIONBODY)
    1594        ELSEMATCH (ASSOCMLEADERACTIONBODY)
    1595        ELSEMATCH (ASSOC3POINTANGULARDIMACTIONBODY)
    1596        ELSEMATCH (ASSOCALIGNEDDIMACTIONBODY)
    1597        ELSEMATCH (ASSOCORDINATEDIMACTIONBODY)
    1598        ELSEMATCH (ASSOCROTATEDDIMACTIONBODY)
    1599        ELSEMATCH (BLOCKPARAMDEPENDENCYBODY)
    1600        ELSEMATCH (BLOCKBASEPOINTPARAMETER)
    1601        ELSEMATCH (BLOCKFLIPPARAMETER)
    1602        ELSEMATCH (BLOCKLINEARPARAMETER)
    1603        ELSEMATCH (BLOCKROTATIONPARAMETER)
    1604        ELSEMATCH (BLOCKXYPARAMETER)
    1605        ELSEMATCH (BLOCKVISIBILITYPARAMETER)
    1606        ELSEMATCH (BLOCKMOVEACTION)
    1607        ELSEMATCH (BLOCKSTRETCHACTION)
    1608        ELSEMATCH (BLOCKROTATEACTION)
    1609        ELSEMATCH (BLOCKVISIBILITYGRIP)
    1610        ELSEMATCH (BLOCKGRIPLOCATIONCOMPONENT)
    1611        ELSEMATCH (NAVISWORKSMODELDEF)
    1612      }
    1613    return found;
    1614  }
    1615  
    1616  static int
    1617  match_preR13_entities (const char *restrict filename,
    1618                         const Dwg_Data *restrict dwg, const bool blocks)
    1619  {
    1620    int found = 0;
    1621    char *text;
    1622  
    1623    // TODO skip block entities for now
    1624    if (blocks)
    1625      return found;
    1626    for (unsigned j = 0; j < dwg->num_objects; j++)
    1627      {
    1628        const Dwg_Object *obj = &dwg->object[j];
    1629        if (obj->fixedtype == DWG_TYPE_UNUSED)
    1630          continue;
    1631        if (verbose)
    1632          fprintf (stderr, "%s [%d]\n", obj->name, obj->index);
    1633        if (numtype) // search for allowed --type and skip if not
    1634          {
    1635            int typeok = 0;
    1636            for (int i = 0; i < numtype; i++)
    1637              {
    1638                if (obj->dxfname && !strcmp (type[i], obj->dxfname))
    1639                  {
    1640                    typeok = 1;
    1641                    break;
    1642                  }
    1643              }
    1644            if (!typeok) // next obj
    1645              continue;
    1646          }
    1647  
    1648        if (obj->fixedtype == DWG_TYPE_TEXT)
    1649          found += match_TEXT (filename, obj);
    1650  #ifdef WITH_SUBENTS
    1651        ELSEMATCH (ATTRIB)
    1652  #endif
    1653        ELSEMATCH (ATTDEF)
    1654        if (!opt_text)
    1655          {
    1656            if (obj->type == DWG_TYPE_DIMENSION_r11)
    1657              found += match_DIMENSION (filename, obj);
    1658            ELSEMATCH (VIEWPORT)
    1659            ELSEMATCH (BLOCK)
    1660          }
    1661        if (!opt_text)
    1662          {
    1663            // common entity names
    1664            MATCH_TABLE (ENTITY, layer, LAYER, 8);
    1665            MATCH_TABLE (ENTITY, ltype, LTYPE, 8);
    1666          }
    1667      }
    1668    return found;
    1669  }
    1670  
    1671  static int
    1672  match_BLOCK_HEADER (const char *restrict filename,
    1673                      Dwg_Object_Ref *restrict ref)
    1674  {
    1675    int found = 0;
    1676    const Dwg_Object *hdr;
    1677    const Dwg_Object *obj;
    1678    char *text;
    1679  
    1680    if (!ref)
    1681      return 0;
    1682    obj = hdr = ref->obj;
    1683    if (!hdr || hdr->supertype != DWG_SUPERTYPE_OBJECT
    1684        || hdr->type != DWG_TYPE_BLOCK_HEADER)
    1685      return 0;
    1686  
    1687    MATCH_OBJECT (BLOCK_HEADER, name, 2);
    1688    if (opt_tables)
    1689      return found;
    1690    MATCH_OBJECT (BLOCK_HEADER, xref_pname, 1);
    1691    MATCH_OBJECT (BLOCK_HEADER, description, 4);
    1692  
    1693    if (verbose)
    1694      fprintf (stderr, "HDR: %d, HANDLE: " FORMAT_RLLx "\n", hdr->index,
    1695               hdr->handle.value);
    1696    for (obj = get_first_owned_entity (hdr); obj;
    1697         obj = get_next_owned_entity (hdr, obj)) // without subentities
    1698      {
    1699        if (!obj)
    1700          break;
    1701        if (verbose)
    1702          fprintf (stderr, "%s [%d], HANDLE: " FORMAT_RLLx "\n", obj->name,
    1703                   obj->index, obj->handle.value);
    1704        if (numtype) // search for allowed --type and skip if not
    1705          {
    1706            int typeok = 0;
    1707            for (int i = 0; i < numtype; i++)
    1708              {
    1709                if (obj->dxfname && !strcmp (type[i], obj->dxfname))
    1710                  {
    1711                    typeok = 1;
    1712                    break;
    1713                  }
    1714              }
    1715            if (!typeok) // next obj
    1716              continue;
    1717          }
    1718  
    1719        if (obj->fixedtype == DWG_TYPE_TEXT)
    1720          found += match_TEXT (filename, obj);
    1721  #ifdef WITH_SUBENTS
    1722        ELSEMATCH (ATTRIB)
    1723  #endif
    1724        ELSEMATCH (ATTDEF)
    1725        ELSEMATCH (MTEXT)
    1726        ELSEMATCH (ARCALIGNEDTEXT)
    1727        else if (obj->fixedtype == DWG_TYPE_INSERT)
    1728        {
    1729  #ifndef WITH_SUBENTS
    1730          const Dwg_Data *dwg = obj->parent;
    1731          Dwg_Entity_INSERT *_obj = obj->tio.entity->tio.INSERT;
    1732          if (_obj->has_attribs)
    1733            {
    1734              if (dwg->header.version >= R_13b1 && dwg->header.version <= R_2000)
    1735                {
    1736                  Dwg_Object *last_attrib = _obj->last_attrib->obj;
    1737                  Dwg_Object *o
    1738                      = _obj->first_attrib ? _obj->first_attrib->obj : NULL;
    1739                  while (o && o->type == DWG_TYPE_ATTRIB)
    1740                    {
    1741                      found += match_ATTRIB (filename, o);
    1742                      o = dwg_next_entity (o);
    1743                      if (o == last_attrib)
    1744                        break;
    1745                    }
    1746                }
    1747              else if (dwg->header.version >= R_2004)
    1748                {
    1749                  Dwg_Object *o;
    1750                  for (BITCODE_BL j = 0; j < _obj->num_owned; j++)
    1751                    {
    1752                      o = _obj->attribs[j] ? _obj->attribs[j]->obj : NULL;
    1753                      if (o && o->type == DWG_TYPE_ATTRIB)
    1754                        found += match_ATTRIB (filename, o);
    1755                    }
    1756                }
    1757            }
    1758  #endif
    1759        }
    1760        else if (obj->fixedtype == DWG_TYPE_MINSERT)
    1761        {
    1762  #ifndef WITH_SUBENTS
    1763          const Dwg_Data *dwg = obj->parent;
    1764          Dwg_Entity_MINSERT *_obj = obj->tio.entity->tio.MINSERT;
    1765          if (_obj->has_attribs)
    1766            {
    1767              if (dwg->header.version >= R_13b1 && dwg->header.version <= R_2000)
    1768                {
    1769                  Dwg_Object *last_attrib = _obj->last_attrib->obj;
    1770                  Dwg_Object *o
    1771                      = _obj->first_attrib ? _obj->first_attrib->obj : NULL;
    1772                  while (o && o->type == DWG_TYPE_ATTRIB)
    1773                    {
    1774                      found += match_ATTRIB (filename, o);
    1775                      o = dwg_next_entity (o);
    1776                      if (o == last_attrib)
    1777                        break;
    1778                    }
    1779                }
    1780              else if (dwg->header.version >= R_2004)
    1781                {
    1782                  Dwg_Object *o;
    1783                  for (BITCODE_BL j = 0; j < _obj->num_owned; j++)
    1784                    {
    1785                      o = _obj->attribs[j] ? _obj->attribs[j]->obj : NULL;
    1786                      if (o && o->type == DWG_TYPE_ATTRIB)
    1787                        found += match_ATTRIB (filename, o);
    1788                    }
    1789                }
    1790            }
    1791  #endif
    1792        }
    1793        if (!opt_text)
    1794          {
    1795            if (obj->fixedtype == DWG_TYPE_DIMENSION_ORDINATE
    1796                || obj->fixedtype == DWG_TYPE_DIMENSION_LINEAR
    1797                || obj->fixedtype == DWG_TYPE_DIMENSION_ALIGNED
    1798                || obj->fixedtype == DWG_TYPE_DIMENSION_ANG3PT
    1799                || obj->fixedtype == DWG_TYPE_DIMENSION_ANG2LN
    1800                || obj->fixedtype == DWG_TYPE_DIMENSION_RADIUS
    1801                || obj->fixedtype == DWG_TYPE_DIMENSION_DIAMETER)
    1802              found += match_DIMENSION (filename, obj);
    1803            ELSEMATCH (VIEWPORT)
    1804            else if (obj->fixedtype == DWG_TYPE__3DSOLID
    1805                     || obj->fixedtype == DWG_TYPE_BODY
    1806                     || obj->fixedtype == DWG_TYPE_REGION) found
    1807                += match_3DSOLID (filename, obj);
    1808  
    1809            ELSEMATCH (BLOCK)
    1810            ELSEMATCH (HATCH)
    1811            ELSEMATCH (TOLERANCE)
    1812            ELSEMATCH (TABLE)
    1813            ELSEMATCH (GEOPOSITIONMARKER)
    1814            ELSEMATCH (LEADER)
    1815            ELSEMATCH (MULTILEADER)
    1816            ELSEMATCH (LIGHT)
    1817          }
    1818  
    1819        if (!opt_text)
    1820          {
    1821            // common entity names
    1822            MATCH_TABLE (ENTITY, layer, LAYER, 8);
    1823            MATCH_TABLE (ENTITY, ltype, LTYPE, 8);
    1824            if (obj->parent->header.version >= R_2000)
    1825              {
    1826                MATCH_TABLE (ENTITY, plotstyle, PLOTSTYLE, 8);
    1827              }
    1828            if (obj->parent->header.version >= R_2007)
    1829              {
    1830                MATCH_TABLE (ENTITY, material, MATERIAL, 8);
    1831                MATCH_TABLE (ENTITY, shadow, DICTIONARY, 8);
    1832              }
    1833            if (obj->parent->header.version >= R_2010)
    1834              {
    1835                MATCH_TABLE (ENTITY, full_visualstyle, VISUALSTYLE, 8);
    1836                MATCH_TABLE (ENTITY, face_visualstyle, VISUALSTYLE, 8);
    1837                MATCH_TABLE (ENTITY, edge_visualstyle, VISUALSTYLE, 8);
    1838              }
    1839          }
    1840      }
    1841    return found;
    1842  }
    1843  
    1844  int
    1845  main (int argc, char *argv[])
    1846  {
    1847    int error = 0;
    1848    int i = 1, j;
    1849    char *filename;
    1850    Dwg_Data dwg;
    1851    size_t plen;
    1852    int errcode;
    1853  #ifdef HAVE_PCRE2_H
    1854    PCRE2_SIZE erroffset;
    1855    int have_jit;
    1856  #  ifdef HAVE_PCRE2_16
    1857    BITCODE_TU pattern16;
    1858  #  endif
    1859  #endif
    1860    int opt_recurse = 0;
    1861    int count = 0;
    1862    int c;
    1863  #ifdef HAVE_GETOPT_LONG
    1864    int option_index = 0;
    1865    static struct option long_options[]
    1866        = { { "case", 0, 0, 'i' },      { "extended", 0, 0, 'x' },
    1867            { "count", 0, 0, 'c' },     { "no-filename", 0, 0, 'h' },
    1868            { "recursive", 0, 0, 'r' }, { "recursive", 0, 0, 'R' },
    1869            { "type", 1, 0, 'y' },      { "dxf", 1, 0, 'd' },
    1870            { "text", 0, 0, 't' },      { "blocks", 0, 0, 'b' },
    1871            { "tables", 0, 0, 0 },      { "help", 0, 0, 0 },
    1872            { "version", 0, 0, 0 },     { NULL, 0, NULL, 0 } };
    1873  #endif
    1874  
    1875    // check args
    1876    if (argc < 2)
    1877      return usage ();
    1878    memset (dxf, 0, 10 * sizeof (short));
    1879  
    1880    while
    1881  #ifdef HAVE_GETOPT_LONG
    1882        ((c = getopt_long (argc, argv, "ixchrRy:d:tb", long_options,
    1883                           &option_index))
    1884         != -1)
    1885  #else
    1886        ((c = getopt (argc, argv, "ixchrRy:d:tbvu")) != -1)
    1887  #endif
    1888      {
    1889        if (c == -1)
    1890          break;
    1891        switch (c)
    1892          {
    1893  #ifdef HAVE_GETOPT_LONG
    1894          case 0:
    1895            if (!strcmp (long_options[option_index].name, "help"))
    1896              return help ();
    1897            if (!strcmp (long_options[option_index].name, "version"))
    1898              return opt_version ();
    1899            if (!strcmp (long_options[option_index].name, "tables"))
    1900              opt_tables = 1;
    1901            break;
    1902  #else
    1903          case 'v':
    1904            return opt_version ();
    1905  #endif
    1906  #ifdef HAVE_PCRE2_H
    1907          case 'x':
    1908            options |= PCRE2_EXTENDED;
    1909            break;
    1910  #endif
    1911          case 'i':
    1912            options |= PCRE2_CASELESS;
    1913            break;
    1914          case 'c':
    1915            opt_count = 1;
    1916            break;
    1917          case 'h':
    1918            opt_filename = 0;
    1919            break;
    1920          case 'r':
    1921          case 'R':
    1922            opt_recurse = 1;
    1923            break;
    1924          case 't':
    1925            opt_text = 1;
    1926            break;
    1927          case 'b':
    1928            opt_blocks = 1;
    1929            break;
    1930          case 'y':
    1931            if (numtype >= 10)
    1932              return usage ();        // too many
    1933            type[numtype++] = optarg; // a string
    1934            break;
    1935          case 'd':
    1936            if (numdxf >= 10)
    1937              return usage (); // too many
    1938            // a integer group
    1939            dxf[numdxf++] = (short)strtol (optarg, NULL, 10);
    1940            break;
    1941  
    1942          case 'u':
    1943            return help ();
    1944          case '?':
    1945            fprintf (stderr, "%s: invalid option '-%c' ignored\n", argv[0],
    1946                     optopt);
    1947            break;
    1948          default:
    1949            return usage ();
    1950          }
    1951      }
    1952    i = optind;
    1953    if (i > argc - 2) // need 2 more args. TODO: unless -R given
    1954      return usage ();
    1955  
    1956    pattern = argv[i];
    1957    plen = strlen (pattern);
    1958  #ifdef HAVE_PCRE2_H
    1959    pcre2_config_8 (PCRE2_CONFIG_JIT, &have_jit);
    1960    ri8 = pcre2_compile_8 ((PCRE2_SPTR8)pattern, /* pattern */
    1961                           plen & 0xFFFFFFFF,    /* uint32_t */
    1962                           options,              /* options */
    1963                           &errcode,             /* errors */
    1964                           &erroffset,           /* error offset */
    1965  #  ifdef USE_MATCH_CONTEXT
    1966                           compile_context
    1967  #  else
    1968                           NULL
    1969  #  endif
    1970    );
    1971    if (errcode != 0 && errcode != 100)
    1972      {
    1973        pcre2_get_error_message_8 (errcode, (PCRE2_UCHAR8 *)buf, 4096);
    1974        // cppcheck-suppress preprocessorErrorDirective
    1975        LOG_ERROR ("pcre2_compile_8 error %d: %s with %s", errcode, buf,
    1976                   pattern);
    1977        return 1;
    1978      }
    1979    match_data8 = pcre2_match_data_create_from_pattern_8 (ri8, NULL);
    1980    if (have_jit)
    1981      pcre2_jit_compile_8 (ri8, PCRE2_JIT_COMPILE_OPTIONS);
    1982  
    1983  #  ifdef HAVE_PCRE2_16
    1984    pcre2_config_16 (PCRE2_CONFIG_JIT, &have_jit);
    1985    pattern16 = bit_utf8_to_TU (pattern, 0);
    1986    ri16 = pcre2_compile_16 ((PCRE2_SPTR16)pattern16, /* pattern */
    1987                             plen & 0xFFFFFFFF,       /* uint32_t */
    1988                             options,                 /* options */
    1989                             &errcode,                /* errors */
    1990                             &erroffset,              /* error offset */
    1991  #    ifdef USE_MATCH_CONTEXT
    1992                             compile_context
    1993  #    else
    1994                             NULL
    1995  #    endif
    1996    );
    1997    free (pattern16);
    1998    if (errcode != 0 && errcode != 100)
    1999      {
    2000        pcre2_get_error_message_8 (errcode, (PCRE2_UCHAR8 *)buf, 4096);
    2001        LOG_ERROR ("pcre2_compile_16 error %d: %s with %s", errcode, buf,
    2002                   pattern);
    2003        return 1;
    2004      }
    2005    match_data16 = pcre2_match_data_create_from_pattern_16 (ri16, NULL);
    2006    if (have_jit)
    2007      pcre2_jit_compile_16 (ri16, PCRE2_JIT_COMPILE_OPTIONS);
    2008  #  endif
    2009  #endif
    2010  
    2011    // for all filenames...
    2012    for (j = i + 1; j < argc; j++)
    2013      {
    2014        Dwg_Object_Ref *mspace_ref = NULL;
    2015        filename = argv[j];
    2016        memset (&dwg, 0, sizeof (Dwg_Data));
    2017        dwg.opts = 0;
    2018        error = dwg_read_file (filename, &dwg);
    2019        if (error > DWG_ERR_CRITICAL)
    2020          {
    2021            fprintf (stderr, "Error: Could not read DWG file %s, error: 0x%x\n",
    2022                     filename, error);
    2023            continue;
    2024          }
    2025  
    2026        if (!opt_text)
    2027          count += match_OBJECTS (filename, &dwg);
    2028        if (dwg.header.version < R_13b1)
    2029          { // FIXME hack
    2030            // mspace_ref = (Dwg_Object_Ref *)calloc (1, sizeof
    2031            // (Dwg_Object_Ref)); mspace_ref->obj = &dwg.object[0];
    2032            count += match_preR13_entities (filename, &dwg, false);
    2033          }
    2034        else
    2035          mspace_ref = dwg_model_space_ref (&dwg);
    2036  
    2037        if (!opt_tables)
    2038          count += match_BLOCK_HEADER (filename, mspace_ref);
    2039        if (opt_blocks)
    2040          {
    2041            if (dwg.header.version < R_13b1)
    2042              count += match_preR13_entities (filename, &dwg, true);
    2043            else
    2044              for (long k = 0; k < dwg.block_control.num_entries; k++)
    2045                {
    2046                  count += match_BLOCK_HEADER (filename,
    2047                                               dwg.block_control.entries[k]);
    2048                }
    2049          }
    2050        if (!opt_tables)
    2051          count += match_BLOCK_HEADER (filename, dwg_paper_space_ref (&dwg));
    2052  
    2053        fflush (stdout);
    2054        // if (dwg.header.version < R_13b1)
    2055        //   free (mspace_ref);
    2056        if (j < argc)
    2057          dwg_free (&dwg); // skip the last free
    2058      }
    2059    if (opt_count)
    2060      printf ("%d\n", count);
    2061  
    2062    return count ? 0 : 1;
    2063  }