Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – tendra.SVN – Blame – /branches/tendra4/src/utilities/make_mf/output.c – Rev 2

Subversion Repositories tendra.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
2
    		 Crown Copyright (c) 1997
3
 
4
    This TenDRA(r) Computer Program is subject to Copyright
5
    owned by the United Kingdom Secretary of State for Defence
6
    acting through the Defence Evaluation and Research Agency
7
    (DERA).  It is made available to Recipients with a
8
    royalty-free licence for its use, reproduction, transfer
9
    to other parties and amendment for any purpose not excluding
10
    product development provided that any such use et cetera
11
    shall be deemed to be acceptance of the following conditions:-
12
 
13
        (1) Its Recipients shall ensure that this Notice is
14
        reproduced upon any copies or amended versions of it;
15
 
16
        (2) Any amended version of it shall be clearly marked to
17
        show both the nature of and the organisation responsible
18
        for the relevant amendment or amendments;
19
 
20
        (3) Its onward transfer from a recipient to another
21
        party shall be deemed to be that party's acceptance of
22
        these conditions;
23
 
24
        (4) DERA gives no warranty or assurance as to its
25
        quality or suitability for any purpose and DERA accepts
26
        no liability whatsoever in relation to any use to which
27
        it may be put.
28
*/
29
 
30
 
31
#include "config.h"
32
#include "types.h"
33
#include "depend.h"
34
#include "error.h"
35
#include "option.h"
36
#include "output.h"
37
#include "path.h"
38
 
39
 
40
/*
41
    OUTPUT VARIABLES
42
 
43
    The variable max_column controls the maximum width of the output.  The
44
    flag dos_output determines whether filenames are output in DOS form.
45
*/
46
 
47
int max_column = 75 ;
48
int dos_output = 0 ;
49
int relative_output = 0 ;
50
 
51
 
52
/*
53
    STRING LENGTH
54
 
55
    This macro finds the length of a string, converting the result to an
56
    int.
57
*/
58
 
59
#define length( S )	( ( int ) strlen ( S ) )
60
 
61
 
62
/*
63
    PRINT A PATHNAME
64
 
65
    This routine prints the pathname p to the file f, substituting any
66
    aliases.
67
*/
68
 
69
static void output_pathname
70
    PROTO_N ( ( p, f ) )
71
    PROTO_T ( PATHNAME *p X FILE *f )
72
{
73
    char *a = p->alias ;
74
    if ( a ) {
75
	fputc_v ( '$', f ) ;
76
	fputc_v ( '{', f ) ;
77
	fputs_v ( a, f ) ;
78
	fputc_v ( '}', f ) ;
79
    } else {
80
	char *c = p->name ;
81
	int sep = ( dos_output ? '\\' : '/' ) ;
82
	if ( p == root_dir ) {
83
	    fputs_v ( c, f ) ;
84
	    fputc_v ( sep, f ) ;
85
	} else if ( p == anonymous_dir ) {
86
	    fputs_v ( ".", f ) ;
87
	} else {
88
	    PATHNAME *q = p->up ;
89
	    if ( q != anonymous_dir ) {
90
		if ( q == root_dir && q->alias == NULL ) {
91
		    /* Root directory */
92
		} else {
93
		    output_pathname ( q, f ) ;
94
		}
95
		fputc_v ( sep, f ) ;
96
	    }
97
	    fputs_v ( c, f ) ;
98
	}
99
    }
100
    return ;
101
}
102
 
103
 
104
/*
105
    FIND THE LENGTH OF A PATHNAME
106
 
107
    This routine calculates the number of characters printed by a call to
108
    output_pathname with argument p.
109
*/
110
 
111
static int length_pathname
112
    PROTO_N ( ( p ) )
113
    PROTO_T ( PATHNAME *p )
114
{
115
    int len ;
116
    char *a = p->alias ;
117
    if ( a ) {
118
	len = length ( a ) + 3 ;
119
    } else {
120
	char *c = p->name ;
121
	if ( p == root_dir ) {
122
	    len = length ( c ) + 1 ;
123
	} else if ( p == anonymous_dir ) {
124
	    len = 1 ;
125
	} else {
126
	    PATHNAME *q = p->up ;
127
	    if ( q == anonymous_dir ) {
128
		/* Anonymous directory */
129
		len = 0 ;
130
	    } else if ( q == root_dir && q->alias == NULL ) {
131
		/* Root directory */
132
		len = 1 ;
133
	    } else {
134
		len = length_pathname ( q ) + 1 ;
135
	    }
136
	    len += length ( c ) ;
137
	}
138
    }
139
    return ( len ) ;
140
}
141
 
142
 
143
/*
144
    PRINT A PATHNAME
145
 
146
    This routine calls output_pathname, printing a preceding space if ns
147
    is true and taking the column number col into account.  It returns
148
    the new column number.
149
*/
150
 
151
static int output_path
152
    PROTO_N ( ( p, col, ns, f ) )
153
    PROTO_T ( PATHNAME *p X int col X int ns X FILE *f )
154
{
155
    int len = length_pathname ( p ) + 1 ;
156
    if ( col + len >= max_column ) {
157
	fputs_v ( "\\\n", f ) ;
158
	col = 0 ;
159
	ns = 1 ;
160
    }
161
    if ( ns ) fputc_v ( ' ', f ) ;
162
    output_pathname ( p, f ) ;
163
    return ( col + len ) ;
164
}
165
 
166
 
167
/*
168
    PRINT ALL ALIASES
169
 
170
    This routine scans through all the files beneath p, printing any alias
171
    definitions to f.  Note how any alias is temporarily suspended when
172
    printing the definition.
173
*/
174
 
175
static void output_aliases
176
    PROTO_N ( ( p, f ) )
177
    PROTO_T ( PATHNAME *p X FILE *f )
178
{
179
    if ( p ) {
180
	char *a = p->alias ;
181
	output_aliases ( p->next, f ) ;
182
	if ( a && p != anonymous_dir ) {
183
	    p->alias = NULL ;
184
	    fputs_v ( a, f ) ;
185
	    fputc_v ( '=', f ) ;
186
	    if ( relative_output && p->quote ) {
187
		fputs_v ( p->quote, f ) ;
188
	    } else {
189
		output_pathname ( p, f ) ;
190
	    }
191
	    fputc_v ( '\n', f ) ;
192
	    p->alias = a ;
193
	}
194
	output_aliases ( p->sub, f ) ;
195
    }
196
    return ;
197
}
198
 
199
 
200
/*
201
    PRINT A LIST OF OPTIONS
202
 
203
    This routine prints the list of options d to the file f.  Each option
204
    is printed only if it appears in the string opts.  col gives the initial
205
    column number, and ns is true to indicate that a space needs to be
206
    printed.  The final column number is returned.
207
*/
208
 
209
static int output_opts
210
    PROTO_N ( ( d, opts, col, ns, f ) )
211
    PROTO_T ( OPTION *d X char *opts X int col X int ns X FILE *f )
212
{
213
    while ( d != NULL ) {
214
	char *s = d->opt ;
215
	if ( strchr ( opts, s [1] ) ) {
216
	    int len = length ( s ) + 1 ;
217
	    if ( col + len >= max_column ) {
218
		fputs_v ( "\\\n", f ) ;
219
		col = 0 ;
220
		ns = 1 ;
221
	    }
222
	    if ( ns ) fputc_v ( ' ', f ) ;
223
	    fputs_v ( s, f ) ;
224
	    col += len ;
225
	    ns = 1 ;
226
	}
227
	d = d->next ;
228
    }
229
    return ( col ) ;
230
}
231
 
232
 
233
/*
234
    PRINT A LIST OF DIRECTORIES
235
 
236
    This routine prints the list of directories d to the file f.  Each
237
    directory is prefixed by the string pre.  col gives the initial
238
    column number, and ns is true to indicate that a space needs to be
239
    printed.  The final column number is returned.
240
*/
241
 
242
static int output_dirs
243
    PROTO_N ( ( d, pre, post, col, ns, f ) )
244
    PROTO_T ( DIRECTORY *d X char *pre X char *post X int col X int ns X FILE *f )
245
{
246
    while ( d != NULL ) {
247
	if ( d->builtin == 0 ) {
248
	    PATHNAME *p = d->dir ;
249
	    int len = length_pathname ( p ) ;
250
	    len = length ( pre ) + len + length ( post ) + 1 ;
251
	    if ( col + len >= max_column ) {
252
		fputs_v ( "\\\n", f ) ;
253
		col = 0 ;
254
		ns = 1 ;
255
	    }
256
	    if ( ns ) fputc_v ( ' ', f ) ;
257
	    fputs_v ( pre, f ) ;
258
	    output_pathname ( p, f ) ;
259
	    fputs_v ( post, f ) ;
260
	    col += len ;
261
	    ns = 1 ;
262
	}
263
	d = d->next ;
264
    }
265
    return ( col ) ;
266
}
267
 
268
 
269
/*
270
    PRINT A SERIES OF DEPENDENCIES
271
 
272
    This routine prints all the dependencies for the pathname p.  If rec
273
    is true then these dependencies are expanded recursively.
274
*/
275
 
276
static int output_deps
277
    PROTO_N ( ( p, rec, col, ns, f ) )
278
    PROTO_T ( PATHNAME *p X int rec X int col X int ns X FILE *f )
279
{
280
    if ( rec ) {
281
	DEPENDENCY *d ;
282
	static int recursive_mark = 10 ;
283
	for ( d = p->dep ; d != NULL ; d = d->next ) {
284
	    PATHNAME *q = d->file ;
285
	    if ( q->mark != recursive_mark ) {
286
		col = output_path ( q, col, ns, f ) ;
287
		q->mark = recursive_mark ;
288
		ns = 1 ;
289
	    }
290
	}
291
	for ( d = p->dep ; d != NULL ; d = d->next ) {
292
	    PATHNAME *q = d->file ;
293
	    col = output_deps ( q, 2, col, ns, f ) ;
294
	    ns = 1 ;
295
	}
296
	if ( rec == 1 ) recursive_mark++ ;
297
    } else {
298
	DEPENDENCY *d ;
299
	for ( d = p->dep ; d != NULL ; d = d->next ) {
300
	    PATHNAME *q = d->file ;
301
	    col = output_path ( q, col, ns, f ) ;
302
	    ns = 1 ;
303
	}
304
    }
305
    return ( col ) ;
306
}
307
 
308
 
309
/*
310
    CURRENT PATHNAME
311
 
312
    This variable holds the current loop counter.
313
*/
314
 
315
static PATHNAME *crt_file = NULL ;
316
 
317
 
318
/*
319
    FIND ALL FILES OF A TYPE
320
 
321
    This routine returns the file giving all files of type c.
322
*/
323
 
324
static PATHNAME *all_files
325
    PROTO_N ( ( c ) )
326
    PROTO_T ( int c )
327
{
328
    switch ( c ) {
329
	case 'o' : return ( o_files ) ;
330
	case 'c' : return ( c_files ) ;
331
	case 'j' : return ( j_files ) ;
332
	case 'k' : return ( k_files ) ;
333
	case 'h' : return ( h_files ) ;
334
	case 'l' : return ( l_files ) ;
335
	case 'y' : return ( y_files ) ;
336
	case 'L' : return ( l_output ) ;
337
	case 'Y' : return ( y_output ) ;
338
    }
339
    return ( NULL ) ;
340
}
341
 
342
 
343
/*
344
    PRINT A RULE DEFINITION
345
 
346
    This routine prints the rule definition given by the string str
347
    to the file f.
348
*/
349
 
350
static void output_rule
351
    PROTO_N ( ( str, f ) )
352
    PROTO_T ( char *str X FILE *f )
353
{
354
    char c ;
355
    int ns = 0 ;
356
    int col = 0 ;
357
 
358
    /* Scan through string */
359
    while ( c = *( str++ ), c != 0 ) {
360
	if ( c == '%' ) {
361
	    /* Format characters */
362
	    c = *( str++ ) ;
363
	    switch ( c ) {
364
 
365
		case 'C' : {
366
		    /* Current working directory */
367
		    col = output_path ( current_dir, col, ns, f ) ;
368
		    ns = 0 ;
369
		    break ;
370
		}
371
 
372
		case 'F' : {
373
		    /* Include directories */
374
		    col = output_dirs ( incl_dirs, "", "/*.c", col, ns, f ) ;
375
		    ns = 0 ;
376
		    break ;
377
		}
378
 
379
		case 'H' : {
380
		    /* Home directory */
381
		    col = output_path ( home_dir, col, ns, f ) ;
382
		    ns = 0 ;
383
		    break ;
384
		}
385
 
386
		case 'I' : {
387
		    /* Include directories */
388
		    col = output_dirs ( incl_dirs, "-I", "", col, ns, f ) ;
389
		    ns = 0 ;
390
		    break ;
391
		}
392
 
393
		case 'L' : {
394
		    /* Library directories */
395
		    col = output_dirs ( lib_dirs, "-L", "", col, ns, f ) ;
396
		    ns = 0 ;
397
		    break ;
398
		}
399
 
400
		case 'O' : {
401
		    /* Output name */
402
		    col = output_path ( output_file, col, ns, f ) ;
403
		    ns = 0 ;
404
		    break ;
405
		}
406
 
407
		case 'W' : {
408
		    /* Work directory */
409
		    col = output_path ( work_dir, col, ns, f ) ;
410
		    ns = 0 ;
411
		    break ;
412
		}
413
 
414
		case 'B' : {
415
		    /* Current file basename */
416
		    if ( crt_file ) {
417
			char *nm = crt_file->name ;
418
			int len = length ( nm ) ;
419
			if ( col + len >= max_column ) {
420
			    fputs_v ( "\\\n", f ) ;
421
			    col = 0 ;
422
			    ns = 1 ;
423
			}
424
			if ( ns ) fputc_v ( ' ', f ) ;
425
			fputs_v ( nm, f ) ;
426
			col += len + ns ;
427
			ns = 0 ;
428
		    }
429
		    break ;
430
		}
431
 
432
		case 'D' : {
433
		    /* Current file directory */
434
		    if ( crt_file ) {
435
			col = output_path ( crt_file->up, col, ns, f ) ;
436
			ns = 0 ;
437
		    }
438
		    break ;
439
		}
440
 
441
		case 'X' : {
442
		    /* Current file */
443
		    if ( crt_file ) {
444
			col = output_path ( crt_file, col, ns, f ) ;
445
			ns = 0 ;
446
		    }
447
		    break ;
448
		}
449
 
450
		case 'Y' : {
451
		    /* Current file dependencies */
452
		    if ( crt_file ) {
453
			col = output_deps ( crt_file, 0, col, ns, f ) ;
454
			ns = 0 ;
455
		    }
456
		    break ;
457
		}
458
 
459
		case 'Z' : {
460
		    /* Current file dependencies (recursive) */
461
		    if ( crt_file ) {
462
			col = output_deps ( crt_file, 1, col, ns, f ) ;
463
			ns = 0 ;
464
		    }
465
		    break ;
466
		}
467
 
468
		case '[' : {
469
		    /* Options matching a pattern */
470
		    char *begin = str + 1 ;
471
		    char *end = strchr ( begin, ']' ) ;
472
		    if ( end == NULL ) {
473
			error ( ERROR_SERIOUS, "Unterminated escape" ) ;
474
		    } else {
475
			*end = 0 ;
476
			col = output_opts ( cmd_opts, str, col, ns, f ) ;
477
			*end = ']' ;
478
			str = end + 1 ;
479
		    }
480
		    ns = 0 ;
481
		    break ;
482
		}
483
 
484
		default : {
485
		    PATHNAME *p = all_files ( c ) ;
486
		    if ( p ) {
487
			/* All files of a type */
488
			col = output_deps ( p, 0, col, ns, f ) ;
489
			ns = 0 ;
490
		    } else {
491
			/* Unknown escape sequences */
492
			error ( ERROR_SERIOUS, "Unknown escape, '%%%c'", c ) ;
493
			str-- ;
494
		    }
495
		    break ;
496
		}
497
	    }
498
 
499
	} else if ( c == '\\' ) {
500
	    /* Escape sequences */
501
	    c = *( str++ ) ;
502
	    switch ( c ) {
503
		case 'n' : {
504
		    /* Newline */
505
		    fputc_v ( '\n', f ) ;
506
		    col = 0 ;
507
		    ns = 0 ;
508
		    break ;
509
		}
510
		case 't' : {
511
		    /* Tab */
512
		    fputc_v ( '\t', f ) ;
513
		    col = 8 * ( col / 8 ) + 8 ;
514
		    while ( c = *str, ( c == ' ' || c == '\t' ) ) {
515
			str++ ;
516
		    }
517
		    ns = 0 ;
518
		    break ;
519
		}
520
		case ':' :
521
		case '%' :
522
		case '\\' : {
523
		    /* Simple escape sequences */
524
		    goto print_character ;
525
		}
526
		default : {
527
		    /* Unknown escape sequences */
528
		    error ( ERROR_SERIOUS, "Unknown escape, '\\%c'", c ) ;
529
		    str-- ;
530
		    break ;
531
		}
532
	    }
533
 
534
	} else if ( c == ' ' || c == '\t' ) {
535
	    /* Spaces */
536
	    ns = 1 ;
537
 
538
	} else {
539
	    /* Other characters */
540
	    print_character : {
541
		if ( ns ) {
542
		    if ( col >= max_column - 10 ) {
543
			fputs_v ( "\\\n", f ) ;
544
			col = 0 ;
545
		    }
546
		    fputc_v ( ' ', f ) ;
547
		    ns = 0 ;
548
		    col++ ;
549
		}
550
		fputc_v ( c, f ) ;
551
		col++ ;
552
	    }
553
	}
554
    }
555
    fputc_v ( '\n', f ) ;
556
    return ;
557
}
558
 
559
 
560
/*
561
    MAIN OUTPUT ROUTINE
562
 
563
    This routine prints all the output to the file f.
564
*/
565
 
566
void output_all
567
    PROTO_N ( ( f ) )
568
    PROTO_T ( FILE *f )
569
{
570
    int n = 0 ;
571
    OPTION *p = rule_opts ;
572
    OPTION *lab_stack [20] ;
573
    DEPENDENCY *dep_stack [20] ;
574
    lab_stack [0] = NULL ;
575
    dep_stack [0] = NULL ;
576
 
577
    /* Print file header */
578
    fprintf_v ( f, "# Automatically generated by %s version %s\n",
579
		progname, progvers ) ;
580
 
581
    /* Print file alias definitions */
582
    fputs_v ( "\n# Standard directories and files\n", f ) ;
583
    output_aliases ( root_dir, f ) ;
584
    fputc_v ( '\n', f ) ;
585
 
586
    /* Print rule definitions */
587
    while ( p != NULL ) {
588
	char *opt = p->opt ;
589
	if ( opt [0] == ':' ) {
590
	    /* Labels */
591
	    if ( opt [2] == 0 ) {
592
		if ( opt [1] == '<' || opt [1] == '>' ) {
593
		    /* End of loop */
594
		    if ( n == 0 ) {
595
			error ( ERROR_SERIOUS, "Unexpected end of loop" ) ;
596
		    } else if ( dep_stack [n] && opt [1] == '<' ) {
597
			/* Go back to start of loop */
598
			dep_stack [n] = dep_stack [n]->next ;
599
			if ( dep_stack [n] ) {
600
			    crt_file = dep_stack [n]->file ;
601
			} else {
602
			    crt_file = NULL ;
603
			}
604
			p = lab_stack [n] ;
605
		    } else {
606
			/* Continue to next statement */
607
			n-- ;
608
			if ( n && dep_stack [n] ) {
609
			    crt_file = dep_stack [n]->file ;
610
			} else {
611
			    crt_file = NULL ;
612
			}
613
		    }
614
		} else {
615
		    /* Start of loop */
616
		    DEPENDENCY *d = NULL ;
617
		    if ( opt [1] == 'x' ) {
618
			if ( crt_file ) d = crt_file->dep ;
619
		    } else {
620
			/* Start of loop */
621
			PATHNAME *q = all_files ( opt [1] ) ;
622
			if ( q ) {
623
			    d = q->dep ;
624
			} else {
625
			    error ( ERROR_SERIOUS,
626
				    "Unknown label, '%s'", opt ) ;
627
			}
628
		    }
629
		    n++ ;
630
		    if ( n >= 20 ) {
631
			error ( ERROR_SERIOUS, "Label depth too great" ) ;
632
			break ;
633
		    }
634
		    dep_stack [n] = d ;
635
		    lab_stack [n] = p ;
636
		    if ( d ) {
637
			crt_file = d->file ;
638
		    } else {
639
			crt_file = NULL ;
640
		    }
641
		}
642
	    } else {
643
		error ( ERROR_SERIOUS, "Unknown label, '%s'", opt ) ;
644
	    }
645
	} else {
646
	    /* Rules */
647
	    if ( n == 0 || dep_stack [n] ) output_rule ( opt, f ) ;
648
	}
649
	p = p->next ;
650
    }
651
    return ;
652
}