winapi_test 25 KB

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