objects_build_with_stringchecks.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. #include <tools/ccanlint/ccanlint.h>
  2. #include <tools/tools.h>
  3. #include <ccan/talloc/talloc.h>
  4. #include <ccan/str/str.h>
  5. #include <ccan/str_talloc/str_talloc.h>
  6. #include <ccan/foreach/foreach.h>
  7. #include <sys/types.h>
  8. #include <sys/stat.h>
  9. #include <fcntl.h>
  10. #include <unistd.h>
  11. #include <limits.h>
  12. #include <errno.h>
  13. #include <stdlib.h>
  14. #include <stdio.h>
  15. #include <err.h>
  16. #include <string.h>
  17. #include <ctype.h>
  18. #include "reduce_features.h"
  19. static const char *uses_stringfuncs(struct manifest *m)
  20. {
  21. struct list_head *list;
  22. foreach_ptr(list, &m->c_files, &m->h_files) {
  23. struct ccan_file *i;
  24. char *match;
  25. list_for_each(list, i, list) {
  26. if (strreg(m, get_ccan_file_contents(i),
  27. "(isalnum|isalpha|isascii|isblank|iscntrl"
  28. "|isdigit|isgraph|islower|isprint|ispunct"
  29. "|isspace|isupper|isxdigit"
  30. "|strstr|strchr|strrchr)", &match)) {
  31. if (verbose > 2)
  32. printf("Matched '%s' in %s\n",
  33. match, i->fullname);
  34. return NULL;
  35. }
  36. }
  37. }
  38. return "No ctype.h or string functions found";
  39. }
  40. static void write_str(int fd, const char *str)
  41. {
  42. if (write(fd, str, strlen(str)) != strlen(str))
  43. err(1, "Writing to temporary file");
  44. }
  45. static int start_file(const char *filename)
  46. {
  47. int fd;
  48. fd = open(filename, O_WRONLY|O_CREAT, 0600);
  49. write_str(fd, "#define CCAN_STR_DEBUG 1\n#include <ccan/str/str.h>\n");
  50. return fd;
  51. }
  52. static void test_compile(struct score *score,
  53. struct ccan_file *file,
  54. const char *filename,
  55. const char *flags,
  56. bool *errors,
  57. bool *warnings)
  58. {
  59. char *output, *compiled;
  60. compiled = temp_file(score, "", filename);
  61. if (!compile_object(score, filename, ccan_dir, compiler, flags,
  62. compiled, &output)) {
  63. score_file_error(score, file, 0,
  64. "Compiling object files:\n%s",
  65. output);
  66. *errors = true;
  67. } else if (!streq(output, "")) {
  68. score_file_error(score, file, 0,
  69. "Compiling object files gave warnings:\n%s",
  70. output);
  71. *warnings = true;
  72. }
  73. }
  74. static struct ccan_file *get_main_header(struct manifest *m)
  75. {
  76. struct ccan_file *f;
  77. list_for_each(&m->h_files, f, list) {
  78. if (strstarts(f->name, m->basename)
  79. && strlen(f->name) == strlen(m->basename) + 2) {
  80. return f;
  81. }
  82. }
  83. /* Should not happen, since we passed main_header_exists! */
  84. errx(1, "No main header?");
  85. }
  86. static void build_objects_with_stringchecks(struct manifest *m,
  87. unsigned int *timeleft,
  88. struct score *score)
  89. {
  90. struct ccan_file *i;
  91. bool errors = false, warnings = false;
  92. char *tmp, *flags;
  93. int tmpfd;
  94. /* FIXME:: We need -I so local #includes work outside normal dir. */
  95. flags = talloc_asprintf(score, "-I%s %s", m->dir, cflags);
  96. /* Won't work into macros, but will get inline functions. */
  97. if (list_empty(&m->c_files)) {
  98. char *line;
  99. i = get_main_header(m);
  100. tmp = temp_file(score, ".c", i->fullname);
  101. tmpfd = start_file(tmp);
  102. line = talloc_asprintf(score, "#include <ccan/%s/%s.h>\n",
  103. m->basename, m->basename);
  104. write_str(tmpfd, line);
  105. close(tmpfd);
  106. test_compile(score, i, tmp, flags, &errors, &warnings);
  107. } else {
  108. list_for_each(&m->c_files, i, list) {
  109. tmp = temp_file(score, ".c", i->fullname);
  110. tmpfd = start_file(tmp);
  111. write_str(tmpfd, get_ccan_file_contents(i));
  112. close(tmpfd);
  113. test_compile(score, i, tmp, flags, &errors, &warnings);
  114. }
  115. }
  116. /* We don't fail ccanlint for this. */
  117. score->pass = true;
  118. score->total = 1;
  119. if (!errors) {
  120. score->score = !warnings;
  121. }
  122. }
  123. struct ccanlint objects_build_with_stringchecks = {
  124. .key = "objects_build_with_stringchecks",
  125. .name = "Module compiles with extra ctype.h and str function checks",
  126. .check = build_objects_with_stringchecks,
  127. .can_run = uses_stringfuncs,
  128. .needs = "objects_build main_header_exists"
  129. };
  130. REGISTER_TEST(objects_build_with_stringchecks);