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
#include "filename.h"
63
#include "list.h"
64
#include "external.h"
65
#include "flags.h"
66
#include "startup.h"
67
#include "suffix.h"
68
#include "utility.h"
69
 
70
 
71
/*
7 7u83 72
 * CASE SENSITIVITY FLAG
73
 *
74
 * This flag may be set to true to make tcc ignore case in filename suffixes.
75
 */
2 7u83 76
 
7 7u83 77
boolean case_insensitive = 0;
2 7u83 78
 
79
 
80
/*
7 7u83 81
 * IS A CHARACTER UPPER CASE?
82
 *
83
 * This macro checks whether the character C is upper case.  It is ASCII
84
 * dependent.
85
 */
2 7u83 86
 
7 7u83 87
#define is_upper_case(C)	((C) >= 'A' && (C) <= 'Z')
2 7u83 88
 
89
 
90
/*
7 7u83 91
 * CONVERT A STRING TO LOWER CASE
92
 *
93
 * This routine converts the string s to lower case.
94
 */
2 7u83 95
 
7 7u83 96
static void
97
to_lower_case(char *s)
2 7u83 98
{
7 7u83 99
	char c;
100
	while (c = *s, c != 0) {
101
		if (is_upper_case(c)) {
102
			*s = (char)(c - 'A' + 'a');
103
		}
104
		s++;
2 7u83 105
	}
7 7u83 106
	return;
2 7u83 107
}
108
 
109
 
110
/*
7 7u83 111
 * SUFFIX OVERRIDES
112
 *
113
 * This table contains the strings which are used when the suffix overrides are
114
 * set from the command line. Initially, it is empty. This table needs to be
115
 * kept in step with Table 1.
116
 */
2 7u83 117
 
7 7u83 118
char *suffixes[TYPE_ARRAY_SIZE] = {
119
	null,	/* C_SOURCE */
120
	null,	/* PREPROC_C */
121
	"cpp",	/* CPP_SOURCE */
122
	null,	/* PREPROC_CPP */
123
	null,	/* INDEP_TDF */
124
	null,	/* DEP_TDF */
125
	null,	/* AS_SOURCE */
126
	null,	/* BINARY_OBJ */
127
	null,	/* EXECUTABLE */
128
	null,	/* PRETTY_TDF */
129
	null,	/* PL_TDF */
130
	null,	/* TDF_ARCHIVE */
131
	null,	/* MIPS_G_FILE */
132
	null,	/* MIPS_T_FILE */
133
	null,	/* C_SPEC */
134
	null,	/* CPP_SPEC */
135
	null,  	/* ERROR_FILE */
136
	null,	/* STARTUP_FILE */
137
	null,	/* UNKNOWN_TYPE */
138
	null,	/* INDEP_TDF_COMPLEX (dummy type) */
139
	null,	/* C_SPEC_1 (dummy type) */
140
	null,	/* C_SPEC_2 (dummy type) */
141
	null,	/* INDEP_TDF_AUX (dummy type) */
142
	null	/* BINARY_OBJ_AUX (dummy type) */
143
};
2 7u83 144
 
145
 
146
/*
7 7u83 147
 * FILE STORAGE LOCATIONS
148
 *
149
 * Output files may be stored either in the temporary directory, tempdir, or
150
 * the work directory, workdir.
151
 */
2 7u83 152
 
7 7u83 153
char *tempdir = null;
154
char *workdir = null ;
2 7u83 155
 
156
 
157
/*
7 7u83 158
 * FIND THE BASE NAME OF A FILE
159
 *
160
 * This routine returns the basename of the file name s.
161
 */
2 7u83 162
 
7 7u83 163
char *
164
find_basename(char *s)
2 7u83 165
{
7 7u83 166
	char *r = s;
167
	for (; *s; s++) {
168
		if (*s == '/')r = s + 1;
169
	}
170
	return(r);
2 7u83 171
}
172
 
173
 
174
/*
7 7u83 175
 * FIND THE FULL NAME OF A FILE
176
 *
177
 * This routine returns the full name of the file name s.
178
 */
2 7u83 179
 
7 7u83 180
char *
181
find_fullname(char *s)
2 7u83 182
{
7 7u83 183
	static char *pwd = null;
184
	if (*s == '/') {
185
		return (s);
2 7u83 186
	}
7 7u83 187
	if (pwd == null) {
188
		if (get_cwd(buffer, buffer_size)) {
189
			pwd = string_concat(buffer, "/");
190
		} else {
191
			error(WARNING,
192
			      "Can't determine current working directory");
193
			pwd = "";
194
		}
195
	}
196
	return (string_concat(pwd, s));
2 7u83 197
}
198
 
199
 
200
/*
7 7u83 201
 * SPLIT OFF THE SUFFIX OF A FILE NAME
202
 *
203
 * This routine splits the file name s into two part, the base part and the
204
 * file suffix, and returns the latter.
205
 */
2 7u83 206
 
7 7u83 207
static char *
208
split_name(char *s)
2 7u83 209
{
7 7u83 210
	int i, n = (int)strlen(s);
211
	for (i = n - 1; i >= 0; i--) {
212
		if (s[i] == '.') {
213
			s[i] = 0;
214
			if (case_insensitive) {
215
				/* Allow for case insensitive systems */
216
				to_lower_case(s + (i + 1));
217
			}
218
			return (s + (i + 1));
219
		}
2 7u83 220
	}
7 7u83 221
	return ("");
2 7u83 222
}
223
 
224
 
225
/*
7 7u83 226
 * CREATE A NEW FILENAME
227
 *
228
 * This routine allocates a new filename structure.
229
 */
2 7u83 230
 
7 7u83 231
static filename *
232
new_filename(void)
2 7u83 233
{
7 7u83 234
	static int no_free = 0;
235
	static filename *free_objs = null;
236
	if (no_free == 0) {
237
		no_free = 1000;
238
		free_objs = alloc_nof(filename, no_free);
239
	}
240
	return (free_objs + (--no_free));
2 7u83 241
}
242
 
243
 
244
/*
7 7u83 245
 * ADD A FILENAME TO A LIST
246
 *
247
 * This routine joins the two filename lists, p and q, returning the result.
248
 */
2 7u83 249
 
7 7u83 250
filename *
251
add_filename(filename *p, filename *q)
2 7u83 252
{
7 7u83 253
	filename *r;
254
	if (p == null) {
255
		return (q);
256
	}
257
	if (q == null) {
258
		return (p);
259
	}
260
	for (r = p; r->next != null; r = r->next) {
261
		;	/* empty */
262
	}
263
	r->next = q;
264
	return (p);
2 7u83 265
}
266
 
267
 
268
/*
7 7u83 269
 * CONVERT A KEY LETTER TO A FILE TYPE
270
 *
271
 * This routine converts the letter s, which can be a file suffix (if suff is
272
 * true), or a stage identifier (otherwise), to a file type. This routine
273
 * needs to be kept in step with Table 1 and Table 2.
274
 */
2 7u83 275
 
7 7u83 276
int
277
find_type(int s, int suff)
2 7u83 278
{
7 7u83 279
	switch (s) {
280
	case C_SOURCE_KEY:
281
		return (C_SOURCE);
282
	case PREPROC_C_KEY:
283
		return (PREPROC_C);
284
	case CPP_SOURCE_KEY:
285
		return (CPP_SOURCE);
286
	case PREPROC_CPP_KEY:
287
		return (PREPROC_CPP);
288
	case AS_SOURCE_KEY:
289
		return (AS_SOURCE);
290
	case BINARY_OBJ_KEY:
291
		return (BINARY_OBJ);
292
	case C_SPEC_KEY:
293
		return (C_SPEC);
294
	case CPP_SPEC_KEY:
295
		return (CPP_SPEC);
2 7u83 296
	}
7 7u83 297
	if (!checker) {
298
		switch (s) {
299
		case INDEP_TDF_KEY:
300
			return (INDEP_TDF);
301
		case DEP_TDF_KEY:
302
			return (DEP_TDF);
303
		case PRETTY_TDF_KEY:
304
			return (PRETTY_TDF);
305
		}
2 7u83 306
	}
7 7u83 307
	if (suff) {
308
		return(DEFAULT_TYPE);
309
	}
310
	switch (s) {
311
	case MIPS_G_FILE_KEY:
312
		return (MIPS_G_FILE);
313
	case MIPS_T_FILE_KEY:
314
		return (MIPS_T_FILE);
315
	case STARTUP_FILE_KEY:
316
		return (STARTUP_FILE);
317
	case ALL_KEY:
318
		return (ALL_TYPES);
319
	}
320
	if (!checker) {
321
		switch (s) {
322
		case PL_TDF_KEY:
323
			return (PL_TDF);
324
		case TDF_ARCHIVE_KEY:
325
			return (TDF_ARCHIVE);
326
		}
327
	}
328
	error(WARNING, "Unknown file type, '%c'",(unsigned char)s);
329
	return (UNKNOWN_TYPE);
2 7u83 330
}
331
 
332
 
333
/*
7 7u83 334
 * FIND A FILE SUFFIX
335
 *
336
 * This routine converts a file type, t, into the corresponding file suffix. It
337
 * needs to be kept in step with Table 1 and Table 2.
338
 */
2 7u83 339
 
7 7u83 340
static char *
341
file_suffix(int t)
2 7u83 342
{
7 7u83 343
	static char suff[3];
344
	suff[0] = 0;
345
	suff[1] = 0;
346
	suff[2] = 0;
347
	switch (t) {
348
	case C_SOURCE:
349
		suff[0] = C_SOURCE_KEY;
350
		break;
351
	case PREPROC_C:
352
		suff[0] = PREPROC_C_KEY;
353
		break;
354
	case CPP_SOURCE:
355
		suff[0] = CPP_SOURCE_KEY;
356
		break;
357
	case PREPROC_CPP:
358
		suff[0] = PREPROC_CPP_KEY;
359
		break;
360
	case INDEP_TDF:
361
		suff[0] = INDEP_TDF_KEY;
362
		break;
363
	case INDEP_TDF_AUX:
364
		suff[0] = INDEP_TDF_KEY;
365
		suff[1] = EXTRA_KEY;
366
		break;
367
	case DEP_TDF:
368
		suff[0] = DEP_TDF_KEY;
369
		break;
370
	case AS_SOURCE:
371
		suff[0] = AS_SOURCE_KEY;
372
		break;
373
	case BINARY_OBJ:
374
		suff[0] = BINARY_OBJ_KEY;
375
		break;
376
	case BINARY_OBJ_AUX:
377
		if ((use_sparc_cc == 1) && use_system_cc) {
378
			suff[0] = '.';
379
			suff[1] = BINARY_OBJ_KEY;
380
		} else {
381
			suff[0] = BINARY_OBJ_AUX_KEY;
382
		}
383
		break;
384
	case PRETTY_TDF:
385
		suff[0] = PRETTY_TDF_KEY;
386
		break;
387
	case PL_TDF:
388
		suff[0] = PL_TDF_KEY;
389
		break;
390
	case MIPS_G_FILE:
391
		suff[0] = MIPS_G_FILE_KEY;
392
		break;
393
	case MIPS_T_FILE:
394
		suff[0] = MIPS_T_FILE_KEY;
395
		break;
396
	case C_SPEC:
397
		suff[0] = C_SPEC_KEY;
398
		break;
399
	case CPP_SPEC:
400
		suff[0] = CPP_SPEC_KEY;
401
		break;
2 7u83 402
	}
7 7u83 403
	if (suff[0]) {
404
		if (case_insensitive && is_upper_case(suff[0])) {
405
			/* Make allowances for case insensitive systems */
406
			to_lower_case(suff);
407
			suff[1] = suff[0];
408
		}
409
		return (suff);
2 7u83 410
	}
7 7u83 411
	error(SERIOUS, "Illegal file type");
412
	return (file_suffix(DEFAULT_TYPE));
2 7u83 413
}
414
 
415
 
416
/*
7 7u83 417
 * NEXT FILENAME IS ACTUALLY AN INPUT OPTION
418
 *
419
 * Some command-line options, for example, system libraries, are treated like
420
 * input files. This flag is set to indicate that the next input file is
421
 * actually an input option.
422
 */
2 7u83 423
 
7 7u83 424
boolean option_next = 0;
2 7u83 425
 
426
 
427
/*
7 7u83 428
 * COUNT OF NUMBER OF INPUT FILES
429
 *
430
 * The number of calls to find_filename is recorded. Input options are excluded
431
 * from this count.
432
 */
2 7u83 433
 
7 7u83 434
int no_input_files = 0;
2 7u83 435
 
436
 
437
/*
7 7u83 438
 * ALLOCATE A NEW UNIQUE IDENTIFIER
439
 *
440
 * Each file is assigned a unique number which identifies it and all the files
441
 * derived from it. This macro assigns a new unique number.
442
 */
2 7u83 443
 
7 7u83 444
static int uniq_no = 0;
445
#define new_unique()	(uniq_no++)
2 7u83 446
 
447
 
448
/*
7 7u83 449
 * CREATE A FILENAME FROM A PATHNAME
450
 *
451
 * This routine creates a new filename structure, corresponding to the file
452
 * with name s and type t. If t is UNKNOWN_TYPE then the actual file type is
453
 * deduced from the file suffix. This routine needs to be kept in step with
454
 * Table 1, Table 2 and Table 3.
455
 */
2 7u83 456
 
7 7u83 457
filename *
458
find_filename(char *s, int t)
2 7u83 459
{
7 7u83 460
	filename *p = new_filename();
461
	char *b = string_copy(find_basename(s));
462
	char *e = split_name(b);
463
	int i;
2 7u83 464
 
7 7u83 465
	/* Find the file type */
466
	if (suffix_overrides && t == UNKNOWN_TYPE) {
467
		for (i = 0; i < TYPE_ARRAY_SIZE; i++) {
468
			if (suffixes[i]!= null && streq(e, suffixes[i])) {
469
				if (checker) {
470
					if (i == PL_TDF || i == TDF_ARCHIVE) {
471
						continue;
472
					}
473
				}
474
				t = i;
475
				break;
476
			}
2 7u83 477
		}
478
	}
7 7u83 479
	if (t == UNKNOWN_TYPE) {
480
		if (e[0]) {
481
			if (e[1]) {
482
				if (e[2]) {
483
					/* Length >= 3 */
484
					if (streq(e, CPP_2_SUFFIX)) {
485
						t = CPP_SOURCE;
486
					} else if (streq(e, PREPROC_CPP_2_SUFFIX)) {
487
						t = PREPROC_CPP;
488
					} else if (streq(e, AS_2_SUFFIX)) {
489
						t = AS_SOURCE;
490
					} else {
491
						t = DEFAULT_TYPE;
492
					}
493
				} else {
494
					/* Length == 2 */
495
					if (e[1] == EXTRA_KEY) {
496
						t = find_type(e[0], 1);
497
					} else if (streq(e, CPP_1_SUFFIX)) {
498
						t = CPP_SOURCE;
499
					} else if (streq(e, PREPROC_CPP_1_SUFFIX)) {
500
						t = PREPROC_CPP;
501
					} else if (streq(e, CPP_SPEC_1_SUFFIX)) {
502
						t = CPP_SPEC;
503
					} else if (checker) {
504
						t = DEFAULT_TYPE;
505
					} else if (streq(e, PL_TDF_SUFFIX)) {
506
						t = PL_TDF;
507
					} else if (streq(e, TDF_ARCHIVE_SUFFIX)) {
508
						t = TDF_ARCHIVE;
509
					} else {
510
						t = DEFAULT_TYPE;
511
					}
512
				}
513
			} else {
514
				/* Length == 1 */
515
				t = find_type(e[0], 1);
516
			}
2 7u83 517
		} else {
7 7u83 518
			/* Length == 0 */
519
			t = DEFAULT_TYPE;
2 7u83 520
		}
7 7u83 521
	}
522
 
523
	/* Return the result */
524
	p->name = s;
525
	p->bname = b;
526
	p->uniq = new_unique();
527
	p->type = t;
528
	if (option_next) {
529
		p->storage = INPUT_OPTION;
530
		option_next = 0;
2 7u83 531
	} else {
7 7u83 532
		p->storage = INPUT_FILE;
533
		no_input_files++;
2 7u83 534
	}
7 7u83 535
	p->final = 0;
536
	p->aux = null;
537
	p->next = null;
538
	return (p);
2 7u83 539
}
540
 
541
 
542
/*
7 7u83 543
 * FIND WHERE TO STORE FILES OF A GIVEN TYPE
544
 *
545
 * This routine returns the storage class for files of type t. Note that this
546
 * may be PRESERVED_FILE which is only a legal storage type when it is passed
547
 * to make_filename (which turns it into OUTPUT_FILE).
548
 */
2 7u83 549
 
7 7u83 550
int
551
where(int t)
2 7u83 552
{
7 7u83 553
	if (!keeps[t]) {
554
		return (TEMP_FILE);
555
	}
556
	if (!stops[t]) {
557
		return (PRESERVED_FILE);
558
	}
559
	return (OUTPUT_FILE);
2 7u83 560
}
561
 
562
 
563
/*
7 7u83 564
 * CREATE A FILENAME FROM ANOTHER FILENAME
565
 *
566
 * This routine creates a new filename structure by forming the file derived
567
 * from p which has type t and storage s. This routine needs to be kept in step
568
 * with Table 1 and Table 2.
569
 */
2 7u83 570
 
7 7u83 571
filename *
572
make_filename(filename *p, int t, int s)
2 7u83 573
{
7 7u83 574
	boolean f = 0;
575
	char *b, *d, *e;
576
	char *nm = null;
577
	filename *q = new_filename();
2 7u83 578
 
7 7u83 579
	/* Examine the storage class */
580
	switch (s) {
581
	case INPUT_FILE:
582
	case INPUT_OPTION:
583
		/* This shouldn't occur */
584
		d = null;
585
		break;
586
	case OUTPUT_FILE:
587
		/* Check output file name */
588
		if (final_name) {
589
			static boolean used_final_name = 0;
590
			if (used_final_name) {
591
				error(WARNING,
592
				      "Can only name one file with '-o'");
593
			} else {
594
				nm = final_name;
595
				b = find_basename(nm);
2 7u83 596
#ifdef EXECUTABLE_SUFFIX
7 7u83 597
				if (t == EXECUTABLE &&
598
				    strchr(b, '.') == null) {
599
					/* Add '.exe' suffix if necessary */
600
					nm = string_concat(nm,
601
							   EXECUTABLE_SUFFIX);
602
					b = string_concat(b, EXECUTABLE_SUFFIX);
603
				}
2 7u83 604
#endif
7 7u83 605
				used_final_name = 1;
606
				f = 1;
607
			}
2 7u83 608
		}
7 7u83 609
		d = workdir;
610
		break;
611
	case PRESERVED_FILE:
612
		/* Preserved files are turned into output files */
613
		d = workdir;
614
		s = OUTPUT_FILE;
615
		break;
616
	case TEMP_FILE:
617
		/* Temporary files */
618
		d = tempdir;
619
		break;
620
	default:
621
		error(INTERNAL, "Illegal storage type");
622
		d = null;
623
		break;
2 7u83 624
	}
7 7u83 625
 
626
	/* Find the file name */
627
	if (nm == null) {
628
		if (p != null && p->type == t) {
629
			nm = find_basename(p->name);
630
			if (d != null) {
631
				IGNORE sprintf(buffer, "%s/%s", d, nm);
632
				nm = string_copy(buffer);
633
			}
634
			b = p->bname;
635
		} else if (s == TEMP_FILE && p != null && !verbose) {
636
			switch (t) {
637
			case BINARY_OBJ_AUX:
638
			case BINARY_OBJ:
639
				break;
640
			case C_SPEC:
641
				break;
642
			case CPP_SPEC:
643
				break;
644
			case INDEP_TDF_AUX:
645
			case INDEP_TDF:
646
				if (make_archive || make_complex ||
647
				    tokdef_name) {
648
					break;
649
				}
650
				goto default_lab;
651
			default:
652
default_lab:
653
				b = p->bname;
654
				e = file_suffix(t);
655
				IGNORE sprintf(buffer, "%s/%s.%s", d,
656
					       TEMP_NAME, e);
657
				nm = string_copy(buffer);
658
				break;
659
			}
660
		}
2 7u83 661
	}
662
 
7 7u83 663
	/* Find the file name */
664
	if (nm == null) {
665
		if (p == null || make_up_names) {
666
			static int seq = 0;
667
			IGNORE sprintf(buffer, MADE_UP_NAME, seq++);
668
			b = string_copy(buffer);
669
		} else {
670
			b = p->bname;
2 7u83 671
		}
7 7u83 672
		e = file_suffix(t);
673
		if (d == null) {
674
			IGNORE sprintf(buffer, "%s.%s", b, e);
675
		} else {
676
			IGNORE sprintf(buffer, "%s/%s.%s", d, b, e);
2 7u83 677
		}
7 7u83 678
		nm = string_copy(buffer);
2 7u83 679
	}
680
 
7 7u83 681
	/* Fill in the fields of the result */
682
	SET(b);
683
	q->name = nm;
684
	q->bname = b;
685
	q->uniq = (p ? p->uniq : new_unique());
686
	q->type = t;
687
	q->storage = s;
688
	q->final = f;
689
	q->aux = null;
690
	q->next = null;
691
	return (q);
2 7u83 692
}