* Makefile.am (HFILES): Remove cgen-ops.h and cgen-types.h.
[deliverable/binutils-gdb.git] / opcodes / i386-gen.c
CommitLineData
22da050b
L
1/* Copyright 2007, 2008, 2009
2 Free Software Foundation, Inc.
40b8e679 3
9b201bb5 4 This file is part of the GNU opcodes library.
40b8e679 5
9b201bb5 6 This library is free software; you can redistribute it and/or modify
40b8e679 7 it under the terms of the GNU General Public License as published by
9b201bb5
NC
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
40b8e679 10
9b201bb5
NC
11 It is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 License for more details.
40b8e679
L
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
9b201bb5
NC
18 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
40b8e679 20
40fb9820 21#include "sysdep.h"
40b8e679 22#include <stdio.h>
40b8e679
L
23#include <errno.h>
24#include "getopt.h"
25#include "libiberty.h"
c587b3f9 26#include "hashtab.h"
40b8e679
L
27#include "safe-ctype.h"
28
29#include "i386-opc.h"
30
31#include <libintl.h>
32#define _(String) gettext (String)
33
34static const char *program_name = NULL;
35static int debug = 0;
36
40fb9820
L
37typedef struct initializer
38{
39 const char *name;
40 const char *init;
41} initializer;
42
8acd5377 43static initializer cpu_flag_init[] =
40fb9820
L
44{
45 { "CPU_UNKNOWN_FLAGS",
8a9036a4 46 "~CpuL1OM" },
40fb9820
L
47 { "CPU_GENERIC32_FLAGS",
48 "Cpu186|Cpu286|Cpu386" },
49 { "CPU_GENERIC64_FLAGS",
309d3373 50 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuClflush|Cpu387|Cpu687|CpuMMX|CpuSSE|CpuSSE2|CpuLM" },
40fb9820
L
51 { "CPU_NONE_FLAGS",
52 "0" },
53 { "CPU_I186_FLAGS",
54 "Cpu186" },
55 { "CPU_I286_FLAGS",
56 "Cpu186|Cpu286" },
57 { "CPU_I386_FLAGS",
58 "Cpu186|Cpu286|Cpu386" },
59 { "CPU_I486_FLAGS",
60 "Cpu186|Cpu286|Cpu386|Cpu486" },
61 { "CPU_I586_FLAGS",
309d3373 62 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu387" },
40fb9820 63 { "CPU_I686_FLAGS",
309d3373 64 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|Cpu387|Cpu687" },
40fb9820 65 { "CPU_P2_FLAGS",
309d3373 66 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|Cpu387|Cpu687|CpuMMX" },
40fb9820 67 { "CPU_P3_FLAGS",
309d3373 68 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|Cpu387|Cpu687|CpuMMX|CpuSSE" },
40fb9820 69 { "CPU_P4_FLAGS",
309d3373 70 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuClflush|Cpu387|Cpu687|CpuMMX|CpuSSE|CpuSSE2" },
40fb9820 71 { "CPU_NOCONA_FLAGS",
309d3373 72 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuClflush|Cpu387|Cpu687|CpuFISTTP|CpuMMX|CpuSSE|CpuSSE2|CpuSSE3|CpuLM" },
40fb9820 73 { "CPU_CORE_FLAGS",
309d3373 74 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuClflush|Cpu387|Cpu687|CpuFISTTP|CpuMMX|CpuSSE|CpuSSE2|CpuSSE3" },
40fb9820 75 { "CPU_CORE2_FLAGS",
309d3373 76 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuClflush|Cpu387|Cpu687|CpuFISTTP|CpuMMX|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuLM" },
bd5295b2 77 { "CPU_COREI7_FLAGS",
309d3373 78 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuClflush|Cpu387|Cpu687|CpuFISTTP|CpuMMX|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuSSE4_1|CpuSSE4_2|CpuRdtscp|CpuLM" },
40fb9820 79 { "CPU_K6_FLAGS",
309d3373 80 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuSYSCALL|Cpu387|CpuMMX" },
40fb9820 81 { "CPU_K6_2_FLAGS",
309d3373 82 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuSYSCALL|Cpu387|CpuMMX|Cpu3dnow" },
40fb9820 83 { "CPU_ATHLON_FLAGS",
309d3373 84 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuSYSCALL|Cpu387|Cpu687|CpuMMX|Cpu3dnow|Cpu3dnowA" },
40fb9820 85 { "CPU_K8_FLAGS",
309d3373 86 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuSYSCALL|CpuRdtscp|Cpu387|Cpu687|CpuMMX|Cpu3dnow|Cpu3dnowA|CpuSSE|CpuSSE2|CpuLM" },
40fb9820 87 { "CPU_AMDFAM10_FLAGS",
309d3373
JB
88 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuSYSCALL|CpuRdtscp|Cpu387|Cpu687|CpuFISTTP|CpuMMX|Cpu3dnow|Cpu3dnowA|CpuSSE|CpuSSE2|CpuSSE3|CpuSSE4a|CpuABM|CpuLM" },
89 { "CPU_8087_FLAGS",
90 "Cpu8087" },
91 { "CPU_287_FLAGS",
92 "Cpu287" },
93 { "CPU_387_FLAGS",
94 "Cpu387" },
95 { "CPU_ANY87_FLAGS",
96 "Cpu8087|Cpu287|Cpu387|Cpu687|CpuFISTTP" },
bd5295b2
L
97 { "CPU_CLFLUSH_FLAGS",
98 "CpuClflush" },
99 { "CPU_SYSCALL_FLAGS",
100 "CpuSYSCALL" },
40fb9820
L
101 { "CPU_MMX_FLAGS",
102 "CpuMMX" },
103 { "CPU_SSE_FLAGS",
115c7c25 104 "CpuMMX|CpuSSE" },
40fb9820 105 { "CPU_SSE2_FLAGS",
115c7c25 106 "CpuMMX|CpuSSE|CpuSSE2" },
40fb9820 107 { "CPU_SSE3_FLAGS",
115c7c25 108 "CpuMMX|CpuSSE|CpuSSE2|CpuSSE3" },
40fb9820 109 { "CPU_SSSE3_FLAGS",
115c7c25 110 "CpuMMX|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3" },
40fb9820 111 { "CPU_SSE4_1_FLAGS",
115c7c25 112 "CpuMMX|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuSSE4_1" },
40fb9820 113 { "CPU_SSE4_2_FLAGS",
115c7c25 114 "CpuMMX|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuSSE4_1|CpuSSE4_2" },
309d3373
JB
115 { "CPU_ANY_SSE_FLAGS",
116 "CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuSSE4_1|CpuSSE4_2|CpuSSE4a|CpuAVX" },
6305a203
L
117 { "CPU_VMX_FLAGS",
118 "CpuVMX" },
119 { "CPU_SMX_FLAGS",
120 "CpuSMX" },
f03fe4c1
L
121 { "CPU_XSAVE_FLAGS",
122 "CpuXsave" },
c0f3af97
L
123 { "CPU_AES_FLAGS",
124 "CpuMMX|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuSSE4_1|CpuSSE4_2|CpuAES" },
594ab6a3
L
125 { "CPU_PCLMUL_FLAGS",
126 "CpuMMX|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuSSE4_1|CpuSSE4_2|CpuPCLMUL" },
c0f3af97
L
127 { "CPU_FMA_FLAGS",
128 "CpuMMX|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuSSE4_1|CpuSSE4_2|CpuAVX|CpuFMA" },
922d8de8
DR
129 { "CPU_FMA4_FLAGS",
130 "CpuMMX|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuSSE4_1|CpuSSE4_2|CpuAVX|CpuFMA4" },
f1f8f695
L
131 { "CPU_MOVBE_FLAGS",
132 "CpuMovbe" },
1b7f3fb0
L
133 { "CPU_RDTSCP_FLAGS",
134 "CpuRdtscp" },
f1f8f695
L
135 { "CPU_EPT_FLAGS",
136 "CpuEPT" },
40fb9820
L
137 { "CPU_3DNOW_FLAGS",
138 "CpuMMX|Cpu3dnow" },
139 { "CPU_3DNOWA_FLAGS",
115c7c25 140 "CpuMMX|Cpu3dnow|Cpu3dnowA" },
40fb9820
L
141 { "CPU_PADLOCK_FLAGS",
142 "CpuPadLock" },
143 { "CPU_SVME_FLAGS",
144 "CpuSVME" },
145 { "CPU_SSE4A_FLAGS",
115c7c25 146 "CpuMMX|CpuSSE|CpuSSE2|CpuSSE3|CpuSSE4a" },
40fb9820 147 { "CPU_ABM_FLAGS",
3629bb00 148 "CpuABM" },
c0f3af97
L
149 { "CPU_AVX_FLAGS",
150 "CpuMMX|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuSSE4_1|CpuSSE4_2|CpuAVX" },
309d3373
JB
151 { "CPU_ANY_AVX_FLAGS",
152 "CpuAVX" },
8a9036a4
L
153 { "CPU_L1OM_FLAGS",
154 "unknown" },
40fb9820
L
155};
156
8acd5377 157static initializer operand_type_init[] =
40fb9820
L
158{
159 { "OPERAND_TYPE_NONE",
160 "0" },
161 { "OPERAND_TYPE_REG8",
162 "Reg8" },
163 { "OPERAND_TYPE_REG16",
164 "Reg16" },
165 { "OPERAND_TYPE_REG32",
166 "Reg32" },
167 { "OPERAND_TYPE_REG64",
168 "Reg64" },
169 { "OPERAND_TYPE_IMM1",
170 "Imm1" },
171 { "OPERAND_TYPE_IMM8",
172 "Imm8" },
173 { "OPERAND_TYPE_IMM8S",
174 "Imm8S" },
175 { "OPERAND_TYPE_IMM16",
176 "Imm16" },
177 { "OPERAND_TYPE_IMM32",
178 "Imm32" },
179 { "OPERAND_TYPE_IMM32S",
180 "Imm32S" },
181 { "OPERAND_TYPE_IMM64",
182 "Imm64" },
183 { "OPERAND_TYPE_BASEINDEX",
184 "BaseIndex" },
185 { "OPERAND_TYPE_DISP8",
186 "Disp8" },
187 { "OPERAND_TYPE_DISP16",
188 "Disp16" },
189 { "OPERAND_TYPE_DISP32",
190 "Disp32" },
191 { "OPERAND_TYPE_DISP32S",
192 "Disp32S" },
193 { "OPERAND_TYPE_DISP64",
194 "Disp64" },
195 { "OPERAND_TYPE_INOUTPORTREG",
196 "InOutPortReg" },
197 { "OPERAND_TYPE_SHIFTCOUNT",
198 "ShiftCount" },
199 { "OPERAND_TYPE_CONTROL",
200 "Control" },
201 { "OPERAND_TYPE_TEST",
202 "Test" },
203 { "OPERAND_TYPE_DEBUG",
204 "FloatReg" },
205 { "OPERAND_TYPE_FLOATREG",
206 "FloatReg" },
207 { "OPERAND_TYPE_FLOATACC",
208 "FloatAcc" },
209 { "OPERAND_TYPE_SREG2",
210 "SReg2" },
211 { "OPERAND_TYPE_SREG3",
212 "SReg3" },
213 { "OPERAND_TYPE_ACC",
214 "Acc" },
215 { "OPERAND_TYPE_JUMPABSOLUTE",
216 "JumpAbsolute" },
217 { "OPERAND_TYPE_REGMMX",
218 "RegMMX" },
219 { "OPERAND_TYPE_REGXMM",
220 "RegXMM" },
c0f3af97
L
221 { "OPERAND_TYPE_REGYMM",
222 "RegYMM" },
40fb9820
L
223 { "OPERAND_TYPE_ESSEG",
224 "EsSeg" },
225 { "OPERAND_TYPE_ACC32",
7d5e4556 226 "Reg32|Acc|Dword" },
40fb9820 227 { "OPERAND_TYPE_ACC64",
7d5e4556 228 "Reg64|Acc|Qword" },
65da13b5
L
229 { "OPERAND_TYPE_INOUTPORTREG",
230 "InOutPortReg" },
40fb9820
L
231 { "OPERAND_TYPE_REG16_INOUTPORTREG",
232 "Reg16|InOutPortReg" },
233 { "OPERAND_TYPE_DISP16_32",
234 "Disp16|Disp32" },
235 { "OPERAND_TYPE_ANYDISP",
236 "Disp8|Disp16|Disp32|Disp32S|Disp64" },
237 { "OPERAND_TYPE_IMM16_32",
238 "Imm16|Imm32" },
239 { "OPERAND_TYPE_IMM16_32S",
240 "Imm16|Imm32S" },
241 { "OPERAND_TYPE_IMM16_32_32S",
242 "Imm16|Imm32|Imm32S" },
243 { "OPERAND_TYPE_IMM32_32S_DISP32",
244 "Imm32|Imm32S|Disp32" },
245 { "OPERAND_TYPE_IMM64_DISP64",
246 "Imm64|Disp64" },
247 { "OPERAND_TYPE_IMM32_32S_64_DISP32",
248 "Imm32|Imm32S|Imm64|Disp32" },
249 { "OPERAND_TYPE_IMM32_32S_64_DISP32_64",
250 "Imm32|Imm32S|Imm64|Disp32|Disp64" },
251};
252
253typedef struct bitfield
254{
255 int position;
256 int value;
257 const char *name;
258} bitfield;
259
260#define BITFIELD(n) { n, 0, #n }
261
262static bitfield cpu_flags[] =
263{
264 BITFIELD (Cpu186),
265 BITFIELD (Cpu286),
266 BITFIELD (Cpu386),
267 BITFIELD (Cpu486),
268 BITFIELD (Cpu586),
269 BITFIELD (Cpu686),
bd5295b2
L
270 BITFIELD (CpuClflush),
271 BITFIELD (CpuSYSCALL),
309d3373
JB
272 BITFIELD (Cpu8087),
273 BITFIELD (Cpu287),
274 BITFIELD (Cpu387),
275 BITFIELD (Cpu687),
276 BITFIELD (CpuFISTTP),
40fb9820 277 BITFIELD (CpuMMX),
40fb9820
L
278 BITFIELD (CpuSSE),
279 BITFIELD (CpuSSE2),
280 BITFIELD (CpuSSE3),
281 BITFIELD (CpuSSSE3),
282 BITFIELD (CpuSSE4_1),
283 BITFIELD (CpuSSE4_2),
c0f3af97 284 BITFIELD (CpuAVX),
8a9036a4 285 BITFIELD (CpuL1OM),
40fb9820
L
286 BITFIELD (CpuSSE4a),
287 BITFIELD (Cpu3dnow),
288 BITFIELD (Cpu3dnowA),
289 BITFIELD (CpuPadLock),
290 BITFIELD (CpuSVME),
291 BITFIELD (CpuVMX),
47dd174c 292 BITFIELD (CpuSMX),
40fb9820 293 BITFIELD (CpuABM),
475a2301 294 BITFIELD (CpuXsave),
c0f3af97 295 BITFIELD (CpuAES),
594ab6a3 296 BITFIELD (CpuPCLMUL),
c0f3af97 297 BITFIELD (CpuFMA),
922d8de8 298 BITFIELD (CpuFMA4),
c0f3af97 299 BITFIELD (CpuLM),
f1f8f695
L
300 BITFIELD (CpuMovbe),
301 BITFIELD (CpuEPT),
1b7f3fb0 302 BITFIELD (CpuRdtscp),
40fb9820
L
303 BITFIELD (Cpu64),
304 BITFIELD (CpuNo64),
305#ifdef CpuUnused
306 BITFIELD (CpuUnused),
307#endif
308};
309
310static bitfield opcode_modifiers[] =
311{
312 BITFIELD (D),
313 BITFIELD (W),
b6169b20 314 BITFIELD (S),
40fb9820
L
315 BITFIELD (Modrm),
316 BITFIELD (ShortForm),
317 BITFIELD (Jump),
318 BITFIELD (JumpDword),
319 BITFIELD (JumpByte),
320 BITFIELD (JumpInterSegment),
321 BITFIELD (FloatMF),
322 BITFIELD (FloatR),
323 BITFIELD (FloatD),
324 BITFIELD (Size16),
325 BITFIELD (Size32),
326 BITFIELD (Size64),
327 BITFIELD (IgnoreSize),
328 BITFIELD (DefaultSize),
329 BITFIELD (No_bSuf),
330 BITFIELD (No_wSuf),
331 BITFIELD (No_lSuf),
332 BITFIELD (No_sSuf),
333 BITFIELD (No_qSuf),
7ce189b3 334 BITFIELD (No_ldSuf),
40fb9820
L
335 BITFIELD (FWait),
336 BITFIELD (IsString),
337 BITFIELD (RegKludge),
e2ec9d29 338 BITFIELD (FirstXmm0),
c0f3af97 339 BITFIELD (Implicit1stXmm0),
ca61edf2
L
340 BITFIELD (ByteOkIntel),
341 BITFIELD (ToDword),
342 BITFIELD (ToQword),
343 BITFIELD (AddrPrefixOp0),
40fb9820
L
344 BITFIELD (IsPrefix),
345 BITFIELD (ImmExt),
346 BITFIELD (NoRex64),
347 BITFIELD (Rex64),
348 BITFIELD (Ugh),
c0f3af97 349 BITFIELD (Vex),
c0f3af97 350 BITFIELD (VexNDS),
03547503 351 BITFIELD (VexNDD),
c0f3af97
L
352 BITFIELD (VexW0),
353 BITFIELD (VexW1),
354 BITFIELD (Vex0F),
355 BITFIELD (Vex0F38),
356 BITFIELD (Vex0F3A),
357 BITFIELD (Vex3Sources),
358 BITFIELD (VexImmExt),
359 BITFIELD (SSE2AVX),
81f8a913 360 BITFIELD (NoAVX),
1efbbeb4
L
361 BITFIELD (OldGcc),
362 BITFIELD (ATTMnemonic),
e1d4d893 363 BITFIELD (ATTSyntax),
5c07affc 364 BITFIELD (IntelSyntax),
40fb9820
L
365};
366
367static bitfield operand_types[] =
368{
369 BITFIELD (Reg8),
370 BITFIELD (Reg16),
371 BITFIELD (Reg32),
372 BITFIELD (Reg64),
373 BITFIELD (FloatReg),
374 BITFIELD (RegMMX),
375 BITFIELD (RegXMM),
c0f3af97 376 BITFIELD (RegYMM),
40fb9820
L
377 BITFIELD (Imm8),
378 BITFIELD (Imm8S),
379 BITFIELD (Imm16),
380 BITFIELD (Imm32),
381 BITFIELD (Imm32S),
382 BITFIELD (Imm64),
383 BITFIELD (Imm1),
384 BITFIELD (BaseIndex),
385 BITFIELD (Disp8),
386 BITFIELD (Disp16),
387 BITFIELD (Disp32),
388 BITFIELD (Disp32S),
389 BITFIELD (Disp64),
390 BITFIELD (InOutPortReg),
391 BITFIELD (ShiftCount),
392 BITFIELD (Control),
393 BITFIELD (Debug),
394 BITFIELD (Test),
395 BITFIELD (SReg2),
396 BITFIELD (SReg3),
397 BITFIELD (Acc),
398 BITFIELD (FloatAcc),
399 BITFIELD (JumpAbsolute),
400 BITFIELD (EsSeg),
401 BITFIELD (RegMem),
5c07affc 402 BITFIELD (Mem),
7d5e4556
L
403 BITFIELD (Byte),
404 BITFIELD (Word),
405 BITFIELD (Dword),
406 BITFIELD (Fword),
407 BITFIELD (Qword),
408 BITFIELD (Tbyte),
409 BITFIELD (Xmmword),
c0f3af97 410 BITFIELD (Ymmword),
7d5e4556
L
411 BITFIELD (Unspecified),
412 BITFIELD (Anysize),
40fb9820
L
413#ifdef OTUnused
414 BITFIELD (OTUnused),
415#endif
416};
417
3d4d5afa
L
418static const char *filename;
419
40fb9820
L
420static int
421compare (const void *x, const void *y)
422{
423 const bitfield *xp = (const bitfield *) x;
424 const bitfield *yp = (const bitfield *) y;
425 return xp->position - yp->position;
426}
427
40b8e679
L
428static void
429fail (const char *message, ...)
430{
431 va_list args;
432
433 va_start (args, message);
434 fprintf (stderr, _("%s: Error: "), program_name);
435 vfprintf (stderr, message, args);
436 va_end (args);
437 xexit (1);
438}
439
72ffa0fb
L
440static void
441process_copyright (FILE *fp)
442{
443 fprintf (fp, "/* This file is automatically generated by i386-gen. Do not edit! */\n\
22da050b
L
444/* Copyright 2007, 2008, 2009\n\
445 Free Software Foundation, Inc.\n\
72ffa0fb
L
446\n\
447 This file is part of the GNU opcodes library.\n\
448\n\
449 This library is free software; you can redistribute it and/or modify\n\
450 it under the terms of the GNU General Public License as published by\n\
451 the Free Software Foundation; either version 3, or (at your option)\n\
452 any later version.\n\
453\n\
454 It is distributed in the hope that it will be useful, but WITHOUT\n\
455 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n\
456 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\n\
457 License for more details.\n\
458\n\
459 You should have received a copy of the GNU General Public License\n\
460 along with this program; if not, write to the Free Software\n\
461 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,\n\
462 MA 02110-1301, USA. */\n");
463}
464
40b8e679
L
465/* Remove leading white spaces. */
466
467static char *
468remove_leading_whitespaces (char *str)
469{
470 while (ISSPACE (*str))
471 str++;
472 return str;
473}
474
475/* Remove trailing white spaces. */
476
477static void
478remove_trailing_whitespaces (char *str)
479{
480 size_t last = strlen (str);
481
482 if (last == 0)
483 return;
484
485 do
486 {
487 last--;
488 if (ISSPACE (str [last]))
489 str[last] = '\0';
490 else
491 break;
492 }
493 while (last != 0);
494}
495
93b1ec2c 496/* Find next field separated by SEP and terminate it. Return a
40b8e679
L
497 pointer to the one after it. */
498
499static char *
c587b3f9 500next_field (char *str, char sep, char **next, char *last)
40b8e679
L
501{
502 char *p;
503
504 p = remove_leading_whitespaces (str);
93b1ec2c 505 for (str = p; *str != sep && *str != '\0'; str++);
40b8e679
L
506
507 *str = '\0';
508 remove_trailing_whitespaces (p);
509
510 *next = str + 1;
511
c587b3f9
L
512 if (p >= last)
513 abort ();
514
40b8e679
L
515 return p;
516}
517
40fb9820 518static void
8a9036a4
L
519set_bitfield (const char *f, bitfield *array, int value,
520 unsigned int size, int lineno)
40fb9820
L
521{
522 unsigned int i;
523
309d3373
JB
524 if (strcmp (f, "CpuFP") == 0)
525 {
8a9036a4
L
526 set_bitfield("Cpu387", array, value, size, lineno);
527 set_bitfield("Cpu287", array, value, size, lineno);
309d3373
JB
528 f = "Cpu8087";
529 }
530 else if (strcmp (f, "Mmword") == 0)
7d5e4556
L
531 f= "Qword";
532 else if (strcmp (f, "Oword") == 0)
533 f= "Xmmword";
40fb9820
L
534
535 for (i = 0; i < size; i++)
536 if (strcasecmp (array[i].name, f) == 0)
537 {
8a9036a4 538 array[i].value = value;
40fb9820
L
539 return;
540 }
541
2bf05e57
L
542 if (value)
543 {
544 const char *v = strchr (f, '=');
545
546 if (v)
547 {
548 size_t n = v - f;
549 char *end;
550
551 for (i = 0; i < size; i++)
552 if (strncasecmp (array[i].name, f, n) == 0)
553 {
554 value = strtol (v + 1, &end, 0);
555 if (*end == '\0')
556 {
557 array[i].value = value;
558 return;
559 }
560 break;
561 }
562 }
563 }
564
bd5295b2
L
565 if (lineno != -1)
566 fail (_("%s: %d: Unknown bitfield: %s\n"), filename, lineno, f);
567 else
568 fail (_("Unknown bitfield: %s\n"), f);
40fb9820
L
569}
570
571static void
572output_cpu_flags (FILE *table, bitfield *flags, unsigned int size,
573 int macro, const char *comma, const char *indent)
574{
575 unsigned int i;
576
577 fprintf (table, "%s{ { ", indent);
578
579 for (i = 0; i < size - 1; i++)
580 {
581 fprintf (table, "%d, ", flags[i].value);
582 if (((i + 1) % 20) == 0)
583 {
584 /* We need \\ for macro. */
585 if (macro)
586 fprintf (table, " \\\n %s", indent);
587 else
588 fprintf (table, "\n %s", indent);
589 }
590 }
591
592 fprintf (table, "%d } }%s\n", flags[i].value, comma);
593}
594
595static void
596process_i386_cpu_flag (FILE *table, char *flag, int macro,
bd5295b2
L
597 const char *comma, const char *indent,
598 int lineno)
40fb9820
L
599{
600 char *str, *next, *last;
8a9036a4 601 unsigned int i;
40fb9820
L
602 bitfield flags [ARRAY_SIZE (cpu_flags)];
603
604 /* Copy the default cpu flags. */
605 memcpy (flags, cpu_flags, sizeof (cpu_flags));
606
607 if (strcasecmp (flag, "unknown") == 0)
608 {
40fb9820 609 /* We turn on everything except for cpu64 in case of
8a9036a4
L
610 CPU_UNKNOWN_FLAGS. */
611 for (i = 0; i < ARRAY_SIZE (flags); i++)
612 if (flags[i].position != Cpu64)
613 flags[i].value = 1;
614 }
615 else if (flag[0] == '~')
616 {
617 last = flag + strlen (flag);
618
619 if (flag[1] == '(')
620 {
621 last -= 1;
622 next = flag + 2;
623 if (*last != ')')
624 fail (_("%s: %d: Missing `)' in bitfield: %s\n"), filename,
625 lineno, flag);
626 *last = '\0';
627 }
628 else
629 next = flag + 1;
630
631 /* First we turn on everything except for cpu64. */
40fb9820
L
632 for (i = 0; i < ARRAY_SIZE (flags); i++)
633 if (flags[i].position != Cpu64)
634 flags[i].value = 1;
8a9036a4
L
635
636 /* Turn off selective bits. */
637 for (; next && next < last; )
638 {
639 str = next_field (next, '|', &next, last);
640 if (str)
641 set_bitfield (str, flags, 0, ARRAY_SIZE (flags), lineno);
642 }
40fb9820
L
643 }
644 else if (strcmp (flag, "0"))
645 {
8a9036a4 646 /* Turn on selective bits. */
40fb9820
L
647 last = flag + strlen (flag);
648 for (next = flag; next && next < last; )
649 {
c587b3f9 650 str = next_field (next, '|', &next, last);
40fb9820 651 if (str)
8a9036a4 652 set_bitfield (str, flags, 1, ARRAY_SIZE (flags), lineno);
40fb9820
L
653 }
654 }
655
656 output_cpu_flags (table, flags, ARRAY_SIZE (flags), macro,
657 comma, indent);
658}
659
660static void
661output_opcode_modifier (FILE *table, bitfield *modifier, unsigned int size)
662{
663 unsigned int i;
664
665 fprintf (table, " { ");
666
667 for (i = 0; i < size - 1; i++)
668 {
669 fprintf (table, "%d, ", modifier[i].value);
670 if (((i + 1) % 20) == 0)
671 fprintf (table, "\n ");
672 }
673
674 fprintf (table, "%d },\n", modifier[i].value);
675}
676
677static void
bd5295b2 678process_i386_opcode_modifier (FILE *table, char *mod, int lineno)
40fb9820
L
679{
680 char *str, *next, *last;
681 bitfield modifiers [ARRAY_SIZE (opcode_modifiers)];
682
683 /* Copy the default opcode modifier. */
684 memcpy (modifiers, opcode_modifiers, sizeof (modifiers));
685
686 if (strcmp (mod, "0"))
687 {
688 last = mod + strlen (mod);
689 for (next = mod; next && next < last; )
690 {
c587b3f9 691 str = next_field (next, '|', &next, last);
40fb9820 692 if (str)
8a9036a4
L
693 set_bitfield (str, modifiers, 1, ARRAY_SIZE (modifiers),
694 lineno);
40fb9820
L
695 }
696 }
697 output_opcode_modifier (table, modifiers, ARRAY_SIZE (modifiers));
698}
699
700static void
701output_operand_type (FILE *table, bitfield *types, unsigned int size,
702 int macro, const char *indent)
703{
704 unsigned int i;
705
706 fprintf (table, "{ { ");
707
708 for (i = 0; i < size - 1; i++)
709 {
710 fprintf (table, "%d, ", types[i].value);
711 if (((i + 1) % 20) == 0)
712 {
713 /* We need \\ for macro. */
714 if (macro)
715 fprintf (table, "\\\n%s", indent);
716 else
717 fprintf (table, "\n%s", indent);
718 }
719 }
720
721 fprintf (table, "%d } }", types[i].value);
722}
723
724static void
725process_i386_operand_type (FILE *table, char *op, int macro,
bd5295b2 726 const char *indent, int lineno)
40fb9820
L
727{
728 char *str, *next, *last;
729 bitfield types [ARRAY_SIZE (operand_types)];
730
731 /* Copy the default operand type. */
732 memcpy (types, operand_types, sizeof (types));
733
734 if (strcmp (op, "0"))
735 {
736 last = op + strlen (op);
737 for (next = op; next && next < last; )
738 {
c587b3f9 739 str = next_field (next, '|', &next, last);
40fb9820 740 if (str)
8a9036a4 741 set_bitfield (str, types, 1, ARRAY_SIZE (types), lineno);
40fb9820
L
742 }
743 }
744 output_operand_type (table, types, ARRAY_SIZE (types), macro,
745 indent);
746}
747
c587b3f9
L
748static void
749output_i386_opcode (FILE *table, const char *name, char *str,
bd5295b2 750 char *last, int lineno)
c587b3f9
L
751{
752 unsigned int i;
753 char *operands, *base_opcode, *extension_opcode, *opcode_length;
754 char *cpu_flags, *opcode_modifier, *operand_types [MAX_OPERANDS];
755
756 /* Find number of operands. */
757 operands = next_field (str, ',', &str, last);
758
759 /* Find base_opcode. */
760 base_opcode = next_field (str, ',', &str, last);
761
762 /* Find extension_opcode. */
763 extension_opcode = next_field (str, ',', &str, last);
764
765 /* Find opcode_length. */
766 opcode_length = next_field (str, ',', &str, last);
767
768 /* Find cpu_flags. */
769 cpu_flags = next_field (str, ',', &str, last);
770
771 /* Find opcode_modifier. */
772 opcode_modifier = next_field (str, ',', &str, last);
773
774 /* Remove the first {. */
775 str = remove_leading_whitespaces (str);
776 if (*str != '{')
777 abort ();
778 str = remove_leading_whitespaces (str + 1);
779
780 i = strlen (str);
781
782 /* There are at least "X}". */
783 if (i < 2)
784 abort ();
785
786 /* Remove trailing white spaces and }. */
787 do
788 {
789 i--;
790 if (ISSPACE (str[i]) || str[i] == '}')
791 str[i] = '\0';
792 else
793 break;
794 }
795 while (i != 0);
796
797 last = str + i;
798
799 /* Find operand_types. */
800 for (i = 0; i < ARRAY_SIZE (operand_types); i++)
801 {
802 if (str >= last)
803 {
804 operand_types [i] = NULL;
805 break;
806 }
807
808 operand_types [i] = next_field (str, ',', &str, last);
809 if (*operand_types[i] == '0')
810 {
811 if (i != 0)
812 operand_types[i] = NULL;
813 break;
814 }
815 }
816
817 fprintf (table, " { \"%s\", %s, %s, %s, %s,\n",
818 name, operands, base_opcode, extension_opcode,
819 opcode_length);
820
bd5295b2 821 process_i386_cpu_flag (table, cpu_flags, 0, ",", " ", lineno);
c587b3f9 822
bd5295b2 823 process_i386_opcode_modifier (table, opcode_modifier, lineno);
c587b3f9
L
824
825 fprintf (table, " { ");
826
827 for (i = 0; i < ARRAY_SIZE (operand_types); i++)
828 {
829 if (operand_types[i] == NULL || *operand_types[i] == '0')
830 {
831 if (i == 0)
bd5295b2 832 process_i386_operand_type (table, "0", 0, "\t ", lineno);
c587b3f9
L
833 break;
834 }
835
836 if (i != 0)
837 fprintf (table, ",\n ");
838
839 process_i386_operand_type (table, operand_types[i], 0,
bd5295b2 840 "\t ", lineno);
c587b3f9
L
841 }
842 fprintf (table, " } },\n");
843}
844
845struct opcode_hash_entry
846{
847 struct opcode_hash_entry *next;
848 char *name;
849 char *opcode;
bd5295b2 850 int lineno;
c587b3f9
L
851};
852
853/* Calculate the hash value of an opcode hash entry P. */
854
855static hashval_t
856opcode_hash_hash (const void *p)
857{
858 struct opcode_hash_entry *entry = (struct opcode_hash_entry *) p;
859 return htab_hash_string (entry->name);
860}
861
862/* Compare a string Q against an opcode hash entry P. */
863
864static int
865opcode_hash_eq (const void *p, const void *q)
866{
867 struct opcode_hash_entry *entry = (struct opcode_hash_entry *) p;
868 const char *name = (const char *) q;
869 return strcmp (name, entry->name) == 0;
870}
871
40b8e679 872static void
72ffa0fb 873process_i386_opcodes (FILE *table)
40b8e679 874{
3d4d5afa 875 FILE *fp;
40b8e679 876 char buf[2048];
c587b3f9
L
877 unsigned int i, j;
878 char *str, *p, *last, *name;
879 struct opcode_hash_entry **hash_slot, **entry, *next;
880 htab_t opcode_hash_table;
881 struct opcode_hash_entry **opcode_array;
882 unsigned int opcode_array_size = 1024;
bd5295b2 883 int lineno = 0;
40b8e679 884
3d4d5afa
L
885 filename = "i386-opc.tbl";
886 fp = fopen (filename, "r");
887
40b8e679 888 if (fp == NULL)
34edb9ad 889 fail (_("can't find i386-opc.tbl for reading, errno = %s\n"),
40fb9820 890 xstrerror (errno));
40b8e679 891
c587b3f9
L
892 i = 0;
893 opcode_array = (struct opcode_hash_entry **)
894 xmalloc (sizeof (*opcode_array) * opcode_array_size);
895
896 opcode_hash_table = htab_create_alloc (16, opcode_hash_hash,
897 opcode_hash_eq, NULL,
898 xcalloc, free);
899
34edb9ad 900 fprintf (table, "\n/* i386 opcode table. */\n\n");
d3ce72d0 901 fprintf (table, "const insn_template i386_optab[] =\n{\n");
40b8e679 902
c587b3f9 903 /* Put everything on opcode array. */
40b8e679
L
904 while (!feof (fp))
905 {
906 if (fgets (buf, sizeof (buf), fp) == NULL)
907 break;
908
3d4d5afa
L
909 lineno++;
910
40b8e679
L
911 p = remove_leading_whitespaces (buf);
912
913 /* Skip comments. */
914 str = strstr (p, "//");
915 if (str != NULL)
916 str[0] = '\0';
917
918 /* Remove trailing white spaces. */
919 remove_trailing_whitespaces (p);
920
921 switch (p[0])
922 {
923 case '#':
c587b3f9 924 /* Ignore comments. */
40b8e679
L
925 case '\0':
926 continue;
927 break;
928 default:
929 break;
930 }
931
932 last = p + strlen (p);
933
934 /* Find name. */
c587b3f9 935 name = next_field (p, ',', &str, last);
40b8e679 936
c587b3f9
L
937 /* Get the slot in hash table. */
938 hash_slot = (struct opcode_hash_entry **)
939 htab_find_slot_with_hash (opcode_hash_table, name,
940 htab_hash_string (name),
941 INSERT);
40b8e679 942
c587b3f9 943 if (*hash_slot == NULL)
40b8e679 944 {
c587b3f9
L
945 /* It is the new one. Put it on opcode array. */
946 if (i >= opcode_array_size)
40b8e679 947 {
c587b3f9
L
948 /* Grow the opcode array when needed. */
949 opcode_array_size += 1024;
950 opcode_array = (struct opcode_hash_entry **)
951 xrealloc (opcode_array,
952 sizeof (*opcode_array) * opcode_array_size);
40b8e679
L
953 }
954
c587b3f9
L
955 opcode_array[i] = (struct opcode_hash_entry *)
956 xmalloc (sizeof (struct opcode_hash_entry));
957 opcode_array[i]->next = NULL;
958 opcode_array[i]->name = xstrdup (name);
959 opcode_array[i]->opcode = xstrdup (str);
bd5295b2 960 opcode_array[i]->lineno = lineno;
c587b3f9
L
961 *hash_slot = opcode_array[i];
962 i++;
40b8e679 963 }
c587b3f9 964 else
40b8e679 965 {
c587b3f9
L
966 /* Append it to the existing one. */
967 entry = hash_slot;
968 while ((*entry) != NULL)
969 entry = &(*entry)->next;
970 *entry = (struct opcode_hash_entry *)
971 xmalloc (sizeof (struct opcode_hash_entry));
972 (*entry)->next = NULL;
973 (*entry)->name = (*hash_slot)->name;
974 (*entry)->opcode = xstrdup (str);
bd5295b2 975 (*entry)->lineno = lineno;
c587b3f9
L
976 }
977 }
40b8e679 978
c587b3f9
L
979 /* Process opcode array. */
980 for (j = 0; j < i; j++)
981 {
982 for (next = opcode_array[j]; next; next = next->next)
983 {
984 name = next->name;
985 str = next->opcode;
bd5295b2 986 lineno = next->lineno;
c587b3f9 987 last = str + strlen (str);
bd5295b2 988 output_i386_opcode (table, name, str, last, lineno);
40b8e679 989 }
40b8e679
L
990 }
991
34edb9ad
L
992 fclose (fp);
993
4dffcebc 994 fprintf (table, " { NULL, 0, 0, 0, 0,\n");
40fb9820 995
bd5295b2 996 process_i386_cpu_flag (table, "0", 0, ",", " ", -1);
40fb9820 997
bd5295b2 998 process_i386_opcode_modifier (table, "0", -1);
40fb9820
L
999
1000 fprintf (table, " { ");
bd5295b2 1001 process_i386_operand_type (table, "0", 0, "\t ", -1);
40fb9820
L
1002 fprintf (table, " } }\n");
1003
34edb9ad 1004 fprintf (table, "};\n");
40b8e679
L
1005}
1006
1007static void
72ffa0fb 1008process_i386_registers (FILE *table)
40b8e679 1009{
3d4d5afa 1010 FILE *fp;
40b8e679
L
1011 char buf[2048];
1012 char *str, *p, *last;
1013 char *reg_name, *reg_type, *reg_flags, *reg_num;
a60de03c 1014 char *dw2_32_num, *dw2_64_num;
bd5295b2 1015 int lineno = 0;
40b8e679 1016
3d4d5afa
L
1017 filename = "i386-reg.tbl";
1018 fp = fopen (filename, "r");
40b8e679 1019 if (fp == NULL)
34edb9ad 1020 fail (_("can't find i386-reg.tbl for reading, errno = %s\n"),
40fb9820 1021 xstrerror (errno));
40b8e679 1022
34edb9ad
L
1023 fprintf (table, "\n/* i386 register table. */\n\n");
1024 fprintf (table, "const reg_entry i386_regtab[] =\n{\n");
40b8e679
L
1025
1026 while (!feof (fp))
1027 {
1028 if (fgets (buf, sizeof (buf), fp) == NULL)
1029 break;
1030
3d4d5afa
L
1031 lineno++;
1032
40b8e679
L
1033 p = remove_leading_whitespaces (buf);
1034
1035 /* Skip comments. */
1036 str = strstr (p, "//");
1037 if (str != NULL)
1038 str[0] = '\0';
1039
1040 /* Remove trailing white spaces. */
1041 remove_trailing_whitespaces (p);
1042
1043 switch (p[0])
1044 {
1045 case '#':
34edb9ad 1046 fprintf (table, "%s\n", p);
40b8e679
L
1047 case '\0':
1048 continue;
1049 break;
1050 default:
1051 break;
1052 }
1053
1054 last = p + strlen (p);
1055
1056 /* Find reg_name. */
c587b3f9 1057 reg_name = next_field (p, ',', &str, last);
40b8e679
L
1058
1059 /* Find reg_type. */
c587b3f9 1060 reg_type = next_field (str, ',', &str, last);
40b8e679
L
1061
1062 /* Find reg_flags. */
c587b3f9 1063 reg_flags = next_field (str, ',', &str, last);
40b8e679
L
1064
1065 /* Find reg_num. */
c587b3f9 1066 reg_num = next_field (str, ',', &str, last);
a60de03c 1067
40fb9820
L
1068 fprintf (table, " { \"%s\",\n ", reg_name);
1069
bd5295b2 1070 process_i386_operand_type (table, reg_type, 0, "\t", lineno);
40fb9820 1071
a60de03c 1072 /* Find 32-bit Dwarf2 register number. */
c587b3f9 1073 dw2_32_num = next_field (str, ',', &str, last);
a60de03c
JB
1074
1075 /* Find 64-bit Dwarf2 register number. */
c587b3f9 1076 dw2_64_num = next_field (str, ',', &str, last);
a60de03c
JB
1077
1078 fprintf (table, ",\n %s, %s, { %s, %s } },\n",
1079 reg_flags, reg_num, dw2_32_num, dw2_64_num);
40b8e679
L
1080 }
1081
34edb9ad
L
1082 fclose (fp);
1083
1084 fprintf (table, "};\n");
40b8e679 1085
34edb9ad 1086 fprintf (table, "\nconst unsigned int i386_regtab_size = ARRAY_SIZE (i386_regtab);\n");
40b8e679
L
1087}
1088
40fb9820
L
1089static void
1090process_i386_initializers (void)
1091{
1092 unsigned int i;
1093 FILE *fp = fopen ("i386-init.h", "w");
1094 char *init;
1095
1096 if (fp == NULL)
1097 fail (_("can't create i386-init.h, errno = %s\n"),
1098 xstrerror (errno));
1099
1100 process_copyright (fp);
1101
1102 for (i = 0; i < ARRAY_SIZE (cpu_flag_init); i++)
1103 {
1104 fprintf (fp, "\n#define %s \\\n", cpu_flag_init[i].name);
1105 init = xstrdup (cpu_flag_init[i].init);
bd5295b2 1106 process_i386_cpu_flag (fp, init, 1, "", " ", -1);
40fb9820
L
1107 free (init);
1108 }
1109
1110 for (i = 0; i < ARRAY_SIZE (operand_type_init); i++)
1111 {
1112 fprintf (fp, "\n\n#define %s \\\n ", operand_type_init[i].name);
1113 init = xstrdup (operand_type_init[i].init);
bd5295b2 1114 process_i386_operand_type (fp, init, 1, " ", -1);
40fb9820
L
1115 free (init);
1116 }
1117 fprintf (fp, "\n");
1118
1119 fclose (fp);
1120}
1121
40b8e679
L
1122/* Program options. */
1123#define OPTION_SRCDIR 200
1124
1125struct option long_options[] =
1126{
1127 {"srcdir", required_argument, NULL, OPTION_SRCDIR},
1128 {"debug", no_argument, NULL, 'd'},
1129 {"version", no_argument, NULL, 'V'},
1130 {"help", no_argument, NULL, 'h'},
1131 {0, no_argument, NULL, 0}
1132};
1133
1134static void
1135print_version (void)
1136{
1137 printf ("%s: version 1.0\n", program_name);
1138 xexit (0);
1139}
1140
1141static void
1142usage (FILE * stream, int status)
1143{
1144 fprintf (stream, "Usage: %s [-V | --version] [-d | --debug] [--srcdir=dirname] [--help]\n",
1145 program_name);
1146 xexit (status);
1147}
1148
1149int
1150main (int argc, char **argv)
1151{
1152 extern int chdir (char *);
1153 char *srcdir = NULL;
8b40d594 1154 int c;
72ffa0fb 1155 FILE *table;
40b8e679
L
1156
1157 program_name = *argv;
1158 xmalloc_set_program_name (program_name);
1159
1160 while ((c = getopt_long (argc, argv, "vVdh", long_options, 0)) != EOF)
1161 switch (c)
1162 {
1163 case OPTION_SRCDIR:
1164 srcdir = optarg;
1165 break;
1166 case 'V':
1167 case 'v':
1168 print_version ();
1169 break;
1170 case 'd':
1171 debug = 1;
1172 break;
1173 case 'h':
1174 case '?':
1175 usage (stderr, 0);
1176 default:
1177 case 0:
1178 break;
1179 }
1180
1181 if (optind != argc)
1182 usage (stdout, 1);
1183
1184 if (srcdir != NULL)
1185 if (chdir (srcdir) != 0)
1186 fail (_("unable to change directory to \"%s\", errno = %s\n"),
40fb9820
L
1187 srcdir, xstrerror (errno));
1188
1189 /* Check the unused bitfield in i386_cpu_flags. */
1190#ifndef CpuUnused
8b40d594
L
1191 c = CpuNumOfBits - CpuMax - 1;
1192 if (c)
1193 fail (_("%d unused bits in i386_cpu_flags.\n"), c);
40fb9820
L
1194#endif
1195
1196 /* Check the unused bitfield in i386_operand_type. */
1197#ifndef OTUnused
8b40d594
L
1198 c = OTNumOfBits - OTMax - 1;
1199 if (c)
1200 fail (_("%d unused bits in i386_operand_type.\n"), c);
40fb9820
L
1201#endif
1202
1203 qsort (cpu_flags, ARRAY_SIZE (cpu_flags), sizeof (cpu_flags [0]),
1204 compare);
1205
1206 qsort (opcode_modifiers, ARRAY_SIZE (opcode_modifiers),
1207 sizeof (opcode_modifiers [0]), compare);
1208
1209 qsort (operand_types, ARRAY_SIZE (operand_types),
1210 sizeof (operand_types [0]), compare);
40b8e679 1211
34edb9ad
L
1212 table = fopen ("i386-tbl.h", "w");
1213 if (table == NULL)
40fb9820
L
1214 fail (_("can't create i386-tbl.h, errno = %s\n"),
1215 xstrerror (errno));
34edb9ad 1216
72ffa0fb 1217 process_copyright (table);
40b8e679 1218
72ffa0fb
L
1219 process_i386_opcodes (table);
1220 process_i386_registers (table);
40fb9820 1221 process_i386_initializers ();
40b8e679 1222
34edb9ad
L
1223 fclose (table);
1224
40b8e679
L
1225 exit (0);
1226}
This page took 0.178004 seconds and 4 git commands to generate.