ccanlint.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /*
  2. * ccanlint: assorted checks and advice for a ccan package
  3. * Copyright (C) 2008 Rusty Russell
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License as published by the Free
  7. * Software Foundation; either version 2 of the License, or (at your option)
  8. * any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  12. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  13. * more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along with
  16. * this program; if not, write to the Free Software Foundation, Inc., 51
  17. * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. */
  19. #include "ccanlint.h"
  20. #include <unistd.h>
  21. #include <getopt.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <err.h>
  26. #include <ctype.h>
  27. static unsigned int verbose = 0;
  28. static LIST_HEAD(tests);
  29. static void init_tests(void)
  30. {
  31. #include "generated-init-tests"
  32. }
  33. static void usage(const char *name)
  34. {
  35. fprintf(stderr, "Usage: %s [-s] [-v] [-d <dirname>]\n"
  36. " -v: verbose mode\n"
  37. " -s: simply give one line per FAIL and total score\n"
  38. " -d: use this directory instead of the current one\n",
  39. name);
  40. exit(1);
  41. }
  42. static void indent_print(const char *string)
  43. {
  44. while (*string) {
  45. unsigned int line = strcspn(string, "\n");
  46. printf("\t%.*s", line, string);
  47. if (string[line] == '\n') {
  48. printf("\n");
  49. line++;
  50. }
  51. string += line;
  52. }
  53. }
  54. bool ask(const char *question)
  55. {
  56. char reply[2];
  57. printf("%s ", question);
  58. fflush(stdout);
  59. return fgets(reply, sizeof(reply), stdin) != NULL
  60. && toupper(reply[0]) == 'Y';
  61. }
  62. static bool run_test(const struct ccanlint *i,
  63. bool summary,
  64. unsigned int *score,
  65. unsigned int *total_score,
  66. struct manifest *m)
  67. {
  68. void *result;
  69. unsigned int this_score;
  70. if (i->total_score)
  71. *total_score += i->total_score;
  72. result = i->check(m);
  73. if (!result) {
  74. if (verbose)
  75. printf(" %s: OK\n", i->name);
  76. if (i->total_score)
  77. *score += i->total_score;
  78. return true;
  79. }
  80. if (i->score)
  81. this_score = i->score(m, result);
  82. else
  83. this_score = 0;
  84. *score += this_score;
  85. if (summary) {
  86. printf("%s FAILED (%u/%u)\n",
  87. i->name, this_score, i->total_score);
  88. if (verbose)
  89. indent_print(i->describe(m, result));
  90. return false;
  91. }
  92. printf("%s\n", i->describe(m, result));
  93. if (i->handle)
  94. i->handle(m, result);
  95. return false;
  96. }
  97. int main(int argc, char *argv[])
  98. {
  99. int c;
  100. bool summary = false;
  101. unsigned int score, total_score;
  102. struct manifest *m;
  103. const struct ccanlint *i;
  104. /* I'd love to use long options, but that's not standard. */
  105. /* FIXME: getopt_long ccan package? */
  106. while ((c = getopt(argc, argv, "sd:v")) != -1) {
  107. switch (c) {
  108. case 'd':
  109. if (chdir(optarg) != 0)
  110. err(1, "Changing into directory '%s'", optarg);
  111. break;
  112. case 's':
  113. summary = true;
  114. break;
  115. case 'v':
  116. verbose++;
  117. break;
  118. default:
  119. usage(argv[0]);
  120. }
  121. }
  122. if (optind < argc)
  123. usage(argv[0]);
  124. m = get_manifest();
  125. init_tests();
  126. /* If you don't pass the compulsory tests, you don't even get a score */
  127. if (verbose)
  128. printf("Compulsory tests:\n");
  129. list_for_each(&tests, i, list)
  130. if (!i->total_score && !run_test(i, summary, NULL, NULL, m))
  131. exit(1);
  132. if (verbose)
  133. printf("\nNormal tests:\n");
  134. score = total_score = 0;
  135. list_for_each(&tests, i, list)
  136. if (i->total_score)
  137. run_test(i, summary, &score, &total_score, m);
  138. printf("Total score: %u/%u\n", score, total_score);
  139. return 0;
  140. }