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