Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

158 lines
3.4 KiB

  1. use strict;
  2. use warnings;
  3. use File::Basename;
  4. main();
  5. exit(0);
  6. sub usage
  7. {
  8. $0 = basename($0);
  9. return <<DATA;
  10. usage: $0 [-v] prototype <exename> <funcspec>
  11. or $0 [-v] typedef <exename> <funcspec> <typename>
  12. -v is for verbose output
  13. NOTE: For now, the funcspec is an undecorated name that must match exactly.
  14. DATA
  15. }
  16. my $VERBOSE;
  17. sub main
  18. {
  19. my $opt = shift @ARGV || die usage();
  20. if ($opt eq '-v') {
  21. $VERBOSE = $opt;
  22. } else {
  23. unshift(@ARGV, $opt);
  24. }
  25. my $op = shift @ARGV || die usage();
  26. my $exe = shift @ARGV || die usage();
  27. my $funcspec = shift @ARGV || die usage();
  28. my $typename = shift @ARGV;
  29. my $extra = shift @ARGV;
  30. die usage() if $extra;
  31. if ($op eq 'prototype') {
  32. die usage() if $typename;
  33. DoPrototype($exe, $funcspec);
  34. }
  35. elsif ($op eq 'typedef') {
  36. die usage() if !$typename;
  37. DoPrototype($exe, $funcspec, $typename);
  38. }
  39. else {
  40. die usage();
  41. }
  42. }
  43. sub FindModulePath
  44. {
  45. my $exe = shift || die;
  46. my $funcspec = shift || die;
  47. my $cmd = "mage /s $exe /l functions imports";
  48. my @output = GetCommandOutput($cmd, $VERBOSE, 1, "mage");
  49. map { chomp($_); } @output;
  50. my $is_exe;
  51. my $dll;
  52. foreach my $line (@output) {
  53. if ($line eq '') {
  54. # skip
  55. } elsif ($line =~ /^Microsoft Mage/i) {
  56. # skip
  57. } elsif ($line =~ /^Function: ([A-Za-z0-9_]+)$/) {
  58. # undecorated matching
  59. if ($1 eq $funcspec) {
  60. $is_exe = 1;
  61. last;
  62. }
  63. } elsif ($line =~ /^Import: \[([^\]]+)\] (.+)$/) {
  64. # undecorated matching
  65. if ($2 eq $funcspec) {
  66. $dll = $1;
  67. last;
  68. }
  69. } else {
  70. die "Unexpected output from Mage:\n$line\n";
  71. }
  72. }
  73. if (!$is_exe and !$dll) {
  74. return undef;
  75. }
  76. if ($is_exe) {
  77. return $exe;
  78. }
  79. my @where = GetCommandOutput("where $dll", 0, 1); # die on failure
  80. my $path = shift @where || die "Could not locate $dll\n";
  81. chomp($path);
  82. return $path;
  83. }
  84. sub GetCommandOutput
  85. {
  86. my $cmd = shift || die;
  87. my $verbose = shift;
  88. my $die = shift;
  89. my $pretty = shift;
  90. print "Running: $cmd\n" if $verbose;
  91. my @output = `$cmd`;
  92. my $code = $? / 256;
  93. if ($code and $die) {
  94. if ($pretty) {
  95. die "$pretty failed with exit code $code\n";
  96. } else {
  97. die "Command failed (exit code $code):\n$cmd\n";
  98. }
  99. }
  100. return @output;
  101. }
  102. sub DoPrototype
  103. {
  104. my $exe = shift || die;
  105. my $funcspec = shift || die;
  106. my $typename = shift;
  107. my $path = FindModulePath($exe, $funcspec);
  108. if (!$path) {
  109. print "No matches found\n";
  110. exit(1);
  111. }
  112. my $cmd = "mage /s $path /f $funcspec";
  113. my @output = GetCommandOutput($cmd, $VERBOSE, 1, "mage");
  114. map { chomp($_); } @output;
  115. foreach my $line (@output) {
  116. if ($line =~ /^Prototype: (.+)/) {
  117. my $proto = $1;
  118. if (!$typename) {
  119. print "$proto\n";
  120. } else {
  121. print "$proto\n" if $VERBOSE;
  122. # grab func name, previous token is callconv, before that
  123. # is ret type, afterwards, take parens, remove last token
  124. # before each comma...or not...I don't recall whether
  125. # that's required...
  126. die if !($proto =~ /^(.*)\s+(\S+)\s+$funcspec(\(.+)$/);
  127. my $ret = $1;
  128. my $callconv = $2;
  129. my $args = $3;
  130. $args =~ s/(\s*[A-Za-z0-9_]+)\s*([,\)])/$2/g;
  131. print "typedef $ret ($callconv *$typename)$args\n";
  132. }
  133. exit(0);
  134. }
  135. }
  136. }