Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/nmake/object.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1984-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* Glenn Fowler
23
* AT&T Research
24
*
25
* compiler and loader for the architecture independent makefile object format
26
*
27
* The format fields are labeled by sequence number and type:
28
*
29
* # sfputu()/sfgetu()
30
* $ size,string (no trailing 0)
31
* @ 0 terminated string
32
*
33
* The format is designed for per-section backward/forward compatible
34
* additions to the header, rules, variables and trailer sections, with
35
* the proviso that the section order is not changed and that sequence 1
36
* fields must appear in all future formats. This means that the
37
* property, dynamic and status field bit values are permanently fixed
38
* by each sequence. Field addition semantics are controlled by the
39
* sequence number.
40
*
41
* header:
42
*
43
* 1 4 magic must match
44
* 1 @ ident identification string (information only)
45
* 1 # size header size
46
* 1 # sequence to label additions/changes
47
* 1 # flags OBJ_* flags
48
* 1 # strings string table size
49
* 1 # lists number of lists
50
* 1 # rules number of rules
51
* 1 # rulenum (RULENUM-MINRULENUM)
52
* 1 # rulestr (RULESTR-MINRULESTR)
53
* 1 # variables number of variables
54
* 1 # varnum (VARNUM-MINVARNUM)
55
* 1 # varstr (VARSTR-MINVARSTR)
56
* 1 4 magic again for verification
57
* * # ... [header number fields additions here]
58
*
59
* optional headers:
60
*
61
* 1 # size header size
62
* 1 # type header type
63
* * * ... header contents
64
*
65
* HEADER_PREREQS:
66
*
67
* 1 # type {0:end COMP_*:type}
68
* 1 # time time
69
* 1 @ name unbound name
70
* ...
71
*
72
* variables:
73
*
74
* 1 # property
75
* * # ... [variable number field additions here]
76
* 1 $ name name string
77
* 1 $ value value string
78
* * $ ... [variable string field additions here]
79
*
80
* rules:
81
*
82
* 1 # property
83
* 1 # dynamic
84
* 1 # attribute
85
* 1 # encoded status|semaphore|view|scan
86
* 1 # prereqs prereq list index
87
* 1 # time rule time
88
* 1 # nsec rule nsec [2004-12-01]
89
* 1 # eventnsec event nsec [2004-12-01]
90
* * # ... [rule number field additions here]
91
* 1 $ name name string
92
* 1 $ action action string
93
* 1 $ data event time or state string
94
* * $ ... [rule string field additions here]
95
*
96
* lists:
97
*
98
* 1 # rule rule index
99
*
100
* trailer:
101
*
102
* 1 @ options option string
103
* * @ ... [trailer string fields additions here]
104
*
105
* NOTE: the old format compatibility code should probably be dropped in 95
106
* NOTE: HA -- as of 1997-08-11 2.1 was still in production use
107
*/
108
109
#include "make.h"
110
#include "options.h"
111
112
#if !__STDC__
113
#undef canon
114
#endif
115
116
#include <ccode.h>
117
118
/*
119
* old rule load() replacement puns on struct rule
120
*
121
* rule.mark is not used as load() may be triggered
122
* by staterule() while marks are in use
123
*/
124
125
#define getoldrule(r) ((Rule_t*)r->action)
126
#define isoldrule(r) (r->status==OLDRULE)
127
#define setoldrule(r,o) (r->status=OLDRULE,r->action=(char*)o,r->prereqs=(List_t*)oldrules,oldrules=r)
128
129
#define MAGIC "\015\001\013\005"
130
#define MAGICSIZE (sizeof(MAGIC)-1)
131
132
#define SEQUENCE 1 /* track semantic diffs */
133
#define HEADERSIZE 128 /* handle largest header */
134
135
#define HEADER_PREREQS 1 /* prereqs optional header */
136
137
#define MINRULENUM 6 /* min # rule number fields */
138
#define MINRULESTR 3 /* min # rule string fields */
139
#define MINVARNUM 1 /* min # variable number fields */
140
#define MINVARSTR 2 /* min # variable string fields */
141
142
#define RULENUM (MINRULENUM+2) /* # rule number fields */
143
#define RULESTR (MINRULESTR+0) /* # rule string fields */
144
#define VARNUM (MINVARNUM+0) /* # variable number fields */
145
#define VARSTR (MINVARSTR+0) /* # variable string fields */
146
147
typedef struct Compstate_s /* compile state */
148
{
149
char* sp; /* string table pointer */
150
Sfio_t* fp; /* object file pointer */
151
unsigned long lists; /* list index */
152
unsigned long rules; /* rule index */
153
unsigned long strings; /* string index */
154
unsigned long variables; /* variable index */
155
} Compstate_t;
156
157
typedef struct Loadstate_s /* load state */
158
{
159
char* sp; /* string table pointer */
160
} Loadstate_t;
161
162
static struct Object_s /* object global state */
163
{
164
Sfio_t* pp; /* prerequisite ref pointer */
165
char* options; /* preprocess/probe options */
166
unsigned char* a2n; /* CC_ASCII=>CC_NATIVE */
167
unsigned char* n2a; /* CC_NATIVE=>CC_ASCII */
168
unsigned long garbage; /* state garbage count */
169
unsigned long rules; /* state rule count */
170
int initialized; /* state initialized */
171
int lowres; /* low resolution time state */
172
} object;
173
174
/*
175
* old object format compatibility
176
* frozen 1992-12-25
177
*/
178
179
#define OLD_MAGIC 0x0d010b05
180
#define OLD_OLD_MAGIC 0x0000ff5d
181
#define OLD_VERSION "AT&T Bell Laboratories 08/11/89"
182
#define OLD_VERSION_2 "AT&T Bell Laboratories 01/24/89"
183
#define OLD_SEQUENCE 2
184
#define OLD_ALIGN 8
185
186
#define old_data u2.u_data
187
#define old_event u2.u_event
188
189
struct OLD_list_s; typedef struct OLD_list_s OLD_list_t;
190
191
typedef struct OLD_header_s /* old make object file header */
192
{
193
long magic; /* magic number */
194
char version[32]; /* old was str - older was num */
195
unsigned char null; /* 0 byte for long version's */
196
unsigned char sequence; /* different still compatible */
197
unsigned char sizes[10]; /* misc size checks */
198
} OLD_header_t;
199
200
typedef struct OLD_trailer_s /* old make object file trailer */
201
{
202
long magic; /* magic number */
203
char* options; /* options for set() */
204
long lists; /* number of compiled lists */
205
long rules; /* number of compiled rules */
206
long size; /* total sizeof object file */
207
long variables; /* number of compiled variables */
208
} OLD_trailer_t;
209
210
typedef struct OLD_rule_s /* old rule */
211
{
212
char* name; /* rule name */
213
214
union
215
{
216
Frame_t* u_active; /* active target frame */
217
unsigned long u_complink; /* compilation link */
218
Rule_t* u_freelink; /* free list link */
219
} u1;
220
221
union
222
{
223
char* u_uname; /* unbound name */
224
char* u_data; /* state value */
225
unsigned long u_event; /* state rule event time */
226
} u2;
227
228
OLD_list_t* prereqs; /* prerequisites */
229
char* action; /* update action */
230
unsigned long time; /* modify time */
231
232
long attribute; /* external named attributes */
233
long dynamic; /* dynamic properties */
234
long property; /* stable properties */
235
236
#define noswap scan /* 0 or char elts after here */
237
238
unsigned char scan; /* file scan strategy index */
239
unsigned char semaphore; /* semaphore + count */
240
unsigned char status; /* disposition */
241
unsigned char view; /* view bind index */
242
243
#if BINDINDEX
244
unsigned char source; /* source bind index */
245
#else
246
unsigned char spare_1; /* spare */
247
#endif
248
unsigned char preview; /* min prereq view */
249
250
unsigned short must; /* cancel if == 0 */
251
252
char* runtime; /* run time info */
253
} OLD_rule_t;
254
255
typedef struct OLD_var_s /* old variable */
256
{
257
char* name; /* name */
258
char* value; /* value */
259
long property; /* static and dynamic */
260
long length; /* maximum length of value */
261
} OLD_var_t;
262
263
struct OLD_list_s /* old rule cons cell */
264
{
265
OLD_list_t* next; /* next in list */
266
OLD_rule_t* rule; /* list item */
267
};
268
269
static OLD_header_t old_stamp = /* old object header is fixed */
270
{
271
OLD_MAGIC,
272
OLD_VERSION,
273
0,
274
OLD_SEQUENCE,
275
OLD_ALIGN,
276
CHAR_BIT,
277
sizeof(char),
278
sizeof(short),
279
sizeof(long),
280
sizeof(char*),
281
sizeof(OLD_list_t),
282
sizeof(OLD_rule_t),
283
sizeof(OLD_var_t),
284
0,
285
};
286
287
/*
288
* initialize the object ccode tables
289
*/
290
291
void
292
initcode(void)
293
{
294
if (!object.initialized)
295
{
296
object.initialized = 1;
297
object.a2n = ccmap(CC_ASCII, CC_NATIVE);
298
object.n2a = ccmap(CC_NATIVE, CC_ASCII);
299
}
300
}
301
302
/*
303
* read canonical 0 terminated string from object file
304
*/
305
306
static char*
307
getstring(Sfio_t* sp)
308
{
309
char* s;
310
311
if (s = sfgetr(sp, 0, 0))
312
ccmapstr(object.a2n, s, sfvalue(sp));
313
return s;
314
}
315
316
/*
317
* write canonical 0 terminated string to file
318
*/
319
320
static void
321
putstring(register Sfio_t* sp, register const char* s, int sep)
322
{
323
register int c;
324
register unsigned char* map;
325
326
if (map = object.n2a)
327
{
328
while (c = *(unsigned char*)s++)
329
sfputc(sp, map[c]);
330
if (sep >= 0)
331
sfputc(sp, map[sep]);
332
}
333
else
334
sfputr(sp, s, sep);
335
}
336
337
/*
338
* recursively mark r and its prerequisites for compilation
339
*/
340
341
static void
342
markcompile(register Rule_t* r)
343
{
344
register List_t* p;
345
346
r->dynamic &= ~D_compiled;
347
r->mark |= M_compile;
348
for (p = r->prereqs; p; p = p->next)
349
if (!(p->rule->mark & M_compile))
350
markcompile(p->rule);
351
}
352
353
/*
354
* mark state file garbage candidates
355
*/
356
357
static void
358
markgarbage(register Rule_t* r, int garbage)
359
{
360
register List_t* p;
361
register int i;
362
Rule_t* x;
363
364
r->mark |= M_compile;
365
if (garbage)
366
r->dynamic |= D_garbage;
367
else
368
r->dynamic &= ~D_garbage;
369
for (p = r->prereqs; p; p = p->next)
370
if (!(p->rule->mark & M_compile))
371
markgarbage(p->rule, garbage);
372
for (i = RULE; i <= STATERULES; i++)
373
if ((x = staterule(i, r, NiL, 0)) && !(x->mark & M_compile))
374
markgarbage(x, garbage);
375
}
376
377
/*
378
* compile a string
379
*/
380
381
static void
382
compstring(register Compstate_t* cs, register char* s)
383
{
384
register int c;
385
register unsigned char* map;
386
387
if (s)
388
{
389
c = strlen(s) + 1;
390
cs->strings += c;
391
sfputu(cs->fp, c);
392
if (map = object.n2a)
393
while (c = *s++)
394
sfputc(cs->fp, map[c]);
395
else
396
sfwrite(cs->fp, s, c - 1);
397
}
398
else
399
sfputu(cs->fp, 0);
400
}
401
402
/*
403
* initialize rules for compilation
404
* if h!=0 then all rules marked compiled
405
*/
406
407
static int
408
compinit(const char* s, char* v, void* h)
409
{
410
register Rule_t* r = (Rule_t*)v;
411
412
NoP(s);
413
r->complink = 0;
414
r->mark &= ~M_compile;
415
if (r->dynamic & D_alias)
416
{
417
state.compnew = compinit;
418
state.comparg = h;
419
mergestate(makerule(r->name), r);
420
state.compnew = 0;
421
}
422
if (h || (r->property & P_internal))
423
r->dynamic |= D_compiled;
424
return 0;
425
}
426
427
/*
428
* mark selected rules and immediate prereqs for compilation
429
*
430
* NOTE: remember to clear r->mark (from markcompile())
431
*/
432
433
static int
434
compselect(const char* s, char* v, void* h)
435
{
436
register Rule_t* r = (Rule_t*)v;
437
register char* select = (char*)h;
438
439
NoP(s);
440
if (!(r->mark & M_compile) && (r->dynamic & D_compiled))
441
{
442
state.frame->target = r;
443
expand(internal.met, select);
444
if (sfstrtell(internal.met))
445
{
446
sfstrseek(internal.met, 0, SEEK_SET);
447
markcompile(r);
448
}
449
}
450
return 0;
451
}
452
453
/*
454
* mark rules so that only state vars and immediate prereqs will be compiled
455
*
456
* NOTE: remember to clear r->mark (from markgarbage())
457
*/
458
459
static int
460
compstate(const char* s, char* v, void* h)
461
{
462
register Rule_t* r = (Rule_t*)v;
463
464
NoP(s);
465
NoP(h);
466
r->dynamic |= D_compiled;
467
if (r->dynamic & D_garbage)
468
{
469
if (!object.garbage)
470
r->dynamic &= ~D_garbage;
471
else if (!(r->mark & M_compile))
472
markgarbage(r, 1);
473
}
474
return 0;
475
}
476
477
/*
478
* mark prerequisites for compilation
479
*
480
* NOTE: remember to clear r->mark (from markcompile())
481
*/
482
483
static int
484
compmark(const char* s, char* v, void* h)
485
{
486
register Rule_t* r = (Rule_t*)v;
487
register List_t* p;
488
489
NoP(s);
490
NoP(h);
491
r->complink = 0;
492
if (state.stateview == 0)
493
{
494
if ((r->property & P_state) && !r->view && !(r->dynamic & (D_garbage|D_lower)))
495
{
496
r->dynamic &= ~D_compiled;
497
for (p = r->prereqs; p; p = p->next)
498
p->rule->dynamic &= ~D_compiled;
499
}
500
}
501
else if (!(r->dynamic & D_compiled) && !(r->mark & M_compile))
502
markcompile(r);
503
return 0;
504
}
505
506
/*
507
* weed out the real garbage
508
*/
509
510
static int
511
compkeep(const char* s, char* v, void* h)
512
{
513
register Rule_t* r = (Rule_t*)v;
514
515
NoP(s);
516
NoP(h);
517
if (!(r->mark & M_compile) && !(r->dynamic & D_garbage))
518
markgarbage(r, 0);
519
return 0;
520
}
521
522
/*
523
* compile an individual rule
524
*/
525
526
static int
527
comprule(const char* s, char* v, void* h)
528
{
529
register Rule_t* r = (Rule_t*)v;
530
register List_t* p;
531
register Compstate_t* cs = (Compstate_t*)h;
532
Rule_t x;
533
534
NoP(s);
535
536
/*
537
* compile each rule only once
538
*/
539
540
if ((r->dynamic & D_compiled) || s != r->name && !(r->dynamic & D_alias))
541
return 0;
542
r->dynamic |= D_compiled;
543
r->mark |= M_compile;
544
#if DEBUG
545
if (r->property & P_internal)
546
error(1, "internal rule %s should not be compiled", r->name);
547
#endif
548
549
/*
550
* set the current rule index for prerequisite list compilation
551
*/
552
553
r->complink = cs->rules++;
554
x = *r;
555
r = &x;
556
557
/*
558
* make sure the unbound rule name is compiled
559
*/
560
561
if (!(r->property & P_state))
562
{
563
if (state.stateview == 0)
564
{
565
r->prereqs = 0;
566
r->action = 0;
567
r->dynamic &= ~D_compiled;
568
}
569
if (r->uname && !(r->property & P_metarule))
570
{
571
r->name = r->uname;
572
r->uname = 0;
573
}
574
r->time = 0;
575
#if BINDINDEX
576
r->view = 0;
577
#endif
578
}
579
#if !BINDINDEX
580
r->view = 0;
581
#endif
582
583
/*
584
* compile the fields
585
*/
586
587
sfputu(cs->fp, r->property);
588
sfputu(cs->fp, r->dynamic & ~D_CLEAROBJECT);
589
sfputu(cs->fp, r->attribute);
590
sfputu(cs->fp, (r->semaphore<<16)|(r->view<<8)|(r->scan));
591
if (p = r->prereqs)
592
{
593
sfputu(cs->fp, cs->lists);
594
do cs->lists++; while (p = p->next);
595
}
596
else
597
sfputu(cs->fp, 0);
598
sfputu(cs->fp, tmxsec(r->time));
599
600
/*
601
* 2004-12-01
602
*/
603
604
sfputu(cs->fp, tmxnsec(r->time));
605
sfputu(cs->fp, (r->property & P_staterule) ? tmxnsec(r->event) : 0);
606
607
compstring(cs, r->name);
608
compstring(cs, r->action);
609
if (r->property & P_staterule)
610
sfputu(cs->fp, tmxsec(r->event));
611
else
612
compstring(cs, r->statedata);
613
return 0;
614
}
615
616
/*
617
* a final pass before complist() to catch any prereqs
618
* that eluded comprule()
619
*/
620
621
static int
622
compcheck(const char* s, char* v, void* h)
623
{
624
register Rule_t* r = (Rule_t*)v;
625
register List_t* p;
626
register Rule_t* a;
627
628
/*
629
* ignore aliases and rules not set up by comprule()
630
*/
631
632
if (!r->complink || !(r->mark & M_compile) || s != r->name && !(r->dynamic & D_alias) || state.stateview == 0 && !(r->property & P_state))
633
return 0;
634
if (p = r->prereqs)
635
{
636
do
637
{
638
for (r = p->rule; !r->complink || !(r->dynamic & D_compiled); r = a)
639
if ((!(a = getrule(r->name)) || a == r) && ((r->property & P_state) || !r->uname || !(a = getrule(r->uname)) || a == r))
640
{
641
if (state.warn)
642
error(1, "forcing %s %s prerequisite %s", s, a ? "duplicate" : "dangling", r->name);
643
r->dynamic &= ~D_compiled;
644
comprule(r->name, (char*)r, h);
645
if (!p->rule->complink)
646
p->rule->complink = r->complink;
647
break;
648
}
649
} while (p = p->next);
650
}
651
return 0;
652
}
653
654
/*
655
* compile the prerequisite list for r
656
*/
657
658
static int
659
complist(const char* s, char* v, void* h)
660
{
661
register Rule_t* r = (Rule_t*)v;
662
register List_t* p;
663
register Compstate_t* cs = (Compstate_t*)h;
664
665
/*
666
* ignore aliases and rules not set up by comprule()
667
*/
668
669
if (!r->complink || !(r->mark & M_compile) || s != r->name && !(r->dynamic & D_alias) || state.stateview == 0 && !(r->property & P_state))
670
return 0;
671
r->mark &= ~M_compile;
672
if (p = r->prereqs)
673
{
674
do sfputu(cs->fp, p->rule->complink ? p->rule->complink : r->complink); while (p = p->next);
675
sfputu(cs->fp, 0);
676
}
677
return 0;
678
}
679
680
/*
681
* compile an individual variable
682
*/
683
684
static int
685
compvar(const char* s, char* u, void* h)
686
{
687
register Var_t* v = (Var_t*)u;
688
register Compstate_t* cs = (Compstate_t*)h;
689
char* t;
690
unsigned long property;
691
char* value;
692
693
/*
694
* compile each variable only once
695
* don't compile command arg variable definitions
696
*/
697
698
if ((v->property & V_compiled) || state.stateview < 0 && !(v->property & V_frozen) && ((v->property & V_import) || (v->property & (V_oldvalue|V_readonly)) == V_readonly) || state.stateview == 0 && !(v->property & V_retain))
699
return 0;
700
v->property |= V_compiled;
701
property = v->property;
702
value = v->value;
703
704
/*
705
* check for possible old value
706
*
707
* if v->oldvalue is set in load() then the
708
* variable is frozen and the frozen value
709
* is different than the makefile value
710
*/
711
712
if (state.stateview == 0)
713
property &= ~V_CLEAROBJECT;
714
else
715
{
716
property &= ~V_CLEARSTATE;
717
if (property & V_oldvalue)
718
{
719
if (t = getold(v->name))
720
{
721
if (!(property & V_frozen))
722
{
723
value = t;
724
property &= ~V_oldvalue;
725
}
726
else if (streq(value, t))
727
property &= ~V_oldvalue;
728
}
729
#if DEBUG
730
else
731
error(PANIC, "%s->oldvalue set but not in table.oldvalue", s);
732
#endif
733
}
734
else if ((property & (V_frozen|V_readonly)) == (V_frozen|V_readonly))
735
property |= V_oldvalue;
736
}
737
738
/*
739
* write the variable fields
740
*/
741
742
sfputu(cs->fp, property);
743
compstring(cs, v->name);
744
compstring(cs, value);
745
cs->variables++;
746
return 0;
747
}
748
749
/*
750
* clear temporary marks on r
751
*/
752
753
static int
754
clearmarks(const char* s, char* v, void* h)
755
{
756
register Rule_t* r = (Rule_t*)v;
757
758
NoP(s);
759
NoP(h);
760
r->complink = 0;
761
r->mark &= ~M_compile;
762
return 0;
763
}
764
765
/*
766
* compile the current rules and variables into objfile
767
*/
768
769
void
770
compile(char* objfile, char* select)
771
{
772
register Sfio_t* sp;
773
List_t* p;
774
List_t* q;
775
Rule_t* r;
776
Compstate_t cs;
777
778
/*
779
* initialize the object globals
780
*/
781
782
zero(cs);
783
cs.lists++;
784
cs.rules++;
785
786
/*
787
* create the object temporary file
788
*/
789
790
sp = sfstropen();
791
edit(sp, objfile, KEEP, KEEP, external.tmp);
792
state.tmpfile = strdup(sfstruse(sp));
793
sfstrclose(sp);
794
if (!(cs.fp = sfopen(NiL, state.tmpfile, "brw")))
795
{
796
error(ERROR_SYSTEM|1, "%s: cannot create temporary object file", state.tmpfile);
797
return;
798
}
799
800
/*
801
* skip the header until everything else is done
802
*/
803
804
if (sfseek(cs.fp, (Sfoff_t)HEADERSIZE, SEEK_SET) != HEADERSIZE)
805
error(ERROR_SYSTEM|3, "%s: object file header write error", state.tmpfile);
806
807
/*
808
* write the optional headers
809
*/
810
811
if (sp = object.pp)
812
{
813
object.pp = 0;
814
if (!state.base)
815
{
816
sfputu(sp, COMP_OPTIONS);
817
sfputu(sp, 0);
818
for (p = internal.preprocess->prereqs; p; p = p->next)
819
putstring(sp, p->rule->name, p->next ? ' ' : -1);
820
sfputc(sp, 0);
821
sfputu(sp, 0);
822
sfputu(internal.tmp, HEADER_PREREQS);
823
sfputu(cs.fp, sfstrtell(internal.tmp) + sfstrtell(sp));
824
sfstrseek(internal.tmp, 0, SEEK_SET);
825
sfputu(cs.fp, HEADER_PREREQS);
826
sfwrite(cs.fp, sfstrbase(sp), sfstrtell(sp));
827
}
828
sfstrclose(sp);
829
}
830
sp = cs.fp;
831
sfputu(sp, 0);
832
if (sferror(sp))
833
error(ERROR_SYSTEM|3, "%s: object file optional header write error", state.tmpfile);
834
835
/*
836
* mark the rules and prerequisites for compilation
837
*/
838
839
if (select)
840
{
841
Sfio_t* tmp;
842
843
hashwalk(table.rule, 0, compinit, null);
844
tmp = sfstropen();
845
sfprintf(tmp, "$(<:V:%s)", select);
846
r = state.frame->target;
847
hashwalk(table.rule, 0, compselect, sfstruse(tmp));
848
state.frame->target = r;
849
sfstrclose(tmp);
850
}
851
else
852
{
853
/*
854
* compile and write the variables
855
*/
856
857
hashwalk(table.var, 0, compvar, &cs);
858
if (sferror(sp))
859
error(ERROR_SYSTEM|3, "%s: object file variable write error", state.tmpfile);
860
hashwalk(table.rule, 0, compinit, NiL);
861
if (state.stateview == 0)
862
{
863
/*
864
* check state file garbage collection
865
*
866
* NOTE: only the head of each garbage list is
867
* counted so the percentage threshold
868
* should probably be low
869
*/
870
871
if ((100 * object.garbage / (object.rules ? object.rules : 1) < PCTGARBAGE && !(state.test & 0x00008000)))
872
object.garbage = 0;
873
hashwalk(table.rule, 0, compstate, &cs);
874
if (object.garbage)
875
{
876
hashwalk(table.rule, 0, clearmarks, &cs);
877
hashwalk(table.rule, 0, compkeep, &cs);
878
}
879
#if BINDINDEX
880
for (n = 1; n <= state.maxsource; n++)
881
markcompile(state.source[n].path);
882
for (n = 1; n <= state.maxview; n++)
883
markcompile(state.view[n].path);
884
#endif
885
}
886
}
887
hashwalk(table.rule, 0, compmark, &cs);
888
889
/*
890
* some rules must always be compiled and/or appear first
891
*/
892
893
for (p = internal.special->prereqs; p; p = p->next)
894
markcompile(p->rule);
895
for (p = internal.special->prereqs; p; p = p->next)
896
for (q = p->rule->prereqs; q; q = q->next)
897
comprule(q->rule->name, (char*)q->rule, &cs);
898
#if BINDINDEX
899
if (state.stateview == 0)
900
{
901
for (n = 1; n <= state.maxsource; n++)
902
{
903
x = state.source[n].path;
904
comprule(x->name, x);
905
}
906
for (n = 1; n <= state.maxview; n++)
907
{
908
x = state.view[n].path;
909
comprule(x->name, x);
910
}
911
}
912
#endif
913
914
/*
915
* compile and write the rules
916
*/
917
918
hashwalk(table.rule, 0, comprule, &cs);
919
if (sferror(sp))
920
error(ERROR_SYSTEM|3, "%s: object file rule write error", state.tmpfile);
921
922
/*
923
* despite the effort a few elusive prereqs manage to avoid comprule()
924
* the compcheck() pass sets up complink for these prereqs
925
*/
926
927
for (p = internal.special->prereqs; p; p = p->next)
928
for (q = p->rule->prereqs; q; q = q->next)
929
compcheck(q->rule->name, (char*)q->rule, &cs);
930
hashwalk(table.rule, 0, compcheck, &cs);
931
932
/*
933
* compile and write the prerequisite lists
934
*/
935
936
for (p = internal.special->prereqs; p; p = p->next)
937
for (q = p->rule->prereqs; q; q = q->next)
938
complist(q->rule->name, (char*)q->rule, &cs);
939
hashwalk(table.rule, 0, complist, &cs);
940
if (sferror(sp))
941
error(ERROR_SYSTEM|3, "%s: object file prerequisite write error", state.tmpfile);
942
943
/*
944
* write the trailer
945
*/
946
947
if (state.stateview < 0)
948
{
949
/*
950
* pre 2004-09-09 will just do "--"
951
*/
952
953
putstring(sp, "--", 0);
954
if (object.n2a)
955
{
956
listops(internal.wrk, '@');
957
putstring(sp, sfstruse(internal.wrk), 0);
958
}
959
else
960
{
961
listops(sp, '@');
962
sfputc(sp, 0);
963
}
964
}
965
sfputc(sp, 0);
966
967
/*
968
* clear temporary marks
969
*/
970
971
hashwalk(table.rule, 0, clearmarks, &cs);
972
973
/*
974
* write the real header
975
*/
976
977
sfseek(sp, (Sfoff_t)0, SEEK_SET);
978
sfwrite(sp, MAGIC, MAGICSIZE);
979
putstring(sp, version, 0);
980
sfputu(sp, HEADERSIZE);
981
sfputu(sp, SEQUENCE);
982
sfputu(sp, 0);
983
sfputu(sp, cs.strings);
984
sfputu(sp, cs.lists - 1);
985
sfputu(sp, cs.rules - 1);
986
sfputu(sp, RULENUM - MINRULENUM);
987
sfputu(sp, RULESTR - MINRULESTR);
988
sfputu(sp, cs.variables);
989
sfputu(sp, VARNUM - MINVARNUM);
990
sfputu(sp, VARSTR - MINVARSTR);
991
sfwrite(sp, MAGIC, MAGICSIZE);
992
if (sferror(sp))
993
error(ERROR_SYSTEM|3, "%s: temporary object file header write error", state.tmpfile);
994
995
/*
996
* commit to the temporary object and clean up
997
*/
998
999
sfclose(sp);
1000
remove(objfile);
1001
if (rename(state.tmpfile, objfile))
1002
error(1, "%s: object file not recompiled", objfile);
1003
remtmp(0);
1004
if (state.stateview == 0)
1005
{
1006
Stat_t st;
1007
Time_t t;
1008
Time_t x;
1009
1010
/*
1011
* set the state file times to the latest
1012
* possible event time modulo the file
1013
* system time precision
1014
*/
1015
1016
t = CURTIME;
1017
x = tmxsns(tmxsec(t), 999999999);
1018
if (!tmxtouch(objfile, x, x, TMX_NOTIME, 0) && !stat(objfile, &st))
1019
{
1020
t += tmxsns(1,0) - tmxnsec(tmxgetmtime(&st));
1021
tmxtouch(objfile, t, t, TMX_NOTIME, 0);
1022
}
1023
1024
}
1025
r = bindfile(NiL, objfile, BIND_FORCE|BIND_DOT|BIND_RULE);
1026
r->dynamic |= D_built|D_regular;
1027
r->view = 0;
1028
if (state.mam.dynamic || state.mam.regress)
1029
{
1030
mampush(state.mam.out, r, P_force);
1031
sfprintf(state.mam.out, "%sexec %s : compile into %s object\n", state.mam.label, state.mam.dynamic ? mamname(r) : null, error_info.id);
1032
mampop(state.mam.out, r, 0);
1033
}
1034
if (state.stateview == 0 && object.garbage && object.garbage > cs.rules)
1035
message((-1, "%d%% [%d/%d] state file garbage collection recovery", (object.garbage - cs.rules) * 100 / object.garbage, object.garbage - cs.rules, object.garbage));
1036
}
1037
1038
/*
1039
* register input file prerequisite
1040
*/
1041
1042
void
1043
compref(Rule_t* r, int type)
1044
{
1045
if (object.pp)
1046
{
1047
if (r)
1048
{
1049
/*
1050
* COMP_NSEC for subsecond granularity
1051
* and bind checks
1052
* ignored by old implementations
1053
*/
1054
1055
sfputu(object.pp, COMP_NSEC);
1056
sfputu(object.pp, tmxnsec(r->time));
1057
putstring(object.pp, r->name, 0);
1058
sfputu(object.pp, type);
1059
sfputu(object.pp, tmxsec(r->time));
1060
putstring(object.pp, unbound(r), 0);
1061
}
1062
else
1063
{
1064
sfstrclose(object.pp);
1065
object.pp = 0;
1066
}
1067
}
1068
else if (!r && !state.makefile)
1069
object.pp = sfstropen();
1070
}
1071
1072
/*
1073
* promote lower view prereqs of top view state
1074
*/
1075
1076
static int
1077
promote(const char* s, char* v, void* h)
1078
{
1079
register Rule_t* r = (Rule_t*)v;
1080
register List_t* p;
1081
1082
NoP(s);
1083
NoP(h);
1084
if (r->mark & M_compile)
1085
{
1086
r->mark &= ~M_compile;
1087
for (p = r->prereqs; p; p = p->next)
1088
{
1089
r = p->rule;
1090
if (r->dynamic & D_lower)
1091
{
1092
unviewname(r->name);
1093
p->rule = makerule(r->name);
1094
viewname(r->name, r->view);
1095
}
1096
}
1097
}
1098
return 0;
1099
}
1100
1101
/*
1102
* associate one rule with each name
1103
*/
1104
1105
static int
1106
atomize(const char* s, char* v, void* h)
1107
{
1108
register Rule_t* r = (Rule_t*)v;
1109
register List_t* p;
1110
1111
NoP(s);
1112
NoP(h);
1113
if (isoldrule(r))
1114
{
1115
#if DEBUG
1116
error(PANIC, "old rule %s still in table.rule%s", r->name, r == getrule(r->name) ? null : " -- duplicate hash");
1117
#endif
1118
return 0;
1119
}
1120
for (p = r->prereqs; p; p = p->next)
1121
if (isoldrule(p->rule))
1122
p->rule = getoldrule(p->rule);
1123
return 0;
1124
}
1125
1126
/*
1127
* repair prereq list corruption
1128
*/
1129
1130
static int
1131
repair(const char* s, char* v, void* h)
1132
{
1133
register Rule_t* r = (Rule_t*)v;
1134
register List_t* p;
1135
register List_t* q;
1136
1137
NoP(s);
1138
NoP(h);
1139
p = 0;
1140
q = r->prereqs;
1141
while (q)
1142
if (q->rule)
1143
{
1144
p = q;
1145
q = q->next;
1146
}
1147
else if (p)
1148
p->next = q = q->next;
1149
else
1150
r->prereqs = q = q->next;
1151
return 0;
1152
}
1153
1154
/*
1155
* return the object file name
1156
* assumes the main makefile has already been read
1157
*/
1158
1159
char*
1160
objectfile(void)
1161
{
1162
char* dir;
1163
Sfio_t* sp;
1164
Stat_t st;
1165
1166
if (!state.objectfile && state.makefile && state.writeobject)
1167
{
1168
sp = sfstropen();
1169
dir = DELETE;
1170
if (streq(state.writeobject, "-") || !stat(state.writeobject, &st) && S_ISDIR(st.st_mode) && (dir = state.writeobject))
1171
edit(sp, state.makefile, dir, KEEP, external.object);
1172
else
1173
expand(sp, state.writeobject);
1174
state.objectfile = strdup(sfstruse(sp));
1175
sfstrclose(sp);
1176
}
1177
return state.objectfile;
1178
}
1179
1180
/*
1181
* remove temporary compilation files
1182
*/
1183
1184
void
1185
remtmp(int fatal)
1186
{
1187
if (fatal && state.stateview == 0 && state.tmpfile)
1188
error(2, "%s: state file not updated", statefile());
1189
if (state.tmpfile)
1190
{
1191
if (remove(state.tmpfile) && errno != ENOENT)
1192
error(ERROR_SYSTEM|1, "%s: temporary file not removed", state.tmpfile);
1193
free(state.tmpfile);
1194
state.tmpfile = 0;
1195
}
1196
if (fatal)
1197
lockstate(0);
1198
}
1199
1200
/*
1201
* load a string
1202
*/
1203
1204
static char*
1205
loadstring(Loadstate_t* ls, Sfio_t* sp)
1206
{
1207
register int n;
1208
register char* s;
1209
1210
if (!(n = sfgetu(sp)) || sfeof(sp))
1211
return 0;
1212
s = ls->sp;
1213
ls->sp += n--;
1214
sfread(sp, s, n);
1215
ccmapstr(object.a2n, s, n);
1216
return s;
1217
}
1218
1219
/*
1220
* initialize object state
1221
*/
1222
1223
static void
1224
loadinit(void)
1225
{
1226
object.garbage = object.rules = 0;
1227
}
1228
1229
/*
1230
* check if file is loadable object
1231
* if source!=0 then source prereqs are checked
1232
*/
1233
1234
int
1235
loadable(register Sfio_t* sp, register Rule_t* r, int source)
1236
{
1237
register List_t* p;
1238
char* s;
1239
char* sn;
1240
long n;
1241
Sfoff_t off;
1242
Time_t t;
1243
Time_t tm;
1244
Time_t tn;
1245
int lowres;
1246
int ok = 1;
1247
long old = 0;
1248
Rule_t* x;
1249
Stat_t st;
1250
1251
loadinit();
1252
if ((s = sfreserve(sp, 0, 0)) && (n = sfvalue(sp)) >= 0)
1253
{
1254
if (n >= MAGICSIZE && !memcmp(s, MAGIC, MAGICSIZE) || n >= sizeof(old) && ((old = OLD_MAGIC, swapop(s, &old, sizeof(old)) >= 0) || (old = OLD_OLD_MAGIC, swapop(s, &old, sizeof(old)) >= 0)))
1255
{
1256
if (!source)
1257
return state.base || !state.forceread || state.global || state.list;
1258
1259
/*
1260
* check previous source prerequisites
1261
*/
1262
1263
if (!old && !sfseek(sp, (Sfoff_t)0, SEEK_SET) && sfseek(sp, (Sfoff_t)MAGICSIZE, SEEK_SET) == MAGICSIZE)
1264
{
1265
if (getstring(sp) && (off = sfgetu(sp)) && sfgetu(sp))
1266
while (!sfeof(sp) && sfseek(sp, off, SEEK_SET) == off && (off = sfgetu(sp)))
1267
{
1268
off += sfseek(sp, (Sfoff_t)0, SEEK_CUR);
1269
if (sfgetu(sp) == HEADER_PREREQS)
1270
{
1271
/*UNDENT...*/
1272
1273
state.init++;
1274
lowres = 1;
1275
sn = 0;
1276
tn = 0;
1277
while (n = sfgetu(sp))
1278
{
1279
tm = sfgetu(sp);
1280
if (!(s = getstring(sp)))
1281
break;
1282
if (n & (COMP_BASE|COMP_FILE|COMP_GLOBAL|COMP_INCLUDE))
1283
{
1284
if (x = bindfile(NiL, s, BIND_MAKEFILE|BIND_RULE))
1285
{
1286
s = x->name;
1287
t = x->time;
1288
1289
/*
1290
* put bound makefile prereqs in state as a query courtesy
1291
*/
1292
1293
if (!(n & COMP_BASE) && *x->name != '/')
1294
staterule(RULE, x, NiL, 1)->time = t;
1295
if (!(x->dynamic & D_regular))
1296
x->dynamic &= ~D_bound;
1297
}
1298
else
1299
t = 0;
1300
if (!t && sn && !stat(sn, &st))
1301
t = tmxgetmtime(&st);
1302
if (!t)
1303
{
1304
if ((n & COMP_DONTCARE) && !tm)
1305
continue;
1306
error(state.exec || state.mam.out ? -1 : 1, "%s: %s not found", r->name, s);
1307
break;
1308
}
1309
if (tn && t == tmxsns(tm, 0))
1310
tn = 0;
1311
tm = (lowres && tm == tmxsec(t)) ? t : tmxsns(tm, tn);
1312
1313
/*
1314
* check prerequisite file time with previous
1315
*/
1316
1317
debug((-4, "%s%s%s%s%sprerequisite %s [%s] state [%s]", (n & COMP_DONTCARE) ? "optional " : null, (n & COMP_BASE) ? "base " : null, (n & COMP_FILE) ? "-f " : null, (n & COMP_GLOBAL) ? "-g " : null, (n & COMP_INCLUDE) ? "include " : null, s, timestr(t), timestr(tm)));
1318
if (t != tm)
1319
{
1320
if (sn && !streq(sn, x->name))
1321
error(state.exec || state.mam.out ? -1 : 1, "%s: binding changed to %s from %s", s, x->name, sn);
1322
else
1323
error(state.exec || state.mam.out ? -1 : 1, "%s: out of date with %s", r->name, s);
1324
break;
1325
}
1326
sn = 0;
1327
tn = 0;
1328
1329
/*
1330
* check that explicit prerequisite still specified
1331
*/
1332
1333
if (n & (COMP_FILE|COMP_GLOBAL))
1334
{
1335
for (p = ((n & COMP_FILE) ? internal.makefiles : internal.globalfiles)->prereqs; p; p = p->next)
1336
if (!(p->rule->mark & M_compile))
1337
{
1338
if (streq(p->rule->name, s) || p->rule->uname && streq(p->rule->uname, s))
1339
p->rule->mark |= M_compile;
1340
else
1341
{
1342
error(state.exec || state.mam.out ? -1 : 1, "%s: %sfile %s option order changed", r->name, (n & COMP_GLOBAL) ? "global " : null, s);
1343
goto nope;
1344
}
1345
break;
1346
}
1347
if (!p)
1348
{
1349
error(state.exec || state.mam.out ? -1 : 1, "%s: %sfile %s was specified last time", r->name, (n & COMP_GLOBAL) ? "global " : null, s);
1350
break;
1351
}
1352
}
1353
else if ((n & COMP_BASE) && !state.rules)
1354
{
1355
if (n & COMP_RULES)
1356
state.explicitrules = 1;
1357
state.rules = makerule(s)->name;
1358
}
1359
}
1360
else if (n & COMP_NSEC)
1361
{
1362
if (*s)
1363
{
1364
sfputr(internal.met, s, -1);
1365
sn = sfstruse(internal.met);
1366
}
1367
tn = tm;
1368
lowres = 0;
1369
}
1370
else if (n & COMP_OPTIONS)
1371
object.options = strdup(s);
1372
}
1373
nope:
1374
state.init--;
1375
if (n)
1376
ok = 0;
1377
1378
/*
1379
* check for explicit file prereqs not specified last time
1380
*/
1381
1382
for (p = internal.globalfiles->prereqs; p; p = p->next)
1383
if (p->rule->mark & M_compile)
1384
p->rule->mark &= ~M_compile;
1385
else if (ok)
1386
{
1387
ok = 0;
1388
if (state.writeobject)
1389
error(state.exec || state.mam.out ? -1 : 1, "%s: global file %s not specified last time", r->name, p->rule->name);
1390
}
1391
for (p = internal.makefiles->prereqs; p; p = p->next)
1392
if (p->rule->mark & M_compile)
1393
p->rule->mark &= ~M_compile;
1394
else if (ok)
1395
{
1396
ok = 0;
1397
if (state.writeobject)
1398
error(state.exec || state.mam.out ? -1 : 1, "%s: file %s not specified last time", r->name, p->rule->name);
1399
}
1400
if (ok && !sfseek(sp, (Sfoff_t)0, SEEK_SET))
1401
return 1;
1402
1403
/*...INDENT*/
1404
break;
1405
}
1406
}
1407
sfseek(sp, (Sfoff_t)0, SEEK_SET);
1408
}
1409
}
1410
}
1411
return 0;
1412
}
1413
1414
/*
1415
* load compiled rules and variables from objfile
1416
* return:
1417
* -1 partially loaded => punt
1418
* 0 not loaded
1419
* 1 loaded
1420
*/
1421
1422
int
1423
load(register Sfio_t* sp, const char* objfile, int source, int ucheck)
1424
{
1425
register int n;
1426
register Rule_t* r;
1427
register Var_t* v;
1428
register List_t* d;
1429
register char* s;
1430
char* p = 0;
1431
int promoted = 0;
1432
int recompile = 0;
1433
char* corrupt = "2005-03-01";
1434
Rule_t* oldrules = 0;
1435
Rule_t* or;
1436
Rule_t* xr;
1437
Var_t* ov;
1438
Var_t* xv;
1439
Var_t* x;
1440
List_t* xd;
1441
List_t* a;
1442
int flags;
1443
int strings;
1444
int lists;
1445
int rules;
1446
int rulenum;
1447
int rulestr;
1448
int variables;
1449
int varnum;
1450
int varstr;
1451
int attrclash;
1452
int garbage;
1453
int oscan;
1454
int scanclash;
1455
int sequence;
1456
int lowres;
1457
unsigned long attr;
1458
unsigned long attrclear;
1459
unsigned long oattribute;
1460
unsigned long ts;
1461
unsigned long tn;
1462
Frame_t* fp;
1463
Sfoff_t off;
1464
Stat_t st;
1465
unsigned long attrmap[CHAR_BIT * sizeof(unsigned long)];
1466
unsigned char scanmap[UCHAR_MAX + 1];
1467
char ident[64];
1468
Loadstate_t ls;
1469
1470
int old;
1471
int old_swap;
1472
long old_magic;
1473
OLD_rule_t old_rule;
1474
OLD_var_t old_var;
1475
OLD_list_t old_list;
1476
OLD_header_t old_header;
1477
OLD_trailer_t old_trailer;
1478
1479
if (source)
1480
{
1481
/*
1482
* compare with current preprocess options
1483
*/
1484
1485
for (d = internal.preprocess->prereqs; d; d = d->next)
1486
sfputr(internal.nam, d->rule->name, d->next ? ' ' : -1);
1487
s = sfstruse(internal.nam);
1488
if (!object.options)
1489
object.options = (char*)null;
1490
if (!streq(object.options, s))
1491
{
1492
error(state.exec || state.mam.out ? -1 : 1, "%s: options changed from \"%s\" to \"%s\"", objfile, object.options, s);
1493
return 0;
1494
}
1495
}
1496
loadinit();
1497
zero(ls);
1498
1499
/*
1500
* empty object files are ok
1501
*/
1502
1503
if (fstat(sffileno(sp), &st))
1504
{
1505
error(1, "%s: cannot stat object file", objfile);
1506
return 0;
1507
}
1508
if (!st.st_size)
1509
{
1510
if (state.stateview >= 0)
1511
{
1512
error(1, "%s: empty state file", objfile);
1513
return 0;
1514
}
1515
return 1;
1516
}
1517
1518
/*
1519
* check for other users within last ucheck minutes
1520
*/
1521
1522
if (ucheck && st.st_uid != geteuid() && (n = CURSECS - st.st_mtime) < ucheck * 60)
1523
error(1, "%s: another user was here %s ago", state.makefile, fmtelapsed(n, 1));
1524
1525
/*
1526
* check the header
1527
*/
1528
1529
if (!(s = sfreserve(sp, MAGICSIZE, 0)))
1530
goto badmagic;
1531
errno = 0;
1532
if (memcmp(s, MAGIC, MAGICSIZE) || !(s = getstring(sp)) || streq(s, OLD_VERSION))
1533
{
1534
old = 1;
1535
if (sfseek(sp, (Sfoff_t)0, SEEK_SET) ||
1536
sfread(sp, (char*)&old_header, sizeof(old_header)) != sizeof(old_header) ||
1537
sfseek(sp, -(Sfoff_t)sizeof(old_trailer), SEEK_END) == -1 ||
1538
sfread(sp, (char*)&old_trailer, sizeof(old_trailer)) != sizeof(old_trailer))
1539
goto badio;
1540
if ((old_magic = OLD_MAGIC, (old_swap = swapop(&old_header.magic, &old_magic, sizeof(old_magic)))) < 0 && (old_magic = OLD_OLD_MAGIC, (old_swap = swapop(&old_header.magic, &old_magic, sizeof(old_magic)))) < 0)
1541
goto badmagic;
1542
sequence = old_header.sequence;
1543
old_header.sequence = old_stamp.sequence;
1544
if (old_swap)
1545
{
1546
swapmem(old_swap, &old_header, &old_header, sizeof(old_header));
1547
swapmem(old_swap, &old_trailer, &old_trailer, sizeof(old_trailer));
1548
}
1549
if ((st.st_size - sizeof(old_trailer)) & (OLD_ALIGN - 1))
1550
goto badversion;
1551
strcpy(old_stamp.version, OLD_VERSION);
1552
if (memcmp(((char*)&old_header) + sizeof(old_header.magic), ((char*)&old_stamp) + sizeof(old_stamp.magic), sizeof(old_header) - sizeof(old_header.magic)))
1553
{
1554
strcpy(old_stamp.version, OLD_VERSION_2);
1555
if (memcmp(((char*)&old_header) + sizeof(old_header.magic), ((char*)&old_stamp) + sizeof(old_stamp.magic), sizeof(old_header) - sizeof(old_header.magic)))
1556
goto badversion;
1557
sequence = 2;
1558
}
1559
if (s = strrchr(old_stamp.version, ' '))
1560
s++;
1561
else
1562
s = old_stamp.version;
1563
strncopy(ident, s, sizeof(ident));
1564
if (old_trailer.magic != old_header.magic || old_trailer.size != st.st_size)
1565
goto badmagic;
1566
if (state.exec && streq(objfile, state.objectfile))
1567
return 0;
1568
lists = old_trailer.lists;
1569
rules = old_trailer.rules;
1570
variables = old_trailer.variables;
1571
off = sizeof(old_header) + rules * sizeof(old_rule) + lists * sizeof(old_list) + variables * sizeof(old_var);
1572
strings = st.st_size - sizeof(old_trailer) - off;
1573
if (sfeof(sp) || sfseek(sp, off, SEEK_SET) != off)
1574
goto badio;
1575
lowres = state.stateview >= 0;
1576
}
1577
else
1578
{
1579
old = 0;
1580
if (s = strrchr(s, ' '))
1581
s++;
1582
else
1583
s = "old";
1584
strncopy(ident, s, sizeof(ident));
1585
off = sfgetu(sp);
1586
sequence = sfgetu(sp);
1587
flags = sfgetu(sp);
1588
NoP(flags);
1589
strings = sfgetu(sp);
1590
lists = sfgetu(sp);
1591
rules = sfgetu(sp);
1592
lowres = (rulenum = sfgetu(sp)) < 2 && state.stateview >= 0;
1593
rulestr = sfgetu(sp);
1594
variables = sfgetu(sp);
1595
varnum = sfgetu(sp);
1596
varstr = sfgetu(sp);
1597
if (!(s = sfreserve(sp, MAGICSIZE, 0)) || memcmp(s, MAGIC, MAGICSIZE))
1598
goto badmagic;
1599
1600
/*
1601
* read the optional headers
1602
*/
1603
1604
for (;;)
1605
{
1606
if (sfeof(sp) || sfseek(sp, off, SEEK_SET) != off)
1607
goto badio;
1608
if (!sequence || !(off = sfgetu(sp)))
1609
break;
1610
off += sfseek(sp, (Sfoff_t)0, SEEK_CUR);
1611
}
1612
}
1613
message((-3, "%s sequence=%d lists=%d rules=%d variables=%d strings=%d", ident, sequence, lists, rules, variables, strings));
1614
if (lowres && !object.lowres)
1615
{
1616
object.lowres = 1;
1617
if (!state.silent)
1618
error(1, "%s: low time resolution state file -- subsecond differences ignored", objfile);
1619
}
1620
1621
/*
1622
* allocate strings and structs in one chunk
1623
* and compute pointers to the compiled data
1624
*/
1625
1626
if (!(p = newof(0, char, lists * sizeof(List_t) + rules * sizeof(Rule_t) + variables * sizeof(Var_t) + strings, 0)))
1627
{
1628
error(3, "out of space");
1629
goto bad;
1630
}
1631
r = or = (Rule_t*)p;
1632
d = (List_t*)((char*)r + rules * sizeof(Rule_t));
1633
v = ov = (Var_t*)((char*)d + lists * sizeof(List_t));
1634
s = ((char*)v + variables * sizeof(Var_t));
1635
1636
/*
1637
* read the string table
1638
*/
1639
1640
if (!old)
1641
ls.sp = s;
1642
else if (sfread(sp, s, strings) != strings)
1643
goto badio;
1644
1645
/*
1646
* load the variables and check for any frozen
1647
* variables that may have changed
1648
*/
1649
1650
if (old)
1651
{
1652
off = sizeof(old_header) + rules * sizeof(old_rule) + lists * sizeof(old_list);
1653
if (sfseek(sp, off, SEEK_SET) != off)
1654
goto badio;
1655
}
1656
oattribute = internal.attribute->attribute;
1657
oscan = internal.scan->scan;
1658
attrclash = scanclash = 0;
1659
for (xv = v + variables; v < xv; v++)
1660
{
1661
if (old)
1662
{
1663
if (sfread(sp, (char*)&old_var, sizeof(old_var)) != sizeof(old_var))
1664
goto badio;
1665
if (old_swap)
1666
swapmem(old_swap, &old_var, &old_var, sizeof(old_var));
1667
v->property = old_var.property;
1668
if (old_var.name)
1669
v->name = s + (unsigned long)old_var.name - 1;
1670
if (old_var.value)
1671
v->value = s + (unsigned long)old_var.value - 1;
1672
switch (sequence)
1673
{
1674
case 2: /* 01/24/89 */
1675
v->property = (v->property & 0x000003ffL);
1676
break;
1677
}
1678
}
1679
else
1680
{
1681
v->property = sfgetu(sp);
1682
#if !_HUH_1993_10_01 /* drop this eventually */
1683
v->property &= ~V_free;
1684
#endif
1685
1686
/*
1687
* variable number field additions here
1688
*/
1689
1690
for (n = varnum; n > 0; n--)
1691
sfgetu(sp);
1692
v->name = loadstring(&ls, sp);
1693
v->value = loadstring(&ls, sp);
1694
1695
/*
1696
* variable string field additions here
1697
*/
1698
1699
for (n = varstr; n > 0; n--)
1700
loadstring(&ls, sp);
1701
}
1702
if ((state.exec || !state.base || state.compileonly) && (v->property & V_frozen) && (!(x = getvar(v->name)) && ((v->property & V_oldvalue) || (v->property & V_import) && *v->value) || x && ((x->property & (V_append|V_readonly)) == (V_append|V_readonly) || ((v->property|x->property) & (V_import|V_readonly)) && !streq(v->value, x->value)) || (v->property & V_functional)))
1703
{
1704
error((state.exec || state.mam.out) && !state.explain ? -1 : 1, "%s: frozen %svariable %s changed", objfile, ((v->property|(x ? x->property : 0)) & V_import) ? "environment " : ((x ? x->property : 0) & V_readonly) ? "command argument " : null, v->name);
1705
recompile = 1;
1706
v->property &= ~V_readonly;
1707
}
1708
else
1709
v->property &= ~(V_oldvalue|V_readonly);
1710
}
1711
if (sfeof(sp))
1712
goto badio;
1713
if (recompile)
1714
{
1715
recompile = 0;
1716
goto bad;
1717
}
1718
recompile = -1;
1719
p = 0;
1720
v = ov;
1721
1722
/*
1723
* enter the variables
1724
*/
1725
1726
hashclear(table.var, HASH_ALLOCATE);
1727
for (xv = v + variables; v < xv; v++)
1728
{
1729
if (!(x = getvar(v->name)) || !(x->property & (V_readonly|V_restored)) && (!(x->property & V_import) || !state.global))
1730
{
1731
putvar(v->name, v);
1732
if (x)
1733
freevar(x);
1734
}
1735
else
1736
{
1737
if ((x->property & (V_append|V_readonly)) == (V_append|V_readonly))
1738
{
1739
n = state.reading;
1740
state.reading = 1;
1741
setvar(x->name, v->value, 0);
1742
state.reading = n;
1743
}
1744
x->property |= v->property & (V_functional|V_scan);
1745
}
1746
if ((v->property & V_retain) && state.stateview >= 0)
1747
v->property |= V_restored;
1748
}
1749
hashset(table.var, HASH_ALLOCATE);
1750
1751
#if BINDINDEX
1752
/*
1753
* initialize the bind index maps
1754
*/
1755
1756
for (n = 0; n <= state.maxsource; n++)
1757
state.source[i].map = 0;
1758
for (n = 0; n <= state.maxview; n++)
1759
state.view[i].map = 0;
1760
state.view[0].map = state.stateview;
1761
#endif
1762
1763
/*
1764
* load and enter the rules
1765
*/
1766
1767
if (old)
1768
{
1769
off = sizeof(old_header);
1770
if (sfseek(sp, off, SEEK_SET) != off)
1771
goto badio;
1772
}
1773
garbage = 0;
1774
hashclear(table.rule, HASH_ALLOCATE);
1775
for (xr = r + rules; r < xr; r++)
1776
{
1777
register Rule_t* o;
1778
1779
if (old)
1780
{
1781
if (sfread(sp, (char*)&old_rule, sizeof(old_rule)) != sizeof(old_rule))
1782
goto badio;
1783
if (old_swap)
1784
swapmem(old_swap, &old_rule, &old_rule, (char*)&old_rule.noswap - (char*)&old_rule);
1785
r->property = old_rule.property;
1786
r->dynamic = old_rule.dynamic;
1787
r->attribute = old_rule.attribute;
1788
switch (sequence)
1789
{
1790
case 2: /* 01/24/89 */
1791
r->property =
1792
((r->property & 0x0000ffffL)) |
1793
((r->property & 0x3ffb0000L) << 1);
1794
r->dynamic =
1795
((r->dynamic & 0x000003ffL)) |
1796
((r->dynamic & 0x00000800L) << 1) |
1797
((r->dynamic & 0x00034000L) << 2) |
1798
((r->dynamic & 0x00040000L) << 4);
1799
break;
1800
}
1801
if (old_rule.name)
1802
r->name = s + (unsigned long)old_rule.name - 1;
1803
if (r->property & P_staterule)
1804
{
1805
r->dynamic |= D_lowres;
1806
r->event = old_rule.old_event;
1807
}
1808
else if (old_rule.old_data)
1809
r->statedata = s + (unsigned long)old_rule.old_data - 1;
1810
if (old_rule.prereqs)
1811
r->prereqs = d + (unsigned long)old_rule.prereqs / sizeof(old_list) - 1;
1812
if (old_rule.action)
1813
r->action = s + (unsigned long)old_rule.action - 1;
1814
r->scan = old_rule.scan;
1815
r->semaphore = old_rule.semaphore;
1816
r->view = old_rule.view;
1817
r->time = tmxsns(old_rule.time, 0);
1818
switch (sequence)
1819
{
1820
case 0: /* 1989-09-11 */
1821
if ((r->property & P_attribute) && (r->attribute && !(r->property & P_use) && !streq(r->name, internal.attribute->name) || r->scan && !streq(r->name, internal.scan->name)))
1822
r->dynamic |= D_index;
1823
/*FALLTHROUGH*/
1824
case 1: /* 1991-07-17 */
1825
if (r->property & P_staterule)
1826
{
1827
if (isaltstate(r->name))
1828
{
1829
r->property |= P_implicit;
1830
r->time = 0;
1831
}
1832
r->event = r->time;
1833
}
1834
/*FALLTHROUGH*/
1835
}
1836
}
1837
else
1838
{
1839
r->property = sfgetu(sp);
1840
r->dynamic = sfgetu(sp);
1841
r->attribute = sfgetu(sp);
1842
if (n = sfgetu(sp))
1843
{
1844
r->semaphore = (n>>16) & ((1<<8)-1);
1845
r->view = (n>>8) & ((1<<8)-1);
1846
r->scan = (n) & ((1<<8)-1);
1847
}
1848
if (n = sfgetu(sp))
1849
r->prereqs = d + n - 1;
1850
ts = sfgetu(sp);
1851
1852
/*
1853
* 2004-12-01
1854
*/
1855
1856
if (n = rulenum)
1857
{
1858
n--;
1859
tn = sfgetu(sp);
1860
}
1861
else
1862
tn = 0;
1863
r->time = tmxsns(ts, tn);
1864
1865
/*
1866
* 2004-12-01
1867
*/
1868
1869
if ((r->property & P_staterule) && n)
1870
{
1871
n--;
1872
tn = sfgetu(sp);
1873
}
1874
else
1875
tn = 0;
1876
1877
/*
1878
* rule number field additions here
1879
*/
1880
1881
while (n--)
1882
sfgetu(sp);
1883
r->name = loadstring(&ls, sp);
1884
r->action = loadstring(&ls, sp);
1885
if (r->property & P_staterule)
1886
{
1887
ts = sfgetu(sp);
1888
r->event = tmxsns(ts, tn);
1889
if (lowres)
1890
r->dynamic |= D_lowres;
1891
}
1892
else
1893
r->statedata = loadstring(&ls, sp);
1894
1895
/*
1896
* rule string field additions here
1897
*/
1898
1899
for (n = rulestr; n > 0; n--)
1900
loadstring(&ls, sp);
1901
}
1902
if (sfeof(sp))
1903
goto badio;
1904
r->preview = state.maxview + 1;
1905
o = getrule(r->name);
1906
if (r->dynamic & D_index)
1907
{
1908
/*
1909
* check for index atom consistency
1910
* remap inconsistent state file atoms
1911
*/
1912
1913
if (r->scan)
1914
{
1915
attr = ~0;
1916
if (o && (o->property & P_attribute) && o->scan)
1917
{
1918
if (r->scan != o->scan)
1919
{
1920
error((state.exec || state.mam.out) && !state.explain ? -1 : 1, "%s: %s %s definition changed", objfile, r->name, internal.scan->name);
1921
if (state.stateview < 0)
1922
return -1;
1923
attr = o->scan;
1924
}
1925
}
1926
else
1927
{
1928
for (a = internal.scan->prereqs; a; a = a->next)
1929
if (r->scan == a->rule->scan)
1930
{
1931
error((state.exec || state.mam.out) && !state.explain ? -1 : 1, "%s: %s %s definition clashes with %s", objfile, r->name, internal.scan->name, a->rule->name);
1932
if (state.stateview < 0)
1933
return -1;
1934
attr = 0;
1935
break;
1936
}
1937
if (state.stateview >= 0)
1938
attr = 0;
1939
}
1940
if (attr != ~0)
1941
{
1942
if (!scanclash)
1943
{
1944
scanclash = 1;
1945
for (n = 0; n < elementsof(scanmap); n++)
1946
scanmap[n] = n;
1947
}
1948
if (!(r->scan = scanmap[r->scan] = attr))
1949
r->property &= ~P_attribute;
1950
if (o)
1951
continue;
1952
}
1953
}
1954
else if (r->attribute)
1955
{
1956
attr = ~0;
1957
if (o && (o->property & P_attribute) && o->attribute)
1958
{
1959
if (r->attribute != o->attribute)
1960
{
1961
error((state.exec || state.mam.out) && !state.explain ? -1 : 1, "%s: %s %s definition changed", objfile, r->name, internal.attribute->name);
1962
if (state.stateview < 0)
1963
return -1;
1964
attr = o->attribute;
1965
}
1966
}
1967
else
1968
for (a = internal.attribute->prereqs; a; a = a->next)
1969
if (r->attribute == a->rule->attribute)
1970
{
1971
error((state.exec || state.mam.out) && !state.explain ? -1 : 1, "%s: %s %s definition clashes with %s", objfile, r->name, internal.attribute->name, a->rule->name);
1972
if (state.stateview < 0)
1973
return -1;
1974
attr = 0;
1975
}
1976
if (attr != ~0)
1977
{
1978
if (!attrclash)
1979
{
1980
attrclash = 1;
1981
attrclear = 0;
1982
for (n = 0; n < CHAR_BIT * sizeof(unsigned long); n++)
1983
attrmap[n] = (1<<n);
1984
}
1985
attrclear |= r->attribute;
1986
for (n = 0; n < CHAR_BIT * sizeof(unsigned long); n++)
1987
if (r->attribute == (1<<n))
1988
{
1989
attrmap[n] = attr;
1990
break;
1991
}
1992
continue;
1993
}
1994
}
1995
}
1996
else
1997
{
1998
if (attrclash)
1999
{
2000
attr = r->attribute & ~attrclear;
2001
for (n = 0; n < CHAR_BIT * sizeof(unsigned long); n++)
2002
if (r->attribute & (1<<n))
2003
attr |= attrmap[n];
2004
r->attribute = attr;
2005
}
2006
if (scanclash)
2007
r->scan = scanmap[r->scan];
2008
}
2009
if (r->dynamic & D_compiled)
2010
{
2011
n = state.stateview > 0 && viewable(r);
2012
if (n && (o || (state.questionable & 0x00000020)))
2013
{
2014
r->dynamic |= D_compiled|D_lower;
2015
viewname(r->name, state.stateview);
2016
r->view = state.stateview;
2017
maprule(r->name, r);
2018
if (o && (r->property & P_statevar) && !o->time)
2019
o->time = r->time;
2020
}
2021
else
2022
{
2023
if (n)
2024
{
2025
r->mark |= M_compile;
2026
promoted = 1;
2027
}
2028
if (!o)
2029
{
2030
if (state.stateview >= 0 && (r->property & (P_joint|P_target)) == P_target)
2031
{
2032
r->dynamic |= D_garbage;
2033
garbage++;
2034
}
2035
}
2036
else if (state.stateview >= 0 && (r->property & P_statevar) && (r->prereqs || r->action))
2037
{
2038
/*
2039
* ignore state file prereqs and action
2040
*/
2041
2042
if (o->action && r->action && !streq(o->action, r->action))
2043
r->time = CURTIME;
2044
o->time = r->time;
2045
o->statedata = r->statedata;
2046
setoldrule(r, o);
2047
continue;
2048
}
2049
else if (state.stateview >= 0 && (r->property & P_staterule) && o->event > r->event)
2050
{
2051
/*
2052
* o was updated after r was saved
2053
*/
2054
2055
setoldrule(r, o);
2056
continue;
2057
}
2058
else if (!isoldrule(o))
2059
{
2060
if (o->dynamic & (D_bound|D_scanned))
2061
{
2062
r->statedata = o->statedata;
2063
r->time = o->time;
2064
r->status = o->status;
2065
r->view = o->view;
2066
r->property &= ~(P_parameter|P_state|P_staterule|P_statevar);
2067
r->property |= o->property & (P_parameter|P_state|P_staterule|P_statevar);
2068
r->dynamic &= ~(D_bound|D_entries|D_global|D_regular|D_scanned);
2069
r->dynamic |= o->dynamic & (D_bound|D_entries|D_global|D_regular|D_scanned);
2070
if (!(o->property & P_state) && o->uname)
2071
{
2072
r->uname = maprule(o->uname, r);
2073
getrule(o->name);
2074
}
2075
}
2076
else if ((r->property & (P_parameter|P_statevar)) == P_statevar && (o->property & (P_parameter|P_statevar)) == (P_parameter|P_statevar))
2077
r->property |= P_parameter;
2078
setoldrule(o, r);
2079
}
2080
r->name = putrule(0, r);
2081
}
2082
}
2083
else if (o)
2084
{
2085
/*
2086
* r is just a reference -- keep the old rule
2087
* but retain some attributes
2088
*/
2089
2090
o->attribute |= r->attribute & internal.retain->attribute;
2091
o->property |= r->property & (P_dontcare|P_ignore|P_terminal);
2092
setoldrule(r, o);
2093
}
2094
else
2095
{
2096
r->name = putrule(0, r);
2097
if (!(r->property & P_state))
2098
r->time = 0;
2099
if (state.stateview >= 0)
2100
{
2101
if ((r->property & (P_joint|P_target)) == P_target)
2102
{
2103
r->dynamic |= D_garbage;
2104
garbage++;
2105
}
2106
2107
/*
2108
* clear reference secondary attributes
2109
*/
2110
2111
r->attribute &= internal.retain->attribute;
2112
r->property &= (P_attribute|P_dontcare|P_ignore|P_parameter|P_state|P_staterule|P_statevar|P_terminal);
2113
r->dynamic &= D_garbage;
2114
}
2115
}
2116
#if BINDINDEX
2117
if (r->dynamic & D_bindindex)
2118
{
2119
if (o)
2120
{
2121
if (o->dynamic & D_bindindex)
2122
{
2123
if (r->source)
2124
{
2125
state.source[r->source].map = o->source;
2126
if (isoldrule(o))
2127
state.source[o->source].path = r;
2128
}
2129
else if (r->view)
2130
{
2131
state.view[r->view].map = o->view;
2132
if (isoldrule(o))
2133
state.view[o->view].path = r;
2134
}
2135
}
2136
else if (r->source)
2137
{
2138
if (++state.maxsource >= elementsof(state.source))
2139
error(3, "%s: too many %s directories -- %d max", r->name, internal.source->name, elementsof(state.source));
2140
state.source[r->source].map = state.maxsource;
2141
if (isoldrule(o))
2142
state.source[state.maxsource].path = r;
2143
else
2144
{
2145
o->dynamic |= D_bindindex;
2146
o->source = state.maxsource;
2147
state.source[o->source].path = o;
2148
}
2149
}
2150
}
2151
else if (r->source)
2152
{
2153
if (++state.maxsource >= elementsof(state.source))
2154
error(3, "%s: too many %s directories -- %d max", r->name, internal.source->name, elementsof(state.source));
2155
state.source[r->source].map = state.maxsource;
2156
state.source[state.maxsource].path = r;
2157
}
2158
}
2159
r->source = state.source[r->source].map;
2160
r->view = state.view[r->view].map;
2161
#endif
2162
}
2163
hashset(table.rule, HASH_ALLOCATE);
2164
r = or;
2165
2166
/*
2167
* load the prerequisite lists
2168
*/
2169
2170
if (old)
2171
{
2172
off = sizeof(old_header) + rules * sizeof(old_rule);
2173
if (sfseek(sp, off, SEEK_SET) != off)
2174
goto badio;
2175
}
2176
if (lists)
2177
{
2178
for (xd = d + lists; d < xd;)
2179
{
2180
if (old)
2181
{
2182
if (sfread(sp, (char*)&old_list, sizeof(old_list)) != sizeof(old_list))
2183
goto badio;
2184
if (old_swap)
2185
swapmem(old_swap, &old_list, &old_list, sizeof(old_list));
2186
if (old_list.rule)
2187
d->rule = r + (unsigned long)old_list.rule / sizeof(old_rule) - 1;
2188
if (old_list.next)
2189
d->next = d + 1;
2190
d++;
2191
}
2192
else if (!(n = sfgetu(sp)))
2193
(d - 1)->next = 0;
2194
else if (n < 0)
2195
{
2196
if (strcmp(ident, corrupt) < 0 && (((lists - (xd - d)) * 100) / lists) >= 90)
2197
{
2198
while (d < xd)
2199
{
2200
(d - 1)->next = 0;
2201
d++;
2202
}
2203
hashwalk(table.rule, 0, repair, NiL);
2204
error(1, "%s: pre-%s make object corruption repaired", objfile, corrupt);
2205
corrupt = 0;
2206
}
2207
break;
2208
}
2209
else
2210
{
2211
d->rule = r + n - 1;
2212
d->next = d + 1;
2213
d++;
2214
}
2215
}
2216
if (!old)
2217
{
2218
sfgetu(sp);
2219
(d - 1)->next = 0;
2220
}
2221
}
2222
if (sfeof(sp) && corrupt)
2223
goto badio;
2224
2225
/*
2226
* collect state file garbage collection stats
2227
*/
2228
2229
if (state.stateview >= 0)
2230
{
2231
Time_t t;
2232
Time_t q;
2233
2234
object.garbage += garbage;
2235
object.rules += rules;
2236
2237
/*
2238
* handle low time resolution by making
2239
* sure the current time is at least as
2240
* recent as the state file time, previously
2241
* set in compile() to take into account
2242
* the file system time precision
2243
*/
2244
2245
t = tmxgetmtime(&st);
2246
if (state.tolerance)
2247
t += tmxsns(state.tolerance, 0);
2248
q = CURTIME;
2249
if (q >= t)
2250
t = 0;
2251
else if ((t -= q) > tmxsns(5,0))
2252
t = tmxsns(5,0);
2253
if (t)
2254
{
2255
error(state.tolerance ? 1 : -1, "%s: state time sync delay %lu.%09lu", objfile, tmxsec(t), tmxnsec(t));
2256
tmxsleep(t);
2257
}
2258
}
2259
2260
/*
2261
* readjust the internal rule pointers
2262
*/
2263
2264
initrule();
2265
2266
/*
2267
* make sure top view state has top view prereqs
2268
*/
2269
2270
if (promoted)
2271
hashwalk(table.rule, 0, promote, NiL);
2272
2273
/*
2274
* associate one rule with each name
2275
*/
2276
2277
if (oldrules)
2278
{
2279
hashwalk(table.rule, 0, atomize, NiL);
2280
fp = state.frame;
2281
for (;;)
2282
{
2283
if (isoldrule(fp->target))
2284
{
2285
fp->target = getoldrule(fp->target);
2286
fp->target->active = fp;
2287
}
2288
if (fp == fp->parent)
2289
break;
2290
fp = fp->parent;
2291
}
2292
do
2293
{
2294
xr = (Rule_t*)oldrules->prereqs;
2295
freerule(oldrules);
2296
} while (oldrules = xr);
2297
}
2298
2299
/*
2300
* check special indices
2301
*/
2302
2303
if (internal.attribute->attribute == 1)
2304
internal.attribute->attribute = oattribute;
2305
if (internal.scan->scan == SCAN_USER)
2306
internal.scan->scan = oscan;
2307
2308
/*
2309
* reset compiled options
2310
*/
2311
2312
if (!state.list)
2313
{
2314
state.loading = (char*)objfile;
2315
if (old)
2316
{
2317
if (old_trailer.options)
2318
set(s + (unsigned long)old_trailer.options - 1, 1, NiL);
2319
}
2320
else if ((s = getstring(sp)) && *s && (!streq(s, "--") || (s = getstring(sp)) && *s))
2321
set(s, 1, NiL);
2322
if (state.stateview < 0)
2323
{
2324
/*
2325
* check for load time actions
2326
*
2327
* state.global++ enables setvar() V_import override
2328
*/
2329
2330
if (state.global)
2331
state.global++;
2332
for (xr = r + rules; r < xr; r++)
2333
if ((r->property & (P_immediate|P_target)) == (P_immediate|P_target))
2334
immediate(r);
2335
if (state.global)
2336
state.global--;
2337
}
2338
state.loading = 0;
2339
}
2340
return 1;
2341
badversion:
2342
if (strncmp(old_header.version, old_stamp.version, sizeof(old_header.version)))
2343
{
2344
/*
2345
* old old versions were only numbers
2346
*/
2347
2348
if (!isalpha(*old_header.version))
2349
sfsprintf(old_header.version, sizeof(old_header.version), "%d", (unsigned long)old_header.version);
2350
error(1, "%s: old format (%s) incompatible with make loader (%s)", objfile, old_header.version, old_stamp.version);
2351
}
2352
else
2353
error(1, "%s: old format (%s) generated on an incompatible architecture", objfile, old_header.version);
2354
return 0;
2355
badio:
2356
error(ERROR_SYSTEM|2, "%s: object file io error", objfile);
2357
goto bad;
2358
badmagic:
2359
error(1, "%s: not a %s object file", objfile, version);
2360
bad:
2361
if (p)
2362
free(p);
2363
return recompile;
2364
}
2365
2366