cpp-preproc.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. /*
  2. * Invoke an external C preprocessor
  3. *
  4. * Copyright (C) 2007 Paul Barker
  5. * Copyright (C) 2001-2007 Peter Johnson
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
  17. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
  20. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  21. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  22. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  23. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  24. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  25. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  26. * POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. #include <util.h>
  29. #include <libyasm.h>
  30. /* TODO: Use autoconf to get the limit on the command line length. */
  31. #define CMDLINE_SIZE 32770
  32. #define BSIZE 512
  33. /* Pre-declare the preprocessor module object. */
  34. yasm_preproc_module yasm_cpp_LTX_preproc;
  35. /*******************************************************************************
  36. Structures.
  37. *******************************************************************************/
  38. /* An entry in a list of arguments to pass to cpp. */
  39. typedef struct cpp_arg_entry {
  40. TAILQ_ENTRY(cpp_arg_entry) entry;
  41. /*
  42. The operator (eg "-I") and the parameter (eg "include/"). op is expected
  43. to point to a string literal, whereas param is expected to be a copy of
  44. the parameter which is free'd when no-longer needed (in
  45. cpp_preproc_destroy()).
  46. */
  47. const char *op;
  48. char *param;
  49. } cpp_arg_entry;
  50. typedef struct yasm_preproc_cpp {
  51. yasm_preproc_base preproc; /* base structure */
  52. /* List of arguments to pass to cpp. */
  53. TAILQ_HEAD(cpp_arg_head, cpp_arg_entry) cpp_args;
  54. char *filename;
  55. FILE *f, *f_deps;
  56. yasm_linemap *cur_lm;
  57. yasm_errwarns *errwarns;
  58. int flags;
  59. } yasm_preproc_cpp;
  60. /* Flag values for yasm_preproc_cpp->flags. */
  61. #define CPP_HAS_BEEN_INVOKED 0x01
  62. #define CPP_HAS_GENERATED_DEPS 0x02
  63. /*******************************************************************************
  64. Internal functions and helpers.
  65. *******************************************************************************/
  66. /*
  67. Append a string to the command line, ensuring that we don't overflow the
  68. buffer.
  69. */
  70. #define APPEND(s) do { \
  71. size_t _len = strlen(s); \
  72. if (p + _len >= limit) \
  73. yasm__fatal(N_("command line too long!")); \
  74. strcpy(p, s); \
  75. p += _len; \
  76. } while (0)
  77. /*
  78. Put all the options together into a command line that can be used to invoke
  79. cpp.
  80. */
  81. static char *
  82. cpp_build_cmdline(yasm_preproc_cpp *pp, const char *extra)
  83. {
  84. char *cmdline, *p, *limit;
  85. cpp_arg_entry *arg;
  86. /* Initialize command line. */
  87. cmdline = p = yasm_xmalloc(strlen(CPP_PROG)+CMDLINE_SIZE);
  88. limit = p + CMDLINE_SIZE;
  89. strcpy(p, CPP_PROG);
  90. p += strlen(CPP_PROG);
  91. arg = TAILQ_FIRST(&pp->cpp_args);
  92. /* Append arguments from the list. */
  93. while ( arg ) {
  94. APPEND(" ");
  95. APPEND(arg->op);
  96. APPEND(" ");
  97. APPEND(arg->param);
  98. arg = TAILQ_NEXT(arg, entry);
  99. }
  100. /* Append extra arguments. */
  101. if (extra) {
  102. APPEND(" ");
  103. APPEND(extra);
  104. }
  105. /* Append final arguments. */
  106. APPEND(" -x assembler-with-cpp ");
  107. APPEND(pp->filename);
  108. return cmdline;
  109. }
  110. /* Invoke the c preprocessor. */
  111. static void
  112. cpp_invoke(yasm_preproc_cpp *pp)
  113. {
  114. char *cmdline;
  115. cmdline = cpp_build_cmdline(pp, NULL);
  116. #ifdef HAVE_POPEN
  117. pp->f = popen(cmdline, "r");
  118. if (!pp->f)
  119. yasm__fatal( N_("Failed to execute preprocessor") );
  120. #else
  121. yasm__fatal( N_("Cannot execute preprocessor, no popen available") );
  122. #endif
  123. yasm_xfree(cmdline);
  124. }
  125. /* Free memory used by the list of arguments. */
  126. static void
  127. cpp_destroy_args(yasm_preproc_cpp *pp)
  128. {
  129. cpp_arg_entry *arg;
  130. while ( (arg = TAILQ_FIRST(&pp->cpp_args)) ) {
  131. TAILQ_REMOVE(&pp->cpp_args, arg, entry);
  132. yasm_xfree(arg->param);
  133. yasm_xfree(arg);
  134. }
  135. }
  136. /* Invoke the c preprocessor to generate dependency info. */
  137. static void
  138. cpp_generate_deps(yasm_preproc_cpp *pp)
  139. {
  140. char *cmdline;
  141. cmdline = cpp_build_cmdline(pp, "-M");
  142. #ifdef HAVE_POPEN
  143. pp->f_deps = popen(cmdline, "r");
  144. if (!pp->f_deps)
  145. yasm__fatal( N_("Failed to execute preprocessor") );
  146. #else
  147. yasm__fatal( N_("Cannot execute preprocessor, no popen available") );
  148. #endif
  149. yasm_xfree(cmdline);
  150. }
  151. /*******************************************************************************
  152. Interface functions.
  153. *******************************************************************************/
  154. static yasm_preproc *
  155. cpp_preproc_create(const char *in, yasm_symtab *symtab, yasm_linemap *lm,
  156. yasm_errwarns *errwarns)
  157. {
  158. yasm_preproc_cpp *pp = yasm_xmalloc(sizeof(yasm_preproc_cpp));
  159. void * iter;
  160. const char * inc_dir;
  161. pp->preproc.module = &yasm_cpp_LTX_preproc;
  162. pp->f = pp->f_deps = NULL;
  163. pp->cur_lm = lm;
  164. pp->errwarns = errwarns;
  165. pp->flags = 0;
  166. pp->filename = yasm__xstrdup(in);
  167. TAILQ_INIT(&pp->cpp_args);
  168. /* Iterate through the list of include dirs. */
  169. iter = NULL;
  170. while ((inc_dir = yasm_get_include_dir(&iter)) != NULL) {
  171. cpp_arg_entry *arg = yasm_xmalloc(sizeof(cpp_arg_entry));
  172. arg->op = "-I";
  173. arg->param = yasm__xstrdup(inc_dir);
  174. TAILQ_INSERT_TAIL(&pp->cpp_args, arg, entry);
  175. }
  176. return (yasm_preproc *)pp;
  177. }
  178. static void
  179. cpp_preproc_destroy(yasm_preproc *preproc)
  180. {
  181. yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc;
  182. if (pp->f) {
  183. #ifdef HAVE_POPEN
  184. if (pclose(pp->f) != 0)
  185. yasm__fatal( N_("Preprocessor exited with failure") );
  186. #endif
  187. }
  188. cpp_destroy_args(pp);
  189. yasm_xfree(pp->filename);
  190. yasm_xfree(pp);
  191. }
  192. static char *
  193. cpp_preproc_get_line(yasm_preproc *preproc)
  194. {
  195. yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc;
  196. int bufsize = BSIZE;
  197. char *buf, *p;
  198. if (! (pp->flags & CPP_HAS_BEEN_INVOKED) ) {
  199. pp->flags |= CPP_HAS_BEEN_INVOKED;
  200. cpp_invoke(pp);
  201. }
  202. /*
  203. Once the preprocessor has been run, we're just dealing with a normal
  204. file.
  205. */
  206. /* Loop to ensure entire line is read (don't want to limit line length). */
  207. buf = yasm_xmalloc((size_t)bufsize);
  208. p = buf;
  209. for (;;) {
  210. if (!fgets(p, bufsize-(p-buf), pp->f)) {
  211. if (ferror(pp->f)) {
  212. yasm_error_set(YASM_ERROR_IO,
  213. N_("error when reading from file"));
  214. yasm_errwarn_propagate(pp->errwarns,
  215. yasm_linemap_get_current(pp->cur_lm));
  216. }
  217. break;
  218. }
  219. p += strlen(p);
  220. if (p > buf && p[-1] == '\n')
  221. break;
  222. if ((p-buf) >= bufsize) {
  223. /* Increase size of buffer */
  224. char *oldbuf = buf;
  225. bufsize *= 2;
  226. buf = yasm_xrealloc(buf, (size_t)bufsize);
  227. p = buf + (p-oldbuf);
  228. }
  229. }
  230. if (p == buf) {
  231. /* No data; must be at EOF */
  232. yasm_xfree(buf);
  233. return NULL;
  234. }
  235. /* Strip the line ending */
  236. buf[strcspn(buf, "\r\n")] = '\0';
  237. return buf;
  238. }
  239. static size_t
  240. cpp_preproc_get_included_file(yasm_preproc *preproc, char *buf,
  241. size_t max_size)
  242. {
  243. char *p = buf;
  244. int ch = '\0';
  245. size_t n = 0;
  246. yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc;
  247. if (! (pp->flags & CPP_HAS_GENERATED_DEPS) ) {
  248. pp->flags |= CPP_HAS_GENERATED_DEPS;
  249. cpp_generate_deps(pp);
  250. /* Skip target name and first dependency. */
  251. while (ch != ':')
  252. ch = fgetc(pp->f_deps);
  253. fgetc(pp->f_deps); /* Discard space after colon. */
  254. while (ch != ' ' && ch != EOF)
  255. ch = fgetc(pp->f_deps);
  256. if (ch == EOF)
  257. return 0;
  258. }
  259. while (n < max_size) {
  260. ch = fgetc(pp->f_deps);
  261. if (ch == ' ' || ch == EOF) {
  262. *p = '\0';
  263. return n;
  264. }
  265. /* Eat any silly characters. */
  266. if (ch < ' ')
  267. continue;
  268. *p++ = ch;
  269. n++;
  270. }
  271. /* Ensure the buffer is null-terminated. */
  272. *(p - 1) = '\0';
  273. return n;
  274. }
  275. static void
  276. cpp_preproc_add_include_file(yasm_preproc *preproc, const char *filename)
  277. {
  278. yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc;
  279. cpp_arg_entry *arg = yasm_xmalloc(sizeof(cpp_arg_entry));
  280. arg->op = "-include";
  281. arg->param = yasm__xstrdup(filename);
  282. TAILQ_INSERT_TAIL(&pp->cpp_args, arg, entry);
  283. }
  284. static void
  285. cpp_preproc_predefine_macro(yasm_preproc *preproc, const char *macronameval)
  286. {
  287. yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc;
  288. cpp_arg_entry *arg = yasm_xmalloc(sizeof(cpp_arg_entry));
  289. arg->op = "-D";
  290. arg->param = yasm__xstrdup(macronameval);
  291. TAILQ_INSERT_TAIL(&pp->cpp_args, arg, entry);
  292. }
  293. static void
  294. cpp_preproc_undefine_macro(yasm_preproc *preproc, const char *macroname)
  295. {
  296. yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc;
  297. cpp_arg_entry *arg = yasm_xmalloc(sizeof(cpp_arg_entry));
  298. arg->op = "-U";
  299. arg->param = yasm__xstrdup(macroname);
  300. TAILQ_INSERT_TAIL(&pp->cpp_args, arg, entry);
  301. }
  302. static void
  303. cpp_preproc_define_builtin(yasm_preproc *preproc, const char *macronameval)
  304. {
  305. /* Handle a builtin as if it were a predefine. */
  306. cpp_preproc_predefine_macro(preproc, macronameval);
  307. }
  308. static void
  309. cpp_preproc_add_standard(yasm_preproc *preproc, const char **macros)
  310. {
  311. /* TODO */
  312. }
  313. /*******************************************************************************
  314. Preprocessor module object.
  315. *******************************************************************************/
  316. yasm_preproc_module yasm_cpp_LTX_preproc = {
  317. "Run input through external C preprocessor",
  318. "cpp",
  319. cpp_preproc_create,
  320. cpp_preproc_destroy,
  321. cpp_preproc_get_line,
  322. cpp_preproc_get_included_file,
  323. cpp_preproc_add_include_file,
  324. cpp_preproc_predefine_macro,
  325. cpp_preproc_undefine_macro,
  326. cpp_preproc_define_builtin,
  327. cpp_preproc_add_standard
  328. };