make_macros 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. #!/usr/bin/perl
  2. # Purpose:
  3. # Generates Assert/Fail macros for use with check.
  4. #
  5. # Usage:
  6. # make_macros macros.in > macros.h
  7. #
  8. # macros.in: one or more lines containing...
  9. # Assert
  10. # Assert_(|not)(Success|Error|Failure|NULL|True|False|Same)
  11. # Fail_(if|unless)(Success|Error|Failure|NULL|True|False|Same)
  12. # Assert_(|not)(0[0-7]+|0x[0-9A-Fa-f]+|0b[01]+|[1-9][0-9]+)
  13. # Fail_(if|unless)(0[0-7]+|0x[0-9A-Fa-f]+|0b[01]+|[1-9][0-9]+)
  14. # Assert_(|not)(LT|LE|EQ|GE|GT|NE)
  15. # Fail_(if|unless)(LT|LE|EQ|GE|GT|NE)
  16. # Assert_(|not){Type}(LT|LE|EQ|GE|GT|NE)
  17. # Fail_(if|unless){Type}(LT|LE|EQ|GE|GT|NE)
  18. # {Type}_compare
  19. #
  20. # Example:
  21. # echo -e 'Assert_notNULL\nAssertStringEQ' | make_macros > macros.h
  22. #
  23. # #include "macros.h"
  24. # ...
  25. # char *foo;
  26. # Assert_notNULL( foo = strdup( "foo" ) , NULL );
  27. # Assert_StringEQ( foo, "foo", NULL );
  28. #
  29. # author: unknown... if you know, please correct or email check-devel
  30. use warnings;
  31. use strict;
  32. use Switch 'Perl6';
  33. use Text::Wrap;
  34. our %need;
  35. our %include;
  36. our %macros;
  37. sub make_macro {
  38. my ($name, $fh) = @_;
  39. my ($condition) = $name;
  40. my ($failIf, $failUnless, $assertNot, $assert);
  41. for ($condition) {
  42. $failIf = 1, next if s/^ Fail_ if ([A-Z0-9]?) /$1/x;
  43. $failUnless = 1, next if s/^ Fail_ unless ([A-Z0-9]?) /$1/x;
  44. $assertNot = 1, next if s/^ Assert_ not ([A-Z0-9] ) /$1/x;
  45. $assert = 1, next if s/^ Assert_ (. ) /$1/x;
  46. $assert = 1, next if s/^ Assert $//x;
  47. print $fh "#error don't know how to make ${name}\n\n";
  48. return;
  49. }
  50. my ($invert) = 0;
  51. foreach ($failIf, $assertNot) {
  52. $invert = !$invert if $_;
  53. }
  54. my $type = "";
  55. if ($condition =~ s/(LT|LE|EQ|GE|GT|NE)$//) {
  56. $type = $condition;
  57. $condition = $1;
  58. }
  59. $type = "Number" unless length $type;
  60. my (@args) = qw( expr );
  61. my ($expr) = qw( (expr) );
  62. my ($msg);
  63. my ($doc);
  64. my (%argdocs) = (
  65. expr => "The expression to test."
  66. );
  67. my ($not) = sub { $invert ? "not " : "" };
  68. my ($Not) = sub { $invert ? "" : "not " };
  69. my ($EQ) = sub { $invert ? "!=" : "==" };
  70. my ($NE) = sub { $invert ? "==" : "!=" };
  71. given ($condition) {
  72. when "" {
  73. unless ( $invert ) {
  74. $doc = "Asserts that \@p expr is true.";
  75. $msg = "Assertion '\"#expr\"' failed.";
  76. } else {
  77. $doc = "Asserts that \@p expr is false.";
  78. $msg = "Negative assertion '\"#expr\"' failed";
  79. }
  80. }
  81. when [qw(Error error Failure failure Success success)] {
  82. $invert = !$invert when [qw(Success success)];
  83. unless ( $invert ) {
  84. $doc = "Asserts that \@p expr failed.";
  85. $msg = "'\"#expr\"' did not fail";
  86. } else {
  87. $doc = "Asserts that \@p expr did not fail.";
  88. $msg = "'\"#expr\"' failed";
  89. }
  90. $invert = !$invert;
  91. }
  92. when [qw(True true False false)] {
  93. $invert = !$invert when "false";
  94. $doc = "Asserts that \@p expr is ".( $invert ? "false" : "true" ).".";
  95. $msg = "'\"#expr\"' was " . ( $invert ? "true" : "false" );
  96. }
  97. when "NULL" {
  98. $msg = "'\"#expr\"' was ".&$Not."NULL";
  99. $doc = "Asserts that \@p expr is ".&$not."NULL";
  100. $expr = "(expr) ".&$EQ." NULL";
  101. $invert = 0;
  102. $include{"stddef.h"} = 1;
  103. }
  104. when m/^(?:[1-9]\d*|0x[0-9A-Fa-f]+|0b[01]+|0[0-7]+)$/x {
  105. $msg = "'\"#expr\"' was ".&$Not."equal to $condition";
  106. $doc = "Asserts that \@p expr is ".&$not."equal to $condition.";
  107. $condition = oct($condition) if $condition =~ /^0/;
  108. $expr = "(expr) ".&$EQ." $condition";
  109. $invert = 0;
  110. }
  111. when [qw(GT GE LT LE EQ NE Equal equal)] {
  112. my $op;
  113. given ( $condition ) {
  114. $op = [ "less than" , "<" ] when "LT";
  115. $op = [ "less than that or equal to", "<=" ] when "LE";
  116. $op = [ "equal to" , "==" ] when ["EQ", "Equal", "equal", "NE"];
  117. $op = [ "greater than or equal to" , ">=" ] when "GE";
  118. $op = [ "greater than" , ">" ] when "GT";
  119. };
  120. $invert = !$invert when "NE";
  121. @args = ( $type."1", $type."2" );
  122. %argdocs = (
  123. $type."1" => "The expression to test.",
  124. $type."2" => "The test value."
  125. );
  126. $msg = "'\"#$args[0]\"' is ".&$Not.$op->[0]." '\"#$args[1]\"'";
  127. $doc = "Asserts that \@p $args[0] is ".&$not.$op->[0]." \@p $args[1].";
  128. $expr = "(${type}_compare( $args[0], $args[1] ) ".$op->[1]." 0)";
  129. $need{$type."_compare"} = 1;
  130. }
  131. when [qw(Same same)] {
  132. @args = qw( arg1 arg2 );
  133. %argdocs = (
  134. arg1 => "The expression to test.",
  135. arg2 => "The expected value."
  136. );
  137. $msg = "'\"#arg1\"' and '\"#arg2\"' are ".&$Not."the same";
  138. $msg = "Asserts that \@p arg1 and \@p arg2 are ".&$not."the same";
  139. $expr = "(arg1) ".&$EQ." (arg2)";
  140. $invert = 0;
  141. }
  142. default {
  143. print $fh "#error don't know how to make ${name}\n\n";
  144. return;
  145. }
  146. }
  147. if ($invert) {
  148. $expr = "!$expr";
  149. }
  150. if ($doc) {
  151. print $fh "/**\n";
  152. print $fh wrap(" * "," * ","$doc\n");
  153. my ($maxlength) = 3;
  154. foreach (keys %argdocs) {
  155. $maxlength = length $_ if length $_ > $maxlength;
  156. }
  157. my ($indent) = " " x ($maxlength + 1 + 7);
  158. foreach (keys %argdocs) {
  159. print $fh wrap(" * ",
  160. " * $indent",
  161. "\@param $_ ".(" " x ($maxlength - length $_)).
  162. "$argdocs{$_}\n");
  163. }
  164. print $fh wrap(" * ",
  165. " * $indent",
  166. "\@param ... ".(" " x ($maxlength - 3)).
  167. "An optional message to indicate the assertion failed; ".
  168. "Omit for a default message.\n");
  169. print $fh " */\n";
  170. }
  171. print $fh "#define ${name}(",(join ", ", @args, '...'),") \\\n";
  172. print $fh " _ck_assert_msg( $expr, __FILE__, __LINE__, \\\n";
  173. print $fh " \"$msg\", ## __VA_ARGS__, NULL)\n";
  174. print $fh "\n";
  175. $macros{$name} = 1;
  176. }
  177. sub make_compare {
  178. my ($name, $fh) = @_;
  179. my ($type) = $name;
  180. $type =~ s/_compare$//;
  181. my ($expr);
  182. my ($warning);
  183. my ($ord);
  184. my (@name) = ( "", "" );
  185. given ($type) {
  186. when "Number" {
  187. $expr = "( ${type}1 - ${type}2 )";
  188. $ord = "is";
  189. }
  190. when "String" {
  191. $expr = "strcmp( ${type}1, ${type}2 )";
  192. $include{"string.h"} = 1;
  193. $ord = "is";
  194. }
  195. default {
  196. $expr = "memcmp( ${type}1, ${type}2, sizeof( ${type} ) )";
  197. $include{"string.h"} = 1;
  198. $ord = "are";
  199. @name = ( "'s bytes ", "'s" );
  200. $warning = "This compares \@p ${type}1 and \@p ${type}2 "
  201. . "byte-for-byte, this is probably not what you want "
  202. . "for all but the simplest of structures.";
  203. }
  204. }
  205. print $fh "/**\n";
  206. print $fh " * Compares \@p ${type}1 and \@p ${type}2.\n";
  207. print $fh wrap(" * "," * ",$warning . "\n") if $warning;
  208. print $fh " * \@param ${type}1 The first ${type}.\n";
  209. print $fh " * \@param ${type}2 The second ${type}.\n";
  210. my (%val_name) = (
  211. ">0" => "greater than",
  212. "0 " => "equal to",
  213. "<0" => "less than",
  214. );
  215. while (my ($val, $name) = each %val_name) {
  216. print $fh " * \@retval $val If \@p ${type}1 $name[0]$ord $name \@p ${type}2 $name[1].\n";
  217. }
  218. print $fh " */\n";
  219. print $fh "#define ${type}_compare(${type}1, ${type}2) \\\n";
  220. print $fh " $expr\n";
  221. print $fh "\n";
  222. $macros{$name} = 1;
  223. }
  224. my $INCLUDES = '';
  225. open my $includes, ">", \$INCLUDES or die;
  226. my $MACROS = '';
  227. open my $macros, ">", \$MACROS or die;
  228. my $MACROS2 = '';
  229. open my $macros2, ">", \$MACROS2 or die;
  230. while (<>) {
  231. chomp;
  232. make_macro( $_, $macros2 ) if /^(?:Assert|Fail)/;
  233. make_compare( $_, $macros ) if /_compare$/;
  234. }
  235. foreach my $need (keys %need) {
  236. given ($need) {
  237. when /^(?:String|Number)_compare$/ {
  238. make_compare( $need, $macros );
  239. delete $need{$need};
  240. }
  241. }
  242. }
  243. foreach my $macro (keys %macros) {
  244. delete $need{$macro};
  245. }
  246. if (scalar %need) {
  247. print $includes "/* needed functions/macros:\n";
  248. foreach my $need (keys %need) {
  249. if ($need =~ /^(.*)_compare$/) {
  250. print $includes " * int $need(${1}1,${1}2);\n";
  251. } else {
  252. print $includes " * $need\n";
  253. }
  254. }
  255. print $includes " */\n\n";
  256. }
  257. foreach my $include (keys %include) {
  258. print $includes "#include <$include>\n";
  259. }
  260. print <<'END';
  261. #ifndef _CHECK_MACROS_H
  262. #define _CHECK_MACROS_H
  263. END
  264. print $INCLUDES;
  265. print "\n";
  266. print $MACROS;
  267. print $MACROS2;
  268. print <<'END';
  269. #endif /* _CHECK_MACROS_H */
  270. END