Subversion Repositories tendra.SVN

Rev

Rev 5 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
6 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
6 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:-
6 7u83 42
 
2 7u83 43
        (1) Its Recipients shall ensure that this Notice is
44
        reproduced upon any copies or amended versions of it;
6 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;
6 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;
6 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 "object.h"
63
#include "hash.h"
64
#include "name.h"
65
#include "type.h"
66
#include "print.h"
67
#include "utility.h"
68
 
69
 
70
/*
71
    COPYRIGHT MESSAGE
72
 
73
    These variables give the file containing the copyright message, and,
74
    after the first time it is processed, the message text.
75
*/
76
 
6 7u83 77
char *copyright = null;
78
static char *copyright_text = null;
2 7u83 79
 
80
 
81
/*
82
    OUTPUT MACROS
83
 
84
    These macros are used as convenient shorthands for various print
85
    routines.
86
*/
87
 
88
#define OUT		IGNORE fprintf
6 7u83 89
#define OUTC(X, Y)	IGNORE fputc(Y, X)
90
#define OUTS(X, Y)	IGNORE fputs(Y, X)
2 7u83 91
 
92
 
93
/*
94
    OUTPUT TRICKS
95
 
96
    A number of minor tricks are required in the headers, mostly due to
97
    library building problems.
98
*/
99
 
6 7u83 100
static boolean weak_proto = 0;
2 7u83 101
#define enum_hack	"__enum_"
6 7u83 102
#define is_hidden(X)	strneq(X, HIDDEN_NAME, HIDDEN_LEN)
2 7u83 103
 
104
 
105
/*
106
    OUTPUT FILE
107
 
108
    These variables hold information about the current output file.
109
*/
110
 
6 7u83 111
static info *crt_info = null;
112
static int column = 0;
2 7u83 113
 
114
 
115
/*
116
    DOES A TYPE HAVE A TAIL COMPONENT?
117
 
118
    This routine checks whether the type t has an array, bitfield or
119
    function component.
120
*/
121
 
6 7u83 122
static int
123
is_tailed_type(type *t)
2 7u83 124
{
6 7u83 125
    if (t) {
126
	switch (t->id) {
127
	    case TYPE_ARRAY:
128
	    case TYPE_BITFIELD:
129
	    case TYPE_PROC: {
130
		return(1);
2 7u83 131
	    }
132
	}
133
    }
6 7u83 134
    return(0);
2 7u83 135
}
136
 
137
 
138
/*
139
    PRINT THE HEAD OF A TYPE
140
 
141
    This routine prints the head of the type t, that is to say the base type
142
    and the pointer components, to the file output.
143
*/
144
 
6 7u83 145
static int
146
print_head(FILE *output, type *t, int sp, int tok)
2 7u83 147
{
6 7u83 148
    if (t == null) return(sp);
149
    switch (t->id) {
150
	case TYPE_VOID:
151
	case TYPE_INT:
152
	case TYPE_SIGNED:
153
	case TYPE_UNSIGNED:
154
	case TYPE_FLOAT:
155
	case TYPE_ARITH:
156
	case TYPE_SCALAR:
157
	case TYPE_STRUCT:
158
	case TYPE_UNION:
159
	case TYPE_ENUM:
160
	case TYPE_GENERIC:
161
	case TYPE_DEFINED:
162
	case TYPE_PROMOTE: {
163
	    OUTS(output, t->u.obj->name);
164
	    sp = 1;
165
	    break;
2 7u83 166
	}
6 7u83 167
	case TYPE_STRUCT_TAG: {
168
	    OUT(output, "struct %s", t->u.obj->name);
169
	    sp = 1;
170
	    break;
2 7u83 171
	}
6 7u83 172
	case TYPE_UNION_TAG: {
173
	    OUT(output, "union %s", t->u.obj->name);
174
	    sp = 1;
175
	    break;
2 7u83 176
	}
6 7u83 177
	case TYPE_ENUM_TAG: {
178
	    if (tok) {
179
		OUT(output, "%s%s", enum_hack, t->u.obj->name);
2 7u83 180
	    } else {
6 7u83 181
		OUT(output, "enum %s", t->u.obj->name);
2 7u83 182
	    }
6 7u83 183
	    sp = 1;
184
	    break;
2 7u83 185
	}
6 7u83 186
	case TYPE_LVALUE: {
187
	    OUTS(output, "lvalue ");
188
	    if (tok)OUTS(output, ": ");
189
	    sp = print_head(output, t->u.subtype, 0, tok);
190
	    break;
2 7u83 191
	}
6 7u83 192
	case TYPE_QUALIFIER: {
193
	    OUT(output, "%s ", t->v.str);
194
	    sp = print_head(output, t->u.subtype, 0, tok);
195
	    break;
2 7u83 196
	}
6 7u83 197
	case TYPE_RVALUE: {
198
	    if (tok)OUTS(output, "rvalue : ");
199
	    sp = print_head(output, t->u.subtype, 0, tok);
200
	    break;
2 7u83 201
	}
6 7u83 202
	case TYPE_PTR: {
203
	    type *s = t->u.subtype;
204
	    char *q = t->v.str;
205
	    sp = print_head(output, s, sp, tok);
206
	    if (sp)OUTC(output, ' ');
207
	    if (is_tailed_type(s)) {
208
		OUTS(output, "( *");
2 7u83 209
	    } else {
6 7u83 210
		OUTS(output, "*");
2 7u83 211
	    }
6 7u83 212
	    sp = 0;
213
	    if (q) {
214
		OUT(output, " %s", q);
215
		sp = 1;
2 7u83 216
	    }
6 7u83 217
	    break;
2 7u83 218
	}
6 7u83 219
	case TYPE_ARRAY:
220
	case TYPE_BITFIELD:
221
	case TYPE_PROC: {
222
	    sp = print_head(output, t->u.subtype, sp, tok);
223
	    break;
2 7u83 224
	}
225
	default : {
226
	    /* Unknown types */
6 7u83 227
	    error(ERR_INTERNAL, "Unknown type identifier, '%d'", t->id);
228
	    break;
2 7u83 229
	}
230
    }
6 7u83 231
    return(sp);
2 7u83 232
}
233
 
234
 
235
/*
236
    PRINT THE TAIL OF A TYPE
237
 
238
    This routine prints the tail of the type t, that is to say the array,
239
    bitfield and function components, to the file output.
240
*/
241
 
6 7u83 242
static void
243
print_tail(FILE *output, type *t, int tok)
2 7u83 244
{
6 7u83 245
    if (t == null) return;
246
    switch (t->id) {
247
	case TYPE_LVALUE:
248
	case TYPE_RVALUE:
249
	case TYPE_QUALIFIER: {
250
	    print_tail(output, t->u.subtype, tok);
251
	    break;
2 7u83 252
	}
6 7u83 253
	case TYPE_PTR: {
254
	    type *s = t->u.subtype;
255
	    if (is_tailed_type(s)) {
256
		OUTS(output, " )");
2 7u83 257
	    }
6 7u83 258
	    print_tail(output, s, tok);
259
	    break;
2 7u83 260
	}
6 7u83 261
	case TYPE_ARRAY: {
262
	    OUT(output, " [%s]", t->v.str);
263
	    print_tail(output, t->u.subtype, tok);
264
	    break;
2 7u83 265
	}
6 7u83 266
	case TYPE_BITFIELD: {
267
	    if (tok) {
268
		OUT(output, " %% %s", t->v.str);
2 7u83 269
	    } else {
6 7u83 270
		OUT(output, " : %s", t->v.str);
2 7u83 271
	    }
6 7u83 272
	    print_tail(output, t->u.subtype, tok);
273
	    break;
2 7u83 274
	}
6 7u83 275
	case TYPE_PROC: {
276
	    type *s = t->v.next;
277
	    if (s) {
278
		OUTS(output, " ( ");
279
		while (s) {
280
		    print_type(output, s->u.subtype, null_str, tok);
281
		    s = s->v.next;
282
		    if (s)OUTS(output, ", ");
2 7u83 283
		}
6 7u83 284
		OUTS(output, " )");
2 7u83 285
	    } else {
6 7u83 286
		OUTS(output, " ()");
2 7u83 287
	    }
6 7u83 288
	    print_tail(output, t->u.subtype, tok);
289
	    break;
2 7u83 290
	}
291
    }
6 7u83 292
    return;
2 7u83 293
}
294
 
295
 
296
/*
297
    PRINT A TYPE
298
 
299
    This routine prints the object nm of type t to the file output.
300
*/
301
 
6 7u83 302
void
303
print_type(FILE *output, type *t, char *nm, int tok)
2 7u83 304
{
6 7u83 305
    if (t) {
306
	int sp = print_head(output, t, 0, tok);
307
	if (nm) {
308
	    if (sp)OUTC(output, ' ');
309
	    OUTS(output, nm);
2 7u83 310
	}
6 7u83 311
	print_tail(output, t, tok);
2 7u83 312
    }
6 7u83 313
    return;
2 7u83 314
}
315
 
316
 
317
/*
318
    PRINT A STRUCT OR UNION DEFINITION
319
 
320
    This routine prints the specification for a structure or union type,
321
    t, with internal name nm and external name tnm, to output.
322
*/
323
 
6 7u83 324
static void
325
print_struct_defn(FILE *output, type *t, char *nm, char *tnm, int d)
2 7u83 326
{
6 7u83 327
    char *tok, *tag;
328
    object *q = t->v.obj2;
329
    boolean show_token = 1, show_interface = 1;
330
    boolean show_ignore = 1, show_defn = 1;
2 7u83 331
 
332
    /* Find the token type */
6 7u83 333
    switch (t->id)EXHAUSTIVE {
334
	case TYPE_STRUCT: tok = "STRUCT"; tag = ""; break;
335
	case TYPE_STRUCT_TAG: tok = "STRUCT"; tag = "TAG "; break;
336
	case TYPE_UNION: tok = "UNION"; tag = ""; break;
337
	case TYPE_UNION_TAG: tok = "UNION"; tag = "TAG "; break;
2 7u83 338
    }
339
 
340
    /* Deal with undefined tokens immediately */
6 7u83 341
    if (q == null) {
342
	OUT(output, "#pragma token %s %s%s # %s\n", tok, tag, nm, tnm);
343
	return;
2 7u83 344
    }
345
 
346
    /* Deal with the various definition cases */
6 7u83 347
    switch (t->state) {
348
	case 0: {
2 7u83 349
	    /* Definition is immediate */
6 7u83 350
	    if (is_hidden(nm)) {
351
		show_token = 0;
352
		show_interface = 0;
353
		show_ignore = 0;
2 7u83 354
	    }
6 7u83 355
	    break;
2 7u83 356
	}
6 7u83 357
	case 1: {
2 7u83 358
	    /* Definition is elsewhere */
6 7u83 359
	    show_interface = 0;
360
	    show_ignore = 0;
361
	    show_defn = 0;
362
	    t->state = 2;
363
	    break;
2 7u83 364
	}
6 7u83 365
	case 2: {
2 7u83 366
	    /* Declaration was earlier in file */
6 7u83 367
	    show_token = 0;
368
	    t->state = 0;
369
	    break;
2 7u83 370
	}
6 7u83 371
	case 3: {
2 7u83 372
	    /* Declaration was in another file */
6 7u83 373
	    if (d) {
374
		show_token = 0;
375
		show_interface = 0;
376
		t->state = 1;
2 7u83 377
	    } else {
6 7u83 378
		show_interface = 0;
379
		show_ignore = 0;
380
		show_defn = 0;
381
		t->state = 2;
2 7u83 382
	    }
6 7u83 383
	    break;
2 7u83 384
	}
385
    }
386
 
387
    /* Print the token if necessary */
6 7u83 388
    if (show_token) {
389
	OUT(output, "#pragma token %s %s%s # %s\n", tok, tag, nm, tnm);
2 7u83 390
    }
391
 
392
    /* Print the interface statement */
6 7u83 393
    if (show_interface) {
394
	char *b = BUILDING_MACRO;
395
	OUT(output, "#ifdef %s\n", b);
396
	OUT(output, "#pragma interface %s%s\n", tag, nm);
2 7u83 397
	OUT ( output, "#else /* %s */\n", b ) ;
398
    }
399
 
400
    /* Print the ignore statement */
6 7u83 401
    if (show_ignore) {
402
	if (!show_interface) {
403
	    char *b = BUILDING_MACRO;
404
	    OUT(output, "#ifndef %s\n", b);
2 7u83 405
	}
6 7u83 406
	OUT(output, "#pragma ignore %s%s\n", tag, nm);
2 7u83 407
    }
408
 
409
    /* Print the type definition */
6 7u83 410
    if (show_defn) {
411
	tok = (tok [0] == 'S' ? "struct" : "union");
412
	if (*tag) {
413
	    OUT(output, "%s %s {\n", tok, nm);
2 7u83 414
	} else {
6 7u83 415
	    OUT(output, "typedef %s {\n", tok);
2 7u83 416
	}
6 7u83 417
	while (q) {
418
	    field *f = q->u.u_obj->u.u_field;
419
	    OUTS(output, "    ");
420
	    print_type(output, f->ftype, f->fname, 0);
421
	    OUTS(output, " ;\n");
422
	    q = q->next;
2 7u83 423
	}
6 7u83 424
	if (*tag) {
425
	    OUTS(output, "} ;\n");
2 7u83 426
	} else {
6 7u83 427
	    OUT(output, "} %s ;\n", nm);
2 7u83 428
	}
429
    }
430
 
431
    /* Print the final #endif */
6 7u83 432
    if (show_interface || show_ignore) {
433
	char *b = BUILDING_MACRO;
2 7u83 434
	OUT ( output, "#endif /* %s */\n", b ) ;
435
    }
6 7u83 436
    return;
2 7u83 437
}
438
 
439
 
440
/*
441
    PRINT A TOKENISED TYPE
442
 
443
    This routine is the special case of print_token which deals with
444
    tokenised types.
445
*/
446
 
6 7u83 447
static void
448
print_token_type(FILE *output, object *p, char *tnm)
2 7u83 449
{
6 7u83 450
    char *tok = "TYPE";
451
    char *nm = p->name;
452
    type *t = p->u.u_type;
453
    int i = t->id;
454
    switch (i) {
2 7u83 455
 
6 7u83 456
	case TYPE_DEFINED: {
2 7u83 457
	    /* Defined types */
6 7u83 458
	    char *tm, *sp;
459
	    type *s = t->v.next;
460
	    char *b = BUILDING_MACRO;
461
	    if (s == type_bottom) {
462
		sp = "bottom";
463
	    } else if (s == type_printf) {
464
		sp = "... printf";
465
	    } else if (s == type_scanf) {
466
		sp = "... scanf";
2 7u83 467
	    } else {
6 7u83 468
		OUTS(output, "typedef ");
469
		print_type(output, s, nm, 0);
470
		OUTS(output, " ;\n");
471
		break;
2 7u83 472
	    }
473
	    /* Allow for special types */
6 7u83 474
	    tm = "__TenDRA__";
475
	    OUT(output, "#ifndef %s\n", b);
476
	    OUT(output, "#ifdef %s\n", tm);
477
	    OUT(output, "#pragma TenDRA type %s for %s\n", nm, sp);
2 7u83 478
	    OUT ( output, "#else /* %s */\n", tm ) ;
6 7u83 479
	    OUT(output, "typedef %s %s ;\n", s->u.obj->name, nm);
2 7u83 480
	    OUT ( output, "#endif /* %s */\n", tm ) ;
481
	    OUT ( output, "#else /* %s */\n", b ) ;
6 7u83 482
	    OUT(output, "typedef %s %s ;\n", s->u.obj->name, nm);
2 7u83 483
	    OUT ( output, "#endif /* %s */\n", b ) ;
6 7u83 484
	    break;
2 7u83 485
	}
486
 
6 7u83 487
	case TYPE_INT: tok = "VARIETY"; goto generic_lab;
488
	case TYPE_SIGNED: tok = "VARIETY signed"; goto generic_lab;
489
	case TYPE_UNSIGNED: tok = "VARIETY unsigned"; goto generic_lab;
490
	case TYPE_FLOAT: tok = "FLOAT"; goto generic_lab;
491
	case TYPE_ARITH: tok = "ARITHMETIC"; goto generic_lab;
492
	case TYPE_SCALAR: tok = "SCALAR"; goto generic_lab;
2 7u83 493
 
6 7u83 494
	case TYPE_GENERIC:
2 7u83 495
	generic_lab : {
496
	    /* Generic types */
6 7u83 497
	    OUT(output, "#pragma token %s %s # %s\n", tok, nm, tnm);
498
	    break;
2 7u83 499
	}
500
 
6 7u83 501
	case TYPE_PROMOTE: {
2 7u83 502
	    /* Promotion types */
6 7u83 503
	    char *pt = t->v.next->u.obj->name;
504
	    OUT(output, "#pragma token VARIETY %s # %s\n", nm, tnm);
505
	    OUT(output, "#pragma promote %s : %s\n", pt, nm);
506
	    break;
2 7u83 507
	}
508
 
6 7u83 509
	case TYPE_STRUCT:
510
	case TYPE_STRUCT_TAG:
511
	case TYPE_UNION:
512
	case TYPE_UNION_TAG: {
2 7u83 513
	    /* Structure or union types */
6 7u83 514
	    print_struct_defn(output, t, nm, tnm, 0);
515
	    break;
2 7u83 516
	}
517
 
6 7u83 518
	case TYPE_ENUM:
519
	case TYPE_ENUM_TAG: {
2 7u83 520
	    /* Enumeration types are a complete hack */
6 7u83 521
	    char *b = BUILDING_MACRO;
522
	    boolean tagged = (boolean)(i == TYPE_ENUM ? 0 : 1);
523
	    object *q = t->v.obj2;
524
	    OUT(output, "#ifndef %s\n", b);
2 7u83 525
 
526
	    /* Print the enumeration type */
6 7u83 527
	    if (tagged) {
528
		OUT(output, "typedef enum %s {", nm);
2 7u83 529
	    } else {
6 7u83 530
		OUTS(output, "typedef enum {");
2 7u83 531
	    }
532
 
533
	    /* Print the enumeration elements */
6 7u83 534
	    while (q) {
535
		object *r = q->u.u_obj;
536
		char *v = r->u.u_str;
537
		if (v && v [0]) {
538
		    OUT(output, "\n    %s = %s", r->name, v);
2 7u83 539
		} else {
6 7u83 540
		    OUT(output, "\n    %s", r->name);
2 7u83 541
		}
6 7u83 542
		q = q->next;
543
		if (q)OUTC(output, ',');
2 7u83 544
	    }
545
 
546
	    /* Print the end of the enumeration type */
6 7u83 547
	    if (tagged) {
548
		IGNORE sprintf(buffer, "%s%s", enum_hack, nm);
549
		OUT(output, "\n} %s ;\n", buffer);
2 7u83 550
	    } else {
6 7u83 551
		OUT(output, "\n} %s ;\n", nm);
2 7u83 552
	    }
553
 
554
	    /* Print the hacked library building version */
555
	    OUT ( output, "#else /* %s */\n", b ) ;
6 7u83 556
	    if (tagged) {
557
		OUT(output, "typedef int %s ;\n", buffer);
2 7u83 558
	    } else {
6 7u83 559
		OUT(output, "#pragma token VARIETY %s # %s\n", nm, tnm);
560
		OUT(output, "#pragma promote %s : %s\n", nm, nm);
561
		OUT(output, "#pragma interface %s\n", nm);
2 7u83 562
	    }
563
	    OUT ( output, "#endif /* %s */\n", b ) ;
6 7u83 564
	    break;
2 7u83 565
	}
566
 
567
	default : {
568
	    /* Other types */
6 7u83 569
	    error(ERR_INTERNAL, "Unknown type identifier, '%d'", i);
570
	    break;
2 7u83 571
	}
572
    }
6 7u83 573
    return;
2 7u83 574
}
575
 
576
 
577
/*
578
    PRINT A TOKEN
579
 
580
    This routine prints the object p, representing the token tnm, to the
581
    file output.
582
*/
583
 
6 7u83 584
static void
585
print_token(FILE *output, object *p, char *tnm)
2 7u83 586
{
6 7u83 587
    char *nm = p->name;
588
    switch (p->objtype) {
2 7u83 589
 
6 7u83 590
	case OBJ_CONST:
591
	case OBJ_EXP: {
2 7u83 592
	    /* Constants and expressions */
6 7u83 593
	    type *t = p->u.u_type;
594
	    OUTS(output, "#pragma token EXP ");
595
	    if (p->objtype == OBJ_CONST && t->id == TYPE_RVALUE) {
596
		OUTS(output, "const : ");
597
		t = t->u.subtype;
2 7u83 598
	    }
6 7u83 599
	    print_type(output, t, null_str, 1);
600
	    OUT(output, " : %s # %s\n", nm, tnm);
601
	    break;
2 7u83 602
	}
603
 
6 7u83 604
	case OBJ_EXTERN: {
2 7u83 605
	    /* External expressions */
6 7u83 606
	    type *t = p->u.u_type;
607
	    if (t->id == TYPE_LVALUE)t = t->u.subtype;
608
	    OUTS(output, "extern ");
609
	    print_type(output, t, nm, 0);
610
	    OUTS(output, " ;\n");
611
	    break;
2 7u83 612
	}
613
 
6 7u83 614
	case OBJ_WEAK: {
2 7u83 615
	    /* Weak prototype declarations */
6 7u83 616
	    int sp;
617
	    char *w = WEAK_PROTO;
618
	    type *t = p->u.u_type;
619
	    if (!weak_proto) {
620
		char *b = BUILDING_MACRO;
621
		OUT(output, "#ifndef %s\n", w);
622
		OUT(output, "#ifndef %s\n", b);
623
		OUT(output, "#pragma TenDRA keyword %s_KEY for weak\n", w);
624
		OUT(output, "#define %s( A )\t%s_KEY A\n", w, w);
2 7u83 625
		OUT ( output, "#else /* %s */\n", b ) ;
6 7u83 626
		OUT(output, "#define %s( A )\t()\n", w);
2 7u83 627
		OUT ( output, "#endif /* %s */\n", b ) ;
628
		OUT ( output, "#endif /* %s */\n\n", w ) ;
6 7u83 629
		weak_proto = 1;
2 7u83 630
	    }
6 7u83 631
	    OUTS(output, "extern ");
632
	    sp = print_head(output, t, 0, 0);
633
	    if (sp)OUTC(output, ' ');
634
	    OUT(output, "%s %s (", nm, w);
635
	    print_tail(output, t, 0);
636
	    OUTS(output, " ) ;\n");
637
	    break;
2 7u83 638
	}
639
 
6 7u83 640
	case OBJ_DEFINE: {
2 7u83 641
	    /* Macro definitions */
6 7u83 642
	    char *s = p->u.u_str;
643
	    OUT(output, "#define %s%s\n", nm, s);
644
	    break;
2 7u83 645
	}
646
 
6 7u83 647
	case OBJ_DEFMIN: {
648
	    /* Macro definitions */
649
	    char *s = p->u.u_str;
650
	    OUT(output, "#if defined(%s) && %s < %s\n", nm, nm, s);
651
	    OUT(output, "/* Should probably me an #error */\n");
652
	    OUT(output, "#define %s%s\n", nm, s);
653
	    OUT(output, "#elif !defined(%s)\n", nm);
654
	    OUT(output, "#define %s%s\n", nm, s);
655
	    OUT(output, "#endif\n");
656
	    break;
657
	}
658
 
659
	case OBJ_FIELD: {
2 7u83 660
	    /* Field selectors */
6 7u83 661
	    field *f = p->u.u_field;
662
	    OUTS(output, "#pragma token MEMBER ");
663
	    print_type(output, f->ftype, null_str, 1);
664
	    OUTS(output, " : ");
665
	    print_type(output, f->stype, null_str, 1);
666
	    OUT(output, " : %s # %s\n", f->fname, tnm);
667
	    break;
2 7u83 668
	}
669
 
6 7u83 670
	case OBJ_FUNC: {
2 7u83 671
	    /* Functions */
6 7u83 672
	    type *t = p->u.u_type;
673
	    OUTS(output, "#pragma token FUNC ");
674
	    print_type(output, t, null_str, 1);
675
	    OUT(output, " : %s # %s\n", nm, tnm);
676
	    break;
2 7u83 677
	}
678
 
6 7u83 679
	case OBJ_MACRO: {
2 7u83 680
	    /* Macros */
6 7u83 681
	    type *t = p->u.u_type;
682
	    type *s = t->v.next;
683
	    OUTS(output, "#pragma token PROC ( ");
2 7u83 684
	    /* Print the macro arguments */
6 7u83 685
	    while (s && s != type_none ) {
686
		OUTS(output, "EXP ");
687
		print_type(output, s->u.subtype, null_str, 1);
688
		s = s->v.next;
689
		OUTS(output,(s ? " : , " : " : "));
2 7u83 690
	    }
691
	    /* Print the macro result */
6 7u83 692
	    OUTS(output, ") EXP ");
693
	    print_type(output, t->u.subtype, null_str, 1);
694
	    OUT(output, " : %s # %s\n", nm, tnm);
695
	    break;
2 7u83 696
	}
697
 
6 7u83 698
	case OBJ_NAT: {
2 7u83 699
	    /* Nats */
6 7u83 700
	    OUT(output, "#pragma token NAT %s # %s\n", nm, tnm);
701
	    break;
2 7u83 702
	}
703
 
6 7u83 704
	case OBJ_STATEMENT: {
2 7u83 705
	    /* Statements */
6 7u83 706
	    type *t = p->u.u_type;
707
	    if (t != null) {
2 7u83 708
		/* Statements with arguments */
6 7u83 709
		type *s = t->v.next;
710
		OUTS(output, "#pragma token PROC ( ");
711
		while (s && s != type_none) {
712
		    OUTS(output, "EXP ");
713
		    print_type(output, s->u.subtype, null_str, 1);
714
		    s = s->v.next;
715
		    OUTS(output,(s ? " : , " : " : "));
2 7u83 716
		}
6 7u83 717
		OUT(output, ") STATEMENT %s # %s\n", nm, tnm);
2 7u83 718
	    } else {
719
		/* Statements with no arguments */
6 7u83 720
		OUT(output, "#pragma token STATEMENT %s # %s\n", nm, tnm);
2 7u83 721
	    }
6 7u83 722
	    break;
2 7u83 723
	}
724
 
6 7u83 725
	case OBJ_TOKEN: {
2 7u83 726
	    /* Tokens */
6 7u83 727
	    char *s = p->u.u_str;
728
	    OUT(output, "#pragma token %s %s # %s\n", s, nm, tnm);
729
	    break;
2 7u83 730
	}
731
 
6 7u83 732
	case OBJ_TYPE: {
2 7u83 733
	    /* Types */
6 7u83 734
	    print_token_type(output, p, tnm);
735
	    break;
2 7u83 736
	}
737
 
738
	default : {
739
	    /* Unknown objects */
6 7u83 740
	    error(ERR_INTERNAL, "Unknown object type, '%d'", p->objtype);
741
	    break;
2 7u83 742
	}
743
    }
6 7u83 744
    return;
2 7u83 745
}
746
 
747
 
748
/*
749
    TYPE REPRESENTING AN IF STATEMENT
750
 
751
    All if, else and endif statements are stored and simplified prior to
752
    output.  The ifcmd structure is used to represent the commands, with
753
    the dir field giving the command type and the nm field the associated
754
    expression.
755
*/
756
 
757
typedef struct {
6 7u83 758
    int dir;
759
    char *nm;
760
} ifcmd;
2 7u83 761
 
762
 
763
/*
764
    PRINT A NUMBER OF IF STATEMENTS
765
 
766
    This routine outputs the list of if statements, ifs, to the file
767
    output.
768
*/
769
 
6 7u83 770
static void
771
print_ifs(FILE *output, ifcmd *ifs)
2 7u83 772
{
6 7u83 773
    ifcmd *p;
774
    boolean changed;
2 7u83 775
 
776
    /* Simplify the list of statements */
777
    do {
6 7u83 778
	ifcmd *q = null;
779
	changed = 0;
780
	for (p = ifs; p->dir != CMD_END; p++) {
781
	    int d = p->dir;
782
	    if (d != CMD_NONE) {
783
		if (q && q->dir != CMD_NONE) {
784
		    int e = q->dir;
785
		    if (d == CMD_ENDIF) {
786
			if (e == CMD_ELSE) {
2 7u83 787
			    /* else + endif -> endif */
6 7u83 788
			    q->dir = CMD_NONE;
789
			    changed = 1;
790
			} else if (e != CMD_ENDIF) {
2 7u83 791
			    /* if + endif -> nothing */
6 7u83 792
			    p->dir = CMD_NONE;
793
			    q->dir = CMD_NONE;
794
			    changed = 1;
2 7u83 795
			}
796
		    }
6 7u83 797
		    if (d == CMD_ELSE) {
798
			if (e == CMD_IFDEF) {
2 7u83 799
			    /* ifdef + else -> ifndef */
6 7u83 800
			    p->dir = CMD_IFNDEF;
801
			    q->dir = CMD_NONE;
802
			    changed = 1;
803
			} else if (e == CMD_IFDEF) {
2 7u83 804
			    /* ifndef + else -> ifdef */
6 7u83 805
			    p->dir = CMD_IFDEF;
806
			    q->dir = CMD_NONE;
807
			    changed = 1;
2 7u83 808
			}
809
		    }
810
		}
6 7u83 811
		q = p;
2 7u83 812
	    }
813
	}
6 7u83 814
    } while (changed);
2 7u83 815
 
816
    /* Print the result */
6 7u83 817
    if (column)OUTC(output, '\n');
818
    for (p = ifs; p->dir != CMD_END; p++) {
819
	switch (p->dir) {
820
	    case CMD_IF: {
821
		OUT(output, "#if %s\n", p->nm);
822
		break;
2 7u83 823
	    }
6 7u83 824
	    case CMD_IFDEF: {
825
		OUT(output, "#ifdef %s\n", p->nm);
826
		break;
2 7u83 827
	    }
6 7u83 828
	    case CMD_IFNDEF: {
829
		OUT(output, "#ifndef %s\n", p->nm);
830
		break;
2 7u83 831
	    }
6 7u83 832
	    case CMD_ELSE: {
2 7u83 833
		OUT ( output, "#else /* %s */\n", p->nm ) ;
6 7u83 834
		break;
2 7u83 835
	    }
6 7u83 836
	    case CMD_ENDIF: {
2 7u83 837
		OUT ( output, "#endif /* %s */\n", p->nm ) ;
6 7u83 838
		break;
2 7u83 839
	    }
840
	}
841
    }
6 7u83 842
    column = 0;
843
    ifs [0].dir = CMD_END;
844
    return;
2 7u83 845
}
846
 
847
 
848
/*
849
    PRINT AN INTERFACE ITEM
850
 
851
    This routine prints an interface statement for the object p to the
852
    file output.
853
*/
854
 
6 7u83 855
static void
856
print_interface(FILE *output, object *p, ifcmd *ifs)
2 7u83 857
{
6 7u83 858
    char *nm = p->name;
859
    switch (p->objtype) {
2 7u83 860
 
6 7u83 861
	case OBJ_CONST:
862
	case OBJ_EXP:
863
	case OBJ_MACRO:
864
	case OBJ_NAT:
865
	case OBJ_STATEMENT:
866
	case OBJ_TOKEN: {
2 7u83 867
	    /* Simple tokens are easy */
6 7u83 868
	    break;
2 7u83 869
	}
870
 
6 7u83 871
	case OBJ_EXTERN:
872
	case OBJ_WEAK: {
2 7u83 873
	    /* Deal with externals */
6 7u83 874
	    nm = null;
875
	    break;
2 7u83 876
	}
877
 
6 7u83 878
	case OBJ_FIELD: {
2 7u83 879
	    /* Deal with fields */
6 7u83 880
	    field *f = p->u.u_field;
881
	    switch (f->stype->id) {
882
		case TYPE_STRUCT_TAG:
883
		case TYPE_UNION_TAG: {
2 7u83 884
		    /* Tagged types require some attention */
6 7u83 885
		    IGNORE sprintf(buffer, "TAG %s", nm);
886
		    nm = buffer;
887
		    break;
2 7u83 888
		}
889
	    }
6 7u83 890
	    break;
2 7u83 891
	}
892
 
6 7u83 893
	case OBJ_FUNC: {
2 7u83 894
	    /* Functions containing ... are not actually tokens */
6 7u83 895
	    type *t = p->u.u_type->v.next;
896
	    while (t != null) {
897
		if (t->u.subtype == type_ellipsis) {
898
		    nm = null;
899
		    break;
2 7u83 900
		}
6 7u83 901
		t = t->v.next;
2 7u83 902
	    }
6 7u83 903
	    break;
2 7u83 904
	}
905
 
6 7u83 906
	case OBJ_DEFINE: {
2 7u83 907
	    /* Macro definitions are not tokens */
6 7u83 908
	    nm = null;
909
	    break;
2 7u83 910
	}
911
 
6 7u83 912
	case OBJ_DEFMIN: {
913
	    /* Macro definitions are not tokens */
914
	    nm = null;
915
	    break;
916
	}
917
 
918
 
919
	case OBJ_TYPE: {
2 7u83 920
	    /* Deal with types */
6 7u83 921
	    type *t = p->u.u_type;
922
	    switch (t->id) {
923
		case TYPE_STRUCT_TAG:
924
		case TYPE_UNION_TAG: {
2 7u83 925
		    /* Tagged types require some attention */
6 7u83 926
		    IGNORE sprintf(buffer, "TAG %s", nm);
927
		    nm = buffer;
928
		    goto type_struct_lab;
2 7u83 929
		}
6 7u83 930
		case TYPE_STRUCT:
931
		case TYPE_UNION:
2 7u83 932
		type_struct_lab : {
933
		    /* Some structures and unions are not tokens */
6 7u83 934
		    if (t->v.obj2) {
935
			if (t->state == 2) {
936
			    t->state = 3;
2 7u83 937
			} else {
6 7u83 938
			    nm = null;
2 7u83 939
			}
940
		    }
6 7u83 941
		    break;
2 7u83 942
		}
6 7u83 943
		case TYPE_DEFINED: {
2 7u83 944
		    /* Type definitions are not tokens */
6 7u83 945
		    nm = null;
946
		    break;
2 7u83 947
		}
6 7u83 948
		case TYPE_ENUM:
949
		case TYPE_ENUM_TAG: {
2 7u83 950
		    /* Enumeration types are not tokens */
6 7u83 951
		    nm = null;
952
		    break;
2 7u83 953
		}
954
	    }
6 7u83 955
	    break;
2 7u83 956
	}
957
 
958
	default : {
959
	    /* Unknown objects */
6 7u83 960
	    error(ERR_INTERNAL, "Unknown object type, '%d'", p->objtype);
961
	    nm = null;
962
	    break;
2 7u83 963
	}
964
    }
965
 
966
    /* Print the interface statement */
6 7u83 967
    if (nm) {
968
	int n = (int)strlen(nm) + 1;
969
	if (ifs [0].dir != CMD_END)print_ifs(output, ifs);
970
	if (column + n >= 60) {
971
	    OUTC(output, '\n');
972
	    column = 0;
2 7u83 973
	}
6 7u83 974
	if (column == 0)OUTS(output, "#pragma interface");
975
	OUTC(output, ' ');
976
	OUTS(output, nm);
977
	column += n;
2 7u83 978
    }
6 7u83 979
    return;
2 7u83 980
}
981
 
982
 
983
/*
984
    PRINT AN INCLUDED FILE
985
*/
986
 
6 7u83 987
static void
988
print_include(FILE *output, char *nm, int on)
2 7u83 989
{
6 7u83 990
    object *p;
991
    if (nm == null) return;
992
    IGNORE sprintf(buffer, "%s[%s]", crt_info->src, nm);
993
    if (search_hash(files, buffer, no_version)) return;
994
    p = make_object(string_copy(buffer), OBJ_FILE);
995
    p->u.u_file = null;
996
    IGNORE add_hash(files, p, no_version);
997
    if (on)OUT(output, "#include <%s>\n", nm);
998
    return;
2 7u83 999
}
1000
 
1001
 
1002
/*
1003
    PRINT AN OBJECT
1004
 
1005
    This routine prints the list of objects input to the file output, the
1006
    form of the information to be printed being indicated by pass.
1007
*/
1008
 
6 7u83 1009
static void
1010
print_object(FILE *output, object *input, int pass)
2 7u83 1011
{
6 7u83 1012
    object *p;
1013
    ifcmd ifs [100];
1014
    ifs [0].dir = CMD_END;
1015
    for (p = input; p != null; p = p->next) {
1016
	char *nm = p->name;
1017
	switch (p->objtype) {
2 7u83 1018
 
6 7u83 1019
	    case OBJ_IF	: {
2 7u83 1020
		/* If statements etc. */
6 7u83 1021
		if (pass != 1) {
1022
		    int i = 0;
1023
		    while (ifs [i].dir != CMD_END)i++;
1024
		    ifs [i].dir = p->u.u_num;
1025
		    ifs [i].nm = p->name;
1026
		    ifs [ i + 1 ].dir = CMD_END;
1027
		    if (i >= 90)print_ifs(output, ifs);
2 7u83 1028
		}
6 7u83 1029
		break;
2 7u83 1030
	    }
1031
 
6 7u83 1032
	    case OBJ_IMPLEMENT:
1033
	    case OBJ_USE: {
2 7u83 1034
		/* Inclusion statements */
6 7u83 1035
		if (pass < 2 && nm [ pass ] == '1') {
1036
		    object *q = p->u.u_obj;
1037
		    info *i = q->u.u_info;
1038
		    char *b = BUILDING_MACRO;
1039
		    if (streq(i->api, LOCAL_API))break;
1040
		    if (ifs [0].dir != CMD_END)print_ifs(output, ifs);
1041
		    if (pass == 0) {
1042
			char *f;
1043
			char *dir;
1044
			char *m = i->protect;
1045
			int n = output_incl_len;
1046
			if (nm [2] == 'G') {
1047
			    OUT(output, "#ifndef %s\n", b);
1048
			    dir = "#pragma extend interface [%s]\n";
1049
			    OUT(output, dir, i->file);
2 7u83 1050
			    OUT ( output, "#else /* %s */\n", b ) ;
6 7u83 1051
			    m = "";
2 7u83 1052
			}
6 7u83 1053
			if (*m)OUT(output, "#ifndef %s\n", m);
1054
			if (local_input) {
1055
			    f = i->incl + n;
1056
			    dir = "#pragma extend interface <../%s>\n";
2 7u83 1057
			} else {
6 7u83 1058
			    f = relative(crt_info->incl, i->incl, n);
1059
			    dir = "#pragma extend interface \"%s\"\n";
2 7u83 1060
			}
6 7u83 1061
			OUT(output, dir, f);
2 7u83 1062
			if ( *m ) OUT ( output, "#endif /* %s */\n", m ) ;
6 7u83 1063
			if (nm [2] == 'G') {
2 7u83 1064
			    OUT ( output, "#endif /* %s */\n", b ) ;
1065
			}
1066
		    } else {
6 7u83 1067
			print_include(output, i->file, 1);
2 7u83 1068
		    }
1069
		}
6 7u83 1070
		break;
2 7u83 1071
	    }
1072
 
6 7u83 1073
	    case OBJ_SET: {
2 7u83 1074
		/* Subsets */
6 7u83 1075
		object *q = p->u.u_obj;
1076
		info *i = q->u.u_info;
1077
		if (streq(i->api, LOCAL_API)) {
1078
		    if (ifs [0].dir != CMD_END)print_ifs(output, ifs);
1079
		    print_object(output, i->elements, pass);
2 7u83 1080
		} else {
6 7u83 1081
		    if (pass < 2) {
1082
			if (ifs [0].dir != CMD_END) {
1083
			    print_ifs(output, ifs);
2 7u83 1084
			}
6 7u83 1085
			print_set(p, pass);
2 7u83 1086
		    }
1087
		}
6 7u83 1088
		break;
2 7u83 1089
	    }
1090
 
6 7u83 1091
	    case OBJ_TEXT_INCL: {
2 7u83 1092
		/* Include file quoted text */
6 7u83 1093
		if (pass == 0) {
1094
		    if (ifs [0].dir != CMD_END)print_ifs(output, ifs);
1095
		    OUTS(output, nm);
1096
		    OUTC(output, '\n');
2 7u83 1097
		}
6 7u83 1098
		break;
2 7u83 1099
	    }
1100
 
6 7u83 1101
	    case OBJ_TEXT_SRC: {
2 7u83 1102
		/* Source file quoted text */
6 7u83 1103
		if (pass == 1) {
1104
		    if (ifs [0].dir != CMD_END)print_ifs(output, ifs);
1105
		    OUTS(output, nm);
1106
		    OUTC(output, '\n');
2 7u83 1107
		}
6 7u83 1108
		break;
2 7u83 1109
	    }
1110
 
6 7u83 1111
	    case OBJ_TOKEN: {
2 7u83 1112
		/* Tokenised objects */
6 7u83 1113
		if (pass == 0) {
1114
		    if (ifs [0].dir != CMD_END)print_ifs(output, ifs);
1115
		    print_token(output, p->u.u_obj, nm);
1116
		} else if (pass == 2) {
1117
		    print_interface(output, p->u.u_obj, ifs);
2 7u83 1118
		}
6 7u83 1119
		break;
2 7u83 1120
	    }
1121
 
6 7u83 1122
	    case OBJ_TYPE: {
2 7u83 1123
		/* Definition of previously declared type */
6 7u83 1124
		if (pass == 0) {
1125
		    type *t = p->u.u_type;
1126
		    char *tnm = t->u.obj->name;
1127
		    print_struct_defn(output, t, tnm, tnm, 1);
2 7u83 1128
		}
6 7u83 1129
		break;
2 7u83 1130
	    }
1131
 
1132
	    default : {
1133
		/* Unknown objects */
6 7u83 1134
		char *err = "Unknown object type, '%d'";
1135
		error(ERR_INTERNAL, err, p->objtype);
1136
		break;
2 7u83 1137
	    }
1138
	}
1139
    }
6 7u83 1140
    if (ifs [0].dir != CMD_END)print_ifs(output, ifs);
1141
    return;
2 7u83 1142
}
1143
 
1144
 
1145
/*
1146
    SCAN AN OBJECT
1147
 
1148
    This routine scans the object input, calling print_set on any subsets.
1149
*/
1150
 
6 7u83 1151
static void
1152
scan_object(object *input, int pass)
2 7u83 1153
{
6 7u83 1154
    object *p;
1155
    for (p = input; p != null; p = p->next) {
1156
	if (p->objtype == OBJ_SET) {
1157
	    object *q = p->u.u_obj;
1158
	    info *i = q->u.u_info;
1159
	    if (streq(i->api, LOCAL_API)) {
1160
		scan_object(i->elements, pass);
2 7u83 1161
	    } else {
6 7u83 1162
		if (pass < 2)print_set(p, pass);
2 7u83 1163
	    }
1164
	}
1165
    }
6 7u83 1166
    return;
2 7u83 1167
}
1168
 
1169
 
1170
/*
1171
    PRINT A SET
1172
 
1173
    This routine prints the set of objects given by input.  The form of the
1174
    output is indicated by pass.
1175
*/
1176
 
6 7u83 1177
void
1178
print_set(object *input, int pass)
2 7u83 1179
{
6 7u83 1180
    char *nm;
1181
    time_t t1, t2;
1182
    FILE *output = null;
1183
    object *ss = input->u.u_obj;
1184
    info *i = ss->u.u_info;
1185
    column = 0;
2 7u83 1186
 
6 7u83 1187
    if (streq(i->api, LOCAL_API)) {
2 7u83 1188
	/* Local files go to the standard output */
6 7u83 1189
	if (pass != 0) return;
1190
	nm = "stdout";
1191
	output = stdout;
1192
	t1 = (time_t)0;
1193
	t2 = (time_t)0;
2 7u83 1194
    } else {
6 7u83 1195
	nm = (pass ? i->src : i->incl);
1196
	if (nm == null || (restrict_use && i->implemented == 0)) {
1197
	    scan_object(i->elements, 1);
1198
	    return;
2 7u83 1199
	}
6 7u83 1200
	if (pass == 1 && i->tokens == 0) {
1201
	    if (verbose > 1) {
1202
		IGNORE printf("%s is not required ...\n", nm);
2 7u83 1203
	    }
6 7u83 1204
	    scan_object(i->elements, 1);
1205
	    return;
2 7u83 1206
	}
6 7u83 1207
	t1 = i->age;
1208
	if (progdate > t1)t1 = progdate;
1209
	t2 = date_stamp(nm);
2 7u83 1210
    }
1211
 
6 7u83 1212
    if ((t1 && t1 < t2) && !force_output) {
2 7u83 1213
	/* Output file is up to date */
6 7u83 1214
	object *q;
1215
	if (verbose > 1) IGNORE printf("%s is up to date ...\n", nm);
1216
	q = make_object(nm, OBJ_FILE);
1217
	q->u.u_file = null;
1218
	IGNORE add_hash(files, q, no_version);
1219
	for (q = i->elements; q != null; q = q->next) {
1220
	    if (q->objtype == OBJ_SET)print_set(q, pass);
2 7u83 1221
	}
1222
    } else {
1223
	/* Output file needs updating */
6 7u83 1224
	object *q = null;
1225
	info *old_info = crt_info;
1226
	int old_column = column;
1227
	boolean old_weak_proto = weak_proto;
1228
	weak_proto = 0;
2 7u83 1229
 
1230
	/* Open output file */
6 7u83 1231
	if (output == null) {
1232
	    create_dir(nm);
1233
	    if (verbose) IGNORE printf("Creating %s ...\n", nm);
1234
	    check_name(nm);
1235
	    q = make_object(nm, OBJ_FILE);
1236
	    q->u.u_file = null;
1237
	    IGNORE add_hash(files, q, no_version);
1238
	    output = fopen(nm, "w");
1239
	    q->u.u_file = output;
1240
	    if (output == null) {
1241
		error(ERR_SERIOUS, "Can't open output file, %s", nm);
1242
		return;
2 7u83 1243
	    }
1244
	}
1245
 
6 7u83 1246
	crt_info = i;
1247
	if (pass == 0) {
2 7u83 1248
	    /* Include output file */
6 7u83 1249
	    char *m = i->protect;
1250
	    char *v = i->version;
2 7u83 1251
 
1252
	    /* Print the copyright message */
6 7u83 1253
	    if (copyright) {
1254
		if (copyright_text == null) {
1255
		    FILE *f = fopen(copyright, "r");
1256
		    if (f == null) {
1257
			char *err = "Can't open copyright file, %s";
1258
			error(ERR_SERIOUS, err, copyright);
1259
			copyright_text = "";
2 7u83 1260
		    } else {
6 7u83 1261
			int c, j = 0;
1262
			while (c = getc(f), c != EOF) {
1263
			    buffer [j] = (char)c;
1264
			    if (++j >= buffsize) {
1265
				error(ERR_SERIOUS, "Copyright too long");
1266
				break;
2 7u83 1267
			    }
1268
			}
6 7u83 1269
			buffer [j] = 0;
1270
			copyright_text = string_copy(buffer);
1271
			IGNORE fclose(f);
2 7u83 1272
		    }
1273
		}
6 7u83 1274
		OUTS(output, copyright_text);
2 7u83 1275
	    }
1276
 
1277
	    /* Find the version number */
6 7u83 1278
	    if (v == null && i->subset) {
1279
		char *a = subset_name(i->api, i->file, null_str);
1280
		object *ap = make_subset(a);
1281
		v = ap->u.u_info->version;
2 7u83 1282
	    }
6 7u83 1283
	    if (v == null && i->file) {
1284
		char *a = subset_name(i->api, null_str, null_str);
1285
		object *ap = make_subset(a);
1286
		v = ap->u.u_info->version;
2 7u83 1287
	    }
1288
 
1289
	    /* Print the file header */
1290
	    OUTS ( output, "/*\n    AUTOMATICALLY GENERATED BY " ) ;
1291
	    OUT ( output, "%s %s\n", progname, progvers ) ;
1292
	    OUT ( output, "    API SUBSET: %s", ss->name ) ;
1293
	    if ( v ) OUT ( output, " (VERSION %s)", v ) ;
1294
	    OUTS ( output, "\n*/\n\n" ) ;
1295
 
1296
	    /* Print the file body */
6 7u83 1297
	    if (*m) {
1298
		OUT(output, "#ifndef %s\n", m);
1299
		OUT(output, "#define %s\n\n", m);
2 7u83 1300
	    }
6 7u83 1301
	    if (i->elements) {
1302
		boolean is_cpplus = 0;
1303
		if (i->linkage) {
1304
		    if (streq(i->linkage, "C++")) {
1305
			OUT(output, "extern \"%s\" {\n\n", i->linkage);
1306
			is_cpplus = 1;
2 7u83 1307
		    } else {
6 7u83 1308
			OUT(output, "#ifdef __cplusplus\n");
1309
			OUT(output, "extern \"%s\" {\n", i->linkage);
1310
			OUT(output, "#endif\n\n");
2 7u83 1311
		    }
1312
		}
6 7u83 1313
		if (i->nspace) {
1314
		    if (is_cpplus) {
1315
			OUT(output, "namespace %s {\n\n", i->nspace);
2 7u83 1316
		    } else {
6 7u83 1317
			OUT(output, "#ifdef __cplusplus\n");
1318
			OUT(output, "namespace %s {\n", i->nspace);
1319
			OUT(output, "#endif\n\n");
2 7u83 1320
		    }
1321
		}
6 7u83 1322
		if (i->block) {
1323
		    char *dir;
1324
		    dir = "#pragma TenDRA declaration block %s begin\n\n";
1325
		    OUT(output, dir, i->block);
2 7u83 1326
		}
6 7u83 1327
		print_object(output, i->elements, 0);
1328
		if (i->tokens)OUTC(output, '\n');
1329
		print_object(output, i->elements, 2);
1330
		if (column)OUTC(output, '\n');
1331
		if (i->block) {
1332
		    char *dir;
1333
		    dir = "\n#pragma TenDRA declaration block end\n";
1334
		    OUT(output, dir);
2 7u83 1335
		}
6 7u83 1336
		if (i->nspace) {
1337
		    if (is_cpplus) {
1338
			OUT(output, "\n}\n");
2 7u83 1339
		    } else {
6 7u83 1340
			OUT(output, "\n#ifdef __cplusplus\n");
1341
			OUT(output, "}\n");
1342
			OUT(output, "#endif\n");
2 7u83 1343
		    }
1344
		}
6 7u83 1345
		if (i->linkage) {
1346
		    if (is_cpplus) {
1347
			OUT(output, "\n}\n");
2 7u83 1348
		    } else {
6 7u83 1349
			OUT(output, "\n#ifdef __cplusplus\n");
1350
			OUT(output, "}\n");
1351
			OUT(output, "#endif\n");
2 7u83 1352
		    }
1353
		}
1354
	    }
1355
	    if ( *m ) OUT ( output, "\n#endif /* %s */\n", m ) ;
1356
 
1357
	} else {
1358
	    /* Source output file */
6 7u83 1359
	    if (i->method == null) {
1360
		char *m, *s;
1361
		char *w1, *w2;
1362
		int n = output_incl_len;
1363
		m = macro_name(DEFINE_PREFIX, i->api, i->file, i->subset);
1364
		w1 = macro_name(WRONG_PREFIX, i->api, null_str, null_str);
1365
		w2 = macro_name(WRONG_PREFIX, i->api, i->file, i->subset);
1366
		s = i->incl + n;
2 7u83 1367
		OUTS ( output, "/* AUTOMATICALLY GENERATED BY " ) ;
1368
		OUT ( output, "%s %s */\n", progname, progvers ) ;
6 7u83 1369
		OUT(output, "#ifndef %s\n", w1);
1370
		OUT(output, "#ifndef %s\n", w2);
1371
		OUT(output, "#if #include ( %s )\n", i->file);
1372
		OUT(output, "#define %s\n", m);
1373
		print_include(output, i->file, 0);
1374
		print_object(output, i->elements, 1);
1375
		OUT(output, "#include <%s>\n", i->file);
1376
		OUT(output, "#endif\n");
1377
		OUT(output, "#endif\n\n");
1378
		OUT(output, "#ifndef %s\n", m);
1379
		OUT(output, "#pragma TenDRA no token definition allow\n");
1380
		OUT(output, "#endif\n");
1381
		OUT(output, "#pragma implement interface <../%s>\n", s);
1382
		OUT(output, "#endif\n");
2 7u83 1383
	    } else {
6 7u83 1384
		print_object(output, i->elements, 1);
2 7u83 1385
	    }
1386
	}
1387
 
1388
	/* End the output */
6 7u83 1389
	IGNORE fclose(output);
1390
	if (q)q->u.u_file = null;
1391
	crt_info = old_info;
1392
	column = old_column;
1393
	weak_proto = old_weak_proto;
2 7u83 1394
    }
6 7u83 1395
    return;
2 7u83 1396
}