Subversion Repositories tendra.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
7 7u83 2
 * Copyright (c) 2002-2005 The TenDRA Project <http://www.tendra.org/>.
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *
8
 * 1. Redistributions of source code must retain the above copyright notice,
9
 *    this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright notice,
11
 *    this list of conditions and the following disclaimer in the documentation
12
 *    and/or other materials provided with the distribution.
13
 * 3. Neither the name of The TenDRA Project nor the names of its contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific, prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
18
 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
21
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
 * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 *
29
 * $Id$
30
 */
31
/*
2 7u83 32
    		 Crown Copyright (c) 1997
7 7u83 33
 
2 7u83 34
    This TenDRA(r) Computer Program is subject to Copyright
35
    owned by the United Kingdom Secretary of State for Defence
36
    acting through the Defence Evaluation and Research Agency
37
    (DERA).  It is made available to Recipients with a
38
    royalty-free licence for its use, reproduction, transfer
39
    to other parties and amendment for any purpose not excluding
40
    product development provided that any such use et cetera
41
    shall be deemed to be acceptance of the following conditions:-
7 7u83 42
 
2 7u83 43
        (1) Its Recipients shall ensure that this Notice is
44
        reproduced upon any copies or amended versions of it;
7 7u83 45
 
2 7u83 46
        (2) Any amended version of it shall be clearly marked to
47
        show both the nature of and the organisation responsible
48
        for the relevant amendment or amendments;
7 7u83 49
 
2 7u83 50
        (3) Its onward transfer from a recipient to another
51
        party shall be deemed to be that party's acceptance of
52
        these conditions;
7 7u83 53
 
2 7u83 54
        (4) DERA gives no warranty or assurance as to its
55
        quality or suitability for any purpose and DERA accepts
56
        no liability whatsoever in relation to any use to which
57
        it may be put.
58
*/
59
 
60
 
61
#include "config.h"
62
#if FS_STDARG
63
#include <stdarg.h>
64
#else
65
#include <varargs.h>
66
#endif
67
#include "list.h"
7 7u83 68
#include "environ.h"
2 7u83 69
#include "flags.h"
70
#include "main.h"
7 7u83 71
#include "options.h"
2 7u83 72
#include "suffix.h"
73
#include "utility.h"
74
 
75
 
76
/*
7 7u83 77
 * ERROR VARIABLES
78
 *
79
 * The value exit_status gives the overall status of the program. It can be
80
 * EXIT_SUCCESS or EXIT_FAILURE. The variable progname gives the name of the
81
 * program, which is used in error reports.
82
 */
2 7u83 83
 
7 7u83 84
int exit_status = EXIT_SUCCESS;
85
char *progname = PROGNAME_TCC;
2 7u83 86
 
87
 
7 7u83 88
/*
89
 * Static function prototypes.
90
 */
2 7u83 91
 
7 7u83 92
static int	key_match(char *, char *);
93
 
94
 
2 7u83 95
/*
7 7u83 96
 * PRINT AN ERROR MESSAGE
97
 *
98
 * This routine prints an error message s (a printf-style string, which may be
99
 * followed by any number of arguments) of severity e (see utility.h).
100
 */
2 7u83 101
 
7 7u83 102
void
103
error(int e, char *s, ...) /* VARARGS */
2 7u83 104
{
7 7u83 105
	va_list args;
106
	char *errtype = null;
2 7u83 107
#if FS_STDARG
7 7u83 108
	va_start(args, s);
2 7u83 109
#else
7 7u83 110
	int e;
111
	char *s;
112
	va_start(args);
113
	e = va_arg(args, int);
114
	s = va_arg(args, char *);
2 7u83 115
#endif
7 7u83 116
	switch (e) {
117
	case FATAL:
118
		exit_status = EXIT_FAILURE;
119
		errtype = "Fatal";
120
		break;
121
	case INTERNAL:
122
		exit_status = EXIT_FAILURE;
123
		errtype = "Internal";
124
		break;
125
	case SERIOUS:
126
		exit_status = EXIT_FAILURE;
127
		errtype = "Error";
128
		break;
129
	case OPTION:
130
		exit_status = EXIT_FAILURE;
131
		errtype = "Option interpreter";
132
		break;
133
	case WARNING:
134
		if (!warnings) {
135
			va_end(args);
136
			return;
137
		}
138
		errtype = "Warning";
139
		break;
140
	case INFO:
141
		errtype = "Information";
142
		break;
2 7u83 143
	}
7 7u83 144
 
145
	if (checker) {
146
		progname = PROGNAME_TCHK;
2 7u83 147
	}
7 7u83 148
	IGNORE fprintf(stderr, "%s: ", progname);
149
	if (errtype) {
150
		IGNORE fprintf(stderr, "%s: ", errtype);
2 7u83 151
	}
7 7u83 152
	IGNORE vfprintf(stderr, s, args);
153
	IGNORE fprintf(stderr, ".\n");
154
	va_end(args);
155
	if (e == FATAL) {
156
		main_end();
2 7u83 157
	}
7 7u83 158
	return;
159
}
160
 
161
 
162
/*
163
 * HASH TABLE
164
 *
165
 * These functions provide access to a hash table of tccenv(5) keys and values.
166
 * When created, the hash table is populated with tccenv keys taken from the
167
 * environ_optmap[] array, and flaged as tccenv-derived instead of
168
 * user-created.
169
 */
170
 
171
hashtable*
172
init_table(int tblsize, int keysize, int (*hashfcn) (char*, int, int))
173
{
174
	int i;
175
	hashtable* ht;
176
	htnode *hn;
177
	optmap *t;
178
 
179
	ht = malloc(sizeof(hashtable));
180
	ht->tblsize = tblsize;
181
	ht->keysize = keysize;
182
	ht->hashfcn = hashfcn;
183
	ht->node = malloc(sizeof(htnode*) * tblsize);
184
 
185
	for (i = 0; i < tblsize; i++) {
186
		ht->node[i] = NULL;
2 7u83 187
	}
7 7u83 188
 
189
	for (t = environ_optmap; t->in != NULL; t++) {
190
		/* initialize hash table with tccenv keys */
191
		hn = update_table(ht, t->in, NULL, TCCENV, NULL, -1);
2 7u83 192
	}
7 7u83 193
 
194
	return ht;
2 7u83 195
}
196
 
7 7u83 197
htnode *
198
lookup_table(hashtable *ht, char *key)
199
{
200
	int  hashval;
201
	htnode *hn;
202
	char *v = NULL;
2 7u83 203
 
7 7u83 204
	if (!key) {
205
		error(WARNING, "Looking up null key in tccenv hashtable");
206
 
207
		return NULL;
208
	}
209
 
210
	hashval = ht->hashfcn(key, ht->tblsize, ht->keysize);
211
	hn = ht->node[hashval];
212
 
213
	if (hn) {
214
		v = hn->key;
215
	}
216
 
217
	while (hn != NULL && !key_match(key, hn->key)) {
218
		hn = hn->next;
219
	}
220
 
221
	if (hn) {
222
		hn->flag |= READ;
223
	}
224
 
225
	return hn;
226
}
227
 
228
static int
229
key_match(char *key, char *keyfield)
230
{
231
	int i;
232
 
233
	if (!key || !keyfield) {
234
		return 0;
235
	}
236
 
237
	/* advance pointers past command chars */
238
	while(key && !is_alphanum(*key)) {
239
		key++;
240
	}
241
 
242
	while(keyfield && !is_alphanum(*keyfield)) {
243
		keyfield++;
244
	}
245
 
246
	for (i = 0; i < strlen(key); i++) {
247
		if (key[i] != keyfield[i]) {
248
			return 0;
249
		}
250
	}
251
 
252
	return 1;
253
}
254
 
255
htnode *
256
update_table(hashtable *ht, char *key, char *val, unsigned int flag,
257
	     char *file, int line_num)
258
{
259
	int hashval;
260
	htnode *hn;
261
	hashval = ht->hashfcn(key, ht->tblsize, ht->keysize);
262
	hn = ht->node[hashval];
263
 
264
	/* locate matching node */
265
	while (hn != NULL && !key_match(key, hn->key)) {
266
		hn = hn->next;
267
	}
268
 
269
	/* Case 1.  Node was not found; push */
270
	if (hn == NULL) {
271
		hn = malloc(sizeof(htnode));
272
		hn->flag = flag;
273
		hn->key = key;
274
		hn->val = val;
275
		hn->file = file;
276
		hn->line_num = line_num;
277
		hn->next = ht->node[hashval];
278
		ht->node[hashval] = hn;
279
	} else {
280
		/* Case 2.  Update */
281
		if (!val) {
282
			hn->val = NULL;
283
		} else {
284
			switch (*key) {
285
			case '+':
286
				/* assignment */
287
				hn->val = val;
288
				break;
289
			case '>':
290
				/* append */
291
				if (hn->val) {
292
					hn->val =
293
					    string_append(hn->val, val, ' ');
294
				}
295
				hn->val = val;
296
				break;
297
			case '<':
298
				/* prepend */
299
				if (hn->val) {
300
					hn->val =
301
					    string_append(val, hn->val, ' ');
302
				}
303
				hn->val = val;
304
				break;
305
			default:
306
				/*
307
				 * This should never happen, since read_env_aux
308
				 * screens for this.
309
				 */
310
				error(FATAL, "Attempt to update hashtable with"
311
				      " invalid key %s\n", key);
312
			}
313
		}
314
	}
315
 
316
	return hn;
317
}
318
 
2 7u83 319
/*
7 7u83 320
 * Hash function. The function takes in a char * to a key, presumed to be in
321
 * the form of <cmd><tccenv_var>, e.g., "+AS /usr/bin/as". The hash calculated
322
 * skips over the leading command char, either +, <, >, or ?.
323
 */
324
int
325
hash(char *key, int tblsize, int keysize)
326
{
327
	int i = 1;
328
	int hashval = 0;
2 7u83 329
 
7 7u83 330
	/* skip leading +, <, >, ?, / chars */
331
	while (key && !(is_alphanum(*key))) {
332
		key++;
333
	}
2 7u83 334
 
7 7u83 335
	if (!key) {
336
		error(FATAL, "hash operation requested on empty key");
337
	}
338
 
339
	while (*key && !is_whitespace(*key) && i < keysize) {
340
		hashval += (hashval * 37) + (int) *key;
341
		*key++;
342
		i++;
343
	}
344
 
345
	hashval %= tblsize;
346
	if (hashval < 0) {
347
		hashval += tblsize;
348
	}
349
 
350
	return hashval;
351
}
352
 
353
 
354
/*
355
 * PRINT A COMMENT
356
 *
357
 * This routine prints the comments (a printf-style string, which may be
358
 * followed by any number of arguments) to the standard output.
359
 */
360
 
361
void
362
comment(int e, char *s, ...) /* VARARGS */
2 7u83 363
{
7 7u83 364
	FILE *f;
365
	va_list args;
2 7u83 366
#if FS_STDARG
7 7u83 367
	va_start(args, s);
2 7u83 368
#else
7 7u83 369
	int e;
370
	char *s;
371
	va_start(args);
372
	e = va_arg(args, int);
373
	s = va_arg(args, char *);
2 7u83 374
#endif
7 7u83 375
	f = (e ? stdout : stderr);
376
	IGNORE fflush(f);
377
	IGNORE vfprintf(f, s, args);
378
	IGNORE fflush(f);
379
	va_end(args);
380
	return;
2 7u83 381
}
382
 
383
 
384
/*
7 7u83 385
 * ALLOCATE A BLOCK OF MEMORY
386
 *
387
 * This routine allocates a block of memory of size sz and returns the result.
388
 */
2 7u83 389
 
7 7u83 390
pointer
391
xalloc(int sz)
392
{
393
	pointer p = (pointer)malloc((size_t)sz);
394
	if (p == null) {
395
		error(FATAL, "Memory allocation error");
396
	}
397
	return (p);
398
}
2 7u83 399
 
7 7u83 400
 
401
/*
402
 * REALLOCATE A BLOCK OF MEMORY
403
 *
404
 * This routine reallocates the block of memory p to have size sz.
405
 * xrealloc(*null, sz) is equivalent to xalloc(sz).
406
 */
407
 
408
pointer
409
xrealloc(pointer p, int sz)
2 7u83 410
{
7 7u83 411
    pointer q;
412
    if (p == null) {
413
	    return (xalloc(sz));
414
    }
415
    q = (pointer)realloc(p,(size_t)sz);
416
    if (q == null) {
417
	    error(FATAL, "Memory reallocation error");
418
    }
419
    return (q);
2 7u83 420
}
421
 
422
 
423
/*
7 7u83 424
 * Takes in a substitution variable as an argument, and returns its
425
 * corresponding value. This routine is used by the env substitution function
426
 * (see format_path) to map variables to paths.
427
 *
428
 * For example, input is "<TCCDIR_BASE>", and return value is
429
 * "/usr/local/share/". Variable lookup is prioritized:
430
 *
431
 *   a) command line args have highest priority,
432
 *   b) environment variables are used next,
433
 *   c) for a select group of variables, sane defaults are used.
434
 */
2 7u83 435
 
7 7u83 436
char *
437
find_path_subst(char *var)
438
{
439
	char *ret;
440
	char **subs;
441
	int i = 0;
2 7u83 442
 
7 7u83 443
	i = 0;
444
	subs = PATH_SUBS;
445
	while (*subs){
446
		if (!strcmp(var, *subs)) {
447
			if (env_paths[i] == NULL){
448
				error(FATAL, "The env variable <%s> is null.\n"
449
				      "Check your environment or edit your env"
450
				      " files", PATH_SUBS[i]);
451
			}
452
			return env_paths[i];
453
		}
454
		i++;
455
		subs++;
456
	}
457
	if (!*subs) {
458
		error(WARNING, "Expected command line option -y%s=[value]; "
459
		      "trying environment", var);
460
	}
461
	ret = getenv(var);
2 7u83 462
 
7 7u83 463
	/* XXX: Perhaps this should not be fatal? */
464
	if (!ret) {
465
		error(FATAL, "Unknown environment variable %s", var);
466
	}
467
	return ret;
2 7u83 468
}
469
 
470
 
471
/*
7 7u83 472
 * ALLOCATE SPACE FOR A STRING
473
 *
474
 * This routine allocates n characters of memory for use in the string memory
475
 * allocation routines.
476
 */
2 7u83 477
 
7 7u83 478
static char *
479
string_alloc(int n)
2 7u83 480
{
7 7u83 481
	char *r;
482
	if (n >= 1000) {
483
		/* Long strings are allocated space by alloc_nof */
484
		r = alloc_nof(char, n);
485
	} else {
486
		/* Short strings are allocated space from a buffer */
487
		static int no_free = 0;
488
		static char *free_chars = null;
489
		if (n >= no_free) {
490
			no_free = 4000;
491
			free_chars = alloc_nof(char, no_free);
492
		}
493
		r = free_chars;
494
		no_free -= n;
495
		free_chars += n;
2 7u83 496
	}
7 7u83 497
	return (r);
2 7u83 498
}
499
 
500
 
501
/*
7 7u83 502
 * COPY A STRING
503
 *
504
 * This routine allocates space for a copy of the string s and copies the
505
 * string into this space. This copy is returned.
506
 */
2 7u83 507
 
7 7u83 508
char *
509
string_copy(char *s)
2 7u83 510
{
7 7u83 511
	int n = (int)strlen(s);
512
	char *r = string_alloc(n + 1);
513
	IGNORE strcpy(r, s);
514
	return (r);
2 7u83 515
}
516
 
517
 
518
/*
7 7u83 519
 * COPY TWO STRINGS
520
 *
521
 * This routine allocates space for a copy of the string s followed by a copy
522
 * of the string t and concatenates the strings into this space. This copy is
523
 * returned.
524
 */
2 7u83 525
 
7 7u83 526
char *
527
string_concat(char *s, char *t)
2 7u83 528
{
7 7u83 529
	int n = (int)strlen(s);
530
	int m = (int)strlen(t);
531
	char *r = string_alloc(n + m + 1);
532
	IGNORE strcpy(r, s);
533
	IGNORE strcpy(r + n, t);
534
	return (r);
2 7u83 535
}
536
 
537
 
7 7u83 538
/*	
539
 * APPEND TWO STRINGS	
540
 *   
541
 * This routine allocates space for a copy of the string s followed by a copy
542
 * of the string t and concatenates the strings into this space, placing the
543
 * delimiter character between them. The copy is returned.  E.g.,:	
544
 *   
545
 * Given:    "foo" + "bar" + ':'	
546
 * Returns:  "foo:bar"	
547
 */	
548
 
549
char *	
550
string_append(char *s, char *t, char delimeter)	
551
{	
552
	int n = (int)strlen(s);	
553
	int m = (int)strlen(t);	
554
	char *r = string_alloc(n + m + 2);	
555
	IGNORE strcpy(r, s);	
556
	*(r + n) = delimeter;	
557
	IGNORE strcpy(r + n + 1, t);	
558
	return (r);
559
}
560
 
561
 
2 7u83 562
/*
7 7u83 563
 * TEMPORARY WORK SPACE
564
 *
565
 * This variable gives a temporary work space of size buffer_size (see
566
 * utility.h) which is used as a scratch work area.
567
 */
2 7u83 568
 
7 7u83 569
char *buffer;