objects_build_with_stringchecks.c 3.6 KB

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