1 /*
2 * TCC - Tiny C Compiler
3 *
4 * Copyright (c) 2001-2004 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20 #include <r_util.h>
21 #include "tcc.h"
22
23 /********************************************************/
24 /* global variables */
25 ST_DATA RPVector *tcc_typedefs;
26
27 /* use GNU C extensions */
28 ST_DATA int gnu_ext = 1;
29
30 /* use TinyCC extensions */
31 ST_DATA int tcc_ext = 1;
32
33 /* XXX: get rid of this ASAP */
34 ST_DATA struct TCCState *tcc_state;
35
36 /********************************************************/
37
38 #ifdef __WINDOWS__
39 // GCC appears to use '/' for relative paths and '\\' for absolute paths on Windows
normalize_slashes(char * path)40 static char *normalize_slashes(char *path)
41 {
42 char *p;
43 if (path[1] == ':') {
44 for (p = path + 2; *p; ++p) {
45 if (*p == '/') {
46 *p = '\\';
47 }
48 }
49 } else {
50 for (p = path; *p; ++p) {
51 if (*p == '\\') {
52 *p = '/';
53 }
54 }
55 }
56 return path;
57 }
58 #endif
59
60 /********************************************************/
61 /* copy a string and truncate it. */
pstrcpy(char * buf,int buf_size,const char * s)62 PUB_FUNC char *pstrcpy(char *buf, int buf_size, const char *s)
63 {
64 char *q, *q_end;
65 int c;
66
67 if (buf_size > 0) {
68 q = buf;
69 q_end = buf + buf_size - 1;
70 while (q < q_end) {
71 c = *s++;
72 if (c == '\0') {
73 break;
74 }
75 *q++ = c;
76 }
77 *q = '\0';
78 }
79 return buf;
80 }
81
82 /* strcat and truncate. */
pstrcat(char * buf,int buf_size,const char * s)83 PUB_FUNC char *pstrcat(char *buf, int buf_size, const char *s)
84 {
85 int len;
86 len = strlen (buf);
87 if (len < buf_size) {
88 pstrcpy (buf + len, buf_size - len, s);
89 }
90 return buf;
91 }
92
pstrncpy(char * out,const char * in,size_t num)93 PUB_FUNC char *pstrncpy(char *out, const char *in, size_t num)
94 {
95 memcpy (out, in, num);
96 out[num] = '\0';
97 return out;
98 }
99
100 /* extract the basename of a file */
tcc_basename(const char * name)101 PUB_FUNC char *tcc_basename(const char *name)
102 {
103 char *p = strchr (name, 0);
104 while (p && p > name && !IS_DIRSEP (p[-1]))
105 --p;
106 return p;
107 }
108
109 /* extract extension part of a file
110 *
111 * (if no extension, return pointer to end-of-string)
112 */
tcc_fileextension(const char * name)113 PUB_FUNC char *tcc_fileextension(const char *name)
114 {
115 char *b = tcc_basename (name);
116 char *e = strrchr (b, '.');
117 return e? e: strchr (b, 0);
118 }
119
120 /********************************************************/
121 /* memory management */
122
123
tcc_mallocz(unsigned long size)124 PUB_FUNC void *tcc_mallocz(unsigned long size)
125 {
126 void *ptr;
127 ptr = malloc (size);
128 memset (ptr, 0, size);
129 return ptr;
130 }
131
132
tcc_memstats(void)133 PUB_FUNC void tcc_memstats(void)
134 {
135 #ifdef MEM_DEBUG
136 printf ("memory: %d byte(s), max = %d byte(s)\n", mem_cur_size, mem_max_size);
137 #endif
138 }
139
140 /********************************************************/
141 /* dynarrays */
142
dynarray_add(void *** ptab,int * nb_ptr,void * data)143 ST_FUNC void dynarray_add(void ***ptab, int *nb_ptr, void *data)
144 {
145 int nb, nb_alloc;
146 void **pp;
147
148 nb = *nb_ptr;
149 pp = *ptab;
150 /* every power of two we double array size */
151 if ((nb & (nb - 1)) == 0) {
152 if (!nb) {
153 nb_alloc = 1;
154 } else {
155 nb_alloc = nb * 2;
156 }
157 pp = realloc (pp, nb_alloc * sizeof(void *));
158 *ptab = pp;
159 }
160 pp[nb++] = data;
161 *nb_ptr = nb;
162 }
163
dynarray_reset(void * pp,int * n)164 ST_FUNC void dynarray_reset(void *pp, int *n)
165 {
166 void **p;
167 for (p = *(void ***) pp; *n; ++p, --*n) {
168 if (*p) {
169 free (*p);
170 }
171 }
172 free (*(void **) pp);
173 *(void **) pp = NULL;
174 }
175
tcc_split_path(TCCState * s,void *** p_ary,int * p_nb_ary,const char * in)176 static void tcc_split_path(TCCState *s, void ***p_ary, int *p_nb_ary, const char *in)
177 {
178 const char *p;
179 do {
180 int c;
181 CString str;
182
183 cstr_new (&str);
184 for (p = in; c = *p, c != '\0' && c != PATHSEP; ++p) {
185 if (c == '{' && p[1] && p[2] == '}') {
186 c = p[1], p += 2;
187 if (c == 'B') {
188 cstr_cat (&str, s->tcc_lib_path);
189 }
190 } else {
191 cstr_ccat (&str, c);
192 }
193 }
194 cstr_ccat (&str, '\0');
195 dynarray_add (p_ary, p_nb_ary, str.data);
196 in = p + 1;
197 } while (*p);
198 }
199
200 /********************************************************/
201
strcat_vprintf(char * buf,int buf_size,const char * fmt,va_list ap)202 static void strcat_vprintf(char *buf, int buf_size, const char *fmt, va_list ap)
203 {
204 int len;
205 len = strlen (buf);
206 vsnprintf (buf + len, buf_size - len, fmt, ap);
207 }
208
strcat_printf(char * buf,int buf_size,const char * fmt,...)209 PUB_FUNC void strcat_printf(char *buf, int buf_size, const char *fmt, ...)
210 {
211 va_list ap;
212 va_start (ap, fmt);
213 strcat_vprintf (buf, buf_size, fmt, ap);
214 va_end (ap);
215 }
216
error1(TCCState * s1,int is_warning,const char * fmt,va_list ap)217 static void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap)
218 {
219 char buf[2048];
220 BufferedFile **pf, *f;
221
222 buf[0] = '\0';
223 /* use upper file if inline ":asm:" or token ":paste:" */
224 for (f = file; f && f->filename[0] == ':'; f = f->prev) {
225 ;
226 }
227 if (f) {
228 for (pf = s1->include_stack; pf < s1->include_stack_ptr; pf++) {
229 strcat_printf (buf, sizeof(buf), "In file included from %s:%d:\n",
230 (*pf)->filename, (*pf)->line_num);
231 }
232 if (f->line_num > 0) {
233 strcat_printf (buf, sizeof(buf), "%s:%d: ",
234 f->filename, f->line_num);
235 } else {
236 strcat_printf (buf, sizeof(buf), "%s: ",
237 f->filename);
238 }
239 } else {
240 strcat_printf (buf, sizeof(buf), "tcc: ");
241 }
242 if (is_warning) {
243 strcat_printf (buf, sizeof(buf), "warning: ");
244 } else {
245 strcat_printf (buf, sizeof(buf), "error: ");
246 }
247 strcat_vprintf (buf, sizeof(buf), fmt, ap);
248
249 if (!s1->error_func) {
250 /* default case: stderr */
251 fprintf (stderr, "%s\n", buf);
252 } else {
253 s1->error_func (s1->error_opaque, buf);
254 }
255 if (!is_warning || s1->warn_error) {
256 s1->nb_errors++;
257 }
258 }
259
tcc_set_error_func(TCCState * s,void * error_opaque,void (* error_func)(void * opaque,const char * msg))260 LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque,
261 void (*error_func)(void *opaque, const char *msg))
262 {
263 s->error_opaque = error_opaque;
264 s->error_func = error_func;
265 }
266
267 /* error without aborting current compilation */
tcc_error(const char * fmt,...)268 PUB_FUNC void tcc_error(const char *fmt, ...)
269 {
270 TCCState *s1 = tcc_state;
271 va_list ap;
272
273 va_start (ap, fmt);
274 error1 (s1, 0, fmt, ap);
275 va_end (ap);
276 }
277
tcc_warning(const char * fmt,...)278 PUB_FUNC void tcc_warning(const char *fmt, ...)
279 {
280 TCCState *s1 = tcc_state;
281 va_list ap;
282
283 if (s1->warn_none) {
284 return;
285 }
286
287 va_start (ap, fmt);
288 error1 (s1, 1, fmt, ap);
289 va_end (ap);
290 }
291
292 /********************************************************/
293 /* I/O layer */
294
tcc_open_bf(TCCState * s1,const char * filename,int initlen)295 ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen)
296 {
297 BufferedFile *bf;
298 int buflen = initlen? initlen: IO_BUF_SIZE;
299
300 bf = malloc (sizeof(BufferedFile) + buflen);
301 bf->buf_ptr = bf->buffer;
302 bf->buf_end = bf->buffer + initlen;
303 bf->buf_end[0] = CH_EOB;/* put eob symbol */
304 pstrcpy (bf->filename, sizeof(bf->filename), filename);
305 #ifdef __WINDOWS__
306 normalize_slashes (bf->filename);
307 #endif
308 bf->line_num = 1;
309 bf->ifndef_macro = 0;
310 bf->ifdef_stack_ptr = s1->ifdef_stack_ptr;
311 bf->fd = -1;
312 bf->prev = file;
313 file = bf;
314 }
315
tcc_close(void)316 ST_FUNC void tcc_close(void)
317 {
318 BufferedFile *bf = file;
319 if (bf->fd > 0) {
320 close (bf->fd);
321 total_lines += bf->line_num;
322 }
323 file = bf->prev;
324 free (bf);
325 }
326
tcc_open(TCCState * s1,const char * filename)327 ST_FUNC int tcc_open(TCCState *s1, const char *filename)
328 {
329 int fd;
330 if (strcmp (filename, "-") == 0) {
331 fd = 0, filename = "stdin";
332 } else {
333 fd = open (filename, O_RDONLY | O_BINARY);
334 }
335 if ((s1->verbose == 2 && fd >= 0) || s1->verbose == 3) {
336 printf ("%s %*s%s\n", fd < 0? "nf": "->",
337 (int) (s1->include_stack_ptr - s1->include_stack), "", filename);
338 }
339 if (fd < 0) {
340 return -1;
341 }
342
343 tcc_open_bf (s1, filename, 0);
344 file->fd = fd;
345 return fd;
346 }
347
348 /* compile the C file opened in 'file'. Return non zero if errors. */
tcc_compile(TCCState * s1)349 static int tcc_compile(TCCState *s1)
350 {
351 Sym *define_start;
352
353 #ifdef INC_DEBUG
354 printf ("%s: **** new file\n", file->filename);
355 #endif
356 preprocess_init (s1);
357
358 funcname = "";
359
360 /* define some often used types */
361 int8_type.t = VT_INT8;
362 int16_type.t = VT_INT16;
363 int32_type.t = VT_INT32;
364 int64_type.t = VT_INT64;
365
366 char_pointer_type.t = VT_INT8;
367 mk_pointer (&char_pointer_type);
368
369 if (tcc_state->bits != 64) {
370 size_type.t = VT_INT32;
371 } else {
372 size_type.t = VT_INT64;
373 }
374
375 func_old_type.t = VT_FUNC;
376 func_old_type.ref = sym_push (SYM_FIELD, &int32_type, FUNC_CDECL, FUNC_OLD);
377
378 // FIXME: Should depend on the target options too
379 #ifdef TCC_TARGET_ARM
380 arm_init_types ();
381 #endif
382
383 #if 0
384 /* define 'void *alloca(unsigned int)' builtin function */
385 {
386 Sym *s1;
387
388 p = anon_sym++;
389 sym = sym_push (p, mk_pointer (VT_VOID), FUNC_CDECL, FUNC_NEW);
390 s1 = sym_push (SYM_FIELD, VT_UNSIGNED | VT_INT, 0, 0);
391 s1->next = NULL;
392 sym->next = s1;
393 sym_push (TOK_alloca, VT_FUNC | (p << VT_STRUCT_SHIFT), VT_CONST, 0);
394 }
395 #endif
396
397 define_start = define_stack;
398 nocode_wanted = 1;
399
400 if (setjmp (s1->error_jmp_buf) == 0) {
401 s1->nb_errors = 0;
402 s1->error_set_jmp_enabled = 1;
403
404 ch = file->buf_ptr[0];
405 tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
406 parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM;
407 // pvtop = vtop;
408 next ();
409 decl (VT_CONST);
410 if (tok != TOK_EOF) {
411 expect ("declaration");
412 }
413 #if 0
414 if (pvtop != vtop) {
415 fprintf (stderr, "internal compiler error:"
416 " vstack leak? (%d)", vtop - pvtop);
417 }
418 #endif
419 }
420
421 s1->error_set_jmp_enabled = 0;
422
423 /* reset define stack, but leave -Dsymbols (may be incorrect if
424 they are undefined) */
425 free_defines (define_start);
426
427 sym_pop (&global_stack, NULL);
428 sym_pop (&local_stack, NULL);
429
430 return s1->nb_errors != 0? -1: 0;
431 }
432
tcc_compile_string(TCCState * s,const char * str)433 LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str)
434 {
435 int len, ret;
436 len = strlen (str);
437
438 tcc_open_bf (s, "<string>", len);
439 memcpy (file->buffer, str, len);
440 ret = tcc_compile (s);
441 tcc_close ();
442 return ret;
443 }
444
445 /* define a preprocessor symbol. A value can also be provided with the '=' operator */
tcc_define_symbol(TCCState * s1,const char * sym,const char * value)446 LIBTCCAPI void tcc_define_symbol(TCCState *s1, const char *sym, const char *value)
447 {
448 int len1, len2;
449 /* default value */
450 if (!value) {
451 value = "1";
452 }
453 len1 = strlen (sym);
454 len2 = strlen (value);
455
456 /* init file structure */
457 tcc_open_bf (s1, "<define>", len1 + len2 + 1);
458 memcpy (file->buffer, sym, len1);
459 file->buffer[len1] = ' ';
460 memcpy (file->buffer + len1 + 1, value, len2);
461
462 /* parse with define parser */
463 ch = file->buf_ptr[0];
464 next_nomacro ();
465 parse_define ();
466
467 tcc_close ();
468 }
469
470 /* undefine a preprocessor symbol */
tcc_undefine_symbol(TCCState * s1,const char * sym)471 LIBTCCAPI void tcc_undefine_symbol(TCCState *s1, const char *sym)
472 {
473 TokenSym *ts;
474 Sym *s;
475 ts = tok_alloc (sym, strlen (sym));
476 s = define_find (ts->tok);
477 /* undefine symbol by putting an invalid name */
478 if (s) {
479 define_undef (s);
480 }
481 }
482
483 /* cleanup all static data used during compilation */
tcc_cleanup(void)484 static void tcc_cleanup(void)
485 {
486 int i, n;
487 if (NULL == tcc_state) {
488 return;
489 }
490 tcc_state = NULL;
491
492 /* free -D defines */
493 free_defines (NULL);
494
495 /* free tokens */
496 n = tok_ident - TOK_IDENT;
497 for (i = 0; i < n; i++) {
498 free (table_ident[i]);
499 }
500 free (table_ident);
501
502 /* free sym_pools */
503 dynarray_reset (&sym_pools, &nb_sym_pools);
504 /* string buffer */
505 cstr_free (&tokcstr);
506 /* reset symbol stack */
507 sym_free_first = NULL;
508 /* cleanup from error/setjmp */
509 macro_ptr = NULL;
510 }
511
tcc_new(const char * arch,int bits,const char * os)512 LIBTCCAPI TCCState *tcc_new(const char *arch, int bits, const char *os)
513 {
514 TCCState *s;
515 char buffer[100];
516 int a, b, c;
517
518 if (!arch || !os) {
519 return NULL;
520 }
521 tcc_cleanup ();
522 s = tcc_mallocz (sizeof(TCCState));
523 if (!s) {
524 return NULL;
525 }
526 tcc_state = s;
527 s->arch = strdup (arch);
528 s->bits = bits;
529 s->os = strdup (os);
530 s->output_type = TCC_OUTPUT_MEMORY;
531 preprocess_new ();
532 s->include_stack_ptr = s->include_stack;
533
534 /* we add dummy defines for some special macros to speed up tests
535 and to have working defined() */
536 define_push (TOK___LINE__, MACRO_OBJ, NULL, NULL);
537 define_push (TOK___FILE__, MACRO_OBJ, NULL, NULL);
538 define_push (TOK___DATE__, MACRO_OBJ, NULL, NULL);
539 define_push (TOK___TIME__, MACRO_OBJ, NULL, NULL);
540
541 /* define __TINYC__ 92X */
542 sscanf (TCC_VERSION, "%d.%d.%d", &a, &b, &c);
543 sprintf (buffer, "%d", a * 10000 + b * 100 + c);
544 tcc_define_symbol (s, "__TINYC__", buffer);
545 tcc_define_symbol (s, "__R2TINYC__", buffer);
546
547 /* standard defines */
548 tcc_define_symbol (s, "__STDC__", NULL);
549 tcc_define_symbol (s, "__STDC_VERSION__", "199901L");
550 tcc_define_symbol (s, "__STDC_HOSTED__", NULL);
551
552 /* type defines */
553 tcc_define_symbol (s, "ut8", "uint8_t");
554 tcc_define_symbol (s, "ut16", "uint16_t");
555 tcc_define_symbol (s, "ut32", "uint32_t");
556 tcc_define_symbol (s, "ut64", "uint64_t");
557 if (bits == 64) {
558 tcc_define_symbol (s, "size_t", "uint64_t");
559 } else {
560 tcc_define_symbol (s, "size_t", "uint32_t");
561 }
562
563 tcc_define_symbol (s, "st8", "int8_t");
564 tcc_define_symbol (s, "st16", "int16_t");
565 tcc_define_symbol (s, "st32", "int32_t");
566 tcc_define_symbol (s, "st64", "int64_t");
567
568 /* target defines */
569 if (!strncmp (arch, "x86", 3)) {
570 if (bits == 32 || bits == 16) {
571 tcc_define_symbol (s, "__i386__", NULL);
572 tcc_define_symbol (s, "__i386", NULL);
573 tcc_define_symbol (s, "i386", NULL);
574 } else {
575 tcc_define_symbol (s, "__x86_64__", NULL);
576 }
577 } else if (!strncmp (arch, "arm", 3)) {
578 tcc_define_symbol (s, "__ARM_ARCH_4__", NULL);
579 tcc_define_symbol (s, "__arm_elf__", NULL);
580 tcc_define_symbol (s, "__arm_elf", NULL);
581 tcc_define_symbol (s, "arm_elf", NULL);
582 tcc_define_symbol (s, "__arm__", NULL);
583 tcc_define_symbol (s, "__arm", NULL);
584 tcc_define_symbol (s, "arm", NULL);
585 tcc_define_symbol (s, "__APCS_32__", NULL);
586 }
587 // TODO: Add other architectures
588 // TODO: Move that in SDB
589
590 if (!strncmp (os, "windows", 7)) {
591 tcc_define_symbol (s, "__WINDOWS__", NULL);
592 if (bits == 64) {
593 tcc_define_symbol (s, "_WIN64", NULL);
594 }
595 } else {
596 tcc_define_symbol (s, "__unix__", NULL);
597 tcc_define_symbol (s, "__unix", NULL);
598 tcc_define_symbol (s, "unix", NULL);
599
600 if (!strncmp (os, "linux", 5)) {
601 tcc_define_symbol (s, "__linux__", NULL);
602 tcc_define_symbol (s, "__linux", NULL);
603 }
604 #define str(s) #s
605 if (!strncmp (os, "freebsd", 7)) {
606 tcc_define_symbol (s, "__FreeBSD__", str ( __FreeBSD__));
607 }
608 #undef str
609 }
610
611 /* TinyCC & gcc defines */
612 if (!strncmp (os, "windows", 7) && (bits == 64)) {
613 tcc_define_symbol (s, "__SIZE_TYPE__", "unsigned long long");
614 tcc_define_symbol (s, "__PTRDIFF_TYPE__", "long long");
615 } else {
616 tcc_define_symbol (s, "__SIZE_TYPE__", "unsigned long");
617 tcc_define_symbol (s, "__PTRDIFF_TYPE__", "long");
618 }
619
620 if (!strncmp (os, "windows", 7)) {
621 tcc_define_symbol (s, "__WCHAR_TYPE__", "unsigned short");
622 } else {
623 tcc_define_symbol (s, "__WCHAR_TYPE__", "int");
624 /* glibc defines */
625 tcc_define_symbol (s, "__REDIRECT(name, proto, alias)", "name proto __asm__(#alias)");
626 tcc_define_symbol (s, "__REDIRECT_NTH(name, proto, alias)", "name proto __asm__(#alias) __THROW");
627 }
628
629 s->alacarte_link = 1;
630 s->nocommon = 1;
631
632 #ifdef CHAR_IS_UNSIGNED
633 s->char_is_unsigned = 1;
634 #endif
635 /* enable this if you want symbols with leading underscore on windows: */
636 #if 0 /* def TCC_TARGET_PE */
637 s->leading_underscore = 1;
638 #endif
639 if (!strncmp (arch, "x86", 3)) {
640 // TODO: Set it to 16 for 16bit x86
641 if (bits == 32 || bits == 16) {
642 s->seg_size = 32;
643 }
644 }
645 return s;
646 }
647
tcc_delete(TCCState * s1)648 LIBTCCAPI void tcc_delete(TCCState *s1)
649 {
650 tcc_cleanup ();
651
652 /* free library paths */
653 dynarray_reset (&s1->library_paths, &s1->nb_library_paths);
654 dynarray_reset (&s1->crt_paths, &s1->nb_crt_paths);
655
656 /* free include paths */
657 dynarray_reset (&s1->cached_includes, &s1->nb_cached_includes);
658 dynarray_reset (&s1->include_paths, &s1->nb_include_paths);
659 dynarray_reset (&s1->sysinclude_paths, &s1->nb_sysinclude_paths);
660
661 free (s1->tcc_lib_path);
662 free (s1->soname);
663 free (s1->rpath);
664 free (s1->init_symbol);
665 free (s1->fini_symbol);
666 free (s1->outfile);
667 free (s1->deps_outfile);
668 dynarray_reset (&s1->files, &s1->nb_files);
669 dynarray_reset (&s1->target_deps, &s1->nb_target_deps);
670
671 /* target config */
672 free (s1->arch);
673 free (s1->os);
674
675 #ifdef TCC_IS_NATIVE
676 #ifdef HAVE_SELINUX
677 munmap (s1->write_mem, s1->mem_size);
678 munmap (s1->runtime_mem, s1->mem_size);
679 #else
680 free (s1->runtime_mem);
681 #endif
682 #endif
683
684 free (s1);
685 }
686
tcc_add_include_path(TCCState * s,const char * pathname)687 LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname)
688 {
689 tcc_split_path (s, (void ***) &s->include_paths, &s->nb_include_paths, pathname);
690 return 0;
691 }
692
tcc_add_sysinclude_path(TCCState * s,const char * pathname)693 LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname)
694 {
695 tcc_split_path (s, (void ***) &s->sysinclude_paths, &s->nb_sysinclude_paths, pathname);
696 return 0;
697 }
698
tcc_add_file_internal(TCCState * s1,const char * filename,int flags)699 ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
700 {
701 const char *ext;
702 int ret;
703
704 /* find source file type with extension */
705 ext = tcc_fileextension (filename);
706 if (ext[0]) {
707 ext++;
708 }
709
710 /* open the file */
711 ret = tcc_open (s1, filename);
712 if (ret < 0) {
713 if (flags & AFF_PRINT_ERROR) {
714 tcc_error ("file '%s' not found", filename);
715 }
716 return ret;
717 }
718
719 /* update target deps */
720 dynarray_add ((void ***) &s1->target_deps, &s1->nb_target_deps,
721 strdup (filename));
722
723 if (flags & AFF_PREPROCESS) {
724 ret = tcc_preprocess (s1);
725 goto the_end;
726 }
727
728 if (!ext[0] || !PATHCMP (ext, "c") || !PATHCMP (ext, "h") || !PATHCMP (ext, "cparse")) {
729 /* C file assumed */
730 ret = tcc_compile (s1);
731 goto the_end;
732 }
733 if (ret < 0) {
734 tcc_error ("unrecognized file type");
735 }
736
737 the_end:
738 tcc_close ();
739 return ret;
740 }
741
tcc_add_file(TCCState * s,const char * filename,const char * directory)742 LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename, const char *directory)
743 {
744 if (directory) {
745 dir_name = strdup (directory);
746 }
747
748 if (s->output_type == TCC_OUTPUT_PREPROCESS) {
749 return tcc_add_file_internal (s, filename, AFF_PRINT_ERROR | AFF_PREPROCESS);
750 } else {
751 return tcc_add_file_internal (s, filename, AFF_PRINT_ERROR);
752 }
753 }
754
755 #define WD_ALL 0x0001/* warning is activated when using -Wall */
756 #define FD_INVERT 0x0002/* invert value before storing */
757
758 typedef struct FlagDef {
759 uint16_t offset;
760 uint16_t flags;
761 const char *name;
762 } FlagDef;
763
set_flag(TCCState * s,const FlagDef * flags,int nb_flags,const char * name,int value)764 ST_FUNC int set_flag(TCCState *s, const FlagDef *flags, int nb_flags,
765 const char *name, int value)
766 {
767 int i;
768 const FlagDef *p;
769 const char *r;
770
771 r = name;
772 if (r[0] == 'n' && r[1] == 'o' && r[2] == '-') {
773 r += 3;
774 value = !value;
775 }
776 for (i = 0, p = flags; i < nb_flags; i++, p++) {
777 if (!strcmp (r, p->name)) {
778 goto found;
779 }
780 }
781 return -1;
782 found:
783 if (p->flags & FD_INVERT) {
784 value = !value;
785 }
786 *(int *) ((uint8_t *) s + p->offset) = value;
787 return 0;
788 }
789
790 void (*tcc_cb)(const char *, char **);
791
tcc_set_callback(TCCState * s,void (* cb)(const char *,char **),char ** p)792 PUB_FUNC void tcc_set_callback(TCCState *s, void (*cb)(const char *, char **), char **p) {
793 tcc_cb = cb;
794 tcc_cb_ptr = p;
795 }
796
tcc_appendf(const char * fmt,...)797 PUB_FUNC void tcc_appendf(const char *fmt, ...) {
798 char b[1024];
799 va_list ap;
800 va_start (ap, fmt);
801 vsnprintf (b, sizeof (b), fmt, ap);
802 tcc_cb (b, tcc_cb_ptr);
803 va_end (ap);
804 }
805
tcc_typedef_appendf(const char * fmt,...)806 PUB_FUNC void tcc_typedef_appendf(const char *fmt, ...) {
807 if (!tcc_typedefs) {
808 tcc_typedefs = r_pvector_new ((RPVectorFree) free);
809 }
810 char typedefs_tail[1024];
811 va_list ap;
812 va_start (ap, fmt);
813 if (vsnprintf (typedefs_tail, sizeof (typedefs_tail), fmt, ap) > 0) {
814 r_pvector_push (tcc_typedefs, strdup (typedefs_tail));
815 } // XXX else? how this should behave if sizeof (typedefs_tail) is not enough?
816 va_end (ap);
817 }
818
tcc_typedef_alias_fields(const char * alias)819 PUB_FUNC void tcc_typedef_alias_fields(const char *alias) {
820 if (tcc_typedefs) {
821 void **it;
822 r_pvector_foreach (tcc_typedefs, it) {
823 tcc_appendf (*it, alias);
824 }
825 r_pvector_free (tcc_typedefs);
826 tcc_typedefs = NULL;
827 }
828 }
829