winapi_test 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887
  1. #!/usr/bin/perl -w
  2. # Copyright 2002 Patrik Stridvall
  3. #
  4. # This library is free software; you can redistribute it and/or
  5. # modify it under the terms of the GNU Lesser General Public
  6. # License as published by the Free Software Foundation; either
  7. # version 2.1 of the License, or (at your option) any later version.
  8. #
  9. # This library is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. # Lesser General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU Lesser General Public
  15. # License along with this library; if not, write to the Free Software
  16. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  17. #
  18. use strict;
  19. BEGIN {
  20. $0 =~ m%^(.*?/?tools)/winapi/winapi_test$%;
  21. require "$1/winapi/setup.pm";
  22. }
  23. use config qw(
  24. file_type files_skip files_filter
  25. $current_dir $wine_dir $winapi_dir
  26. );
  27. use output qw($output);
  28. use winapi_test_options qw($options);
  29. if($options->progress) {
  30. $output->enable_progress;
  31. } else {
  32. $output->disable_progress;
  33. }
  34. use c_parser;
  35. use tests qw($tests);
  36. use type;
  37. use util qw(replace_file);
  38. my $pointer_size = 4;
  39. my @tests = ();
  40. if ($options->pack) {
  41. push @tests, "pack";
  42. }
  43. my @files;
  44. {
  45. my %files;
  46. foreach my $test (@tests)
  47. {
  48. foreach my $test_dir ($tests->get_test_dirs($test))
  49. {
  50. foreach my $header ($tests->get_section($test_dir, $test, "header"))
  51. {
  52. if (!$files{$header})
  53. {
  54. push @files, "include/$header";
  55. $files{$header} = 1;
  56. }
  57. }
  58. }
  59. }
  60. }
  61. if (0) {
  62. my $file = "tests.dat";
  63. $file .= "2"; # FIXME: For tests
  64. open(OUT, "> $winapi_dir/$file") || die "Error: Can't open $winapi_dir/$file: $!\n";
  65. my $x = 0;
  66. my @test_dirs = $tests->get_test_dirs();
  67. foreach my $test_dir (@test_dirs) {
  68. print OUT "\n" if $x++;
  69. print OUT "%%%$test_dir\n";
  70. print OUT "\n";
  71. my $y = 0;
  72. my @tests = $tests->get_tests($test_dir);
  73. foreach my $test (@tests) {
  74. print OUT "\n" if $y++;
  75. print OUT "%%$test\n";
  76. print OUT "\n";
  77. my @types;
  78. my $z = 0;
  79. my @sections = $tests->get_sections($test_dir, $test);
  80. foreach my $section (@sections) {
  81. my @lines = $tests->get_section($test_dir, $test, $section);
  82. if ($section =~ /^(?:struct|type)$/) {
  83. foreach my $line (@lines) {
  84. push @types, $line;
  85. }
  86. next;
  87. }
  88. print OUT "\n" if $z++;
  89. print OUT "%$section\n";
  90. print OUT "\n";
  91. foreach my $line (@lines) {
  92. print OUT "$line\n";
  93. }
  94. }
  95. @types = sort { $x = $a; $y = $b; $x =~ s/^!//; $y =~ s/^!//; $x cmp $y } @types;
  96. print OUT "\n" if $z++;
  97. print OUT "%type\n";
  98. print OUT "\n";
  99. foreach my $type (@types) {
  100. print OUT "$type\n";
  101. }
  102. }
  103. }
  104. close(OUT);
  105. exit(0);
  106. }
  107. my %file2types;
  108. my $progress_output;
  109. my $progress_current = 0;
  110. my $progress_max = scalar(@files);
  111. ########################################################################
  112. # find_type
  113. my %type_name2type;
  114. my %defines = (
  115. "ANYSIZE_ARRAY" => 1,
  116. "CCHDEVICENAME" => 32,
  117. "CCHILDREN_TITLEBAR+1" => 6,
  118. "ELF_VENDOR_SIZE" => 4,
  119. "EXCEPTION_MAXIMUM_PARAMETERS" => 15,
  120. "HW_PROFILE_GUIDLEN" => 39,
  121. "IMAGE_NUMBEROF_DIRECTORY_ENTRIES" => 16,
  122. "IMAGE_SIZEOF_SHORT_NAME" => 8,
  123. "LF_FACESIZE" => 32,
  124. "LF_FULLFACESIZE" => 64,
  125. "MAXIMUM_SUPPORTED_EXTENSION" => 512,
  126. "MAX_GOPHER_DISPLAY_TEXT + 1" => 129,
  127. "MAX_GOPHER_LOCATOR_LENGTH + 1" => 654,
  128. "MAX_PATH" => 260,
  129. "MAX_PROFILE_LEN" => 80,
  130. "NUM_POINTS" => 3,
  131. "OFS_MAXPATHNAME" => 128,
  132. "SIZE_OF_80387_REGISTERS" => 80,
  133. "TOKEN_SOURCE_LENGTH" => 8,
  134. );
  135. my %align_kludge_reported = ("FILETIME" => 1, "LARGE_INTEGER" => 1);
  136. my %size_kludge_reported = ("FILETIME" => 1, "LARGE_INTEGER" => 1);
  137. my %size_parse_reported;
  138. sub _find_align_kind_size($) {
  139. my $type_name = shift;
  140. local $_ = $type_name;
  141. my $align;
  142. my $kind;
  143. my $size;
  144. if (/\*+$/) {
  145. $align = $pointer_size;
  146. $kind = "pointer";
  147. $size = $pointer_size;
  148. } elsif(/^char$/) {
  149. $align = 1;
  150. $kind = "char";
  151. $size = 1;
  152. } elsif(/^(?:(signed|unsigned)\s+)?(?:__int8|char|byte)$/) {
  153. $align = 1;
  154. $kind = defined($1) ? $1 : "signed";
  155. $size = 1;
  156. } elsif (/^(?:(signed|unsigned)\s+)?(?:__int16|short(?:\s+int)?)$/) {
  157. $align = 2;
  158. $kind = defined($1) ? $1 : "signed";
  159. $size = 2;
  160. } elsif (/^(?:wchar_t)$/) {
  161. $align = 2;
  162. $kind = "signed";
  163. $size = 2;
  164. } elsif (/^(signed|unsigned)$/) {
  165. $align = 4;
  166. $kind = defined($1) ? $1 : "signed";
  167. $size = 4;
  168. } elsif (/^(?:(signed|unsigned)\s+)?(?:__int32|int)$/) {
  169. $align = 4;
  170. $kind = defined($1) ? $1 : "signed";
  171. $size = 4;
  172. } elsif (/^(?:(signed|unsigned)\s+)?(?:long(?:\s+int)?)$/) {
  173. $align = $pointer_size;
  174. $kind = defined($1) ? $1 : "signed";
  175. $size = $pointer_size;
  176. } elsif (/^(?:float)$/) {
  177. $align = 4;
  178. $kind = "float";
  179. $size = 4;
  180. } elsif (/^(?:(signed|unsigned)\s+)?__int64$/) {
  181. $align = 8;
  182. $kind = defined($1) ? $1 : "signed";
  183. $size = 8;
  184. } elsif (/^(?:double|DOUBLE|DATE)$/) {
  185. $align = 8;
  186. $kind = "float";
  187. $size = 8;
  188. } elsif (/^(?:long\s+double)$/) {
  189. $align = 4;
  190. $kind = "float";
  191. $size = 12;
  192. } elsif (/^H(?:DC|BITMAP|BRUSH|ICON|INSTANCE|KEY|MENU|METAFILE|WND)$/) {
  193. $align = $pointer_size;
  194. $kind = "pointer";
  195. $size = $pointer_size;
  196. } elsif (/^LP(?:BYTE|CSTR|CWSTR|DWORD|STR|VOID|WSTR)$/) {
  197. $align = $pointer_size;
  198. $kind = "pointer";
  199. $size = $pointer_size;
  200. } elsif (/^(?:FILETIME)$/) {
  201. $align = 4;
  202. $kind = "struct";
  203. $size = 8;
  204. } elsif (/^GUID$/) {
  205. $align = 4;
  206. $kind = "struct";
  207. $size = 16;
  208. } elsif (/^(?:VOID)$/) {
  209. $align = 4;
  210. $kind = "signed";
  211. $size = 4;
  212. } elsif (/^(?:SHORT)$/) {
  213. $align = 2;
  214. $kind = "unsigned";
  215. $size = 2;
  216. } elsif (/^(?:BYTE)$/) {
  217. $align = 1;
  218. $kind = "unsigned";
  219. $size = 1;
  220. } elsif (/^(?:DWORD)$/) {
  221. $align = 4;
  222. $kind = "unsigned";
  223. $size = 4;
  224. } elsif (/^(?:WORD)$/) {
  225. $align = 2;
  226. $kind = "unsigned";
  227. $size = 2;
  228. } elsif (/^(?:INT64|LONG64|LONGLONG)$/) {
  229. $align = 8;
  230. $kind = "signed";
  231. $size = 8;
  232. } elsif (/^(?:UINT64|ULONG64|DWORD64|ULONGLONG|DWORDLONG)$/) {
  233. $align = 8;
  234. $kind = "unsigned";
  235. $size = 8;
  236. } elsif (/^(?:LARGE_INTEGER)$/) {
  237. $align = 8;
  238. $kind = "union";
  239. $size = 8;
  240. } elsif (/^(?:POINTS)$/) {
  241. $align = 2;
  242. $kind = "struct";
  243. $size = 4;
  244. } elsif (/^(struct|union)$/) {
  245. $kind = $1;
  246. if (!$size_parse_reported{$_}) {
  247. $output->write("$type_name: can't parse type\n");
  248. $size_parse_reported{$_} = 1;
  249. }
  250. } elsif (/^\w+\s*\((?:\s*CALLBACK|\s*NTAPI|\s*WINAPI)?\s*\*\s*\)\s*\(.*?\)$/) {
  251. $align = $pointer_size;
  252. $kind = "pointer";
  253. $size = $pointer_size;
  254. }
  255. my $align2;
  256. if (defined(my $type = $type_name2type{$pointer_size}{$_})) {
  257. $align2 = $type->align;
  258. }
  259. if (!defined($align)) {
  260. $align = $align2;
  261. } elsif (defined($align2) && !$align_kludge_reported{$_}) {
  262. $align_kludge_reported{$_} = 1;
  263. $output->write("$type_name: type needn't be kludged\n");
  264. }
  265. if (!defined($align)) {
  266. # $output->write("$type_name: can't find type\n");
  267. }
  268. my $size2;
  269. if (defined(my $type = $type_name2type{$pointer_size}{$_})) {
  270. $size2 = $type->size;
  271. }
  272. if (!defined($size)) {
  273. $size = $size2;
  274. } elsif (defined($size2) && !$size_kludge_reported{$_}) {
  275. $size_kludge_reported{$_} = 1;
  276. $output->write("$type_name: type needn't be kludged\n");
  277. }
  278. return ($align, $kind, $size);
  279. }
  280. sub find_align($) {
  281. my $type_name = shift;
  282. (my $align, my $kind, my $size) = _find_align_kind_size($type_name);
  283. return $align;
  284. }
  285. sub find_kind($) {
  286. my $type_name = shift;
  287. (my $align, my $kind, my $size) = _find_align_kind_size($type_name);
  288. return $kind;
  289. }
  290. sub find_size($) {
  291. my $type_name = shift;
  292. (my $align, my $kind, my $size) = _find_align_kind_size($type_name);
  293. return $size;
  294. }
  295. sub find_count($) {
  296. my $count = shift;
  297. return $defines{$count};
  298. }
  299. foreach my $file (@files) {
  300. $progress_current++;
  301. foreach my $ptr (4, 8) {
  302. $pointer_size = $ptr;
  303. {
  304. open(IN, "< $wine_dir/$file") || die "Error: Can't open $wine_dir/$file: $!\n";
  305. local $/ = undef;
  306. $_ = <IN>;
  307. close(IN);
  308. }
  309. my $max_line = 0;
  310. {
  311. local $_ = $_;
  312. while(s/^.*?\n//) { $max_line++; }
  313. if($_) { $max_line++; }
  314. }
  315. my $parser = new c_parser($file);
  316. my $line;
  317. my $type;
  318. my @packs = ();
  319. my @ifdefs = ();
  320. my $update_output = sub {
  321. my $progress = "";
  322. my $prefix = "";
  323. $progress .= "$file (file $progress_current of $progress_max" . sprintf ", %u-bit)", $pointer_size * 8;
  324. $prefix .= "$file: ";
  325. if(defined($line)) {
  326. $progress .= ": line $line of $max_line";
  327. }
  328. $output->progress($progress);
  329. $output->prefix($prefix);
  330. };
  331. &$update_output();
  332. my $found_line = sub {
  333. $line = shift;
  334. &$update_output;
  335. };
  336. $parser->set_found_line_callback($found_line);
  337. my $found_preprocessor = sub {
  338. my $begin_line = shift;
  339. my $begin_column = shift;
  340. my $preprocessor = shift;
  341. #print "found_preprocessor: $begin_line: [$_]\n";
  342. if ($preprocessor =~ /^\#\s*include\s+[\"<]pshpack(\d+)\.h[\">]$/) {
  343. push @packs, $1 unless @ifdefs && !$ifdefs[$#ifdefs];
  344. #print "found pack $1 on line $begin_line\n";
  345. } elsif($preprocessor =~ /^\#\s*include\s+[\"<]poppack\.h[\">]$/) {
  346. pop @packs unless @ifdefs && !$ifdefs[$#ifdefs];
  347. #print "found poppack on line $begin_line\n";
  348. } elsif ($preprocessor =~ /^\#\s*ifdef\s+_WIN64/) {
  349. push @ifdefs, ($pointer_size == 8);
  350. } elsif ($preprocessor =~ /^\#\s*ifndef\s+_WIN64/) {
  351. push @ifdefs, ($pointer_size == 4);
  352. } elsif ($preprocessor =~ /^\#\s*elif\s+defined(_WIN64)/) {
  353. $ifdefs[$#ifdefs] = ($pointer_size == 8);
  354. } elsif ($preprocessor =~ /^\#\s*ifdef\s/) {
  355. push @ifdefs, 2;
  356. } elsif ($preprocessor =~ /^\#\s*ifndef\s/) {
  357. push @ifdefs, 2;
  358. } elsif ($preprocessor =~ /^\#\s*if/) {
  359. push @ifdefs, 2;
  360. } elsif ($preprocessor =~ /^\#\s*else/) {
  361. $ifdefs[$#ifdefs] = $ifdefs[$#ifdefs] ^ 1;
  362. } elsif ($preprocessor =~ /^\#\s*elif/) {
  363. $ifdefs[$#ifdefs] = 2;
  364. } elsif ($preprocessor =~ /^\#\s*endif/) {
  365. pop @ifdefs;
  366. }
  367. return 1;
  368. };
  369. $parser->set_found_preprocessor_callback($found_preprocessor);
  370. my $found_type = sub {
  371. $type = shift;
  372. return if @ifdefs && !$ifdefs[$#ifdefs];
  373. &$update_output();
  374. my $name = $type->name;
  375. $file2types{$pointer_size}{$file}{$name} = $type;
  376. $type->set_find_align_callback(\&find_align);
  377. $type->set_find_kind_callback(\&find_kind);
  378. $type->set_find_size_callback(\&find_size);
  379. $type->set_find_count_callback(\&find_count);
  380. my $pack = $packs[$#packs];
  381. if (!defined($type->pack) && $type->kind =~ /^(?:struct|union)$/) {
  382. $type->pack($pack);
  383. }
  384. my $size = $type->size();
  385. if (defined($size)) {
  386. my $max_field_base_size = 0;
  387. foreach my $field ($type->fields()) {
  388. my $field_type_name = $field->type_name;
  389. my $field_name = $field->name;
  390. my $field_size = $field->size;
  391. my $field_base_size = $field->base_size;
  392. my $field_offset = $field->offset;
  393. my $field_align = $field->align;
  394. # $output->write("$name: $field_type_name: $field_name: $field_offset: $field_size($field_base_size): $field_align\n");
  395. }
  396. # $output->write("$name: $size\n");
  397. $type_name2type{$pointer_size}{$name} = $type;
  398. } else {
  399. # $output->write("$name: can't find size\n");
  400. }
  401. return 1;
  402. };
  403. $parser->set_found_type_callback($found_type);
  404. {
  405. my $line = 1;
  406. my $column = 0;
  407. if(!$parser->parse_c_file(\$_, \$line, \$column)) {
  408. $output->write("can't parse file\n");
  409. }
  410. }
  411. $output->prefix("");
  412. }
  413. }
  414. ########################################################################
  415. # output_header
  416. sub output_header($$$) {
  417. local *OUT = shift;
  418. my $test_dir = shift;
  419. my @tests = @{(shift)};
  420. print OUT "/* File generated automatically from tools/winapi/tests.dat; do not edit! */\n";
  421. print OUT "/* This file can be copied, modified and distributed without restriction. */\n";
  422. print OUT "\n";
  423. print OUT "/*\n";
  424. foreach my $test (@tests) {
  425. my @description = $tests->get_section($test_dir, $test, "description");
  426. foreach my $description (@description) {
  427. print OUT " * $description\n";
  428. }
  429. }
  430. print OUT " */\n";
  431. print OUT "\n";
  432. print OUT "#define WINE_NOWINSOCK\n";
  433. print OUT "\n";
  434. foreach my $test (@tests) {
  435. my @includes = $tests->get_section($test_dir, $test, "include");
  436. foreach my $include (@includes) {
  437. print OUT "#include $include\n";
  438. }
  439. }
  440. print OUT "\n";
  441. print OUT "#include \"wine/test.h\"\n";
  442. print OUT "\n";
  443. print OUT "/***********************************************************************\n";
  444. print OUT " * Compatibility macros\n";
  445. print OUT " */\n";
  446. print OUT "\n";
  447. print OUT "#define DWORD_PTR UINT_PTR\n";
  448. print OUT "#define LONG_PTR INT_PTR\n";
  449. print OUT "#define ULONG_PTR UINT_PTR\n";
  450. print OUT "\n";
  451. print OUT "/***********************************************************************\n";
  452. print OUT " * Windows API extension\n";
  453. print OUT " */\n";
  454. print OUT "\n";
  455. print OUT "#if defined(_MSC_VER) && (_MSC_VER >= 1300) && defined(__cplusplus)\n";
  456. print OUT "# define _TYPE_ALIGNMENT(type) __alignof(type)\n";
  457. print OUT "#elif defined(__GNUC__)\n";
  458. print OUT "# define _TYPE_ALIGNMENT(type) __alignof__(type)\n";
  459. print OUT "#else\n";
  460. print OUT "/*\n";
  461. print OUT " * FIXME: May not be possible without a compiler extension\n";
  462. print OUT " * (if type is not just a name that is, otherwise the normal\n";
  463. print OUT " * TYPE_ALIGNMENT can be used)\n";
  464. print OUT " */\n";
  465. print OUT "#endif\n";
  466. print OUT "\n";
  467. print OUT "#if defined(TYPE_ALIGNMENT) && defined(_MSC_VER) && _MSC_VER >= 800 && !defined(__cplusplus)\n";
  468. print OUT "#pragma warning(disable:4116)\n";
  469. print OUT "#endif\n";
  470. print OUT "\n";
  471. print OUT "#if !defined(TYPE_ALIGNMENT) && defined(_TYPE_ALIGNMENT)\n";
  472. print OUT "# define TYPE_ALIGNMENT _TYPE_ALIGNMENT\n";
  473. print OUT "#endif\n";
  474. print OUT "\n";
  475. print OUT "/***********************************************************************\n";
  476. print OUT " * Test helper macros\n";
  477. print OUT " */\n";
  478. print OUT "\n";
  479. print OUT "#define TEST_TYPE_SIZE(type, size) C_ASSERT(sizeof(type) == size);\n";
  480. print OUT "\n";
  481. print OUT "#ifdef TYPE_ALIGNMENT\n";
  482. print OUT "# define TEST_TYPE_ALIGN(type, align) C_ASSERT(TYPE_ALIGNMENT(type) == align);\n";
  483. print OUT "#else\n";
  484. print OUT "# define TEST_TYPE_ALIGN(type, align)\n";
  485. print OUT "#endif\n";
  486. print OUT "\n";
  487. print OUT "#ifdef _TYPE_ALIGNMENT\n";
  488. print OUT "# define TEST_TARGET_ALIGN(type, align) C_ASSERT(_TYPE_ALIGNMENT(*(type)0) == align);\n";
  489. print OUT "# define TEST_FIELD_ALIGN(type, field, align) C_ASSERT(_TYPE_ALIGNMENT(((type*)0)->field) == align);\n";
  490. print OUT "#else\n";
  491. print OUT "# define TEST_TARGET_ALIGN(type, align)\n";
  492. print OUT "# define TEST_FIELD_ALIGN(type, field, align)\n";
  493. print OUT "#endif\n";
  494. print OUT "\n";
  495. print OUT "#define TEST_FIELD_OFFSET(type, field, offset) C_ASSERT(FIELD_OFFSET(type, field) == offset);\n";
  496. print OUT "\n";
  497. print OUT "#define TEST_TARGET_SIZE(type, size) TEST_TYPE_SIZE(*(type)0, size)\n";
  498. print OUT "#define TEST_FIELD_SIZE(type, field, size) TEST_TYPE_SIZE((((type*)0)->field), size)\n";
  499. print OUT "#define TEST_TYPE_SIGNED(type) C_ASSERT((type) -1 < 0);\n";
  500. print OUT "#define TEST_TYPE_UNSIGNED(type) C_ASSERT((type) -1 > 0);\n";
  501. print OUT "\n";
  502. print OUT "\n";
  503. }
  504. ########################################################################
  505. # output_footer
  506. sub output_footer($$$) {
  507. local *OUT = shift;
  508. my $test_dir = shift;
  509. my @tests = @{(shift)};
  510. print OUT "START_TEST(generated)\n";
  511. print OUT "{\n";
  512. foreach my $test (@tests) {
  513. print OUT " test_$test();\n";
  514. }
  515. print OUT "}\n";
  516. }
  517. ########################################################################
  518. # output_test_pack_type
  519. sub output_test_pack_type($$$$$$) {
  520. local *OUT = shift;
  521. my $type_name2type = shift;
  522. my $type_name2optional = shift;
  523. my $type_name2optional_fields = shift;
  524. my $type_name = shift;
  525. my $type = shift;
  526. my $optional_fields = $$type_name2optional_fields{$type_name};
  527. my $type_align = $type->align;
  528. my $type_pack = $type->pack;
  529. my $type_size = $type->size;
  530. my $type_kind = $type->kind;
  531. if (defined($type_pack)) {
  532. print OUT " /* $type_name (pack $type_pack) */\n";
  533. } else {
  534. print OUT " /* $type_name */\n";
  535. }
  536. if (!scalar(keys(%$optional_fields)) && defined($type_align) && defined($type_size)) {
  537. print OUT " TEST_TYPE_SIZE ($type_name, $type_size)\n";
  538. print OUT " TEST_TYPE_ALIGN ($type_name, $type_align)\n";
  539. }
  540. if ($type_kind eq "float") {
  541. # Nothing
  542. } elsif ($type_kind eq "pointer") {
  543. my $dereference_type;
  544. $dereference_type = sub {
  545. my $type = shift;
  546. my @fields = $type->fields;
  547. my $type_name2 =$fields[0]->type_name;
  548. if ($type_name2 =~ s/\s*\*$//) {
  549. my $type2 = $$type_name2type{$type_name2};
  550. if (defined($type2)) {
  551. return $type2;
  552. } else {
  553. if ($type_name2 !~ /^(?:PVOID|VOID|void)$/) {
  554. $output->write("$type_name2: warning: type not found 1\n");
  555. }
  556. return undef;
  557. }
  558. } elsif ($type_name2 =~ /^\w+$/) {
  559. my $type2 = $$type_name2type{$type_name2};
  560. if (defined($type2)) {
  561. return &$dereference_type($type2);
  562. } else {
  563. $output->write("$type_name2: warning: type not found\n");
  564. return undef;
  565. }
  566. } elsif ($type_name2 =~ /^\w+\s*\((?:\s*CALLBACK|\s*NTAPI|\s*WINAPI)?\s*\*\s*\)\s*\(.*?\)$/) {
  567. return undef;
  568. } else {
  569. $output->write("$type_name2: warning: type can't be parsed\n");
  570. return undef;
  571. }
  572. };
  573. my $type2 = &$dereference_type($type);
  574. if (defined($type2)) {
  575. my $type_name2 = $type2->name;
  576. my $type_align2 = $type2->align;
  577. my $type_size2 = $type2->size;
  578. my $optional = $$type_name2optional{$type_name};
  579. my $optional_fields2 = $$type_name2optional_fields{$type_name2};
  580. if (!$optional && !scalar(keys(%$optional_fields2)) && defined($type_align2) && defined($type_size2)) {
  581. print OUT " TEST_TARGET_SIZE ($type_name, $type_size2)\n";
  582. print OUT " TEST_TARGET_ALIGN($type_name, $type_align2)\n";
  583. } else {
  584. # $output->write("$type_name: warning: type size not found\n");
  585. }
  586. }
  587. } elsif ($type_kind eq "signed") {
  588. print OUT " TEST_TYPE_SIGNED($type_name)\n";
  589. } elsif ($type_kind eq "unsigned") {
  590. print OUT " TEST_TYPE_UNSIGNED($type_name)\n";
  591. }
  592. }
  593. sub output_test_pack_fields($$$$$$$);
  594. sub output_test_pack_fields($$$$$$$) {
  595. local *OUT = shift;
  596. my $type_name2type = shift;
  597. my $type_name2optional = shift;
  598. my $type_name2optional_fields = shift;
  599. my $type_name = shift;
  600. my $type = shift;
  601. my $offset = shift;
  602. my $optional_fields = $$type_name2optional_fields{$type_name};
  603. foreach my $field ($type->fields()) {
  604. my $field_type_name = $field->type_name;
  605. $field_type_name =~ s/\s+DECLSPEC_ALIGN\(\d+\)//;
  606. my $field_name = $field->name;
  607. my $field_size = $field->size;
  608. my $field_offset = $field->offset;
  609. my $field_align = $field->align;
  610. next if $field_name eq "" || (defined($field_size) && $field_size < 0);
  611. # We cannot take the address of a bitfield with MSVC
  612. next if ($field_type_name =~ /:/);
  613. if ($$optional_fields{$field_name}) {
  614. # Nothing
  615. } elsif (defined($field_size) && defined($field_offset)) {
  616. $field_offset += $offset;
  617. if ($field_name eq "DUMMYSTRUCTNAME") {
  618. print OUT "#ifdef NONAMELESSSTRUCT\n";
  619. print OUT " TEST_TYPE_SIZE ($type_name.$field_name, $field_size)\n";
  620. print OUT " TEST_FIELD_ALIGN ($type_name, $field_name, $field_align)\n";
  621. print OUT " TEST_FIELD_OFFSET($type_name, $field_name, $field_offset)\n";
  622. print OUT "#else\n";
  623. output_test_pack_fields(\*OUT, $type_name2type, $type_name2optional, $type_name2optional_fields,
  624. $type_name, $$type_name2type{$field_type_name}, $field_offset);
  625. print OUT "#endif\n";
  626. } else {
  627. print OUT " TEST_FIELD_SIZE ($type_name, $field_name, $field_size)\n";
  628. print OUT " TEST_FIELD_ALIGN ($type_name, $field_name, $field_align)\n";
  629. print OUT " TEST_FIELD_OFFSET($type_name, $field_name, $field_offset)\n";
  630. }
  631. } else {
  632. # $output->write("$type_name: $field_type_name: $field_name: test not generated (offset not defined)\n");
  633. }
  634. }
  635. }
  636. ########################################################################
  637. # output_test_pack
  638. sub output_test_pack($$$$) {
  639. local *OUT = shift;
  640. my $test_dir = shift;
  641. my $test = shift;
  642. my $type_names_used = shift;
  643. $output->prefix("$test_dir: $test: ");
  644. my @headers = $tests->get_section($test_dir, $test, "header");
  645. my @type_names = $tests->get_section($test_dir, $test, "type");
  646. my %type_name2optional;
  647. my %type_name2optional_fields;
  648. foreach my $_type_name (@type_names) {
  649. my $type_name = $_type_name;
  650. if ($type_name =~ s/^!//) {
  651. $type_name2optional{$type_name}++;
  652. }
  653. my $optional_fields = {};
  654. if ($type_name =~ s/:\s*(.*?)$//) {
  655. my @fields = split /\s+/, $1;
  656. foreach my $field (@fields) {
  657. if ($field =~ s/^!//) {
  658. $$optional_fields{$field}++;
  659. }
  660. }
  661. }
  662. $type_name2optional_fields{$type_name} = $optional_fields;
  663. }
  664. foreach my $header (@headers) {
  665. my $type_name2type = $file2types{$pointer_size}{"include/$header"};
  666. foreach my $_type_name (@type_names) {
  667. my $type_name = $_type_name;
  668. my $skip = ($type_name =~ s/^!//);
  669. $type_name =~ s/:.*?$//;
  670. my $type = $$type_name2type{$type_name};
  671. if (!defined($type)) {
  672. next;
  673. }
  674. $$type_names_used{$type_name} = $skip ? -1 : 1;
  675. next if $skip;
  676. print OUT "static void test_${test}_$type_name(void)\n";
  677. print OUT "{\n";
  678. output_test_pack_type(\*OUT, $type_name2type, \%type_name2optional, \%type_name2optional_fields,
  679. $type_name, $type);
  680. output_test_pack_fields(\*OUT, $type_name2type, \%type_name2optional, \%type_name2optional_fields,
  681. $type_name, $type, 0);
  682. print OUT "}\n";
  683. print OUT "\n";
  684. }
  685. }
  686. }
  687. ########################################################################
  688. # output_file
  689. sub output_file($$$$) {
  690. local *OUT = shift;
  691. my $test_dir = shift;
  692. my @tests = @{(shift)};
  693. my $type_names_used = shift;
  694. output_header(\*OUT, $test_dir, \@tests);
  695. foreach my $test (@tests) {
  696. my %type_names_used2;
  697. if ($test eq "pack") {
  698. print OUT "#ifdef _WIN64\n\n";
  699. $pointer_size = 8;
  700. output_test_pack(\*OUT, $test_dir, $test, \%type_names_used2);
  701. print OUT "#else /* _WIN64 */\n\n";
  702. $pointer_size = 4;
  703. output_test_pack(\*OUT, $test_dir, $test, \%type_names_used2);
  704. print OUT "#endif /* _WIN64 */\n\n";
  705. } else {
  706. die "no such test ($test)\n";
  707. }
  708. print OUT "static void test_$test(void)\n";
  709. print OUT "{\n";
  710. foreach my $type_name (sort(keys(%type_names_used2))) {
  711. $$type_names_used{$type_name} = $type_names_used2{$type_name};
  712. if ($type_names_used2{$type_name} > 0) {
  713. print OUT " test_${test}_$type_name();\n";
  714. }
  715. }
  716. print OUT "}\n";
  717. print OUT "\n";
  718. }
  719. output_footer(\*OUT, $test_dir, \@tests);
  720. return 1;
  721. }
  722. ########################################################################
  723. # main
  724. my %type_names_used = ();
  725. my @test_dirs = $tests->get_test_dirs();
  726. foreach my $test_dir (@test_dirs) {
  727. my $file = "$wine_dir/$test_dir/generated.c";
  728. replace_file($file, \&output_file, $test_dir, \@tests, \%type_names_used);
  729. }
  730. foreach my $header (sort(keys(%{$file2types{$pointer_size}}))) {
  731. $output->prefix("$header: ");
  732. $header =~ s%^include/%%;
  733. my $type_name2type = $file2types{$pointer_size}{"include/$header"};
  734. foreach my $_type_name (sort(keys(%$type_name2type))) {
  735. my $type_name = $_type_name;
  736. if (!exists($type_names_used{$type_name})) {
  737. $output->write("$type_name: type not used\n");
  738. }
  739. }
  740. }
  741. $output->prefix("$winapi_dir/tests.dat: ");
  742. foreach my $type_name (sort(keys(%type_names_used))) {
  743. my $found = 0;
  744. foreach my $header (sort(keys(%{$file2types{$pointer_size}}))) {
  745. my $type_name2type = $file2types{$pointer_size}{"include/$header"};
  746. if (exists($type_name2type{$type_name})) {
  747. $found = 1;
  748. }
  749. }
  750. if (!$found) {
  751. $output->write("$type_name: type not used\n");
  752. }
  753. }