Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/nmake/bind.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 binding routines
26
*/
27
28
#include "make.h"
29
#include "options.h"
30
31
/*
32
* embedded spaces in file name wreak havoc
33
* we wreak hack to get through
34
*/
35
36
#define HACKSPACE(f,s) for (s = f; s = strchr(s, ' '); *s++ = (state.test & 0x00080000) ? '?' : FILE_SPACE)
37
#define FIGNORE(s) ((s)[0]=='.'&&((s)[1]==0||(s)[1]=='.'&&(s)[2]==0))
38
39
#if DEBUG
40
#define DEBUGSOURCE(n,r,p) \
41
do \
42
{ \
43
if (error_info.trace <= -14) \
44
{ \
45
List_t* q; \
46
message((-14, " [%d] %s", n, (r)->name)); \
47
for (q = p; q; q = q->next) \
48
message((-14, " %s", q->rule->name)); \
49
} \
50
} while (0)
51
#else
52
#define DEBUGSOURCE(n,r,p)
53
#endif
54
55
#if _WINIX
56
57
/*
58
* we have a system in which some directories preserve
59
* mixed case entries but ignore case on name lookup
60
* maybe they can get a patent on that
61
* hey, maybe we can get a patent on this
62
*/
63
64
static int
65
file_compare(register const char* s, register const char* t)
66
{
67
return ((File_t*)hashgetbucket(s)->value)->dir->ignorecase ? strcasecmp(s, t) : strcmp(s, t);
68
}
69
70
static unsigned int
71
file_hash(const char* s)
72
{
73
register const unsigned char* p = (const unsigned char*)s;
74
register unsigned int h = 0;
75
register unsigned int c;
76
77
while (c = *p++)
78
{
79
if (isupper(c))
80
c = tolower(c);
81
HASHPART(h, c);
82
}
83
return h;
84
}
85
86
static int
87
rule_compare(register const char* s, register const char* t)
88
{
89
register int c;
90
register int d;
91
register int x;
92
93
x = (*s == '.') ? 0 : -1;
94
while (c = *s++)
95
{
96
if (!x)
97
{
98
if (c == '%')
99
x = (*(s - 2) == '.') ? 1 : -1;
100
else if (c != '.' && !isupper(c))
101
x = -1;
102
}
103
if ((d = *t++) != c)
104
{
105
if (x > 0)
106
{
107
if (isupper(c))
108
c = tolower(c);
109
else if (isupper(d))
110
d = tolower(d);
111
if (c == d)
112
continue;
113
}
114
return c - d;
115
}
116
}
117
return c - *t;
118
}
119
120
static unsigned int
121
rule_hash(const char* s)
122
{
123
register const unsigned char* p = (const unsigned char*)s;
124
register unsigned int h = 0;
125
register unsigned int c;
126
register int x;
127
128
x = (*s == '.') ? 0 : -1;
129
while (c = *p++)
130
{
131
if (!x)
132
{
133
if (c == '%')
134
x = (*(p - 2) == '.') ? 1 : -1;
135
else if (c != '.' && !isupper(c))
136
x = -1;
137
}
138
if (x > 0 && isupper(c))
139
c = tolower(c);
140
HASHPART(h, c);
141
}
142
return h;
143
}
144
145
#endif
146
147
/*
148
* initialize the hash tables
149
*/
150
151
void
152
inithash(void)
153
{
154
table.ar = hashalloc(NiL, HASH_name, "archives", 0);
155
table.bound = hashalloc(table.ar, HASH_name, "bound-directories", 0);
156
#if _WINIX
157
table.file = hashalloc(NiL, HASH_set, HASH_ALLOCATE, HASH_compare, file_compare, HASH_hash, file_hash, HASH_name, "files", 0);
158
table.oldvalue = hashalloc(NiL, HASH_name, "old-values", 0);
159
table.rule = hashalloc(NiL, HASH_compare, rule_compare, HASH_hash, rule_hash, HASH_name, "atoms", 0);
160
#else
161
table.file = hashalloc(table.ar, HASH_set, HASH_ALLOCATE, HASH_name, "files", 0);
162
table.oldvalue = hashalloc(table.file, HASH_name, "old-values", 0);
163
table.rule = hashalloc(table.oldvalue, HASH_name, "atoms", 0);
164
#endif
165
table.var = hashalloc(table.oldvalue, HASH_name, "variables", 0);
166
table.dir = hashalloc(NiL, HASH_set, HASH_ALLOCATE, HASH_namesize, sizeof(Fileid_t), HASH_name, "directories", 0);
167
optinit();
168
}
169
170
/*
171
* determine if a directory (archive) has already been scanned
172
*/
173
174
Dir_t*
175
unique(register Rule_t* r)
176
{
177
register Dir_t* d;
178
Rule_t* x;
179
Fileid_t id;
180
Stat_t st;
181
182
if (rstat(r->name, &st, 0))
183
{
184
r->time = 0;
185
return 0;
186
}
187
id.dev = st.st_dev;
188
id.ino = st.st_ino;
189
if ((d = getdir(&id)) && state.alias && d->directory == (S_ISDIR(st.st_mode) != 0) && (!state.mam.statix || S_ISDIR(st.st_mode)))
190
{
191
/*
192
* internal.unbind causes directory rescan
193
*/
194
195
if (r->name == d->name || (r->dynamic & D_alias) && makerule(r->name)->name == d->name || (x = makerule(d->name)) == r)
196
return d;
197
198
/*
199
* the physical directory alias can go either way
200
* but we bias the choice towards shorter pathnames
201
*/
202
203
if (!x->uname && strlen(r->name) < strlen(x->name))
204
{
205
Rule_t* t;
206
207
t = r;
208
r = x;
209
x = t;
210
x->time = d->time;
211
}
212
message((-2, "%s %s is also specified as %s", (r->property & P_archive) ? "archive" : "directory", unbound(r), x->name));
213
r->dynamic |= D_alias;
214
merge(r, x, MERGE_ALL|MERGE_BOUND);
215
r->view = x->view;
216
r->time = x->time;
217
r->uname = r->name;
218
d->name = r->name = x->name;
219
return 0;
220
}
221
d = newof(0, Dir_t, 1, 0);
222
d->name = r->name;
223
d->time = r->time = tmxgetmtime(&st);
224
d->directory = S_ISDIR(st.st_mode) != 0;
225
putdir(0, d);
226
#if _WINIX
227
d->ignorecase = d->directory;
228
#endif
229
return d;
230
}
231
232
/*
233
* add a directory (archive) entry to the file hash
234
*/
235
236
File_t*
237
addfile(Dir_t* d, char* name, Time_t date)
238
{
239
register File_t* f;
240
register File_t* n;
241
register char* s;
242
243
HACKSPACE(name, s);
244
245
/*
246
* this test avoids duplicate entries for systems that
247
* support viewed or covered directories in the pathname
248
* system calls
249
*
250
* we assume that the cover directories are read in order
251
* from top to bottom
252
*
253
* the entries for a directory and its covered directories
254
* all have the same file.dir value
255
*/
256
257
if ((n = getfile(name)) && n->dir == d)
258
{
259
if (d->archive)
260
{
261
if (n->time < date)
262
n->time = date;
263
#if DEBUG
264
message((-12, "%s: %s %s [duplicate member]", d->name, name, timestr(n->time)));
265
#endif
266
}
267
return n;
268
}
269
#if DEBUG
270
message((-12, "%s: %s %s%s", d->name, name, timestr(date), d->ignorecase ? " [ignorecase]" : null));
271
#endif
272
f = newof(0, File_t, 1, 0);
273
f->next = n;
274
f->dir = d;
275
f->time = date;
276
putfile(0, f);
277
#if _WINIX
278
if (!d->archive && (s = strchr(name, '.')))
279
{
280
s++;
281
if (streq(s, "exe") || streq(s, "EXE"))
282
{
283
*--s = 0;
284
addfile(d, name, date);
285
*s = '.';
286
}
287
}
288
#endif
289
return f;
290
}
291
292
/*
293
* add new file r to the directory hash at dir
294
*/
295
296
void
297
newfile(register Rule_t* r, char* dir, Time_t date)
298
{
299
register char* s;
300
register char* t;
301
char* nam;
302
Rule_t* z;
303
Dir_t* d;
304
Hash_position_t* pos;
305
Sfio_t* tmp;
306
307
tmp = sfstropen();
308
sfputc(tmp, '.');
309
sfputc(tmp, '/');
310
edit(tmp, r->name, dir ? dir : KEEP, KEEP, KEEP);
311
s = (nam = sfstruse(tmp)) + 1;
312
do
313
{
314
*s = 0;
315
if ((z = getrule(nam)) && (z->dynamic & D_entries))
316
{
317
if (t = strchr(s + 1, '/'))
318
*t = 0;
319
320
/*
321
* sequential scan is OK since this is uncommon
322
*/
323
324
if (pos = hashscan(table.dir, 0))
325
{
326
while (hashnext(pos))
327
{
328
d = (Dir_t*)pos->bucket->value;
329
if (d->name == z->name)
330
{
331
addfile(d, s + 1, date);
332
break;
333
}
334
}
335
hashdone(pos);
336
}
337
if (t)
338
*t = '/';
339
}
340
*s++ = '/';
341
} while (s = strchr(s, '/'));
342
sfstrclose(tmp);
343
}
344
345
/*
346
* scan directory r and record all its entries
347
*/
348
349
void
350
dirscan(Rule_t* r)
351
{
352
register DIR* dirp;
353
register Dir_t* d;
354
register Dirent_t* entry;
355
char* s;
356
int n;
357
Stat_t st;
358
359
if (r->dynamic & D_scanned)
360
return;
361
if ((n = strlen(r->name)) > 1)
362
s = canon(r->name) - 1;
363
else
364
s = r->name;
365
if (s > r->name && *s == '/')
366
*s-- = 0;
367
if ((s - r->name + 1) != n)
368
r->name = maprule(r->name, r);
369
r->dynamic |= D_scanned;
370
r->dynamic &= ~D_entries;
371
if (!(r->property & P_state))
372
{
373
if (d = unique(r))
374
{
375
s = r->name;
376
if (d->directory && (dirp = opendir(s)))
377
{
378
debug((-5, "scan directory %s", s));
379
while (entry = readdir(dirp))
380
if (!FIGNORE(entry->d_name))
381
addfile(d, entry->d_name, NOTIME);
382
r->dynamic |= D_entries;
383
if (!(r->dynamic & D_bound) && !stat(s, &st))
384
{
385
r->dynamic |= D_bound;
386
r->time = tmxgetmtime(&st);
387
if (!r->view && ((state.questionable & 0x00000800) || !(r->property & P_target)) && *s == '/' && (strncmp(s, internal.pwd, internal.pwdlen) || *(s + internal.pwdlen) != '/'))
388
r->dynamic |= D_global;
389
}
390
closedir(dirp);
391
return;
392
}
393
debug((-5, "dirscan(%s) failed", s));
394
}
395
else if (r->time)
396
r->dynamic |= D_entries;
397
}
398
}
399
400
typedef struct Globstate_s
401
{
402
char* name;
403
DIR* dirp;
404
int view;
405
int root;
406
Hash_table_t* overlay;
407
} Globstate_t;
408
409
#if 0
410
411
static void*
412
trace_opendir(const char* dir, int line)
413
{
414
void* p;
415
416
p = opendir(dir);
417
error(-1, "AHA#%d opendir %s = %p", line, dir, p);
418
return p;
419
}
420
421
#define opendir(f) trace_opendir(f,__LINE__)
422
423
#endif
424
425
/*
426
* glob() diropen for 2d views
427
*/
428
429
static void*
430
glob_diropen(glob_t* gp, const char* path)
431
{
432
Globstate_t* gs = (Globstate_t*)gp->gl_handle;
433
const char* dir;
434
register int i;
435
register int n;
436
437
if (!(gs->overlay = hashalloc(NiL, HASH_set, HASH_ALLOCATE, 0)))
438
return 0;
439
gs->view = 0;
440
gs->root = 0;
441
dir = path;
442
if (*path == '/')
443
for (i = 0; i <= state.maxview; i++)
444
{
445
if (!strncmp(path, state.view[i].root, n = state.view[i].rootlen) && (!*(path + n) || *(path + n) == '/'))
446
{
447
if (!*(path += n + 1))
448
path = internal.dot->name;
449
gs->view = i;
450
gs->root = 1;
451
break;
452
}
453
}
454
gs->name = makerule((char*)path)->name;
455
if (gs->dirp = opendir(dir))
456
return (void*)gs;
457
if (*path != '/')
458
while (gs->view++ < state.maxview)
459
{
460
if (*gs->name == '/')
461
sfprintf(internal.nam, "%s", gs->name);
462
else if (gs->root)
463
sfprintf(internal.nam, "%s/%s", state.view[gs->view].root, gs->name);
464
else
465
{
466
if (*state.view[gs->view].path != '/')
467
sfprintf(internal.nam, "%s/", internal.pwd);
468
sfprintf(internal.nam, "%s/%s", state.view[gs->view].path, gs->name);
469
}
470
if (gs->dirp = opendir(sfstruse(internal.nam)))
471
return (void*)gs;
472
}
473
hashfree(gs->overlay);
474
return 0;
475
}
476
477
/*
478
* glob() dirnext for 2d views
479
*/
480
481
static char*
482
glob_dirnext(glob_t* gp, void* handle)
483
{
484
Globstate_t* gs = (Globstate_t*)handle;
485
Dirent_t* dp;
486
char* s;
487
488
for (;;)
489
{
490
if (dp = readdir(gs->dirp))
491
{
492
if (FIGNORE(dp->d_name))
493
continue;
494
HACKSPACE(dp->d_name, s);
495
if (hashget(gs->overlay, dp->d_name))
496
continue;
497
hashput(gs->overlay, 0, (char*)gs);
498
#if defined(DT_UNKNOWN) && defined(DT_DIR) && defined(DT_LNK)
499
if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_DIR && dp->d_type != DT_LNK)
500
gp->gl_status |= GLOB_NOTDIR;
501
#endif
502
return dp->d_name;
503
}
504
closedir(gs->dirp);
505
gs->dirp = 0;
506
if (*gs->name == '/')
507
return 0;
508
do
509
{
510
if (gs->view++ >= state.maxview)
511
return 0;
512
if (gs->root)
513
sfprintf(internal.nam, "%s/%s", state.view[gs->view].root, gs->name);
514
else
515
{
516
if (*state.view[gs->view].path != '/')
517
sfprintf(internal.nam, "%s/", internal.pwd);
518
sfprintf(internal.nam, "%s/%s", state.view[gs->view].path, gs->name);
519
}
520
} while (!(gs->dirp = opendir(sfstruse(internal.nam))));
521
}
522
}
523
524
/*
525
* glob() dirclose for 2d views
526
*/
527
528
static void
529
glob_dirclose(glob_t* gp, void* handle)
530
{
531
Globstate_t* gs = (Globstate_t*)handle;
532
533
if (gs->dirp)
534
closedir(gs->dirp);
535
if (gs->overlay)
536
hashfree(gs->overlay);
537
}
538
539
/*
540
* glob() type for 2d views
541
*/
542
543
static int
544
glob_type(glob_t* gp, const char* path, int flags)
545
{
546
register int i;
547
register int n;
548
int root;
549
Stat_t st;
550
551
i = 0;
552
if ((*gp->gl_stat)(path, &st))
553
{
554
root = 0;
555
if (*path == '/')
556
for (i = 0; i <= state.maxview; i++)
557
{
558
if (!strncmp(path, state.view[i].root, n = state.view[i].rootlen) && (!*(path + n) || *(path + n) == '/'))
559
{
560
if (!*(path += n + 1))
561
path = internal.dot->name;
562
root = 1;
563
break;
564
}
565
}
566
for (i = 0; i <= state.maxview; i++)
567
{
568
if (root)
569
sfprintf(internal.nam, "%s/%s", state.view[i].root, path);
570
else
571
{
572
if (*state.view[i].path != '/')
573
sfprintf(internal.nam, "%s/", internal.pwd);
574
sfprintf(internal.nam, "%s/%s", state.view[i].path, path);
575
}
576
if (!stat(sfstruse(internal.nam), &st))
577
break;
578
}
579
}
580
if (i > state.maxview)
581
i = 0;
582
else if (S_ISDIR(st.st_mode))
583
i = GLOB_DIR;
584
else if (!S_ISREG(st.st_mode))
585
i = GLOB_DEV;
586
else if (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
587
i = GLOB_EXE;
588
else
589
i = GLOB_REG;
590
return i;
591
}
592
593
/*
594
* return a vector of the top view of files in all views matching pattern s
595
* the vector is placed on the current stack
596
*/
597
598
char**
599
globv(register glob_t* gp, char* s)
600
{
601
register char** q;
602
register char** p;
603
register char** x;
604
int i;
605
int f;
606
glob_t gl;
607
Globstate_t gs;
608
609
static char* nope[1];
610
611
f = GLOB_AUGMENTED|GLOB_DISC|GLOB_STARSTAR;
612
if (!gp)
613
{
614
gp = &gl;
615
f |= GLOB_STACK;
616
}
617
memset(gp, 0, sizeof(gl));
618
gp->gl_intr = &state.caught;
619
gp->gl_stat = pathstat;
620
if (state.maxview && !state.fsview)
621
{
622
gp->gl_handle = (void*)&gs;
623
gp->gl_diropen = glob_diropen;
624
gp->gl_dirnext = glob_dirnext;
625
gp->gl_dirclose = glob_dirclose;
626
gp->gl_type = glob_type;
627
}
628
if (i = glob(s, f, 0, gp))
629
{
630
if (i != GLOB_NOMATCH && !trap())
631
error(2, "glob() internal error %d", i);
632
return nope;
633
}
634
if (state.maxview && !state.fsview)
635
{
636
for (i = 0, p = 0, x = q = gp->gl_pathv; *q; q++)
637
if (!p || !streq(*q, *p))
638
{
639
*x++ = *q;
640
p = q;
641
}
642
*x = 0;
643
}
644
return gp->gl_pathv;
645
}
646
647
/*
648
* enter r as an alias for x
649
* path is the canonical path name for x
650
* d is the bind directory for path
651
* a pointer to r merged with x is returned
652
*/
653
654
static Rule_t*
655
bindalias(register Rule_t* r, register Rule_t* x, char* path, Rule_t* d, int force)
656
{
657
char* s;
658
int i;
659
int n;
660
int na = 0;
661
Rule_t* z;
662
Rule_t* a[3];
663
664
if (x->dynamic & D_alias)
665
{
666
a[na++] = x;
667
x = makerule(x->name);
668
if (x == r || (x->dynamic & D_alias))
669
return r;
670
}
671
if (!force && !((r->dynamic|x->dynamic)&D_bound) && !d && !strchr(x->name, '/'))
672
{
673
debug((-5, "%s alias %s delayed until one or the other is bound", x->name, r->name));
674
return x;
675
}
676
message((-2, "%s is also specified as %s", unbound(r), unbound(x)));
677
#if DEBUG
678
if (state.test & 0x00000040)
679
error(2, "bindalias: path=%s r=%s%s%s x=%s%s%s", path, r->name, r->uname ? "==" : null, r->uname ? r->uname : null, x->name, x->uname ? "==" : null, x->uname ? x->uname : null);
680
#endif
681
r->dynamic |= (D_alias|D_bound);
682
merge(r, x, MERGE_ALL|MERGE_BOUND);
683
if (!(state.questionable & 0x00001000))
684
x->attribute |= r->attribute;
685
if (x->uname && !streq(x->name, path) && !streq(x->uname, path))
686
{
687
putrule(x->name, 0);
688
z = makerule(path);
689
if (z->dynamic & D_alias)
690
{
691
a[na++] = z;
692
z = makerule(z->name);
693
#if DEBUG
694
if (z->dynamic & D_alias)
695
error(PANIC, "multiple alias from %s to %s", z->name, x->name);
696
#endif
697
}
698
if (z != x && z != r)
699
{
700
#if DEBUG
701
if (state.test & 0x00000040)
702
error(2, " z=%s%s%s", z->name, z->uname ? "==" : null, z->uname ? z->uname : null);
703
#endif
704
x->dynamic |= (D_alias|D_bound);
705
merge(x, z, MERGE_ALL|MERGE_BOUND);
706
a[na++] = x;
707
x = z;
708
}
709
}
710
if (x->dynamic & D_bound)
711
{
712
r->time = x->time;
713
r->view = x->view;
714
}
715
else
716
{
717
x->dynamic |= D_bound;
718
x->dynamic &= ~D_member;
719
x->time = r->time;
720
if (!(x->dynamic & D_source) || (x->property & P_target))
721
x->view = r->view;
722
}
723
s = r->uname = r->name;
724
r->name = x->name;
725
if (d)
726
{
727
if (state.fsview && strchr(s, '/') && strchr(r->name, '/') && !streq(s, r->name))
728
{
729
debug((-5, "%s and %s are bound in %s", s, r->name, d->name));
730
putbound(s, d->name);
731
putbound(r->name, d->name);
732
}
733
else if (s[0] == '.' && s[1] == '.' && s[2] == '/' && ((n = strlen(r->name)) < (i = strlen(s)) || r->name[n - i - 1] != '/' || !streq(s, r->name + n - i)))
734
putbound(s, d->name);
735
}
736
if (!(state.questionable & 0x00002000))
737
{
738
if ((!x->uname || x->uname[0] != '.' && x->uname[1] != '.' && x->uname[2] != '/') && ((s = getbound(x->name)) || x->uname && (s = getbound(x->uname))))
739
{
740
debug((-5, "%s rebind %s => %s", r->name, getbound(r->name), s));
741
putbound(r->name, s);
742
}
743
else if ((!r->uname || r->uname[0] != '.' && r->uname[1] != '.' && r->uname[2] != '/') && ((s = getbound(r->name)) || r->uname && (s = getbound(r->uname))))
744
{
745
debug((-5, "%s rebind %s => %s", x->name, getbound(x->name), s));
746
putbound(x->name, s);
747
}
748
else if (r->uname && (n = strlen(r->name)) > (i = strlen(r->uname)) && r->name[n-=i+1] == '/')
749
{
750
r->name[n] = 0;
751
s = (z = getrule(r->name)) ? z->name : strdup(r->name);
752
r->name[n] = '/';
753
debug((-5, "%s and %s are bound in %s", r->name, r->uname, s));
754
putbound(r->name, s);
755
putbound(r->uname, s);
756
}
757
else
758
{
759
debug((-5, "no rebind for %s or %s", unbound(r), unbound(x)));
760
s = 0;
761
}
762
for (i = 0; i < na; i++)
763
{
764
if (s)
765
putbound(a[i]->name, s);
766
x->attribute |= a[i]->attribute;
767
}
768
for (i = 0; i < na; i++)
769
a[i]->attribute |= x->attribute;
770
r->attribute |= x->attribute;
771
}
772
return x;
773
}
774
775
/*
776
* return local view rule for r if defined
777
* force forces the rule to be allocated
778
* 0 always returned if !state && == r or if not in local view
779
*/
780
781
static Rule_t*
782
localrule(register Rule_t* r, int force)
783
{
784
register char* s;
785
register Rule_t* x;
786
char* p;
787
char* v;
788
Sfio_t* tmp;
789
790
if (r->property & P_state)
791
return force ? 0 : r;
792
if (r->dynamic & D_alias)
793
r = makerule(r->name);
794
if (!r->view)
795
return 0;
796
if (!strncmp(r->name, state.view[r->view].path, state.view[r->view].pathlen))
797
{
798
s = r->name + state.view[r->view].pathlen;
799
switch (*s++)
800
{
801
case 0:
802
return internal.dot;
803
case '/':
804
if (!(x = getrule(s)) && force)
805
x = makerule(s);
806
if (x && (x->dynamic & D_alias))
807
x = makerule(x->name);
808
if (x && !x->view && (x != r || force))
809
{
810
merge(r, x, MERGE_ATTR|MERGE_FORCE);
811
x->uname = r->uname;
812
x->time = r->time;
813
x->status = r->status;
814
return x;
815
}
816
return 0;
817
}
818
}
819
p = 0;
820
s = r->name;
821
v = state.view[r->view].path;
822
while (*s && *s == *v++)
823
if (*s++ == '/')
824
p = s;
825
if (p)
826
{
827
s = internal.pwd;
828
v--;
829
while (s = strchr(s, '/'))
830
if (!strcmp(++s, v))
831
{
832
tmp = sfstropen();
833
*--s = 0;
834
sfprintf(tmp, "%s/%s", internal.pwd, p);
835
v = sfstruse(tmp);
836
*s = '/';
837
if (!(x = getrule(v)) && force)
838
x = makerule(v);
839
if (x && (x->dynamic & D_alias))
840
x = makerule(x->name);
841
sfstrclose(tmp);
842
if (x && !x->view && (force || x != r))
843
{
844
merge(r, x, MERGE_ATTR);
845
if (!x->uname)
846
x->uname = r->uname;
847
if (!x->time)
848
x->time = r->time;
849
return x;
850
}
851
return 0;
852
}
853
}
854
return 0;
855
}
856
857
/*
858
* bind a rule to a file
859
*/
860
861
Rule_t*
862
bindfile(register Rule_t* r, char* name, int flags)
863
{
864
register Rule_t* d;
865
register File_t* f;
866
register char* s;
867
List_t* p;
868
File_t* files;
869
File_t* ofiles;
870
char* dir = 0;
871
char* base;
872
char* b;
873
int found;
874
int i;
875
int n;
876
int c;
877
int ndirs;
878
int allocated = 0;
879
int aliased = 0;
880
int reassoc = 0;
881
unsigned int view;
882
Time_t tm;
883
Stat_t st;
884
Rule_t* a;
885
Rule_t* od;
886
Rule_t* x;
887
Rule_t* z;
888
List_t* dirs[5];
889
List_t dot;
890
Sfio_t* buf;
891
Sfio_t* tmp;
892
893
static Dir_t tmp_dir;
894
static File_t tmp_file = { 0, &tmp_dir, NOTIME };
895
896
if (r || (r = getrule(name)))
897
{
898
if ((r->property & P_state) || (r->property & P_virtual) && !(flags & BIND_FORCE))
899
return 0;
900
if (r->dynamic & D_alias)
901
{
902
a = r;
903
r = makerule(unbound(r));
904
if (r == a)
905
{
906
error(1, "%s: alias loop", r->name);
907
r->dynamic &= ~D_alias;
908
}
909
}
910
if (r->dynamic & D_bound)
911
return r;
912
if (!name)
913
name = r->name;
914
}
915
buf = sfstropen();
916
tmp = sfstropen();
917
for (;;)
918
{
919
found = 0;
920
view = 0;
921
od = 0;
922
923
/*
924
* at this point name!=r->name is possible
925
*/
926
927
#if _WINIX
928
if (*name == '/' || isalpha(*name) && *(name + 1) == ':' && (*(name + 2) == '/' || *(name + 2) == '\\'))
929
#else
930
if (*name == '/')
931
#endif
932
{
933
sfputr(buf, name, 0);
934
s = sfstrseek(buf, 0, SEEK_SET);
935
canon(s);
936
if (!rstat(s, &st, 0))
937
{
938
tm = tmxgetmtime(&st);
939
f = 0;
940
found = 1;
941
}
942
else if (state.maxview && !state.fsview)
943
for (i = 0; i <= state.maxview; i++)
944
{
945
if (!strncmp(s, state.view[i].root, n = state.view[i].rootlen) && (!*(s + n) || *(s + n) == '/'))
946
{
947
if (!*(s += n + 1))
948
s = internal.dot->name;
949
for (i = 0; i <= state.maxview; i++)
950
{
951
sfprintf(internal.nam, "%s/%s", state.view[i].root, s);
952
if (!rstat(b = sfstruse(internal.nam), &st, 0))
953
{
954
sfputr(buf, b, 0);
955
tm = tmxgetmtime(&st);
956
f = 0;
957
found = 1;
958
#if 0 /* not sure about this */
959
view = i;
960
#endif
961
break;
962
}
963
}
964
break;
965
}
966
}
967
break;
968
}
969
970
/*
971
* dir contains the directory path name component (usually 0)
972
* base contains the base path name component
973
*/
974
975
edit(tmp, name, KEEP, DELETE, DELETE);
976
dir = sfstruse(tmp);
977
if (*dir)
978
base = name + strlen(dir) + 1;
979
else
980
{
981
dir = 0;
982
base = name;
983
}
984
985
/*
986
* gather the directories to search in reverse order
987
*/
988
989
#if DEBUG
990
message((-11, "bindfile(%s): dir=%s base=%s", name, dir ? dir : internal.dot->name, base));
991
#endif
992
ndirs = 0;
993
if (!(flags & BIND_DOT))
994
{
995
if (!r)
996
a = associate(internal.source_p, NiL, name, NiL);
997
else if (name == r->name)
998
a = associate(internal.source_p, r, NiL, NiL);
999
else
1000
a = 0;
1001
if (!a || !(a->property & P_force))
1002
{
1003
if ((x = internal.source) != a)
1004
{
1005
if (!(x->dynamic & D_cached))
1006
x = source(x);
1007
if ((p = x->prereqs) && (p->rule != internal.dot || (p = p->next)))
1008
{
1009
DEBUGSOURCE(ndirs, x, p);
1010
dirs[ndirs++] = p;
1011
}
1012
}
1013
if ((flags & BIND_MAKEFILE) && (x = catrule(internal.source->name, external.source, NiL, 0)) && x != a)
1014
{
1015
if (!(x->dynamic & D_cached))
1016
x = source(x);
1017
if ((p = x->prereqs) && (p->rule != internal.dot || (p = p->next)))
1018
{
1019
DEBUGSOURCE(ndirs, x, p);
1020
dirs[ndirs++] = p;
1021
}
1022
}
1023
edit(buf, name, DELETE, internal.source->name, KEEP);
1024
if ((z = getrule(sfstruse(buf))) && z != x && z != internal.source && z != internal.source_p)
1025
{
1026
if (!(z->dynamic & D_cached))
1027
z = source(z);
1028
if ((p = z->prereqs) && (p->rule != internal.dot || (p = p->next)))
1029
{
1030
DEBUGSOURCE(ndirs, z, p);
1031
dirs[ndirs++] = p;
1032
}
1033
}
1034
}
1035
if (a)
1036
{
1037
if (!(a->dynamic & D_cached))
1038
a = source(a);
1039
if ((p = a->prereqs) && (p->rule != internal.dot || (p = p->next)))
1040
{
1041
DEBUGSOURCE(ndirs, a, p);
1042
dirs[ndirs++] = p;
1043
}
1044
}
1045
}
1046
dot.rule = internal.dot;
1047
dot.next = 0;
1048
#if DEBUG
1049
message((-14, " [%d] %s", ndirs, internal.dot->name));
1050
#endif
1051
dirs[ndirs++] = &dot;
1052
1053
/*
1054
* the nested loops preserve the directory search order
1055
*
1056
* . current directory
1057
* <source>.<pattern> alternate directories (may pre-empt)
1058
* <source>.x suffix association directories
1059
* <source> default source directories
1060
*/
1061
1062
files = getfile(base);
1063
ofiles = 0;
1064
1065
/*
1066
* first check if r is an archive member
1067
*/
1068
1069
if (r && r->active && (r->active->parent->target->property & P_archive) && !(r->dynamic & D_membertoo))
1070
{
1071
Dir_t* ar;
1072
1073
i = 0;
1074
for (f = files; f; f = f->next)
1075
if (r->active->parent->target->name == f->dir->name && f->dir->archive)
1076
{
1077
i = 1;
1078
if (r->dynamic & D_member)
1079
error(1, "%s is duplicated within %s", r->name, r->active->parent->target->name);
1080
if (f->time >= r->time)
1081
{
1082
r->dynamic |= D_member;
1083
r->time = f->time;
1084
}
1085
}
1086
if (!i && (ar = getar(r->active->parent->target->name)) && (i = ar->truncate) && strlen(base) > i)
1087
{
1088
c = base[i];
1089
base[i] = 0;
1090
for (f = getfile(base); f; f = f->next)
1091
{
1092
if (r->active->parent->target->name == f->dir->name && f->dir->archive)
1093
{
1094
if (r->dynamic & D_member)
1095
error(1, "%s is duplicated within %s", r->name, r->active->parent->target->name);
1096
if (f->time >= r->time)
1097
{
1098
r->dynamic |= D_member;
1099
r->time = f->time;
1100
}
1101
}
1102
}
1103
base[i] = c;
1104
}
1105
}
1106
1107
/*
1108
* now check the directories
1109
*/
1110
1111
view = state.maxview;
1112
for (i = ndirs; i-- > 0;)
1113
{
1114
for (p = dirs[i]; p; p = p->next)
1115
{
1116
d = p->rule;
1117
if (!(d->mark & M_directory))
1118
{
1119
/*UNDENT*/
1120
d->mark |= M_directory;
1121
c = (s = dir) && (s[0] != '.' || s[1] != '.' || s[2] != '/' && s[2] != 0);
1122
if (c && (d->property & P_terminal))
1123
{
1124
if (state.test & 0x00000008)
1125
error(2, "prune: %s + %s TERM", d->name, s);
1126
continue;
1127
}
1128
if (!(d->dynamic & D_scanned))
1129
{
1130
dirscan(d);
1131
files = getfile(base);
1132
}
1133
od = d;
1134
if (s)
1135
{
1136
if (c)
1137
{
1138
if (s = strchr(s, '/'))
1139
*s = 0;
1140
z = catrule(d->name, "/", dir, -1);
1141
if (z->dynamic & (D_entries|D_scanned))
1142
{
1143
if (s)
1144
*s = '/';
1145
if (!(z->dynamic & D_entries))
1146
continue;
1147
}
1148
else
1149
{
1150
for (f = getfile(dir), b = d->name; f; f = f->next)
1151
if (f->dir->name == b)
1152
break;
1153
if (!f && !(z->uname))
1154
{
1155
z->dynamic |= D_scanned;
1156
z->dynamic &= ~D_entries;
1157
if (s)
1158
*s = '/';
1159
if (state.test & 0x00000008)
1160
error(2, "prune: %s + %s HASH", d->name, dir);
1161
continue;
1162
}
1163
if (s)
1164
{
1165
*s = '/';
1166
z->dynamic |= D_entries;
1167
}
1168
}
1169
if (s)
1170
d = catrule(d->name, "/", dir, -1);
1171
else
1172
d = z;
1173
}
1174
else if (!(state.questionable & 0x00000080))
1175
d = catrule(d->name, "/", dir, -1);
1176
else
1177
for (;;)
1178
if (*s++ != '.' || *s++ != '.' || *s++ != '/')
1179
{
1180
d = *(s - 1) ? catrule(d->name, "/", dir, -1) : makerule(dir);
1181
break;
1182
}
1183
if (!(d->dynamic & D_scanned))
1184
{
1185
d->view = od->view;
1186
dirscan(d);
1187
files = getfile(base);
1188
}
1189
}
1190
if (!(d->dynamic & D_entries))
1191
continue;
1192
else if (!files && name[0] == '.' && (name[1] == 0 || name[1] == '/' || name[1] == '.' && (name[2] == 0 || name[2] == '/' || state.fsview && name[2] == '.' && (name[3] == 0 || name[3] == '/'))))
1193
{
1194
tmp_dir.name = d->name;
1195
ofiles = files;
1196
files = &tmp_file;
1197
}
1198
#if DEBUG
1199
message((-11, "bindfile(%s): dir=%s", name, d->name));
1200
#endif
1201
if (d->view <= view)
1202
{
1203
for (f = files; f; f = f->next)
1204
{
1205
s = f->dir->name;
1206
if (s == d->name && !f->dir->archive)
1207
{
1208
if (s == internal.dot->name)
1209
sfputr(buf, base, -1);
1210
else
1211
sfprintf(buf, "%s/%s", s, base);
1212
tm = f->time;
1213
s = sfstruse(buf);
1214
canon(s);
1215
st.st_mode = 0;
1216
if (tm == NOTIME)
1217
{
1218
x = 0;
1219
if (state.believe && d->view >= (state.believe - 1))
1220
{
1221
if (!r)
1222
r = makerule(name);
1223
r->view = d->view;
1224
r->mark |= M_bind;
1225
x = staterule(RULE, r, NiL, 0);
1226
r->mark &= ~M_bind;
1227
}
1228
if (x)
1229
{
1230
view = d->view;
1231
tm = x->time;
1232
message((-3, "%s: believe time [%s] from view %d", r->name, timestr(tm), view));
1233
}
1234
else if (rstat(s, &st, 0))
1235
tm = 0;
1236
else
1237
{
1238
tm = tmxgetmtime(&st);
1239
view = state.fsview ? iview(&st) : d->view;
1240
}
1241
}
1242
else
1243
view = d->view;
1244
if (tm)
1245
{
1246
if (!(flags & BIND_DOT) || !view)
1247
{
1248
if (view && state.fsview && state.expandview)
1249
mount(s, s, FS3D_GET|FS3D_VIEW|FS3D_SIZE(sfstrsize(buf)), NiL);
1250
found = 1;
1251
goto clear;
1252
}
1253
if (d->view > view)
1254
break;
1255
}
1256
else if (errno == ENODEV)
1257
view = d->view;
1258
}
1259
}
1260
}
1261
if (ofiles)
1262
{
1263
files = ofiles;
1264
ofiles = 0;
1265
}
1266
/*INDENT*/
1267
}
1268
}
1269
}
1270
clear:
1271
1272
/*
1273
* clear the visit marks
1274
*/
1275
1276
for (i = ndirs; i-- > 0;)
1277
for (p = dirs[i]; p; p = p->next)
1278
p->rule->mark &= ~M_directory;
1279
if (!found && r && (name == r->name || reassoc) && (a = associate(internal.bind_p, r, NiL, NiL)) && (b = call(a, name)) && (s = getarg(&b, NiL)))
1280
{
1281
char* t;
1282
1283
/*
1284
* [+|-] value [time]
1285
*
1286
* - name = name, time = time(value)
1287
* + name = value, time = OLDTIME
1288
* name = value, time = time(time)
1289
*/
1290
1291
if (streq(s, "-") || streq(s, "+"))
1292
{
1293
n = *s;
1294
s = getarg(&b, NiL);
1295
}
1296
else
1297
n = 0;
1298
if (s && !streq(s, name))
1299
{
1300
t = n ? getarg(&b, NiL) : (char*)0;
1301
message((-3, "%s name=%s n='%c' s=%s t=%s", a->name, name, n ? n : ' ', s, t));
1302
a = getrule(s);
1303
if (n == '+')
1304
{
1305
st.st_mode = 0;
1306
tmxsetmtime(&st, OLDTIME);
1307
sfputr(buf, s, 0);
1308
}
1309
else
1310
{
1311
if (t)
1312
st.st_mode = 0;
1313
else if (rstat(s, &st, 0))
1314
{
1315
if (!a || !(a->dynamic & D_bound) && !(a->property & P_target))
1316
{
1317
if (allocated)
1318
free(name);
1319
else
1320
allocated = 1;
1321
reassoc = !(state.questionable & 0x80000000);
1322
name = strdup(s);
1323
continue;
1324
}
1325
if (!(a->dynamic & D_bound))
1326
{
1327
st.st_mode = 0;
1328
tmxsetmtime(&st, 0);
1329
}
1330
else if (!a->time)
1331
{
1332
st.st_mode = 0;
1333
tm = CURTIME;
1334
tmxsetmtime(&st, tm);
1335
}
1336
else
1337
{
1338
st.st_mode = !(a->dynamic & D_regular);
1339
tmxsetmtime(&st, a->time);
1340
}
1341
}
1342
if (n == '-' || *b)
1343
{
1344
if (*s)
1345
{
1346
x = makerule(s);
1347
if (!(state.questionable & 0x00000004) && r != x && !r->time && !x->time && !(r->property & P_virtual))
1348
{
1349
r->property |= P_virtual;
1350
return bind(r);
1351
}
1352
putbound(name, x->name);
1353
}
1354
sfputr(buf, name, 0);
1355
}
1356
else
1357
{
1358
aliased = 1;
1359
sfputr(buf, s, 0);
1360
s = sfstrseek(buf, 0, SEEK_SET);
1361
canon(s);
1362
if (state.fsview && state.expandview && tmxgetmtime(&st) && iview(&st))
1363
mount(s, s, FS3D_GET|FS3D_VIEW|FS3D_SIZE(sfstrsize(buf)), NiL);
1364
}
1365
}
1366
tm = t ? timenum(t, NiL) : tmxgetmtime(&st);
1367
view = a ? a->view : state.maxview + 1;
1368
od = 0;
1369
found = 1;
1370
}
1371
else
1372
message((-3, "%s name=%s n='%c' s=%s", a->name, name, n ? n : ' ', s));
1373
}
1374
break;
1375
}
1376
if (!found && state.targetcontext && r && name != r->name && (x = getrule(base)) && (x->dynamic & D_context))
1377
{
1378
for (i = ndirs; i-- > 0;)
1379
{
1380
for (p = dirs[i]; p; p = p->next)
1381
{
1382
d = p->rule;
1383
if (!(d->mark & M_directory))
1384
{
1385
d->mark |= M_directory;
1386
if (d->name != internal.dot->name)
1387
{
1388
sfprintf(buf, "%s/%s", d->name, base);
1389
s = sfstruse(buf);
1390
canon(s);
1391
if ((x = getrule(s)) && (x->property & P_target))
1392
{
1393
found = 1;
1394
st.st_mode = 0;
1395
view = 0;
1396
tm = (x->time || (x = staterule(RULE, x, NiL, 0)) && x->time) ? x->time : CURTIME;
1397
goto context;
1398
}
1399
}
1400
}
1401
}
1402
}
1403
context:
1404
for (i = ndirs; i-- > 0;)
1405
for (p = dirs[i]; p; p = p->next)
1406
p->rule->mark &= ~M_directory;
1407
}
1408
if (found)
1409
{
1410
/*
1411
* the file exists with:
1412
*
1413
* buf canonical file path name
1414
* od original directory pointer
1415
* st file stat() info
1416
* tm file time
1417
* view view index of dir containing file
1418
*/
1419
1420
if (view > state.maxview)
1421
view = 0;
1422
b = sfstrseek(buf, 0, SEEK_SET);
1423
#if DEBUG
1424
message((-11, "bindfile(%s): path=%s rule=%s alias=%s view=%d time=%s", name, b, r ? r->name : (char*)0, (x = getrule(b)) && x != r ? x->name : (char*)0, view, timestr(tm)));
1425
#endif
1426
if (!r)
1427
r = makerule(name);
1428
if (internal.openfile)
1429
internal.openfile = r->name;
1430
if (!(r->dynamic & D_member) || tm > r->time)
1431
{
1432
if (r->dynamic & D_member)
1433
{
1434
r->dynamic &= ~D_member;
1435
r->dynamic |= D_membertoo;
1436
}
1437
r->time = tm;
1438
if (!(r->dynamic & D_entries))
1439
{
1440
if (S_ISREG(st.st_mode) || !st.st_mode)
1441
r->dynamic |= D_regular;
1442
if (!(r->dynamic & D_source) || (r->property & P_target))
1443
r->view = view;
1444
}
1445
if (!r->view && *b == '/')
1446
{
1447
if (strncmp(b, internal.pwd, internal.pwdlen) || *(b + internal.pwdlen) != '/')
1448
{
1449
if ((state.questionable & 0x00000800) || !(r->property & P_target))
1450
r->dynamic |= D_global;
1451
}
1452
else if ((r->dynamic & D_regular) && (x = getrule(b + internal.pwdlen + 1)) && x != r)
1453
r = bindalias(r, x, b + internal.pwdlen + 1, od, reassoc);
1454
}
1455
if (!(r->dynamic & D_global))
1456
r->preview = r->view;
1457
if (x = getrule(b))
1458
{
1459
if (x->dynamic & D_alias)
1460
x = makerule(x->name);
1461
else if (x == r && (r->property & P_terminal))
1462
{
1463
putrule(b, 0);
1464
x = 0;
1465
}
1466
}
1467
if (!(state.questionable & 0x00001000) && aliased && !x && !streq(name, r->name))
1468
x = makerule(name);
1469
if (x && x != r)
1470
{
1471
if (internal.openfile && st.st_mode)
1472
internal.openfile = x->name;
1473
if (r->property & x->property & P_target)
1474
{
1475
message((-2, "%s not aliased to %s", unbound(r), unbound(x)));
1476
if (!(state.questionable & 0x00000040))
1477
found = 0;
1478
}
1479
else if (r->dynamic & D_regular)
1480
r = bindalias(r, x, b, od, reassoc);
1481
}
1482
else
1483
{
1484
/*
1485
* bind the rule to file name in b
1486
* saving the unbound name
1487
*/
1488
1489
s = r->name;
1490
r->name = maprule(b, r);
1491
if (internal.openfile && st.st_mode)
1492
internal.openfile = r->name;
1493
if (r->name != s)
1494
{
1495
r->uname = s;
1496
if (od && (s != name || state.mam.statix || (n = strlen(r->name)) < (i = strlen(s)) || r->name[n - i - 1] != '/' || !streq(s, r->name + n - i)))
1497
putbound(s, od->name);
1498
}
1499
}
1500
if ((r->dynamic & D_source) && r->uname)
1501
r->view = r->preview = view;
1502
if ((r->dynamic & D_regular) && r->view && (x = localrule(r, 0)))
1503
merge(x, r, MERGE_ALL|MERGE_BOUND);
1504
}
1505
else if (!state.accept && !view)
1506
r->view = r->active ? r->active->parent->target->view : state.maxview;
1507
}
1508
else if (!r)
1509
{
1510
if (!(flags & BIND_RULE))
1511
goto done;
1512
r = makerule(name);
1513
}
1514
1515
/*
1516
* propagate pattern association attributes
1517
*/
1518
1519
bindattribute(r);
1520
1521
/*
1522
* archive binding and final checks
1523
*/
1524
1525
if (found)
1526
{
1527
if (r->scan == SCAN_IGNORE)
1528
r->dynamic |= D_scanned;
1529
else if ((r->property & (P_archive|P_target)) == (P_archive|P_target))
1530
arscan(r);
1531
1532
/*
1533
* if name is partially qualified then check for
1534
* alias bindings in the path suffixes of name
1535
*/
1536
1537
if (!(state.questionable & 0x00010000) && dir && (r->dynamic & D_regular) && *(s = name) != '/')
1538
while (s = strchr(s, '/'))
1539
if ((a = getrule(++s)) && !(a->dynamic & D_bound))
1540
bindfile(a, NiL, 0);
1541
}
1542
else if (!(r->dynamic & D_member))
1543
{
1544
r->time = ((r->property & P_dontcare) || !(flags & BIND_FORCE)) ? 0 : CURTIME;
1545
if (r->property & P_dontcare)
1546
r->view = state.maxview;
1547
}
1548
done:
1549
if (allocated)
1550
free(name);
1551
sfstrclose(buf);
1552
sfstrclose(tmp);
1553
return r;
1554
}
1555
1556
/*
1557
* propagate pattern association attributes
1558
*/
1559
1560
void
1561
bindattribute(register Rule_t* r)
1562
{
1563
register Rule_t* x;
1564
register Rule_t* z;
1565
1566
r->dynamic |= D_bound;
1567
if (x = associate(internal.attribute_p, r, NiL, NiL))
1568
{
1569
merge(x, r, MERGE_ASSOC|MERGE_ATTR);
1570
*x->name = ATTRCLEAR;
1571
if (z = getrule(x->name))
1572
negate(z, r);
1573
*x->name = ATTRNAME;
1574
}
1575
}
1576
1577
/*
1578
* bind a rule, possibly changing the rule name
1579
*/
1580
1581
Rule_t*
1582
bind(register Rule_t* r)
1583
{
1584
register Rule_t* b;
1585
1586
if (!r)
1587
return 0;
1588
if (r->dynamic & D_alias)
1589
r = makerule(r->name);
1590
if (r->dynamic & D_bound)
1591
return r;
1592
switch (r->property & (P_state|P_virtual))
1593
{
1594
case 0:
1595
if (b = bindfile(r, NiL, 0))
1596
return b;
1597
break;
1598
case P_state:
1599
if (b = bindstate(r, NiL))
1600
{
1601
if (state.mam.regress && (r->property & P_statevar))
1602
dumpregress(state.mam.out, "bind", r->name, r->statedata);
1603
return b;
1604
}
1605
break;
1606
case P_virtual:
1607
r->time = staterule(RULE, r, NiL, 1)->time;
1608
break;
1609
}
1610
bindattribute(r);
1611
return r;
1612
}
1613
1614
/*
1615
* rebind rule r
1616
* op > 0 skips bindfile()
1617
* op < 0 skips statetime()
1618
*/
1619
1620
void
1621
rebind(register Rule_t* r, register int op)
1622
{
1623
char* t;
1624
Rule_t* x;
1625
1626
if (!(r->property & P_state))
1627
{
1628
if (r->uname)
1629
oldname(r);
1630
r->dynamic &= ~(D_bound|D_entries|D_member|D_scanned);
1631
if (op > 0)
1632
r->dynamic |= D_bound;
1633
else
1634
{
1635
newfile(r, NiL, NOTIME);
1636
if ((t = strchr(r->name, '/')) && (x = getrule(t + 1)) && (x = bindfile(x, NiL, 0)))
1637
r = x;
1638
else
1639
bindfile(r, NiL, 0);
1640
}
1641
if (op >= 0)
1642
r->dynamic |= D_triggered;
1643
if (!state.exec)
1644
{
1645
r->time = CURTIME;
1646
r->status = EXISTS;
1647
}
1648
else if (op >= 0)
1649
{
1650
statetime(r, !op);
1651
r->status = r->time ? EXISTS : (op || (r->property & P_dontcare)) ? IGNORE : FAILED;
1652
}
1653
}
1654
else if (r->property & P_statevar)
1655
{
1656
if (op <= 0)
1657
r->dynamic &= ~D_bound;
1658
if (!(r->dynamic & D_bound) && !(r = bindstate(r, NiL)))
1659
return;
1660
if (op > 0)
1661
r->time = OLDTIME;
1662
}
1663
message((-2, "%s(%s) = %s", op > 0 ? "accept" : "rebind", r->name, timestr(r->time)));
1664
}
1665
1666
/*
1667
* remove binding on r
1668
* candidates have s==0 or r->mark==1
1669
* h!=0 for alias reference
1670
*/
1671
1672
int
1673
unbind(const char* s, char* v, void* h)
1674
{
1675
register Rule_t* r = (Rule_t*)v;
1676
1677
if (!s || !h && (r->mark & M_mark) || h && (r->dynamic & D_alias) && (makerule(r->name)->mark & M_mark))
1678
{
1679
message((-2, "unbind(%s)%s%s", r->name, h ? " check-alias" : null, s && streq(s, r->name) ? null : " diff-hash"));
1680
r->mark &= ~M_mark;
1681
if (r->property & P_metarule)
1682
r->uname = 0;
1683
else
1684
{
1685
int u = 0;
1686
1687
if (!(r->property & P_state))
1688
{
1689
newfile(r, NiL, NOTIME);
1690
if (r->uname)
1691
{
1692
oldname(r);
1693
u = 1;
1694
}
1695
}
1696
else if (r->property & P_staterule)
1697
{
1698
error(2, "%s: cannot unbind staterules", r->name);
1699
return 0;
1700
}
1701
r->dynamic &= ~(D_bound|D_entries|D_global|D_member|D_membertoo|D_regular|D_scanned);
1702
r->must = 0;
1703
r->scan = 0;
1704
r->status = NOTYET;
1705
r->time = 0;
1706
if (u || !(r->dynamic & D_source) || (r->property & P_target))
1707
{
1708
r->preview = 0;
1709
r->view = 0;
1710
}
1711
}
1712
}
1713
return 0;
1714
}
1715
1716
/*
1717
* append views of absolute path s to source list z
1718
*/
1719
1720
static List_t*
1721
absolute(List_t* z, char* s, Sfio_t* tmp)
1722
{
1723
int i;
1724
int j;
1725
int n;
1726
Rule_t* x;
1727
char* t;
1728
1729
if (state.questionable & 0x00000004)
1730
return z;
1731
for (i = 0; i < state.maxview; i++)
1732
{
1733
if (!strncmp(s, state.view[i].root, n = state.view[i].rootlen) && (!*(s + n) || *(s + n) == '/'))
1734
{
1735
s += n;
1736
j = i;
1737
while (++j <= state.maxview)
1738
{
1739
sfprintf(tmp, "%s%s", state.view[j].root, s);
1740
t = sfstruse(tmp);
1741
if (!(x = getrule(t)))
1742
x = makerule(t);
1743
if (!(x->mark & M_directory))
1744
{
1745
x->mark |= M_directory;
1746
z = z->next = cons(x, NiL);
1747
}
1748
}
1749
break;
1750
}
1751
}
1752
return z;
1753
}
1754
1755
/*
1756
* fix up .SOURCE prereqs after user assertion
1757
*/
1758
1759
Rule_t*
1760
source(register Rule_t* r)
1761
{
1762
register Rule_t* x;
1763
1764
if (state.compile > COMPILED)
1765
return r;
1766
if (state.compile < COMPILED)
1767
{
1768
x = r;
1769
r = catrule(x->name, internal.internal->name, NiL, 1);
1770
#if _HUH_2001_10_31
1771
freelist(r->prereqs);
1772
#endif
1773
r->prereqs = listcopy(x->prereqs);
1774
r->dynamic |= D_compiled | (x->dynamic & D_dynamic);
1775
r->property |= P_readonly;
1776
}
1777
r->dynamic |= D_cached;
1778
if (r->dynamic & D_dynamic)
1779
dynamic(r);
1780
if (state.maxview && !state.fsview)
1781
{
1782
register char* s;
1783
register char* t;
1784
register List_t* p;
1785
int dot;
1786
unsigned int view;
1787
List_t* z;
1788
List_t lst;
1789
Sfio_t* tmp;
1790
1791
/*
1792
* recompute view cross product
1793
*
1794
* . unit multiplication operand
1795
* A absolute path rooted at /
1796
* R path relative to .
1797
*
1798
* lhs rhs cross-product
1799
* ---- ----- -------------
1800
* . . . *note (1)*
1801
* . A A *note (2)*
1802
* . R R
1803
* A . A
1804
* A R A/R
1805
* A A A *note (2)*
1806
* R . R
1807
* R A A *note (2)*
1808
* R R R/R
1809
*
1810
* (1) the first . lhs operand produces a . in the product
1811
*
1812
* (2) the first A rhs operand is placed in the product
1813
*/
1814
1815
debug((-5, "%s: recompute view cross product", r->name));
1816
tmp = sfstropen();
1817
z = &lst;
1818
z->next = 0;
1819
if (state.strictview)
1820
{
1821
/*
1822
* this follows 3d fs semantics
1823
*/
1824
1825
for (p = r->prereqs; p; p = p->next)
1826
{
1827
if (*(t = unbound(p->rule)) == '/')
1828
{
1829
sfputr(tmp, t, -1);
1830
t = sfstruse(tmp);
1831
pathcanon(t, 0, 0);
1832
if (!(x = getrule(t)))
1833
x = makerule(t);
1834
if (!(x->mark & M_directory))
1835
{
1836
x->mark |= M_directory;
1837
z = z->next = cons(x, NiL);
1838
}
1839
if (*(t = unbound(x)) == '/')
1840
z = absolute(z, t, tmp);
1841
}
1842
else if (!p->rule->view)
1843
{
1844
dot = (*t == '.' && !*(t + 1));
1845
for (view = 0; view <= state.maxview; view++)
1846
{
1847
#if BINDINDEX
1848
s = state.view[view].path->name;
1849
#else
1850
s = state.view[view].path;
1851
#endif
1852
if (dot || *s != '.' || *(s + 1))
1853
{
1854
if (dot)
1855
sfputr(tmp, s, -1);
1856
else
1857
sfprintf(tmp, "%s/%s", s, t);
1858
}
1859
else
1860
sfputr(tmp, t, -1);
1861
s = sfstruse(tmp);
1862
pathcanon(s, 0, 0);
1863
x = makerule(s);
1864
if (!(x->dynamic & D_source))
1865
{
1866
x->dynamic |= D_source;
1867
if (x->view < view)
1868
x->view = view;
1869
}
1870
if (!(x->mark & M_directory))
1871
{
1872
x->mark |= M_directory;
1873
z = z->next = cons(x, NiL);
1874
}
1875
}
1876
}
1877
}
1878
}
1879
else
1880
{
1881
List_t* q;
1882
int dotted = 0;
1883
1884
q = r->prereqs;
1885
do
1886
{
1887
for (view = 0; view <= state.maxview; view++)
1888
{
1889
#if BINDINDEX
1890
s = state.view[view].path->name;
1891
#else
1892
s = state.view[view].path;
1893
#endif
1894
if ((dot = (*s == '.' && !*(s + 1))) && !dotted)
1895
{
1896
dotted = 1;
1897
#if BINDINDEX
1898
z = z->next = cons(state.view[view].path, NiL);
1899
#else
1900
z = z->next = cons(makerule(s), NiL);
1901
#endif
1902
}
1903
for (p = q; p; p = p->next)
1904
{
1905
if (*(t = unbound(p->rule)) == '/')
1906
{
1907
z = absolute(z, t, tmp);
1908
break;
1909
}
1910
if (!p->rule->view || (p->rule->property & P_target) && !strchr(t, '/'))
1911
{
1912
if (*t == '.' && !*(t + 1))
1913
{
1914
if (!dotted)
1915
{
1916
dotted = 1;
1917
sfputr(tmp, t, -1);
1918
t = sfstruse(tmp);
1919
pathcanon(t, 0, 0);
1920
z = z->next = cons(makerule(t), NiL);
1921
}
1922
if (dot)
1923
continue;
1924
sfputr(tmp, s, -1);
1925
}
1926
else
1927
{
1928
if (dot)
1929
sfputr(tmp, t, -1);
1930
else
1931
sfprintf(tmp, "%s/%s", s, t);
1932
}
1933
t = sfstruse(tmp);
1934
pathcanon(t, 0, 0);
1935
x = makerule(t);
1936
if (!(x->dynamic & D_source))
1937
{
1938
x->dynamic |= D_source;
1939
if (x->view < view)
1940
x->view = view;
1941
}
1942
if (!(x->mark & M_directory))
1943
{
1944
x->mark |= M_directory;
1945
z = z->next = cons(x, NiL);
1946
}
1947
}
1948
}
1949
}
1950
for (; p && *(t = unbound(p->rule)) == '/'; p = p->next)
1951
{
1952
sfputr(tmp, t, -1);
1953
t = sfstruse(tmp);
1954
pathcanon(t, 0, 0);
1955
if (!(x = getrule(t)))
1956
x = makerule(t);
1957
if (!(x->mark & M_directory))
1958
{
1959
x->mark |= M_directory;
1960
z = z->next = cons(x, NiL);
1961
}
1962
if (*(s = unbound(x)) == '/')
1963
z = absolute(z, s, tmp);
1964
}
1965
} while (q = p);
1966
}
1967
sfstrclose(tmp);
1968
freelist(r->prereqs);
1969
for (r->prereqs = p = lst.next; p; p = p->next)
1970
p->rule->mark &= ~M_directory;
1971
}
1972
return r;
1973
}
1974
1975
#if BINDINDEX
1976
/*
1977
* copy path name of r to s
1978
* end of s is returned
1979
*/
1980
1981
char*
1982
pathname(register char* s, register Rule_t* r)
1983
{
1984
if ((r->dynamic & D_bound) && !(r->property & (P_state|P_virtual)) && *r->name != '/')
1985
{
1986
if (!state.logical && r->view && !(r->dynamic & D_bindindex))
1987
{
1988
s = strcopy(s, state.view[r->view].path);
1989
*s++ = '/';
1990
}
1991
if (r->source && !(r->dynamic & D_bindindex))
1992
{
1993
s = strcopy(s, state.source[r->source].path);
1994
*s++ = '/';
1995
}
1996
}
1997
return strcopy(s, r->name);
1998
}
1999
#endif
2000
2001
/*
2002
* return local view path name for r
2003
*/
2004
2005
char*
2006
localview(register Rule_t* r)
2007
{
2008
register Rule_t* x;
2009
int i;
2010
2011
if (r->dynamic & D_alias)
2012
r = makerule(unbound(r));
2013
if (state.context && !(r->property & (P_state|P_virtual)))
2014
{
2015
register char* s = r->name;
2016
2017
if (*s == '/' || iscontext(s))
2018
return s;
2019
sfprintf(state.context, "%c%s%c", MARK_CONTEXT, s, MARK_CONTEXT);
2020
x = makerule(sfstruse(state.context));
2021
if (!(x->dynamic & D_alias))
2022
{
2023
x->property |= P_internal;
2024
x->dynamic |= D_alias;
2025
x->uname = x->name;
2026
x->name = s;
2027
}
2028
return x->uname;
2029
}
2030
if (!state.maxview || state.fsview && !state.expandview)
2031
return r->name;
2032
if (x = localrule(r, 1))
2033
return x->name;
2034
if (r->view && r->uname)
2035
{
2036
if (state.mam.statix)
2037
{
2038
if (*r->name != '/')
2039
return r->name;
2040
for (i = 1; i <= state.maxview; i++)
2041
if (strneq(r->name, state.view[i].path, state.view[i].pathlen) && r->name[state.view[i].pathlen] == '/')
2042
return r->name + state.view[i].pathlen + 1;
2043
}
2044
return r->uname;
2045
}
2046
return r->name;
2047
}
2048
2049