Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/nmake/rule.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
* make rule support
26
*
27
* the attribute names defined in this file must agree with ATTRNAME
28
*/
29
30
#include "make.h"
31
#include "options.h"
32
33
#define ANON(name,flags) (void)rinternal(name,P_attribute|(flags))
34
#define ASOC(field,name,flags) internal.field=rassociate(name,flags)
35
#define ATTR(field,name,flags) internal.field=rinternal(name,P_attribute|(flags))
36
#define FUNC(name,func) ((setvar(name,NiL,V_builtin|V_functional))->builtin=(func))
37
#define INIT(field,name,flags) internal.field=rinternal(name,flags)
38
39
/*
40
* return the NAME_* type for name
41
*/
42
43
int
44
nametype(const char* name, char** e)
45
{
46
register const char* s;
47
register int t;
48
register int q;
49
50
t = 0;
51
s = name;
52
switch (*s)
53
{
54
case 0:
55
return 0;
56
case MARK_CONTEXT:
57
q = NAME_context;
58
break;
59
case '.':
60
q = NAME_variable|NAME_intvar;
61
break;
62
case '-':
63
case '+':
64
return NAME_option;
65
case '(':
66
t = NAME_staterule;
67
q = 0;
68
break;
69
default:
70
q = istype(*s, C_ID1) ? (NAME_identifier|NAME_variable) : istype(*s, C_VARIABLE1) ? NAME_variable : 0;
71
break;
72
}
73
for (;;)
74
{
75
switch (*s++)
76
{
77
case 0:
78
s -= 2;
79
break;
80
case '/':
81
q |= NAME_path;
82
q &= ~(NAME_identifier|NAME_variable);
83
continue;
84
case '=':
85
if (q & (NAME_identifier|NAME_variable))
86
q |= NAME_assignment;
87
continue;
88
case '+':
89
if (*s != '=')
90
q &= ~(NAME_identifier|NAME_variable);
91
continue;
92
case '&':
93
if (*s == '=')
94
continue;
95
/*FALLTHROUGH*/
96
case '*':
97
case '?':
98
case '[':
99
case ']':
100
case '|':
101
q |= NAME_glob;
102
q &= ~(NAME_identifier|NAME_variable);
103
continue;
104
case '@':
105
case '!':
106
case '}':
107
if (*s == '(')
108
t |= NAME_glob;
109
q &= ~(NAME_identifier|NAME_variable);
110
continue;
111
case '$':
112
if (*s == '(')
113
t |= NAME_dynamic;
114
q &= ~(NAME_identifier|NAME_variable);
115
continue;
116
case '(':
117
if (s > name + 1)
118
{
119
t &= ~NAME_staterule;
120
q &= ~NAME_staterule;
121
}
122
continue;
123
case ')':
124
if (t & NAME_staterule)
125
{
126
t &= ~NAME_staterule;
127
q |= NAME_staterule;
128
}
129
else
130
{
131
q &= ~NAME_staterule;
132
q |= t & (NAME_glob|NAME_dynamic);
133
}
134
q &= ~(NAME_identifier|NAME_variable);
135
continue;
136
default:
137
if ((q & NAME_variable) && !istype(*(s - 1), C_VARIABLE1|C_VARIABLE2))
138
q &= ~(NAME_identifier|NAME_variable);
139
else if ((q & NAME_identifier) && !istype(*(s - 1), C_ID1|C_ID2))
140
q &= ~NAME_identifier;
141
continue;
142
}
143
break;
144
}
145
if ((q & NAME_context) && *s == MARK_CONTEXT)
146
{
147
if (e)
148
*e = (char*)(s + 1);
149
if (e)
150
*e = (char*)(s + 1);
151
return NAME_context;
152
}
153
if (q & NAME_staterule)
154
{
155
if (*s == ')')
156
return NAME_statevar;
157
if (*(name + 1) == '+')
158
return NAME_altstate;
159
return NAME_staterule;
160
}
161
if (q & NAME_dynamic)
162
return NAME_dynamic;
163
if (q & NAME_assignment)
164
return NAME_assignment;
165
if (q & NAME_glob)
166
return NAME_glob;
167
if (q & NAME_identifier)
168
return NAME_identifier;
169
if (q & NAME_variable)
170
return (q & NAME_intvar) && *s == '.' ? NAME_intvar : NAME_variable;
171
return q & NAME_path;
172
}
173
174
/*
175
* map name s to rule r
176
* previous mappings must be reconciled with the prereq lists
177
*/
178
179
char*
180
maprule(char* s, Rule_t* r)
181
{
182
register List_t* p;
183
Rule_t* q;
184
Rule_t* o;
185
Hash_position_t* pos;
186
187
static unsigned char warned;
188
189
if ((o = getrule(s)) == r)
190
return r->name;
191
s = putrule(0, r);
192
if (o && (pos = hashscan(table.rule, 0)))
193
{
194
if (!warned)
195
{
196
warned++;
197
if (state.warn)
198
error(1, "%d maprule() calls -- should not happen", UCHAR_MAX+1);
199
}
200
while (hashnext(pos))
201
{
202
q = (Rule_t*)pos->bucket->value;
203
if (q == o)
204
pos->bucket->value = (char*)r;
205
for (p = q->prereqs; p; p = p->next)
206
if (p->rule == o)
207
p->rule = r;
208
}
209
hashdone(pos);
210
}
211
return s;
212
}
213
214
/*
215
* return a pointer to a rule given its name,
216
* creating the rule if necessary
217
*/
218
219
Rule_t*
220
makerule(register char* name)
221
{
222
register Rule_t* r;
223
int n;
224
225
if (name)
226
{
227
if (r = getrule(name))
228
return r;
229
if (((n = nametype(name, NiL)) & NAME_path) && (table.rule->flags & HASH_ALLOCATE))
230
{
231
pathcanon(name, 0, 0);
232
if (r = getrule(name))
233
return r;
234
}
235
}
236
newrule(r);
237
r->name = putrule(0, r);
238
if (state.compnew)
239
(*state.compnew)(r->name, (char*)r, state.comparg);
240
if (!name)
241
n = nametype(r->name, NiL);
242
if (n & (NAME_staterule|NAME_altstate))
243
{
244
r->dynamic |= D_compiled;
245
r->property |= P_state|P_staterule;
246
}
247
else if (n & NAME_statevar)
248
{
249
r->dynamic |= D_compiled;
250
r->property |= P_state|P_statevar;
251
}
252
else if (state.init || state.readonly)
253
r->dynamic |= D_compiled;
254
else
255
r->dynamic &= ~D_compiled;
256
r->status = NOTYET;
257
r->preview = state.maxview + 1;
258
#if DEBUG
259
message((-13, "adding %s %s", (r->property & P_state) ? "state variable" : "atom", r->name));
260
#endif
261
return r;
262
}
263
264
/*
265
* check if a rule name is special
266
* special names are ignored in determining the default main target(s)
267
*/
268
269
int
270
special(register Rule_t* r)
271
{
272
register char* s;
273
274
if (r->property & (P_functional|P_metarule|P_operator|P_repeat|P_state))
275
return 1;
276
if ((s = r->name) && !istype(*s, C_ID2))
277
for (;;)
278
switch (*s++)
279
{
280
case 0:
281
return 1;
282
case '/':
283
case '$':
284
return 0;
285
}
286
return 0;
287
}
288
289
/*
290
* return joint list pointer for r
291
* static single element list returned for non-joint target
292
*/
293
294
List_t*
295
joint(register Rule_t* r)
296
{
297
static List_t tmp;
298
299
if ((r->property & (P_joint|P_target)) == (P_joint|P_target))
300
return r->prereqs->rule->prereqs;
301
tmp.rule = r;
302
return &tmp;
303
}
304
305
/*
306
* add a single non-duplicated prerequisite x to rule r
307
* op = {PREREQ_APPEND,PREREQ_DELETE,PREREQ_INSERT,PREREQ_LENGTH}
308
*/
309
310
void
311
addprereq(register Rule_t* r, register Rule_t* x, int op)
312
{
313
register List_t* p;
314
register List_t* q;
315
316
if (x != r)
317
{
318
if (p = r->prereqs)
319
{
320
q = 0;
321
while (p)
322
{
323
if (x == p->rule)
324
{
325
if (op == PREREQ_DELETE)
326
{
327
if (q)
328
q->next = p->next;
329
else
330
r->prereqs = p->next;
331
}
332
if (!(x->property & P_multiple))
333
break;
334
}
335
if (!p->next)
336
{
337
if (op != PREREQ_DELETE)
338
{
339
if (r->property & P_state)
340
state.savestate = 1;
341
if (!state.init && !state.readonly)
342
r->dynamic &= ~D_compiled;
343
if (op == PREREQ_LENGTH)
344
{
345
register int n;
346
347
n = strlen(x->name);
348
p = r->prereqs;
349
q = 0;
350
for (;;)
351
{
352
if (!p || strlen(p->rule->name) < n)
353
{
354
if (q)
355
q->next = cons(x, p);
356
else
357
r->prereqs = cons(x, r->prereqs);
358
break;
359
}
360
q = p;
361
p = p->next;
362
}
363
}
364
else if (op == PREREQ_INSERT)
365
r->prereqs = cons(x, r->prereqs);
366
else p->next = cons(x, NiL);
367
}
368
break;
369
}
370
q = p;
371
p = p->next;
372
}
373
}
374
else if (op != PREREQ_DELETE)
375
{
376
if (r->property & P_state)
377
state.savestate = 1;
378
if (!state.init && !state.readonly)
379
r->dynamic &= ~D_compiled;
380
r->prereqs = cons(x, NiL);
381
}
382
}
383
}
384
385
/*
386
* return the pattern association rule with prefix a that matches r
387
* if r is 0 then s is the rule name
388
* if pos is not 0 then it is the last match position
389
* *pos must be 0 on first call
390
* *pos undefined when 0 returned
391
*/
392
393
Rule_t*
394
associate(register Rule_t* a, register Rule_t* r, register char* s, List_t** pos)
395
{
396
register List_t* p;
397
register Rule_t* x;
398
register Rule_t* z;
399
List_t* u;
400
401
if (r)
402
{
403
if (r->property & (P_attribute|P_readonly))
404
return 0;
405
s = r->name;
406
}
407
do
408
{
409
u = 0;
410
for (p = pos && *pos ? (*pos)->next : a->prereqs; p; p = p->next)
411
if ((x = p->rule) != r)
412
{
413
if (x->property & P_attribute)
414
{
415
if (r && (hasattribute(r, x, NiL) || !r->scan && x->scan && (z = staterule(RULE, r, NiL, -1)) && z->scan == x->scan))
416
break;
417
}
418
else if (x->name[0] == '%' && !x->name[1])
419
u = p;
420
else if (metamatch(NiL, s, x->name) || r && r->uname && !(r->property & P_state) && metamatch(NiL, r->uname, x->name))
421
break;
422
}
423
if (p || (p = u))
424
{
425
if (pos)
426
*pos = p;
427
return (p->rule->property & P_attribute) ?
428
catrule(a->name, "%", p->rule->name, 0) :
429
catrule(a->name, p->rule->name, NiL, 0);
430
}
431
} while (r && s == r->name && r->uname && !(r->property & P_state) && (s = r->uname) != r->name);
432
return 0;
433
}
434
435
/*
436
* check if r's prerequisite list or named attributes have changed
437
*
438
* NOTE: IGNORECHANGE(r,q) prerequisites are ignored in the comparison
439
*/
440
441
#define IGNORECHANGE(r,q) (((q)->property & (P_joint|P_ignore)) || ((q)->dynamic & D_alias) && getrule((q)->name) == r)
442
443
int
444
prereqchange(register Rule_t* r, register List_t* newprereqs, Rule_t* o, register List_t* oldprereqs)
445
{
446
register List_t* p;
447
448
if ((r->property & P_accept) || state.accept)
449
return 0;
450
if ((r->property & (P_joint|P_target)) == (P_joint|P_target) && r != r->prereqs->rule->prereqs->rule)
451
return 0;
452
if ((r->attribute ^ o->attribute) & ~internal.accept->attribute)
453
{
454
reason((1, "%s named attributes changed", r->name));
455
return 1;
456
}
457
more:
458
for (;;)
459
{
460
if (newprereqs)
461
{
462
if (IGNORECHANGE(r, newprereqs->rule))
463
newprereqs = newprereqs->next;
464
else if (oldprereqs)
465
{
466
if (IGNORECHANGE(r, oldprereqs->rule))
467
oldprereqs = oldprereqs->next;
468
else if (newprereqs->rule == oldprereqs->rule || ((newprereqs->rule->dynamic ^ oldprereqs->rule->dynamic) & (D_alias|D_bound)) && getrule(newprereqs->rule) == getrule(oldprereqs->rule))
469
{
470
newprereqs = newprereqs->next;
471
oldprereqs = oldprereqs->next;
472
}
473
else
474
break;
475
}
476
else
477
break;
478
}
479
else if (oldprereqs && IGNORECHANGE(r, oldprereqs->rule))
480
oldprereqs = oldprereqs->next;
481
else
482
break;
483
}
484
if (newprereqs)
485
{
486
if ((r->dynamic & (D_entries|D_regular)) == D_entries || EXPLAIN)
487
{
488
for (p = oldprereqs; p && (newprereqs->rule != p->rule || !((newprereqs->rule->dynamic ^ p->rule->dynamic) & (D_alias|D_bound)) || getrule(newprereqs->rule) != getrule(p->rule)); p = p->next);
489
if (p)
490
{
491
if ((r->dynamic & (D_entries|D_regular)) == D_entries)
492
goto more;
493
reason((1, "%s prerequisite %s re-ordered", r->name, newprereqs->rule->name));
494
}
495
else
496
reason((1, "%s prerequisite %s added", r->name, newprereqs->rule->name));
497
}
498
return 1;
499
}
500
if (oldprereqs)
501
{
502
reason((1, "%s prerequisite %s deleted", r->name, oldprereqs->rule->name));
503
return 1;
504
}
505
return 0;
506
}
507
508
/*
509
* initialize immediate rule info
510
*/
511
512
static void
513
getimmediate(register Rule_t* r, List_t** prereqs, char** action)
514
{
515
if (r->dynamic & D_dynamic)
516
dynamic(r);
517
if (*action = r->action)
518
r->action = 0;
519
if (*prereqs = r->prereqs)
520
r->prereqs = 0;
521
}
522
523
/*
524
* reset all rule info as if we just started
525
*/
526
527
static int
528
reset(const char* s, char* v, void* h)
529
{
530
register Rule_t* r = (Rule_t*)v;
531
Stat_t st;
532
533
if (!(r->property & P_state))
534
{
535
if ((r->status == EXISTS || r->status == FAILED) && !(r->property & P_virtual))
536
{
537
r->status = NOTYET;
538
if (!stat(r->name, &st))
539
r->time = tmxgetmtime(&st);
540
r->dynamic &= ~(D_entries|D_hasafter|D_hasbefore|D_hasmake|D_hasscope|D_hassemaphore|D_scanned|D_triggered);
541
}
542
else
543
r->dynamic &= ~(D_entries|D_scanned);
544
}
545
return 0;
546
}
547
548
/*
549
* check rule r for immediate action
550
* should only be called if r->immediate==1 and r->target==1
551
*/
552
553
void
554
immediate(register Rule_t* r)
555
{
556
register List_t* p;
557
register Rule_t* x;
558
List_t* prereqs;
559
char* action;
560
char* e;
561
Var_t* v;
562
int i;
563
int g;
564
int u;
565
Flags_t a;
566
Seconds_t t;
567
568
if (r == internal.retain || r == internal.state)
569
{
570
getimmediate(r, &prereqs, &action);
571
a = r == internal.retain ? V_retain : V_scan;
572
for (p = prereqs; p; p = p->next)
573
if (v = varstate(p->rule, -1))
574
{
575
if (a == V_scan)
576
setvar(v->name, v->value, V_scan);
577
else
578
v->property |= a;
579
}
580
}
581
else if (r == internal.rebind || r == internal.accept)
582
{
583
getimmediate(r, &prereqs, &action);
584
i = r == internal.accept;
585
for (p = prereqs; p; p = p->next)
586
rebind(p->rule, i);
587
}
588
else if (r == internal.unbind)
589
{
590
getimmediate(r, &prereqs, &action);
591
for (p = prereqs; p; p = p->next)
592
if ((p->rule->dynamic & (D_bound|D_scanned)) && (!(p->rule->mark & M_bind) || (state.questionable & 0x02000000)))
593
p->rule->mark |= M_mark;
594
hashwalk(table.rule, 0, unbind, r);
595
hashwalk(table.rule, 0, unbind, NiL);
596
}
597
else if (r == internal.bind || r == internal.force)
598
{
599
getimmediate(r, &prereqs, &action);
600
for (p = prereqs; p; p = p->next)
601
{
602
x = p->rule;
603
message((-2, "bind(%s)", x->name));
604
x = bind(x);
605
if (r == internal.force)
606
{
607
if (x->time || !(x->property & P_dontcare))
608
x->time = CURTIME;
609
x->property |= P_force;
610
}
611
}
612
}
613
else if (r == internal.always || r == internal.local || r == internal.make || r == internal.run)
614
{
615
int errors;
616
Time_t now;
617
Time_t tm = 0;
618
619
getimmediate(r, &prereqs, &action);
620
i = !prereqs;
621
now = CURTIME;
622
errors = 0;
623
for (p = prereqs; p; p = p->next)
624
{
625
if ((p->rule->status == UPDATE || p->rule->status == MAKING) && !(p->rule->property & P_repeat))
626
p->rule = internal.empty;
627
else
628
{
629
errors += make(p->rule, &tm, NiL, 0);
630
if (tm >= now)
631
i = 1;
632
}
633
}
634
if (r != internal.run)
635
{
636
if (prereqs)
637
errors += complete(NiL, prereqs, &tm, 0);
638
if (tm >= now)
639
i = 1;
640
if (action)
641
{
642
if (!errors && i)
643
{
644
r->status = UPDATE;
645
trigger(r, NiL, action, 0);
646
complete(r, NiL, NiL, 0);
647
}
648
}
649
if (r == internal.make)
650
r->property &= ~(P_always|P_local);
651
}
652
r->property &= ~(P_foreground|P_make|P_read);
653
}
654
else if (r == internal.include)
655
{
656
getimmediate(r, &prereqs, &action);
657
i = COMP_INCLUDE;
658
g = state.global;
659
u = state.user;
660
for (p = prereqs; p; p = p->next)
661
{
662
x = p->rule;
663
if (streq(x->name, "-"))
664
i ^= COMP_DONTCARE;
665
else if (streq(x->name, "+"))
666
{
667
state.global = 1;
668
state.user = 0;
669
}
670
else if (x->property & P_use)
671
action = x->action;
672
else
673
readfile(x->name, i, action);
674
}
675
state.global = g;
676
state.user = u;
677
}
678
else if (r == internal.alarm)
679
{
680
getimmediate(r, &prereqs, &action);
681
if (p = prereqs)
682
{
683
t = strelapsed(p->rule->name, &e, 1);
684
if (*e)
685
t = 0;
686
else
687
p = p->next;
688
}
689
else
690
t = 0;
691
wakeup(t, p);
692
}
693
else if (r == internal.sync)
694
{
695
getimmediate(r, &prereqs, &action);
696
if (!prereqs)
697
savestate();
698
else if (state.compile < COMPILED)
699
error(2, "%s: cannot sync until make object compiled", prereqs->rule->name);
700
else
701
compile(prereqs->rule->name, prereqs->next ? prereqs->next->rule->name : (char*)0);
702
}
703
else if (r == internal.reset)
704
{
705
getimmediate(r, &prereqs, &action);
706
hashwalk(table.rule, 0, reset, NiL);
707
}
708
else if (r == internal.wait)
709
{
710
getimmediate(r, &prereqs, &action);
711
complete(NiL, prereqs, NiL, 0);
712
}
713
else if (r == internal.freeze)
714
{
715
getimmediate(r, &prereqs, &action);
716
for (p = prereqs; p; p = p->next)
717
if (v = getvar(p->rule->name))
718
v->property |= V_frozen;
719
}
720
else if ((r->property & P_attribute) && !r->attribute)
721
return;
722
else if (!state.op && state.reading && state.compileonly)
723
return;
724
else
725
{
726
maketop(r, 0, NiL);
727
getimmediate(r, &prereqs, &action);
728
}
729
if (prereqs)
730
freelist(prereqs);
731
if (r->prereqs)
732
{
733
freelist(r->prereqs);
734
r->prereqs = 0;
735
}
736
r->action = 0;
737
if (r = staterule(RULE, r, NiL, 0))
738
{
739
r->prereqs = 0;
740
r->action = 0;
741
}
742
}
743
744
/*
745
* remove duplicate prerequisites from prerequisite list p
746
*/
747
748
void
749
remdup(register List_t* p)
750
{
751
register List_t* q;
752
register List_t* x;
753
754
for (x = p, q = 0; p; p = p->next)
755
{
756
if (p->rule->mark & M_mark)
757
{
758
if (q)
759
q->next = p->next;
760
#if DEBUG
761
else
762
{
763
dumprule(sfstderr, p->rule);
764
error(PANIC, "stray mark on %s", p->rule->name);
765
}
766
#endif
767
}
768
else
769
{
770
if (!(p->rule->property & P_multiple))
771
p->rule->mark |= M_mark;
772
q = p;
773
}
774
}
775
while (x)
776
{
777
x->rule->mark &= ~M_mark;
778
x = x->next;
779
}
780
}
781
782
/*
783
* do dynamic expansion of rule r's prerequisites
784
* the prerequisite list is permanently modified
785
*/
786
787
void
788
dynamic(register Rule_t* r)
789
{
790
register char* s;
791
register List_t* p;
792
register List_t* q;
793
register List_t* t;
794
char** v;
795
char* buf;
796
int added;
797
int flags;
798
Rule_t* x;
799
Rule_t* u;
800
Frame_t* oframe;
801
Frame_t frame;
802
Sfio_t* tmp;
803
char* vec[2];
804
805
tmp = sfstropen();
806
oframe = state.frame;
807
if ((r->property & P_use) && !(state.frame = r->active))
808
{
809
zero(frame);
810
frame.target = r;
811
state.frame = frame.parent = &frame;
812
}
813
vec[1] = 0;
814
added = 0;
815
for (p = r->prereqs, q = 0; p; p = p->next)
816
{
817
if (isdynamic(p->rule->name))
818
{
819
if (q)
820
q->next = p->next;
821
else
822
r->prereqs = p->next;
823
u = p->rule;
824
expand(tmp, u->name);
825
buf = sfstruse(tmp);
826
flags = 0;
827
while (s = getarg(&buf, &flags))
828
{
829
added = 1;
830
if (isglob(s))
831
v = globv(NiL, s);
832
else
833
*(v = vec) = s;
834
while (s = *v++)
835
{
836
x = makerule(s);
837
if (x->dynamic & D_alias)
838
x = makerule(x->name);
839
if (flags & A_scope)
840
x->dynamic |= D_scope;
841
842
/*
843
* merge u into x
844
*/
845
846
merge(u, x, MERGE_ALL|MERGE_SCANNED);
847
848
/*
849
* replace u with x
850
*/
851
852
t = cons(x, p->next);
853
if (q)
854
q->next = t;
855
else
856
r->prereqs = t;
857
q = t;
858
}
859
}
860
}
861
else q = p;
862
}
863
if (added)
864
remdup(r->prereqs);
865
r->dynamic &= ~D_dynamic;
866
state.frame = oframe;
867
sfstrclose(tmp);
868
}
869
870
/*
871
* return non-zero if r has builtin attribute a
872
* if x!=0 then check if merge(x,r,MERGE_ATTR) would have attribute
873
*/
874
875
int
876
hasattribute(register Rule_t* r, register Rule_t* a, register Rule_t* x)
877
{
878
register Flags_t n;
879
register int attrname;
880
List_t* p;
881
882
attrname = *a->name == ATTRNAME;
883
if (a->property & P_attribute)
884
{
885
n = r->property;
886
if (x && !(n & P_readonly))
887
{
888
n |= x->property & ~(P_attribute|P_immediate|P_implicit|P_internal|P_operator|P_readonly|P_state|P_staterule|P_statevar|P_target);
889
if ((x->property & P_implicit) || (x->property & (P_metarule|P_terminal)) == P_terminal)
890
n &= ~P_implicit;
891
}
892
893
/*
894
* the first group may conflict with a->attribute
895
*/
896
897
if (attrname)
898
{
899
if (a == internal.accept) return n & P_accept;
900
if (a == internal.attribute) return n & P_attribute;
901
if (a == internal.ignore) return n & P_ignore;
902
}
903
if (a != internal.retain)
904
{
905
if (a->attribute & r->attribute) return 1;
906
if (x && (a->attribute & x->attribute & ~internal.ignore->attribute) && ((r->property & (P_attribute|P_use)) != P_attribute || r == internal.accept || r == internal.ignore || r == internal.retain)) return 1;
907
}
908
if (attrname)
909
{
910
/*
911
* the rest have no a->attribute conflicts
912
*/
913
914
if (a == internal.make) return n & P_make;
915
if (a == internal.readonly) return n & P_readonly;
916
if (a == internal.scan) return r->scan || x && x->scan;
917
if (a == internal.semaphore) return r->semaphore;
918
if (a == internal.target) return n & P_target;
919
920
/*
921
* the rest have a corresponding P_*
922
*/
923
924
if (a->property & n & ~(P_accept|P_attribute|P_ignore|P_internal|P_metarule|P_readonly|P_staterule|P_statevar|P_target))
925
{
926
if (a == internal.after) return n & P_after;
927
if (a == internal.always) return n & P_always;
928
if (a == internal.archive) return n & P_archive;
929
if (a == internal.before) return n & P_before;
930
if (a == internal.command) return n & P_command;
931
if (a == internal.dontcare) return n & P_dontcare;
932
if (a == internal.force) return n & P_force;
933
if (a == internal.foreground) return n & P_foreground;
934
if (a == internal.functional) return n & P_functional;
935
if (a == internal.immediate) return n & P_immediate;
936
if (a == internal.implicit) return n & P_implicit;
937
if (a == internal.joint) return n & P_joint;
938
if (a == internal.local) return n & P_local;
939
if (a == internal.multiple) return n & P_multiple;
940
if (a == internal.op) return n & P_operator;
941
if (a == internal.parameter) return n & P_parameter;
942
if (a == internal.read) return n & P_read;
943
if (a == internal.repeat) return n & P_repeat;
944
if (a == internal.state) return n & P_state;
945
if (a == internal.terminal) return n & P_terminal;
946
if (a == internal.use) return n & P_use;
947
if (a == internal.virt) return n & P_virtual;
948
}
949
}
950
if (a->scan) return a->scan == r->scan || !r->scan && x && x->scan == a->scan;
951
}
952
else
953
{
954
if (attrname)
955
{
956
/*
957
* r->dynamic readonly attributes
958
*/
959
960
n = r->dynamic;
961
if (a == internal.bound) return n & D_bound;
962
if (a == internal.built) return n & D_built;
963
if (a == internal.entries) return n & D_entries;
964
if (a == internal.global) return n & D_global;
965
if (a == internal.member) return n & (D_member|D_membertoo);
966
if (a == internal.regular) return n & D_regular;
967
if (a == internal.scanned) return n & D_scanned;
968
if (a == internal.source) return n & D_source;
969
if (a == internal.triggered) return n & D_triggered;
970
if (a == internal.file) return (n & D_bound) && !(r->property & (P_state|P_virtual)) && r->time;
971
972
/*
973
* r->property readonly attributes
974
*/
975
976
n = r->property;
977
if (a == internal.internal) return n & P_internal;
978
if (a == internal.metarule) return n & P_metarule;
979
if (a == internal.staterule) return n & P_staterule;
980
if (a == internal.statevar) return n & P_statevar;
981
982
/*
983
* r->status readonly attributes
984
*/
985
986
n = r->status;
987
if (a == internal.exists) return n == EXISTS;
988
if (a == internal.failed) return n == FAILED;
989
if (a == internal.making) return n == MAKING;
990
if (a == internal.notyet) return n == NOTYET;
991
992
/*
993
* other readonly attributes
994
*/
995
996
if (a == internal.active) return r->active != 0;
997
}
998
999
/*
1000
* r prerequisites as pseudo attributes
1001
*/
1002
1003
for (p = r->prereqs; p; p = p->next)
1004
if (a == p->rule)
1005
return 1;
1006
}
1007
return 0;
1008
}
1009
1010
/*
1011
* return nonzero if r has an after prerequisite with exact property
1012
*/
1013
1014
int
1015
hasafter(register Rule_t* r, register Flags_t property)
1016
{
1017
register List_t* p;
1018
1019
if (r->dynamic & D_hasafter)
1020
for (p = r->prereqs; p; p = p->next)
1021
if ((p->rule->property & P_failure) == property)
1022
return 1;
1023
return 0;
1024
}
1025
1026
/*
1027
* merge <from> into <to> according to op
1028
*/
1029
1030
void
1031
merge(register Rule_t* from, register Rule_t* to, int op)
1032
{
1033
register List_t* p;
1034
1035
if (from->name)
1036
{
1037
if (from == to || to->status != NOTYET && (to->status != UPDATE || !(from->property & P_use)))
1038
{
1039
/*
1040
* this is a workaround to separate the view vs. local binding for this case:
1041
* from sub/foo == foo
1042
* to /dir/foo == foo
1043
* it may need to be examined for cases other than (state.mam.statix)
1044
*/
1045
1046
if (!state.exec && state.mam.statix && (from->dynamic & D_alias) && (to->property & P_terminal) && from->uname && to->uname && *from->name != '/' && *to->name == '/')
1047
{
1048
Rule_t* fromstate;
1049
Rule_t* tostate;
1050
1051
to->uname = from->name;
1052
if (!(tostate = staterule(RULE, to, NiL, 0)) && (fromstate = staterule(RULE, from, NiL, 0)))
1053
*staterule(RULE, to, NiL, 1) = *fromstate;
1054
}
1055
return;
1056
}
1057
#if DEBUG
1058
if (to->name)
1059
debug((-4, "merging %s%s into %s", (op & MERGE_ATTR) ? "attributes of " : null, from->name, to->name));
1060
#endif
1061
}
1062
if (!(to->dynamic & D_bound) || (op & (MERGE_ASSOC|MERGE_FORCE)))
1063
to->property |= from->property & (P_accept|P_after|P_always|P_archive|P_before|P_command|P_dontcare|P_force|P_foreground|P_functional|P_ignore|P_implicit|P_joint|P_local|P_make|P_multiple|P_parameter|P_read|P_repeat|P_terminal|P_virtual);
1064
else
1065
to->property |= from->property & (P_accept|P_after|P_always|P_archive|P_before|P_command|P_force|P_foreground|P_functional|P_implicit|P_joint|P_local|P_make|P_multiple|P_parameter|P_read|P_repeat|P_terminal|P_virtual);
1066
if (from->property & P_implicit)
1067
to->property &= ~P_terminal;
1068
if ((from->property & (P_metarule|P_terminal)) == P_terminal)
1069
to->property &= ~P_implicit;
1070
if (op & MERGE_ALL)
1071
{
1072
if (!to->action)
1073
to->action = from->action;
1074
to->attribute |= from->attribute;
1075
to->property |= from->property & (P_accept|P_immediate|P_target|P_use);
1076
to->dynamic |= from->dynamic & (D_dynamic|D_global|D_regular);
1077
if (!(op & MERGE_SCANNED))
1078
to->dynamic |= from->dynamic & (D_entries|D_scanned);
1079
if (from->scan && from->scan != SCAN_NULL)
1080
to->scan = from->scan;
1081
if (to->status == NOTYET)
1082
to->status = from->status;
1083
for (p = from->prereqs; p; p = p->next)
1084
addprereq(to, p->rule, PREREQ_APPEND);
1085
if (!(to->property & P_state))
1086
{
1087
if (op & MERGE_BOUND)
1088
{
1089
from->mark |= M_bind;
1090
to->mark |= M_bind;
1091
}
1092
mergestate(from, to);
1093
if (op & MERGE_BOUND)
1094
{
1095
from->mark &= ~M_bind;
1096
to->mark &= ~M_bind;
1097
}
1098
}
1099
}
1100
else if (op & MERGE_FORCE)
1101
{
1102
if (from->attribute && from != internal.accept && from != internal.ignore && from != internal.retain && ((to->property & (P_attribute|P_use)) != P_attribute || to == internal.accept || to == internal.ignore || to == internal.retain))
1103
to->attribute |= from->attribute;
1104
if (from->scan)
1105
to->scan = from->scan;
1106
}
1107
else
1108
{
1109
if (from->attribute && from != internal.accept && from != internal.ignore && from != internal.retain && ((to->property & (P_attribute|P_use)) != P_attribute || to == internal.accept || to == internal.ignore || to == internal.retain))
1110
to->attribute |= from->attribute & ~internal.ignore->attribute;
1111
if (!to->scan)
1112
to->scan = from->scan;
1113
}
1114
}
1115
1116
/*
1117
* merge <from> state rules into <to>
1118
*/
1119
1120
void
1121
mergestate(Rule_t* from, Rule_t* to)
1122
{
1123
register int i;
1124
register Rule_t* fromstate;
1125
register Rule_t* tostate;
1126
Rule_t* t;
1127
char* s;
1128
1129
/*
1130
* if RULE merges then RULE+1..STATERULES also merge
1131
*/
1132
1133
if (fromstate = staterule(RULE, from, NiL, 0))
1134
tostate = staterule(RULE, to, NiL, 1);
1135
else if ((from->dynamic & D_alias) && (tostate = staterule(RULE, to, NiL, 0)))
1136
fromstate = staterule(RULE, from, NiL, 1);
1137
else
1138
return;
1139
#if DEBUG
1140
if (state.test & 0x00000800)
1141
{
1142
error(2, "MERGESTATE from: %s: %s time=[%s] event=[%s]", from->name, fromstate->name, timestr(fromstate->time), timestr(fromstate->event));
1143
error(2, "MERGESTATE to: %s: %s time=[%s] event=[%s]", to->name, tostate->name, timestr(tostate->time), timestr(tostate->event));
1144
}
1145
#endif
1146
if ((from->dynamic & D_alias) && fromstate->time && !statetimeq(fromstate, tostate))
1147
{
1148
/*
1149
* the solution is conservative but ok
1150
* since aliases probably don't change
1151
* very often -- every target depending
1152
* on <to> will be forced out of date rather
1153
* than those that just depend on <from>
1154
*/
1155
1156
reason((1, "%s alias has changed to %s", unbound(from), unbound(to)));
1157
to->dynamic |= D_aliaschanged;
1158
}
1159
if (fromstate->event != tostate->event)
1160
{
1161
if (fromstate->event < tostate->event)
1162
{
1163
/*
1164
* merge in the other direction
1165
*/
1166
1167
t = from;
1168
from = to;
1169
to = t;
1170
t = fromstate;
1171
fromstate = tostate;
1172
tostate = t;
1173
}
1174
s = tostate->name;
1175
*tostate = *fromstate;
1176
tostate->prereqs = listcopy(fromstate->prereqs);
1177
tostate->name = s;
1178
for (i = RULE + 1; i <= STATERULES; i++)
1179
if ((fromstate = staterule(i, from, NiL, 0)) && !staterule(i, to, NiL, 0))
1180
{
1181
tostate = staterule(i, to, NiL, 1);
1182
s = tostate->name;
1183
*tostate = *fromstate;
1184
tostate->prereqs = listcopy(fromstate->prereqs);
1185
tostate->name = s;
1186
}
1187
}
1188
}
1189
1190
/*
1191
* negate <from> attributes in <to>
1192
*/
1193
1194
void
1195
negate(register Rule_t* from, register Rule_t* to)
1196
{
1197
to->attribute &= ~from->attribute;
1198
to->property &= ~(from->property & (P_accept|P_after|P_always|P_archive|P_before|P_command|P_dontcare|P_force|P_functional|P_ignore|P_immediate|P_implicit|P_local|P_make|P_multiple|P_parameter|P_repeat|P_target|P_terminal|P_use|P_virtual));
1199
to->dynamic &= ~(from->dynamic & (D_dynamic|D_entries|D_regular));
1200
if (from->scan)
1201
to->scan = 0;
1202
if (from->semaphore)
1203
to->semaphore = 0;
1204
}
1205
1206
/*
1207
* make an internal rule pointer
1208
*/
1209
1210
static Rule_t*
1211
rinternal(char* s, register int flags)
1212
{
1213
register Rule_t* r;
1214
1215
r = makerule(s);
1216
r->property |= flags;
1217
if (!r->prereqs && !r->action)
1218
r->dynamic |= D_compiled;
1219
return r;
1220
}
1221
1222
/*
1223
* make an internal pattern association rule pointer
1224
* NOTE: this is required to sync pre 2001-05-09 make objects
1225
*/
1226
1227
static Rule_t*
1228
rassociate(char* s, register int flags)
1229
{
1230
register Rule_t* r;
1231
register Rule_t* a;
1232
register List_t* p;
1233
1234
r = rinternal(s, flags);
1235
for (p = r->prereqs; p; p = p->next)
1236
if (!(p->rule->property & P_attribute) && p->rule->name[0] == '%' && p->rule->name[1] == ATTRNAME && (a = getrule(p->rule->name + 1)) && (a->property & P_attribute))
1237
p->rule = a;
1238
return r;
1239
}
1240
1241
/*
1242
* maintain atomic dir-rule names
1243
*/
1244
1245
static int
1246
diratom(const char* s, char* v, void* h)
1247
{
1248
Dir_t* d = (Dir_t*)v;
1249
1250
NoP(s);
1251
NoP(h);
1252
d->name = getrule(d->name)->name;
1253
return 0;
1254
}
1255
1256
/*
1257
* # outstanding jobs builtin
1258
*/
1259
1260
static char*
1261
b_outstanding(char** args)
1262
{
1263
sfprintf(internal.val, "%d", state.coshell ? state.coshell->outstanding : 0);
1264
return sfstruse(internal.val);
1265
}
1266
1267
/*
1268
* getconf() builtin
1269
*/
1270
1271
static char*
1272
b_getconf(char** args)
1273
{
1274
char* name;
1275
char* path;
1276
char* value;
1277
1278
if (name = *args)
1279
args++;
1280
if (path = *args)
1281
{
1282
if (path[0] == '-' && !path[1])
1283
path = 0;
1284
args++;
1285
}
1286
if ((value = *args) && value[0] == '-' && !value[1])
1287
value = 0;
1288
return astconf(name, path, value);
1289
}
1290
1291
/*
1292
* getopts() builtin
1293
*/
1294
1295
static char*
1296
b_getopts(char** args)
1297
{
1298
char* id;
1299
char* usage;
1300
char* prefix;
1301
char* oid;
1302
char* s;
1303
Rule_t* r;
1304
Opt_t info;
1305
1306
s = getval(">", 0);
1307
if (*s == '-' && (id = *args++) && (r = getrule(*args++)) && (usage = r->action) && (prefix = *args))
1308
{
1309
if (streq(id, "-"))
1310
oid = 0;
1311
else
1312
{
1313
oid = error_info.id;
1314
error_info.id = id;
1315
}
1316
info = opt_info;
1317
opt_info.index = 0;
1318
opt_info.offset = 0;
1319
for (;;)
1320
{
1321
while (isspace(s[opt_info.offset]))
1322
opt_info.offset++;
1323
if (s[opt_info.offset] != '-')
1324
break;
1325
switch (optstr(s, usage))
1326
{
1327
case 0:
1328
break;
1329
case '?':
1330
error(ERROR_USAGE|0, "%s", opt_info.arg);
1331
opt_info.offset = 0;
1332
s = null;
1333
break;
1334
case ':':
1335
error(2, "%s", opt_info.arg);
1336
opt_info.offset = 0;
1337
s = null;
1338
break;
1339
default:
1340
sfprintf(internal.wrk, "%s%s", prefix, opt_info.name);
1341
setvar(sfstruse(internal.wrk), opt_info.arg && *opt_info.arg ? opt_info.arg : opt_info.num ? "1" : null, 0);
1342
continue;
1343
}
1344
break;
1345
}
1346
s += opt_info.offset;
1347
opt_info = info;
1348
if (oid)
1349
error_info.id = oid;
1350
return s;
1351
}
1352
return null;
1353
}
1354
1355
typedef int (*Systab_f)(void);
1356
1357
typedef struct Systab_s
1358
{
1359
const char* name;
1360
Systab_f call;
1361
} Systab_t;
1362
1363
static const Systab_t systab[] =
1364
{
1365
"getegid", (Systab_f)getegid,
1366
"geteuid", (Systab_f)geteuid,
1367
"getgid", (Systab_f)getgid,
1368
"getpid", (Systab_f)getpid,
1369
"getppid", (Systab_f)getppid,
1370
"getuid", (Systab_f)getuid,
1371
{0}
1372
};
1373
1374
/*
1375
* void arg system call catchall builtin
1376
*/
1377
1378
static char*
1379
b_syscall(char** args)
1380
{
1381
Systab_t* call;
1382
1383
if (!*args)
1384
return null;
1385
sfprintf(internal.val, "%d", (call = (Systab_t*)strlook(systab, sizeof(systab[0]), *args)) ? (*call->call)() : -1);
1386
return sfstruse(internal.val);
1387
}
1388
1389
/*
1390
* external engine name initialization -- the rest are in initrule()
1391
*
1392
* NOTE: version.c may reference some of these names, not to mention
1393
* non-engine source makefiles
1394
*/
1395
1396
External_t external =
1397
{
1398
/*
1399
* variable names
1400
*/
1401
1402
"MAKEARGS",
1403
"MAKECONVERT",
1404
"MAKEFILE",
1405
"MAKEFILES",
1406
"MAKEIMPORT",
1407
"MAKELIB",
1408
"MAKE",
1409
CO_ENV_PROC,
1410
"OLDMAKE",
1411
"PWD",
1412
"MAKERULES",
1413
"MAKESKIP",
1414
"MAKEVERSION",
1415
"MAKEPATH",
1416
"VPATH",
1417
1418
/*
1419
* infrequently used engine interface names
1420
*/
1421
1422
".COMPDONE",
1423
".COMPINIT",
1424
".DONE",
1425
".INIT",
1426
".INTERRUPT",
1427
".JOBDONE",
1428
".MAKEDONE",
1429
".MAKEINIT",
1430
".MAKEPROMPT",
1431
".MAKERUN",
1432
".MAMNAME.",
1433
".MAMACTION.",
1434
".ORDER",
1435
1436
/*
1437
* related file suffixes
1438
*/
1439
1440
".ml",
1441
".mo",
1442
".mk",
1443
".ms",
1444
".mt",
1445
};
1446
1447
/*
1448
* initialize some attribute and internal rule pointers
1449
*/
1450
1451
void
1452
initrule(void)
1453
{
1454
Rule_t* r;
1455
int i;
1456
1457
static int repeat;
1458
1459
hashclear(table.rule, HASH_ALLOCATE);
1460
1461
/*
1462
* dynamic rule attributes
1463
*/
1464
1465
ATTR(accept, ".ACCEPT", P_accept|P_immediate);
1466
ATTR(after, ".AFTER", P_after);
1467
ATTR(always, ".ALWAYS", P_always|P_immediate);
1468
ATTR(archive, ".ARCHIVE", P_archive);
1469
ATTR(attribute, ".ATTRIBUTE", P_readonly);
1470
ATTR(before, ".BEFORE", P_before);
1471
ATTR(command, ".COMMAND", P_command);
1472
ATTR(dontcare, ".DONTCARE", P_dontcare);
1473
ATTR(force, ".FORCE", P_force|P_immediate);
1474
ATTR(foreground, ".FOREGROUND", P_foreground);
1475
ATTR(functional, ".FUNCTIONAL", P_functional);
1476
ATTR(ignore, ".IGNORE", P_ignore);
1477
ATTR(immediate, ".IMMEDIATE", P_immediate);
1478
ATTR(implicit, ".IMPLICIT", P_implicit);
1479
ATTR(joint, ".JOINT", P_joint);
1480
ATTR(local, ".LOCAL", P_local|P_immediate);
1481
ATTR(make, ".MAKE", P_immediate);
1482
ATTR(multiple, ".MULTIPLE", P_multiple);
1483
ATTR(op, ".OPERATOR", P_operator);
1484
ATTR(parameter, ".PARAMETER", P_parameter);
1485
ATTR(read, ".READ", P_read);
1486
ATTR(readonly, ".READONLY", P_readonly);
1487
ATTR(repeat, ".REPEAT", P_repeat);
1488
ATTR(state, ".STATE", P_state|P_immediate);
1489
ATTR(terminal, ".TERMINAL", P_terminal);
1490
ATTR(use, ".USE", P_use);
1491
ATTR(virt, ".VIRTUAL", P_virtual);
1492
1493
/*
1494
* anonymous attributes (no internal handle)
1495
*/
1496
1497
ANON( ".FAILURE", P_failure);
1498
1499
/*
1500
* readonly rule attributes
1501
*/
1502
1503
INIT(active, ".ACTIVE", 0);
1504
INIT(bound, ".BOUND", 0);
1505
INIT(built, ".BUILT", 0);
1506
INIT(entries, ".ENTRIES", 0);
1507
INIT(exists, ".EXISTS", 0);
1508
INIT(failed, ".FAILED", 0);
1509
INIT(file, ".FILE", 0);
1510
INIT(global, ".GLOBAL", 0);
1511
INIT(member, ".MEMBER", 0);
1512
INIT(notyet, ".NOTYET", 0);
1513
INIT(regular, ".REGULAR", 0);
1514
INIT(scanned, ".SCANNED", 0);
1515
INIT(staterule, ".STATERULE", 0);
1516
INIT(statevar, ".STATEVAR", 0);
1517
INIT(target, ".TARGET", P_attribute|P_target);
1518
INIT(triggered, ".TRIGGERED", 0);
1519
1520
/*
1521
* special rules and names
1522
*/
1523
1524
INIT(alarm, ".ALARM", P_immediate);
1525
INIT(args, ".ARGS", P_internal);
1526
INIT(bind, ".BIND", P_immediate);
1527
INIT(clear, ".CLEAR", P_attribute);
1528
INIT(copy, ".COPY", P_attribute);
1529
INIT(delete, ".DELETE", P_attribute);
1530
INIT(dot, ".", 0);
1531
INIT(empty, "", 0);
1532
INIT(error, ".ERROR", 0);
1533
INIT(exports, ".EXPORT", P_attribute|P_immediate);
1534
INIT(freeze, ".FREEZE", P_immediate);
1535
INIT(globalfiles, ".GLOBALFILES", P_internal|P_readonly);
1536
INIT(include, ".INCLUDE", P_immediate);
1537
INIT(insert, ".INSERT", P_attribute);
1538
INIT(internal, ".INTERNAL", P_internal|P_readonly);
1539
INIT(main, ".MAIN", 0);
1540
INIT(makefiles, ".MAKEFILES", P_internal|P_readonly);
1541
INIT(making, ".MAKING", 0);
1542
INIT(metarule, ".METARULE", 0);
1543
INIT(null, ".NULL", P_attribute);
1544
INIT(preprocess, ".PREPROCESS", P_internal|P_readonly);
1545
INIT(query, ".QUERY", P_immediate|P_multiple|P_virtual);
1546
INIT(rebind, ".REBIND", P_immediate);
1547
INIT(reset, ".RESET", P_immediate);
1548
INIT(retain, ".RETAIN", P_immediate);
1549
INIT(run, ".RUN", P_immediate);
1550
INIT(scan, ".SCAN", P_attribute|P_readonly);
1551
INIT(script, ".SCRIPT", P_attribute|P_immediate);
1552
INIT(semaphore, ".SEMAPHORE", P_attribute);
1553
INIT(source, ".SOURCE", 0);
1554
INIT(special, ".SPECIAL", P_attribute|P_internal|P_readonly);
1555
INIT(sync, ".SYNC", P_immediate);
1556
INIT(tmplist, ".TMPLIST", P_internal|P_readonly);
1557
INIT(unbind, ".UNBIND", P_immediate);
1558
INIT(view, ".VIEW", P_internal|P_readonly);
1559
INIT(wait, ".WAIT", P_immediate);
1560
1561
/*
1562
* pattern association rules
1563
*/
1564
1565
ASOC(append_p, ".APPEND.", 0);
1566
ASOC(assert_p, ".ASSERT.", 0);
1567
ASOC(assign_p, ".ASSIGN.", 0);
1568
ASOC(attribute_p, ".ATTRIBUTE.", 0);
1569
ASOC(bind_p, ".BIND.", 0);
1570
ASOC(dontcare_p, ".DONTCARE.", 0);
1571
ASOC(insert_p, ".INSERT.", 0);
1572
ASOC(require_p, ".REQUIRE.", 0);
1573
ASOC(source_p, ".SOURCE.", 0);
1574
1575
/*
1576
* builtin functions
1577
*/
1578
1579
FUNC( ".GETCONF", b_getconf);
1580
FUNC( ".GETOPTS", b_getopts);
1581
FUNC( ".OUTSTANDING", b_outstanding);
1582
FUNC( ".SYSCALL", b_syscall);
1583
1584
#if DEBUG
1585
putrule(".DEBUG", internal.query);
1586
#endif
1587
hashset(table.rule, HASH_ALLOCATE);
1588
1589
/*
1590
* initialize the builtin attributes
1591
*/
1592
1593
if (!repeat)
1594
{
1595
static Frame_t frame;
1596
1597
frame.target = internal.internal;
1598
state.frame = frame.parent = &frame;
1599
internal.attribute->attribute = 1;
1600
internal.empty->dynamic |= D_bound;
1601
internal.empty->status = IGNORE;
1602
internal.empty->time = OLDTIME;
1603
internal.scan->scan = SCAN_USER;
1604
addprereq(internal.source, internal.dot, PREREQ_APPEND);
1605
addprereq(internal.special, internal.attribute, PREREQ_APPEND);
1606
addprereq(internal.special, internal.scan, PREREQ_APPEND);
1607
sfprintf(internal.tmp, "%s?(.*)", internal.source->name);
1608
internal.issource = strdup(sfstruse(internal.tmp));
1609
}
1610
initscan(repeat);
1611
initwakeup(repeat);
1612
1613
/*
1614
* maintain atomic dir-rule names
1615
*/
1616
1617
hashwalk(table.dir, 0, diratom, NiL);
1618
#if !BINDINDEX
1619
for (i = 0; i <= state.maxview; i++)
1620
{
1621
r = getrule(state.view[i].path);
1622
r->view = i;
1623
state.view[i].path = r->name;
1624
}
1625
#endif
1626
1627
/*
1628
* expand some dynamic values now for efficiency
1629
*/
1630
1631
if (internal.metarule->dynamic & D_dynamic)
1632
dynamic(internal.metarule);
1633
1634
/*
1635
* some things are only done once
1636
*/
1637
1638
repeat++;
1639
}
1640
1641
/*
1642
* low level for initview()
1643
*/
1644
1645
static List_t*
1646
view(register char* s, register char* d, List_t* p)
1647
{
1648
register int i;
1649
register Rule_t* r;
1650
1651
if (!d)
1652
d = s;
1653
i = pathcanon(d, 0, 0) - d;
1654
if (i > 2 && d[i - 1] == '/')
1655
d[--i] = 0;
1656
r = makerule(d);
1657
if ((unique(r) || !r->time) && !streq(r->name, internal.dot->name) && !streq(r->name, internal.pwd))
1658
{
1659
if (state.maxview < MAXVIEW - 1)
1660
{
1661
#if BINDINDEX
1662
r->dynamic |= D_bindindex;
1663
state.view[++state.maxview].path = r;
1664
#else
1665
state.view[++state.maxview].path = r->name;
1666
#endif
1667
state.view[state.maxview].pathlen = i;
1668
r->view = state.maxview;
1669
p = p->next = cons(r, NiL);
1670
if (s != d)
1671
{
1672
i = pathcanon(s, 0, 0) - s;
1673
if (i > 2 && s[i - 1] == '/')
1674
s[--i] = 0;
1675
r = makerule(s);
1676
r->view = state.maxview;
1677
}
1678
state.view[state.maxview].root = r->name;
1679
state.view[state.maxview].rootlen = i;
1680
#if BINDINDEX
1681
message((-2, "view[%d]: %s %s", state.maxview, state.view[state.maxview].path->name, state.view[state.maxview].root));
1682
#else
1683
message((-2, "view[%d]: %s %s", state.maxview, state.view[state.maxview].path, state.view[state.maxview].root));
1684
#endif
1685
}
1686
else
1687
error(1, "view level %s ignored -- %d max", r->name, MAXVIEW);
1688
}
1689
return p;
1690
}
1691
1692
/*
1693
* initialize the views
1694
*/
1695
1696
void
1697
initview(void)
1698
{
1699
register char* s;
1700
register char* t;
1701
register int n;
1702
int c;
1703
int pwdlen;
1704
char* pwd;
1705
char* tok;
1706
char* u;
1707
List_t* p;
1708
Rule_t* r;
1709
Stat_t top;
1710
Stat_t bot;
1711
Sfio_t* tmp;
1712
1713
p = internal.view->prereqs = cons(internal.dot, NiL);
1714
tmp = sfstropen();
1715
if (fs3d(FS3D_TEST))
1716
{
1717
if ((n = (s = colonlist(tmp, external.viewnode, 1, ' ')) != 0) || (s = colonlist(tmp, external.viewdot, 1, ' ')))
1718
{
1719
tok = tokopen(s, 0);
1720
if (s = n ? tokread(tok) : ".")
1721
while (t = tokread(tok))
1722
{
1723
message((-2, "vpath %s %s", s, t));
1724
mount(t, s, FS3D_VIEW, NiL);
1725
s = t;
1726
}
1727
tokclose(tok);
1728
}
1729
for (n = 1; n <= MAXVIEW; n++)
1730
sfputr(tmp, "/...", -1);
1731
sfputc(tmp, 0);
1732
s = t = sfstrseek(tmp, 0, SEEK_CUR);
1733
while (!stat(t -= 4, &top))
1734
{
1735
if (state.maxview >= MAXVIEW - 1)
1736
{
1737
error(1, "view levels past %s ignored -- %d max", t += 4, MAXVIEW);
1738
break;
1739
}
1740
p = p->next = cons(r = makerule(t), NiL);
1741
#if BINDINDEX
1742
state.view[++state.maxview].path = r;
1743
#else
1744
state.view[++state.maxview].path = r->name;
1745
#endif
1746
state.view[state.maxview].pathlen = s - t;
1747
message((-2, "view[%d]: %s", state.maxview, r->name));
1748
}
1749
state.fsview = 1;
1750
setvar(external.viewnode, NiL, 0);
1751
if (!stat(".", &top) && !stat("...", &bot) && top.st_ino == bot.st_ino && top.st_dev == bot.st_dev)
1752
state.virtualdot = 1;
1753
}
1754
else
1755
{
1756
unique(internal.dot);
1757
if (s = colonlist(tmp, external.viewnode, 1, ' '))
1758
{
1759
tok = tokopen(s, 1);
1760
while (s = tokread(tok))
1761
{
1762
if (*s != '/')
1763
sfprintf(internal.tmp, "%s/", internal.pwd);
1764
sfputr(internal.tmp, s, -1);
1765
t = sfstruse(internal.tmp);
1766
s = pathcanon(t, 0, 0);
1767
if (*(s - 1) == '/')
1768
*--s = 0;
1769
n = s - t;
1770
pwd = 0;
1771
if (strncmp(internal.pwd, t, n) || (c = internal.pwd[n]) && c != '/')
1772
{
1773
/*
1774
* ksh pwd and ast getcwd() are logical
1775
* others are physical
1776
* this gets PWD and VPATH in sync
1777
* if they're not
1778
*/
1779
1780
if (!stat(t, &top))
1781
{
1782
sfputr(internal.nam, internal.pwd, -1);
1783
u = sfstruse(internal.nam);
1784
c = 0;
1785
for (;;)
1786
{
1787
if (!stat(u, &bot) && bot.st_ino == top.st_ino && bot.st_dev == top.st_dev)
1788
{
1789
sfprintf(internal.nam, "%s%s", t, internal.pwd + (s - u));
1790
pwd = strdup(sfstruse(internal.nam));
1791
pwdlen = strlen(pwd);
1792
break;
1793
}
1794
if (!(s = strrchr(u, '/')))
1795
break;
1796
*s = 0;
1797
c = 1;
1798
}
1799
}
1800
if (!pwd)
1801
{
1802
setvar(external.viewnode, NiL, 0);
1803
break;
1804
}
1805
}
1806
if (pwd)
1807
{
1808
internal.pwd = pwd;
1809
internal.pwdlen = pwdlen;
1810
setvar(external.pwd, internal.pwd, V_import);
1811
}
1812
state.view[0].root = makerule(t)->name;
1813
state.view[0].rootlen = n;
1814
#if BINDINDEX
1815
message((-2, "view[%d]: %s %s", state.maxview, state.view[state.maxview].path->name, state.view[state.maxview].root));
1816
#else
1817
message((-2, "view[%d]: %s %s", state.maxview, state.view[state.maxview].path, state.view[state.maxview].root));
1818
#endif
1819
while (s = tokread(tok))
1820
{
1821
if (!c)
1822
p = view(s, NiL, p);
1823
else
1824
{
1825
if (*s != '/')
1826
sfprintf(internal.tmp, "%s/", internal.pwd);
1827
sfprintf(internal.tmp, "%s%s", s, internal.pwd + n);
1828
p = view(s, sfstruse(internal.tmp), p);
1829
}
1830
}
1831
if (!(optflag(OPT_strictview)->flags & OPT_READONLY))
1832
state.strictview = 1;
1833
break;
1834
}
1835
tokclose(tok);
1836
}
1837
if (s = colonlist(tmp, external.viewdot, 1, ' '))
1838
{
1839
n = state.maxview;
1840
tok = tokopen(s, 1);
1841
while (s = tokread(tok))
1842
{
1843
pathcanon(s, 0, 0);
1844
if (!n || *s != '.' || *(s + 1) != '.' || *(s + 2) && *(s + 2) != '/')
1845
p = view(s, NiL, p);
1846
else for (c = 0; c <= n; c++)
1847
{
1848
#if BINDINDEX
1849
sfprintf(internal.tmp, "%s/%s", c ? state.view[c].path->name : internal.pwd, s);
1850
#else
1851
sfprintf(internal.tmp, "%s/%s", c ? state.view[c].path : internal.pwd, s);
1852
#endif
1853
p = view(sfstruse(internal.tmp), NiL, p);
1854
}
1855
}
1856
tokclose(tok);
1857
}
1858
}
1859
if (!state.maxview)
1860
state.believe = 0;
1861
sfstrclose(tmp);
1862
}
1863
1864