Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/nmake/metarule.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 metarule routines
26
*/
27
28
#include "make.h"
29
30
/*
31
* return a pointer to the metarule that builds
32
* a file that matches the metarule pattern out from
33
* a file that matches the metarule pattern in
34
* force causes the rule to be created
35
*/
36
37
Rule_t*
38
metarule(char* in, char* out, int force)
39
{
40
register Rule_t* r;
41
register char* s;
42
43
sfprintf(internal.met, "%s>%s", in, out ? out : "%");
44
s = sfstruse(internal.met);
45
r = getrule(s);
46
if (force)
47
{
48
if (!r)
49
r = makerule(NiL);
50
r->property |= (P_metarule|P_use);
51
r->property &= ~(P_state|P_staterule|P_statevar);
52
}
53
else
54
{
55
/*
56
* if in -> out is a secondary metrule then return primary
57
*/
58
59
if (!r && (r = metainfo('P', in, out, 0)))
60
{
61
if (r->prereqs)
62
{
63
sfprintf(internal.met, "%s>%s", in, r->prereqs->rule->name);
64
r = getrule(sfstruse(internal.met));
65
}
66
else
67
r = 0;
68
}
69
if (r && (!(r->property & P_metarule) || !r->action && !r->uname))
70
r = 0;
71
}
72
return r;
73
}
74
75
/*
76
* metarule supplementary info
77
*
78
* type
79
*
80
* 'I' inputs
81
* 'N' nonterminal unconstrained inputs
82
* 'O' outputs
83
* 'P' primary output
84
* 'S' primary secondary outputs
85
* 'T' terminal unconstrained inputs
86
* 'X' unconstrained output exclusions
87
*/
88
89
Rule_t*
90
metainfo(int type, char* s1, char* s2, int force)
91
{
92
register Rule_t* r;
93
94
sfprintf(internal.met, "%s.%c.%s%s%s", internal.metarule->name, type, s1 ? s1 : null, s2 ? ">" : null, s2 ? s2 : null);
95
s1 = sfstruse(internal.met);
96
if (!(r = getrule(s1)) && force)
97
{
98
r = makerule(NiL);
99
r->property |= P_readonly;
100
}
101
return r;
102
}
103
104
#if _WINIX
105
106
/*
107
* yes, metarules are affected by the case insensitive filesystem botch
108
* we do case insensitive metarule pattern matching for all patterns that
109
* do not match `[-+]*'
110
*/
111
112
static int
113
metaccmp(register char* p, register int a, register int b)
114
{
115
return a == b || *p != '-' && *p != '+' && (isupper(a) ? tolower(a) : a) == (isupper(b) ? tolower(b) : b);
116
}
117
118
#else
119
120
#define metaccmp(p,a,b) ((a)==(b))
121
122
#endif
123
124
/*
125
* match s against metarule pattern
126
* leading unmatched directories before % are ignored
127
* returns 0 if no match
128
* otherwise if stem!=0 then non-dir part of matched stem is copied there
129
*/
130
131
int
132
metamatch(char* stem, register char* s, char* pattern)
133
{
134
register char* p;
135
register char* t;
136
register char* x;
137
register char* y;
138
char* b;
139
register int targetprefix;
140
141
b = s;
142
p = pattern;
143
targetprefix = state.targetprefix ? *state.targetprefix : -1;
144
while (*p != '%')
145
{
146
if (!*s)
147
return 0;
148
else if (!metaccmp(pattern, *p, *s))
149
{
150
do
151
{
152
if (*s == '/')
153
{
154
while (*++s == '/');
155
break;
156
}
157
else if (*s == targetprefix)
158
{
159
x = state.targetprefix;
160
y = s;
161
while (*++x == *++y && *x);
162
if (!*x)
163
{
164
s = y;
165
break;
166
}
167
}
168
} while (*++s);
169
if (!*(b = s))
170
return 0;
171
p = pattern;
172
}
173
else if (!*p++)
174
{
175
if (p = stem)
176
{
177
s = b;
178
while (*p++ = *s++);
179
}
180
return 1;
181
}
182
else
183
s++;
184
}
185
t = s;
186
while (*s)
187
s++;
188
while (*p)
189
p++;
190
while (*--p != '%')
191
if (s <= t || !metaccmp(pattern, *p, *--s))
192
return 0;
193
if (stem)
194
{
195
if ((p = strrchr(t, '/')) && p < s)
196
t = p + 1;
197
if (state.targetprefix)
198
{
199
b = t;
200
while ((p = strchr(b, targetprefix)) && p < s)
201
{
202
x = state.targetprefix;
203
y = p;
204
while (*++x == *++y && *x);
205
if (!*x)
206
b = t = y;
207
else
208
b++;
209
}
210
}
211
p = stem;
212
while (t < s)
213
*p++ = *t++;
214
*p = 0;
215
}
216
return 1;
217
}
218
219
/*
220
* expand the metarule pattern p into sp using stem
221
*/
222
223
void
224
metaexpand(Sfio_t* sp, char* stem, char* p)
225
{
226
register int c;
227
228
while ((c = *p++) != '%')
229
{
230
if (!c)
231
return;
232
sfputc(sp, c);
233
}
234
sfputr(sp, stem, -1);
235
sfputr(sp, p, -1);
236
}
237
238
/*
239
* update the metarule closure graph
240
*
241
* NOTE: c==0 (PREREQ_APPEND alias) is used to cut off part of the closure recursion
242
*/
243
244
void
245
metaclose(Rule_t* in, Rule_t* out, int c)
246
{
247
char* s;
248
Rule_t* x;
249
Rule_t* y;
250
Rule_t* z;
251
List_t* p;
252
List_t* q;
253
char stem[MAXNAME];
254
255
#if DEBUG
256
static int eloop = 0;
257
#endif
258
259
#if DEBUG
260
if (eloop++ > 64)
261
{
262
eloop--;
263
error(1, "metaclose: %s -> %s recursion!", in->name, out->name);
264
return;
265
}
266
#endif
267
addprereq(internal.metarule, out, c == PREREQ_DELETE ? c : PREREQ_LENGTH);
268
addprereq(metainfo('I', out->name, NiL, 1), in, c);
269
addprereq(metainfo('O', in->name, NiL, 1), out, c);
270
if (!c && !(state.questionable & 0x00000100))
271
return;
272
for (q = internal.metarule->prereqs; q; q = q->next)
273
{
274
if (metamatch(stem, out->name, q->rule->name) && (x = metainfo('O', q->rule->name, NiL, 0)))
275
{
276
for (p = x->prereqs; p; p = p->next)
277
{
278
metaexpand(internal.met, stem, p->rule->name);
279
z = makerule(sfstruse(internal.met));
280
x = metarule(in->name, z->name, 1);
281
if (!x->action || (state.questionable & 0x00000100))
282
{
283
if (c == PREREQ_DELETE)
284
s = 0;
285
else
286
{
287
if (z != in && !(x->mark & M_metarule))
288
{
289
x->mark |= M_metarule;
290
metaclose(in, z, PREREQ_APPEND);
291
x->mark &= ~M_metarule;
292
}
293
s = ((y = metarule(q->rule->name, z->name, 0)) && y->uname) ? y->uname : q->rule->name;
294
}
295
x->uname = s;
296
x->dynamic &= ~D_compiled;
297
}
298
}
299
}
300
if (c != PREREQ_DELETE && metamatch(stem, q->rule->name, in->name) && !streq(stem, "%") && (x = metainfo('I', q->rule->name, NiL, 0)))
301
{
302
metaexpand(internal.met, stem, out->name);
303
if (!streq(stem, q->rule->name))
304
{
305
z = makerule(sfstruse(internal.met));
306
for (p = x->prereqs; p; p = p->next)
307
{
308
x = metarule(p->rule->name, z->name, 1);
309
if (!(x->mark & M_metarule))
310
{
311
x->mark |= M_metarule;
312
metaclose(p->rule, z, 0);
313
x->mark &= ~M_metarule;
314
}
315
x->uname = in->name;
316
x->dynamic &= ~D_compiled;
317
}
318
}
319
}
320
}
321
if (c != PREREQ_DELETE && (z = metainfo('I', in->name, NiL, 0)))
322
for (q = z->prereqs; q; q = q->next)
323
if ((z = q->rule) != out)
324
{
325
x = metarule(z->name, out->name, 1);
326
if (!x->action || (state.questionable & 0x00000100))
327
{
328
if (!(x->mark & M_metarule))
329
{
330
x->mark |= M_metarule;
331
metaclose(z, out, 0);
332
x->mark &= ~M_metarule;
333
}
334
if (!x->uname)
335
{
336
x->uname = in->name;
337
x->dynamic &= ~D_compiled;
338
}
339
}
340
}
341
#if DEBUG
342
eloop--;
343
#endif
344
}
345
346
/*
347
* return the primary metarule source that generates r
348
* *meta is the matching metarule
349
*/
350
351
Rule_t*
352
metaget(Rule_t* r, Frame_t* active, char* stem, Rule_t** meta)
353
{
354
register List_t* p;
355
register List_t* q;
356
register List_t* v;
357
Rule_t* m;
358
Rule_t* s;
359
Rule_t* x;
360
Rule_t* y;
361
List_t* prereqs;
362
List_t* terminal;
363
char* b;
364
char* u;
365
char* t;
366
Flags_t f;
367
int matched;
368
369
u = unbound(r);
370
prereqs = 0;
371
if (active)
372
{
373
f = active->flags & P_implicit;
374
do
375
{
376
if (active->prereqs)
377
{
378
prereqs = active->prereqs;
379
break;
380
}
381
else if (active == active->parent)
382
break;
383
else
384
active = active->parent;
385
} while (active);
386
}
387
else
388
f = 0;
389
if (prereqs)
390
{
391
/*
392
* check explicit constrained prereqs -- easy
393
*/
394
395
debug((-9, "check explicit constrained metarule prerequisites"));
396
t = sfstrbase(internal.met);
397
matched = 0;
398
for (p = internal.metarule->prereqs; p; p = p->next)
399
if (metamatch(stem, u, p->rule->name) && (x = metainfo('I', p->rule->name, NiL, 0)) && (matched = 1, x->prereqs))
400
for (q = prereqs; q; q = q->next)
401
if (q->rule->status != UPDATE)
402
for (v = x->prereqs; v; v = v->next)
403
if (metamatch(t, unbound(q->rule), v->rule->name) && streq(t, stem) && (m = metarule(v->rule->name, p->rule->name, 0)) && (!(r->property & P_terminal) || (m->property & P_terminal)))
404
{
405
s = q->rule;
406
goto primary;
407
}
408
}
409
else
410
matched = 1;
411
if (b = strrchr(u, '/'))
412
b++;
413
else
414
b = u;
415
terminal = (x = metainfo('T', NiL, NiL, 0)) ? x->prereqs : 0;
416
if (matched)
417
{
418
Sfio_t* buf = 0;
419
Sfio_t* tmp = 0;
420
421
/*
422
* check implicit constrained prereqs -- a little harder
423
*/
424
425
debug((-9, "check implicit constrained metarule prerequisites"));
426
matched = 0;
427
for (p = internal.metarule->prereqs; p; p = p->next)
428
if (metamatch(stem, u, p->rule->name) && (x = metainfo('I', p->rule->name, NiL, 0)))
429
for (matched = 1, q = x->prereqs; q; q = q->next)
430
if ((m = metarule(q->rule->name, p->rule->name, 0)) && (!(r->property & P_terminal) || (m->property & P_terminal)) && !(m->property & f))
431
{
432
if (!tmp)
433
tmp = sfstropen();
434
if (b != u && *u != '/' && *q->rule->name && ((state.questionable & 0x00000008) || !strchr(q->rule->name, '/')))
435
{
436
char* x = u;
437
438
for (;;)
439
{
440
sfprintf(tmp, "%-.*s", b - x, x);
441
metaexpand(tmp, stem, q->rule->name);
442
t = sfstruse(tmp);
443
if (m->dynamic & D_dynamic)
444
{
445
if (!buf)
446
buf = sfstropen();
447
expand(buf, t);
448
t = sfstruse(buf);
449
}
450
if ((s = bindfile(NiL, t, 0)) && s->status != UPDATE && (s->time || (s->property & P_target)) || !(state.questionable & 0x08000000) && m->action && !*m->action && (s = makerule(t)))
451
{
452
sfstrclose(tmp);
453
if (buf)
454
sfstrclose(buf);
455
goto primary;
456
}
457
if (!(x = strchr(x, '/')))
458
break;
459
x++;
460
}
461
}
462
else
463
{
464
metaexpand(tmp, stem, q->rule->name);
465
t = sfstruse(tmp);
466
if (m->dynamic & D_dynamic)
467
{
468
if (!buf)
469
buf = sfstropen();
470
expand(buf, t);
471
t = sfstruse(buf);
472
}
473
if (isstatevar(t) && (s = getrule(t)) && (s = bindstate(s, NiL)))
474
goto primary;
475
if ((s = bindfile(NiL, t, 0)) && s->status != UPDATE && (s->time || (s->property & P_target)) || !(state.questionable & 0x08000000) && m->action && !*m->action && (s = makerule(t)))
476
{
477
sfstrclose(tmp);
478
if (buf)
479
sfstrclose(buf);
480
goto primary;
481
}
482
}
483
484
/*
485
* check terminal unconstrained metarules
486
*/
487
488
debug((-9, "check terminal unconstrained metarules"));
489
for (v = terminal; v; v = v->next)
490
if (metarule(v->rule->name, NiL, 0))
491
{
492
if (!buf)
493
buf = sfstropen();
494
metaexpand(buf, t, v->rule->name);
495
if ((s = bindfile(NiL, sfstruse(buf), 0)) && s->status != UPDATE && s->time)
496
{
497
s->status = EXISTS;
498
s = makerule(t);
499
sfstrclose(buf);
500
sfstrclose(tmp);
501
goto primary;
502
}
503
}
504
}
505
if (buf)
506
sfstrclose(buf);
507
if (tmp)
508
sfstrclose(tmp);
509
}
510
511
/*
512
* unconstrained metarules ignored on recursive calls
513
*/
514
515
if (!meta)
516
return 0;
517
518
/*
519
* check terminal unconstrained metarules
520
*/
521
522
if (prereqs)
523
{
524
/*
525
* check explicit terminal unconstrained prereqs
526
*/
527
528
t = sfstrbase(internal.met);
529
for (p = terminal; p; p = p->next)
530
if (m = metarule(p->rule->name, NiL, 0))
531
for (q = prereqs; q; q = q->next)
532
if (metamatch(t, q->rule->name, p->rule->name) && streq(t, b) && (s = bindfile(q->rule, NiL, 0)) && s->time)
533
{
534
s->status = EXISTS;
535
goto unconstrained;
536
}
537
}
538
539
/*
540
* check implicit terminal unconstrained prereqs
541
*/
542
543
for (p = terminal; p; p = p->next)
544
if ((m = metarule(p->rule->name, NiL, 0)) && (!(r->property & P_terminal) || (m->property & P_terminal)) && !(m->property & f))
545
{
546
metaexpand(internal.met, b, p->rule->name);
547
if ((s = bindfile(NiL, sfstruse(internal.met), 0)) && s->time)
548
{
549
s->status = EXISTS;
550
goto unconstrained;
551
}
552
}
553
554
/*
555
* check nonterminal unconstrained metarules
556
* nonterminals skipped if r matched any constrained metarule target
557
*/
558
559
if (!matched && !(r->property & P_terminal) && (x = metainfo('N', NiL, NiL, 0)) && x->prereqs)
560
{
561
/*
562
* don't try to match excluded patterns
563
*/
564
565
if ((s = metainfo('X', NiL, NiL, 0)))
566
for (p = s->prereqs; p; p = p->next)
567
if (metamatch(NiL, u, p->rule->name))
568
{
569
matched = 1;
570
break;
571
}
572
if (!matched)
573
{
574
debug((-9, "check nonterminal unconstrained metarules"));
575
if (prereqs)
576
{
577
/*
578
* check explicit prereqs -- easy
579
*/
580
581
debug((-9, "check explicit nonterminal unconstrained metarule prerequisites"));
582
t = sfstrbase(internal.met);
583
for (p = x->prereqs; p; p = p->next)
584
if (m = metarule(p->rule->name, NiL, 0))
585
for (q = prereqs; q; q = q->next)
586
if (metamatch(t, q->rule->name, p->rule->name) && streq(t, b))
587
{
588
s = q->rule;
589
goto unconstrained;
590
}
591
}
592
593
/*
594
* check implicit prereqs -- hardest
595
*/
596
597
debug((-9, "check implicit nonterminal unconstrained metarule prerequisites"));
598
for (q = x->prereqs; q; q = q->next)
599
if (m = metarule(q->rule->name, NiL, 0))
600
{
601
metaexpand(internal.met, b, q->rule->name);
602
t = sfstruse(internal.met);
603
s = getrule(t);
604
if (isstatevar(t))
605
{
606
if (s && (s = bindstate(s, NiL)))
607
goto unconstrained;
608
}
609
else if (s = bindfile(s, t, BIND_RULE))
610
{
611
/*
612
* use s if it exists
613
*/
614
615
if (s->status != UPDATE && (s->time || (s->property & P_target)))
616
goto unconstrained;
617
618
/*
619
* use s if it can be generated
620
*/
621
622
if (metaget(s, NiL, stem, NiL))
623
goto unconstrained;
624
}
625
}
626
}
627
}
628
629
/*
630
* no metarule match
631
*/
632
633
return 0;
634
635
unconstrained:
636
637
/*
638
* unconstrained match
639
*/
640
641
strcpy(stem, b);
642
643
primary:
644
645
/*
646
* primary match
647
*/
648
649
if (meta)
650
{
651
if (m->uname)
652
{
653
/*
654
* metarule intermediate prerequisite
655
*/
656
657
if (!(x = metarule(m->uname, p->rule->name, 0)) || x->uname)
658
{
659
x = 0;
660
if (y = metainfo('O', m->uname, NiL, 0))
661
for (q = y->prereqs; q; q = q->next)
662
if (metamatch(stem, u, q->rule->name) && (x = metarule(m->uname, q->rule->name, 0)))
663
{
664
if (!x->uname)
665
break;
666
x = 0;
667
}
668
}
669
if (x)
670
{
671
metaexpand(internal.met, stem, m->uname);
672
if (!((y = makerule(sfstruse(internal.met)))->property & P_terminal) && !(y->property & f))
673
{
674
*meta = x;
675
s = y;
676
goto found;
677
}
678
}
679
}
680
*meta = m;
681
}
682
if (m->property & P_terminal)
683
s->property |= P_terminal;
684
else if ((x = metainfo('S', m->name, NiL, 0)) && !(x->property & P_terminal))
685
for (p = x->prereqs; p; p = p->next)
686
{
687
metaexpand(internal.met, stem, p->rule->name);
688
if ((x = getrule(sfstruse(internal.met))) && (x->property & P_terminal))
689
return 0;
690
}
691
found:
692
if (meta && (state.targetcontext || state.targetprefix) && (t = strrchr(u = unbound(r), '/')))
693
{
694
*t = 0;
695
if (!strchr(s->name, '/'))
696
{
697
sfprintf(internal.met, "%s%s%s", u, state.targetprefix ? state.targetprefix : "/", s->name);
698
s = makerule(sfstruse(internal.met));
699
}
700
if (!strchr(stem, '/'))
701
{
702
sfputr(internal.met, stem, 0);
703
sfsprintf(stem, MAXNAME - 1, "%s%s%s", u, state.targetprefix ? state.targetprefix : "/", sfstruse(internal.met));
704
}
705
*t = '/';
706
}
707
return s;
708
}
709
710