1 /*****************************************************************************/
2 /* LibreDWG - free implementation of the DWG file format */
3 /* */
4 /* Copyright (C) 2018-2019 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 * dwglayers.c: print list of layers in a DWG
15 *
16 * written by Reini Urban
17 */
18
19 #include "../src/config.h"
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <assert.h>
24 #include "my_getopt.h"
25 #ifdef HAVE_VALGRIND_VALGRIND_H
26 # include <valgrind/valgrind.h>
27 #endif
28
29 #include <dwg.h>
30 #include "common.h"
31 #include "bits.h"
32 #include "logging.h"
33
34 static int
35 usage (void)
36 {
37 printf ("\nUsage: dwglayers [-f|--flags] [--on] <input_file.dwg>\n");
38 return 1;
39 }
40 static int
41 opt_version (void)
42 {
43 printf ("dwglayers %s\n", PACKAGE_VERSION);
44 return 0;
45 }
46 static int
47 help (void)
48 {
49 printf ("\nUsage: dwglayers [OPTION]... DWGFILE\n");
50 printf ("Print list of layers.\n"
51 "\n");
52 #ifdef HAVE_GETOPT_LONG
53 printf (" -x, --extnames prints EXTNAMES (r13-r14 only)\n"
54 " i.e. space instead of _\n");
55 printf (" -f, --flags prints also flags:\n"
56 " 3 chars for: f for frozen, + or - for ON or OFF, l "
57 "for locked\n");
58 printf (" -o, --on prints only ON layers\n");
59 printf (" -h, --help display this help and exit\n");
60 printf (" --version output version information and exit\n"
61 "\n");
62 #else
63 printf (" -x prints EXTNAMES (r13-r14 only)\n"
64 " i.e. space instead of _\n");
65 printf (" -f prints also flags:\n"
66 " 3 chars for: f for frozen, + or - for ON or OFF, l "
67 "for locked\n");
68 printf (" -o prints only ON layers\n");
69 printf (" -h display this help and exit\n");
70 printf (" -i output version information and exit\n"
71 "\n");
72 #endif
73 printf ("GNU LibreDWG online manual: "
74 "<https://www.gnu.org/software/libredwg/>\n");
75 return 0;
76 }
77
78 int
79 main (int argc, char *argv[])
80 {
81 int error;
82 long i = 1;
83 int flags = 0, on = 0, extnames = 0;
84 char *filename_in;
85 Dwg_Data dwg;
86 Dwg_Object *obj;
87 Dwg_Object_LAYER *layer;
88 Dwg_Object_LAYER_CONTROL *_ctrl;
89 int c;
90 #ifdef HAVE_GETOPT_LONG
91 int option_index = 0;
92 static struct option long_options[]
93 = { { "flags", 0, 0, 'f' }, { "extnames", 0, 0, 'x' },
94 { "on", 0, 0, 'o' }, { "help", 0, 0, 0 },
95 { "version", 0, 0, 0 }, { NULL, 0, NULL, 0 } };
96 #endif
97
98 while
99 #ifdef HAVE_GETOPT_LONG
100 ((c = getopt_long (argc, argv, "xfoh", long_options, &option_index))
101 != -1)
102 #else
103 ((c = getopt (argc, argv, "xfohi")) != -1)
104 #endif
105 {
106 if (c == -1)
107 break;
108 switch (c)
109 {
110 #ifdef HAVE_GETOPT_LONG
111 case 0:
112 if (!strcmp (long_options[option_index].name, "version"))
113 return opt_version ();
114 if (!strcmp (long_options[option_index].name, "help"))
115 return help ();
116 break;
117 #else
118 case 'i':
119 return opt_version ();
120 #endif
121 case 'x':
122 extnames = 1;
123 break;
124 case 'f':
125 flags = 1;
126 break;
127 case 'o':
128 on = 1;
129 break;
130 case 'h':
131 return help ();
132 case '?':
133 fprintf (stderr, "%s: invalid option '-%c' ignored\n", argv[0],
134 optopt);
135 break;
136 default:
137 return usage ();
138 }
139 }
140 i = optind;
141 if (i >= argc)
142 return usage ();
143
144 filename_in = argv[i];
145 memset (&dwg, 0, sizeof (Dwg_Data));
146 error = dwg_read_file (filename_in, &dwg);
147 if (error >= DWG_ERR_CRITICAL)
148 {
149 fprintf (stderr, "READ ERROR %s: 0x%x\n", filename_in, error);
150 goto done;
151 }
152
153 obj = dwg_get_first_object (&dwg, DWG_TYPE_LAYER_CONTROL);
154 if (!obj)
155 {
156 fprintf (stderr, "No layers found\n");
157 goto done;
158 }
159 _ctrl = obj->tio.object->tio.LAYER_CONTROL;
160 for (i = 0; i < _ctrl->num_entries; i++)
161 {
162 char *name;
163 assert (_ctrl->entries);
164 if (!_ctrl->entries[i]) // NULL BITCODE_H
165 continue;
166 obj = _ctrl->entries[i]->obj;
167 if (!obj || obj->type != DWG_TYPE_LAYER) // can be DICTIONARY also
168 continue;
169 assert (_ctrl->entries[i]->obj->tio.object);
170 layer = _ctrl->entries[i]->obj->tio.object->tio.LAYER;
171 if (on && (!layer->on || layer->frozen))
172 continue;
173 if (flags)
174 printf ("%s%s%s\t", layer->frozen ? "f" : " ", layer->on ? "+" : "-",
175 layer->locked ? "l" : " ");
176 if (extnames && dwg.header.from_version >= R_13b1
177 && dwg.header.from_version < R_2000)
178 {
179 if (!(name = dwg_find_table_extname (&dwg, obj)))
180 name = layer->name;
181 }
182 else
183 name = layer->name;
184 if (!name)
185 {
186 LOG_ERROR ("Invalid layer " FORMAT_RLLx " ignored, empty name",
187 _ctrl->entries[i]->obj->handle.value)
188 }
189 else
190 {
191 // since r2007 unicode, converted to utf-8
192 if (dwg.header.from_version >= R_2007)
193 {
194 char *utf8 = bit_convert_TU ((BITCODE_TU)name);
195 printf ("%s\n", utf8);
196 free (utf8);
197 }
198 else
199 printf ("%s\n", name);
200 }
201 fflush (stdout);
202 }
203
204 done:
205 // forget about valgrind. really huge DWG's need endlessly here.
206 if ((dwg.header.version && dwg.num_objects < 1000)
207 #if defined __SANITIZE_ADDRESS__ || __has_feature(address_sanitizer)
208 || 1
209 #endif
210 #ifdef HAVE_VALGRIND_VALGRIND_H
211 || (RUNNING_ON_VALGRIND)
212 #endif
213 )
214 dwg_free (&dwg);
215 return error >= DWG_ERR_CRITICAL ? 1 : 0;
216 }