Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/nmake/scan.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1984-2011 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 language dependent scan support
26
*/
27
28
#include "make.h"
29
30
#include <tm.h>
31
32
#define SCAN_define (1<<0) /* enable D actions */
33
#define SCAN_macro (1<<1) /* macro (default line) style */
34
#define SCAN_nopropagate (1<<2) /* don't propagate scan index */
35
#define SCAN_state (1<<3) /* scan for state vars */
36
#define SCAN_override (1<<4) /* no scan override warning */
37
38
#define QUOTE_blank (1<<0) /* blank out quote */
39
#define QUOTE_comment (1<<1) /* comment quote type */
40
#define QUOTE_nested (1<<2) /* nesting quote */
41
#define QUOTE_newline (1<<3) /* newline terminates quote */
42
#define QUOTE_quote (1<<4) /* normal quote */
43
#define QUOTE_single (1<<5) /* quote next char */
44
#define QUOTE_space (1<<6) /* quote preceded by space */
45
46
#define ANY '\t' /* 0 or more internal code */
47
#define ARG '\n' /* grab arg internal code */
48
#define DIG '\b' /* 0 or more digit internal code*/
49
#define NAM '\v' /* 0 or more var internal code */
50
#define REP '\r' /* repeat group internal code */
51
#define SPC ' ' /* 0 or more space internal code*/
52
#define TOK '\f' /* 0 or more token chars */
53
54
#define SCANARGS 2 /* max number % arg matches */
55
#define SCANBUFFER 4096 /* scan buffer size */
56
57
typedef unsigned short Scanstate_t;
58
59
struct Quote_s; typedef struct Quote_s Quote_t;
60
61
typedef struct Action_s /* state action */
62
{
63
short type; /* action type id */
64
short flags; /* SCAN_* flags */
65
char* pattern; /* match expression */
66
char* map; /* path name map */
67
char* script; /* script */
68
struct
69
{
70
unsigned long clear; /* clear these */
71
unsigned long set; /* set these */
72
} attribute; /* attributes */
73
struct
74
{
75
unsigned long clear; /* clear these */
76
unsigned long set; /* set these */
77
} property; /* properties */
78
int attrprop; /* attribute|property mods */
79
int scan; /* scan index */
80
} Action_t;
81
82
struct Quote_s /* quote/comment match info */
83
{
84
Quote_t* next; /* next in list */
85
char* begin; /* begin pattern */
86
char* end; /* end pattern */
87
int escape; /* end escape char */
88
int flags; /* QUOTE_* flags */
89
};
90
91
typedef struct Scan_s /* scan info */
92
{
93
unsigned char type[UCHAR_MAX];/* SCAN_* types indexed by char */
94
int flags; /* SCAN_* flags */
95
char* external; /* external scan */
96
Action_t* before; /* do this before scanexec */
97
Action_t* after; /* do this after scanexec */
98
Quote_t* quote; /* quote patterns */
99
Action_t* action; /* action table */
100
Action_t* classid; /* classid action */
101
Scanstate_t* state; /* state transition table */
102
void* data; /* private data */
103
} Scan_t;
104
105
/*
106
* default scan strategies
107
*/
108
109
static Namval_t scantab[] =
110
{
111
".IGNORE", SCAN_IGNORE,
112
".NULL", SCAN_NULL,
113
".STATE", SCAN_STATE,
114
};
115
116
static Scan_t* strategy[SCAN_MAX+1];
117
118
/*
119
* initialize the scan atoms
120
*/
121
122
void
123
initscan(int repeat)
124
{
125
register int i;
126
register Rule_t* r;
127
128
if (!repeat)
129
for (i = 0; i < elementsof(scantab); i++)
130
{
131
r = catrule(internal.scan->name, scantab[i].name, NiL, 1);
132
r->property |= P_attribute;
133
r->scan = scantab[i].value;
134
addprereq(internal.scan, r, PREREQ_APPEND);
135
}
136
}
137
138
/*
139
* scan pattern sort -- strcmp(3) convention
140
*/
141
142
static int
143
scansort(register const char* a, register const char* b)
144
{
145
register const char* s;
146
147
while (*++a == *++b)
148
if (!*a)
149
return 0;
150
for (s = "* %@"; *s; s++)
151
if (*a == *s)
152
return 1;
153
else if (*b == *s)
154
return -1;
155
return *a - *b;
156
}
157
158
/*
159
* compile a branch of the expression tree
160
* next state pointer returned
161
*/
162
163
static Scanstate_t*
164
scanbranch(Scanstate_t* u, Action_t* action, Action_t* first, Action_t* last, register int i)
165
{
166
register Action_t* a;
167
Action_t* b;
168
Action_t* m;
169
Scanstate_t* v;
170
171
for (a = first; a <= last; a++)
172
{
173
if (a->pattern)
174
{
175
while (a->pattern[i])
176
{
177
v = u + 1;
178
m = a;
179
for (b = a + 1; b <= last; b++)
180
{
181
if (b->pattern && b->pattern[i] && b->pattern[i] != m->pattern[i])
182
{
183
*u++ = m->pattern[i];
184
*u++ = 0;
185
m = b;
186
}
187
}
188
if (m != a)
189
{
190
*u++ = m->pattern[i];
191
*u++ = 0;
192
*u++ = 0;
193
*u++ = 0;
194
m = a;
195
for (b = a + 1; b <= last; b++)
196
{
197
if (b->pattern && b->pattern[i] != m->pattern[i])
198
{
199
if ((*v = (u - v)) != (u - v))
200
error(3, "pattern transition offset %d too large", (u - v));
201
v += 2;
202
u = scanbranch(u, action, m, b - 1, i + 1);
203
m = b;
204
}
205
}
206
if ((*v = (u - v)) != (u - v))
207
error(3, "pattern transition offset %d too large", (u - v));
208
return scanbranch(u, action, m, last, i + 1);
209
}
210
switch (*u++ = a->pattern[i++])
211
{
212
case DIG:
213
case NAM:
214
case REP:
215
case SPC:
216
case TOK:
217
*u++ = 1;
218
break;
219
default:
220
*u++ = 3;
221
*u++ = 0;
222
*u++ = 0;
223
break;
224
}
225
}
226
*u++ = 0;
227
*u++ = a - action;
228
a->pattern = 0;
229
}
230
}
231
return u;
232
}
233
234
/*
235
* parse scan action for a in s
236
* s points to the first delimiter
237
*/
238
239
static void
240
scanaction(Action_t* a, register char* s)
241
{
242
register int c;
243
register int t;
244
register char* v;
245
register char* n;
246
Rule_t* u;
247
unsigned long m;
248
249
if (c = *s++)
250
do
251
{
252
v = n = s;
253
while (t = *s++)
254
{
255
if (t == c)
256
break;
257
if (t == '\\' && !(t = *s++))
258
break;
259
*n++ = t;
260
}
261
*n = 0;
262
if (!*v)
263
break;
264
switch (*v++)
265
{
266
case 'A':
267
n = tokopen(v, 1);
268
while (v = tokread(n))
269
{
270
if (((t = *v) == ATTRSET || t == ATTRCLEAR) && *(v + 1))
271
{
272
*v = ATTRNAME;
273
u = getrule(v);
274
*v = t;
275
if (!u)
276
u = getrule(v + 1);
277
}
278
else
279
u = getrule(v);
280
if (!u || !(u->property & P_attribute))
281
error(3, "%s: must be an attribute", v);
282
if (u->scan)
283
{
284
if (!a->scan)
285
a->scan = u->scan;
286
}
287
else if (u->attribute && !(u->property & P_ignore))
288
{
289
a->attrprop = 1;
290
if (t == '-')
291
a->attribute.clear |= u->attribute;
292
else
293
a->attribute.set |= u->attribute;
294
}
295
else if (m = u->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_local|P_make|P_multiple|P_parameter|P_repeat|P_terminal|P_virtual))
296
{
297
a->attrprop = 1;
298
if (t == '-')
299
a->property.clear |= m;
300
else
301
a->property.set |= m;
302
}
303
}
304
tokclose(n);
305
break;
306
case 'M':
307
if (a->map)
308
{
309
error(1, "%c: multiply defined", *(v - 1));
310
free(a->map);
311
}
312
a->map = strdup(v);
313
break;
314
case 'O':
315
for (;;)
316
{
317
switch (*v++)
318
{
319
case 0:
320
break;
321
case 'X':
322
a->flags |= SCAN_nopropagate;
323
continue;
324
default:
325
error(1, "%c: invalid match option", *(v - 1));
326
continue;
327
}
328
break;
329
}
330
break;
331
case 'R':
332
if (a->script)
333
{
334
error(1, "%c: multiply defined", *(v - 1));
335
free(a->script);
336
}
337
a->script = strdup(v);
338
break;
339
default:
340
error(1, "%c: invalid match operation", *(v - 1));
341
break;
342
}
343
} while (t);
344
}
345
346
/*
347
* compile scan description in r and return scan pointer
348
*/
349
350
static Scan_t*
351
scancompile(Rule_t* r, int flags)
352
{
353
register char* s;
354
register Scan_t* ss;
355
register Quote_t* q;
356
register int c;
357
int i;
358
int t;
359
int z;
360
int line;
361
char* file;
362
char* n;
363
char* v;
364
char* y;
365
char* x[128];
366
char** p;
367
Action_t* a;
368
Sfio_t* tmp;
369
370
z = 0;
371
p = x;
372
ss = newof(0, Scan_t, 1, 0);
373
ss->flags = flags;
374
tmp = sfstropen();
375
expand(tmp, r->action);
376
s = sfstruse(tmp);
377
file = error_info.file;
378
error_info.file = r->name;
379
line = error_info.line;
380
error_info.line = 0;
381
do
382
{
383
error_info.line++;
384
if (n = strchr(s, '\n'))
385
*n++ = 0;
386
switch (*s++)
387
{
388
case 0:
389
break;
390
case 'C':
391
ss->classid = newof(0, Action_t, 1, 0);
392
scanaction(ss->classid, s);
393
ss->data = hashalloc(NiL, HASH_set, HASH_ALLOCATE, HASH_name, r->name, 0);
394
break;
395
case 'D':
396
if (!(ss->flags & SCAN_define))
397
break;
398
/*FALLTHROUGH*/
399
case 'A':
400
case 'B':
401
case 'E':
402
case 'I':
403
case 'T':
404
if (*s)
405
{
406
if (p >= &x[elementsof(x) - 1])
407
error(3, "too many patterns");
408
*p++ = s - 1;
409
z += n ? (n - s) : strlen(s);
410
}
411
break;
412
case 'F':
413
ss->after = newof(0, Action_t, 1, 0);
414
scanaction(ss->after, s);
415
break;
416
case 'O':
417
c = isalnum(*s) ? 0 : *s++;
418
for (;;)
419
{
420
switch (*s++)
421
{
422
case 0:
423
break;
424
case 'M':
425
ss->flags |= SCAN_macro;
426
continue;
427
case 'O':
428
ss->flags |= SCAN_override;
429
continue;
430
case 'S':
431
ss->flags |= SCAN_state;
432
continue;
433
default:
434
if (*(s - 1) == c)
435
break;
436
error(1, "%c: invalid scan option", *(s - 1));
437
continue;
438
}
439
break;
440
}
441
break;
442
case 'Q':
443
if (c = *s++)
444
{
445
q = newof(0, Quote_t, 1, 0);
446
q->next = ss->quote;
447
ss->quote = q;
448
q->end = null;
449
z = 0;
450
do
451
{
452
v = y = s;
453
while (t = *s++)
454
{
455
if (t == c || t == '\\' && !(t = *s++))
456
break;
457
*y++ = t;
458
}
459
*y = 0;
460
switch (z++)
461
{
462
case 0:
463
q->begin = strdup(v);
464
break;
465
case 1:
466
if (!*(q->end = strdup(v)))
467
q->flags |= QUOTE_newline;
468
break;
469
case 2:
470
q->escape = *v;
471
break;
472
case 3:
473
for (;;)
474
{
475
switch (*v++)
476
{
477
case 0:
478
break;
479
case 'C':
480
q->flags |= QUOTE_comment;
481
continue;
482
case 'L':
483
q->flags |= QUOTE_newline;
484
continue;
485
case 'N':
486
q->flags |= QUOTE_nested;
487
continue;
488
case 'Q':
489
q->flags |= QUOTE_quote;
490
continue;
491
case 'S':
492
q->flags |= QUOTE_single;
493
continue;
494
case 'W':
495
q->flags |= QUOTE_space;
496
continue;
497
default:
498
error(1, "%c: invalid quote option", *(v - 1));
499
continue;
500
}
501
break;
502
}
503
break;
504
case 4:
505
break;
506
default:
507
error(1, "%s: too many quote fields", v - 1);
508
break;
509
}
510
} while (t);
511
ss->type[*q->begin] |= q->flags;
512
}
513
break;
514
case 'S':
515
ss->before = newof(0, Action_t, 1, 0);
516
scanaction(ss->before, s);
517
break;
518
case 'X':
519
if (*s)
520
s++;
521
if (ss->external)
522
{
523
error(1, "%s: external scan multiply defined", s - 1);
524
free(ss->external);
525
}
526
ss->external = strdup(s);
527
break;
528
default:
529
error(1, "%c: invalid scan directive", *(s - 1));
530
break;
531
}
532
} while (s = n);
533
if (p > x)
534
{
535
ss->action = a = newof(0, Action_t, p - x + 1, 0);
536
ss->state = newof(0, Scanstate_t, z * 4, 0);
537
z = p - x;
538
strsort(x, z, scansort);
539
*p = 0;
540
p = x;
541
while (s = *p++)
542
{
543
a++;
544
a->type = *s++;
545
c = *s++;
546
i = 0;
547
a->pattern = n = s;
548
while (t = *s++)
549
{
550
if (t == c)
551
break;
552
if (t == '\\')
553
{
554
if (!(t = *s++))
555
break;
556
switch (t)
557
{
558
case 'D':
559
t = DIG;
560
break;
561
case 'T':
562
t = TOK;
563
break;
564
case 'V':
565
t = NAM;
566
break;
567
}
568
if (n > a->pattern && *(n - 1) == t)
569
continue;
570
}
571
else if (isspace(t))
572
{
573
t = SPC;
574
if (n > a->pattern && *(n - 1) == t)
575
continue;
576
}
577
else if (t == '%')
578
{
579
i++;
580
t = ARG;
581
}
582
else if (t == '*')
583
t = ANY;
584
else if (t == '@')
585
t = REP;
586
*n++ = t;
587
}
588
scanaction(a, s - 1);
589
*n = 0;
590
switch (a->type)
591
{
592
case 'A':
593
case 'I':
594
if (!i)
595
error(3, "%% arg match missing from pattern [%s]", a->pattern);
596
if (i > SCANARGS)
597
error(3, "too many %% arg matches in pattern [%s]", a->pattern);
598
break;
599
}
600
}
601
scanbranch(ss->state, ss->action, ss->action + 1, ss->action + z, 0);
602
}
603
sfstrclose(tmp);
604
error_info.file = file;
605
error_info.line = line;
606
maketop(r, P_virtual, NiL);
607
if (r->dynamic & D_triggered)
608
{
609
message((-2, "%s forces re-scan", r->name));
610
hashwalk(table.rule, 0, forcescan, &r->scan);
611
}
612
return ss;
613
}
614
615
/*
616
* skip quotes in q
617
*/
618
619
static unsigned char*
620
scanquote(int fd, unsigned char* buf, unsigned char** p, register unsigned char* g, Quote_t* q, int flags)
621
{
622
register int c;
623
register unsigned char* t;
624
unsigned char* x;
625
unsigned char* y;
626
unsigned char* z;
627
int e;
628
629
for (x = g; q; q = q->next)
630
if ((flags & q->flags) && (t = (unsigned char*)q->begin) && *(g - 1) == *t++ && (!(q->flags & QUOTE_space) || (g - 1) == *p || *(g - 2) == ' ' || *(g - 2) == '\t'))
631
{
632
for (;;)
633
{
634
while (!(c = *g++))
635
{
636
if (*p >= buf + SCANBUFFER)
637
{
638
c = g - *p - 1;
639
memcpy(buf + SCANBUFFER - c, *p, c);
640
*p = buf + SCANBUFFER - c;
641
}
642
x = (buf + SCANBUFFER) - (g - x - 1);
643
if ((c = read(fd, g = buf + SCANBUFFER, SCANBUFFER)) <= 0)
644
{
645
g[0] = 0;
646
return g;
647
}
648
g[c] = 0;
649
}
650
if (!*t)
651
{
652
if (q->flags & QUOTE_single)
653
goto accept;
654
e = *q->end;
655
y = g;
656
for (;;)
657
{
658
if (c == '\n' && (q->flags & QUOTE_newline) && *(g - 2) != q->escape)
659
{
660
g--;
661
goto accept;
662
}
663
if (c == e && *(g - 2) != q->escape)
664
{
665
z = g;
666
t = (unsigned char*)q->end + 1;
667
/*UNDENT*/
668
for (;;)
669
{
670
if (!*t)
671
{
672
if (c == '\n')
673
g--;
674
goto accept;
675
}
676
while (!(c = *g++))
677
{
678
if (q->flags & QUOTE_comment)
679
{
680
c = g - z;
681
memcpy(buf + SCANBUFFER - c, z - 1, c);
682
z = buf + SCANBUFFER - c;
683
y = (buf + SCANBUFFER) - (g - y - 1);
684
x = (buf + SCANBUFFER) - (g - x - 1);
685
}
686
else
687
{
688
c = g - *p - 1;
689
memcpy(buf + SCANBUFFER - c, *p, c);
690
}
691
*p = buf + SCANBUFFER - c;
692
if ((c = read(fd, g = buf + SCANBUFFER, SCANBUFFER)) <= 0)
693
{
694
g[0] = 0;
695
return g;
696
}
697
g[c] = 0;
698
}
699
if (c != *t++)
700
{
701
g = z;
702
break;
703
}
704
}
705
/*INDENT*/
706
}
707
while (!(c = *g++))
708
{
709
if (*p >= buf + SCANBUFFER)
710
{
711
c = g - *p - 1;
712
memcpy(buf + SCANBUFFER - c, *p, c);
713
*p = buf + SCANBUFFER - c;
714
}
715
x = (buf + SCANBUFFER) - (g - x - 1);
716
y = (buf + SCANBUFFER) - (g - y - 1);
717
if ((c = read(fd, g = buf + SCANBUFFER, SCANBUFFER)) <= 0)
718
{
719
g[0] = 0;
720
return g;
721
}
722
g[c] = 0;
723
}
724
}
725
}
726
if (c != *t++)
727
{
728
g = x;
729
break;
730
}
731
}
732
}
733
return g;
734
accept:
735
if ((flags & (QUOTE_blank|q->flags)) == (QUOTE_blank|QUOTE_comment))
736
for (x--; x < g; *x++ = ' ');
737
return g;
738
}
739
740
/*
741
* parameter definition
742
*/
743
744
static List_t*
745
scandefine(register char* s, List_t* p)
746
{
747
register char* t;
748
char* b;
749
char* z;
750
int c;
751
Rule_t* u;
752
Var_t* v;
753
Sfio_t* tmp;
754
755
while (isspace(*s))
756
s++;
757
t = s;
758
while (*s && istype(*s, C_ID1|C_ID2))
759
s++;
760
if (s > t)
761
{
762
c = *s;
763
*s = 0;
764
u = staterule(VAR, NiL, t, 1);
765
if (!(v = getvar(t)))
766
v = setvar(t, null, 0);
767
*s = c;
768
b = t = s;
769
for (;;)
770
{
771
while (isspace(*s))
772
s++;
773
while (*s && !isspace(*s))
774
*t++ = *s++;
775
if (!*s)
776
break;
777
*t++ = ' ';
778
}
779
for (z = t; z < s; *z++ = ' ');
780
*t = 0;
781
if (*v->value)
782
{
783
tmp = sfstropen();
784
sfprintf(tmp, "%s#%s", v->value, b);
785
setvar(v->name, sfstruse(tmp), 0);
786
sfstrclose(tmp);
787
}
788
else
789
setvar(v->name, b, 0);
790
if (!(u->mark & M_scan))
791
{
792
u->mark |= M_scan;
793
u->property |= P_parameter;
794
v->property |= V_scan;
795
p = cons(u, p);
796
}
797
if (t < s)
798
*t = ' ';
799
}
800
return p;
801
}
802
803
/*
804
* macro scan -- only partial parameterization
805
*
806
* include(<SP>*<FILE><SP>*)
807
* sinclude(<SP>*<FILE><SP>*)
808
* INCLUDE(<SP>*<FILE>[,<FILE>]*<SP>*)
809
* define(<SP>*<VARIABLE><SP>*,<DEFINITION><SP>*)
810
* ifelse(c,t,f)
811
* # comment
812
*
813
* attribute and property from first I pattern propagated to prereq files
814
*/
815
816
/*ARGSUSED*/
817
static List_t*
818
scanmacro(int fd, Rule_t* r, Scan_t* ss, register List_t* p)
819
{
820
register int c;
821
register int inquote;
822
register char* w;
823
int n;
824
int dontcare;
825
int ifparen;
826
int paren;
827
int h;
828
int t;
829
Sfio_t* fp;
830
Sfio_t* tmp;
831
Rule_t* u;
832
Var_t* v;
833
834
if (!(fp = sfnew(NiL, NiL, SF_UNBOUND, fd, SF_READ)))
835
{
836
error(2, "%s: cannot fdopen", r->name);
837
return p;
838
}
839
tmp = sfstropen();
840
ifparen = inquote = paren = 0;
841
while ((c = sfgetc(fp)) != EOF)
842
switch (c)
843
{
844
case ')':
845
if (!inquote)
846
{
847
sfstrseek(tmp, 0, SEEK_SET);
848
if (paren-- == ifparen)
849
ifparen = 0;
850
}
851
break;
852
853
case '"':
854
case '#':
855
case '\n':
856
if (inquote == c)
857
{
858
inquote = 0;
859
sfstrseek(tmp, 0, SEEK_SET);
860
}
861
else if (!inquote && c != '\n')
862
inquote = c == '#' ? '\n' : c;
863
break;
864
865
case '\\':
866
sfstrseek(tmp, 0, SEEK_SET);
867
sfgetc(fp);
868
break;
869
870
default:
871
if (!inquote)
872
{
873
if (!sfstrtell(tmp))
874
{
875
if (c == '(')
876
paren++;
877
else if (istype(c, C_VARPOS1) && state.fullscan)
878
{
879
h = 1;
880
t = C_VARPOS1;
881
sfputc(tmp, c);
882
}
883
else if (istype(c, C_ID1|C_ID2))
884
{
885
h = 0;
886
t = C_ID1|C_ID2;
887
sfputc(tmp, c);
888
}
889
}
890
else
891
{
892
if (t != (C_ID1|C_ID2))
893
{
894
if (t == C_VARPOS8)
895
t = C_ID1|C_ID2;
896
else
897
t <<= 1;
898
}
899
if (istype(c, t))
900
sfputc(tmp, c);
901
else if (t == (C_ID1|C_ID2) || !istype(c, C_ID1|C_ID2))
902
{
903
w = sfstruse(tmp);
904
if (h && (v = getvar(w)) && (v->property & V_scan))
905
{
906
u = staterule(VAR, NiL, w, 1);
907
if (!(u->mark & M_scan))
908
{
909
u->mark |= M_scan;
910
p = cons(u, p);
911
}
912
}
913
if (c == '(')
914
{
915
paren++;
916
/*UNDENT*/
917
if (*w == 's')
918
{
919
dontcare = 1;
920
w++;
921
}
922
else
923
dontcare = ifparen != 0;
924
if (*w == 'i')
925
{
926
if (!strcmp(w, "include"))
927
{
928
sfstrseek(tmp, 0, SEEK_SET);
929
while ((c = sfgetc(fp)) != EOF && c != ')')
930
if (!isspace(c))
931
sfputc(tmp, c);
932
sfungetc(fp, c);
933
u = makerule(sfstruse(tmp));
934
if (!(u->mark & M_scan))
935
{
936
u->mark |= M_scan;
937
if (dontcare)
938
u->property |= P_dontcare;
939
else if (!(u->property & P_target))
940
u->property &= ~P_dontcare;
941
if (ss->action && ss->action[1].attrprop && ss->action[1].type == 'I')
942
{
943
u->attribute &= ~ss->action[1].attribute.clear;
944
u->attribute |= ss->action[1].attribute.set;
945
u->property &= ~ss->action[1].property.clear;
946
u->property |= ss->action[1].property.set;
947
}
948
u->scan = r->scan;
949
staterule(RULE, u, NiL, 1)->scan = r->scan;
950
p = cons(u, p);
951
}
952
}
953
else if (!ifparen && (!strcmp(w, "ifdef") || !strcmp(w, "ifelse")))
954
ifparen = paren;
955
}
956
else if (*w == 'I' && !strcmp(w, "INCLUDE"))
957
{
958
do
959
{
960
sfstrseek(tmp, 0, SEEK_SET);
961
while ((c = sfgetc(fp)) != EOF && c != ')' && c != ',')
962
if (!isspace(c))
963
sfputc(tmp, c);
964
u = makerule(sfstruse(tmp));
965
if (!(u->mark & M_scan))
966
{
967
u->mark |= M_scan;
968
if (dontcare)
969
u->property |= P_dontcare;
970
else if (!(u->property & P_target))
971
u->property &= ~P_dontcare;
972
if (ss->action && ss->action[1].attrprop && ss->action[1].type == 'I')
973
{
974
u->attribute &= ~ss->action[1].attribute.clear;
975
u->attribute |= ss->action[1].attribute.set;
976
u->property &= ~ss->action[1].property.clear;
977
u->property |= ss->action[1].property.set;
978
}
979
u->scan = r->scan;
980
staterule(RULE, u, NiL, 1)->scan = r->scan;
981
p = cons(u, p);
982
}
983
} while (c == ',');
984
sfungetc(fp, c);
985
}
986
else if ((r->property & P_parameter) && *w == 'd' && !strcmp(w, "define"))
987
{
988
sfstrseek(tmp, 0, SEEK_SET);
989
while ((c = sfgetc(fp)) != EOF && c != ',')
990
if (!isspace(c))
991
sfputc(tmp, c);
992
sfputc(tmp, ' ');
993
while (isspace(c = sfgetc(fp)));
994
if (c == '`')
995
inquote = '\'';
996
else
997
sfungetc(fp, c);
998
n = 1;
999
while ((c = sfgetc(fp)) != EOF && c != inquote)
1000
{
1001
if (!inquote)
1002
{
1003
if (c == '(')
1004
n++;
1005
else if (c == ')' && !n--)
1006
break;
1007
}
1008
else if (c == '#')
1009
{
1010
while ((c = sfgetc(fp)) != EOF && c != '\n');
1011
continue;
1012
}
1013
sfputc(tmp, c);
1014
}
1015
inquote = 0;
1016
p = scandefine(sfstruse(tmp), p);
1017
}
1018
/*INDENT*/
1019
}
1020
}
1021
else
1022
{
1023
h = 0;
1024
t = C_ID1|C_ID2;
1025
sfputc(tmp, c);
1026
}
1027
}
1028
}
1029
break;
1030
}
1031
sfstrclose(tmp);
1032
sfsetfd(fp, -1);
1033
sfclose(fp);
1034
return p;
1035
}
1036
1037
/*
1038
* do scan match action a on r with matched string s
1039
* b is beginning of the original line
1040
*/
1041
1042
static List_t*
1043
scanmatch(List_t* p, register Action_t* a, Rule_t* r, char* b, char* s, int iflev, int split)
1044
{
1045
int n;
1046
char* t;
1047
char* o;
1048
Rule_t* u;
1049
Rule_t* x;
1050
Sfio_t* tmp = 0;
1051
1052
static char label[] = "X-scan-action";
1053
1054
if (strchr(s, ' '))
1055
return p;
1056
if (state.test & 0x00100000)
1057
error(2, "scanmatch: %s %c", s, a->type);
1058
if (a->script || a->map)
1059
{
1060
o = state.frame->original;
1061
state.frame->original = b;
1062
t = state.frame->stem;
1063
state.frame->stem = s;
1064
if (a->script)
1065
{
1066
if (state.test & 0x00100000)
1067
error(2, "scanmatch: %s %c script `%s'", s, a->type, a->script);
1068
label[0] = a->type;
1069
parse(NiL, a->script, label, NiL);
1070
}
1071
if (a->map)
1072
{
1073
if (state.test & 0x00100000)
1074
error(2, "scanmatch: %s %c map `%s'", s, a->type, a->map);
1075
tmp = sfstropen();
1076
expand(tmp, a->map);
1077
s = sfstruse(tmp);
1078
}
1079
state.frame->original = o;
1080
state.frame->stem = t;
1081
}
1082
if (*s)
1083
{
1084
if (split)
1085
t = tokopen(s, 1);
1086
do
1087
{
1088
if (split && !(s = tokread(t)))
1089
break;
1090
if (o = strchr(s, ' '))
1091
{
1092
do
1093
{
1094
*o++ = (state.test & 0x00080000) ? '?' : FILE_SPACE;
1095
} while (o = strchr(o, ' '));
1096
o = s;
1097
}
1098
if (!*s || *s == '-' && !*(s + 1))
1099
break;
1100
#if _WINIX
1101
if (isalpha(*s) && *(s + 1) == ':' && (*(s + 2) == '/' || *(s + 2) == '\\'))
1102
{
1103
*(s + 1) = *s;
1104
*s = '/';
1105
for (o = s; o = strchr(s, '\\'); *o++ = '/');
1106
}
1107
#endif
1108
u = makerule(s);
1109
if (u->status == UPDATE)
1110
{
1111
if (u->uname && streq(s, u->name))
1112
{
1113
message((-2, "%s split from %s", u->name, u->uname));
1114
oldname(u);
1115
u = makerule(s);
1116
}
1117
else
1118
{
1119
parentage(internal.tmp, r, " : ");
1120
error(1, "%s : %s: implicit reference before action completed", sfstruse(internal.tmp), unbound(u));
1121
}
1122
}
1123
if (!(u->mark & M_scan))
1124
{
1125
u->mark |= M_scan;
1126
p = cons(u, p);
1127
if (iflev || o)
1128
u->property |= P_dontcare;
1129
else if (!(u->property & P_target))
1130
u->property &= ~P_dontcare;
1131
x = (u->dynamic & D_alias) ? getrule(u->name) : (Rule_t*)0;
1132
if (a->attrprop)
1133
{
1134
u->attribute &= ~a->attribute.clear;
1135
u->attribute |= a->attribute.set;
1136
u->property &= ~a->property.clear;
1137
u->property |= a->property.set;
1138
if (x)
1139
{
1140
x->attribute &= ~a->attribute.clear;
1141
x->attribute |= a->attribute.set;
1142
x->property &= ~a->property.clear;
1143
x->property |= a->property.set;
1144
}
1145
}
1146
if (!(a->flags & SCAN_nopropagate) && (!(u->dynamic & D_scanned) || !u->scan))
1147
{
1148
if (!(n = a->scan))
1149
n = r->scan;
1150
else if (n == SCAN_NULL)
1151
n = 0;
1152
if (n && u->scan != n && !(u->property & P_state))
1153
{
1154
if (u->scan)
1155
{
1156
char* os;
1157
char* ns;
1158
List_t* q;
1159
1160
os = ns = internal.scan->name;
1161
for (q = internal.scan->prereqs; q; q = q->next)
1162
if (q->rule->scan == u->scan)
1163
os = q->rule->name;
1164
else if (q->rule->scan == n)
1165
ns = q->rule->name;
1166
if (!(strategy[n]->flags & SCAN_override))
1167
error(1, "%s: scan strategy %s overrides %s", u->name, ns, os);
1168
}
1169
u->scan = n;
1170
staterule(RULE, u, NiL, 1)->scan = n;
1171
if (x)
1172
x->scan = n;
1173
}
1174
}
1175
}
1176
} while (split);
1177
if (split)
1178
tokclose(t);
1179
}
1180
else
1181
{
1182
x = (r->dynamic & D_alias) ? getrule(r->name) : (Rule_t*)0;
1183
if (a->attrprop)
1184
{
1185
r->attribute &= ~a->attribute.clear;
1186
r->attribute |= a->attribute.set;
1187
r->property &= ~a->property.clear;
1188
r->property |= a->property.set;
1189
if (x)
1190
{
1191
x->attribute &= ~a->attribute.clear;
1192
x->attribute |= a->attribute.set;
1193
x->property &= ~a->property.clear;
1194
x->property |= a->property.set;
1195
}
1196
}
1197
}
1198
if (tmp)
1199
sfstrclose(tmp);
1200
return p;
1201
}
1202
1203
#if DEBUG
1204
static char*
1205
opname(Scanstate_t* s)
1206
{
1207
int i;
1208
1209
static char buf[8];
1210
1211
switch (*s)
1212
{
1213
case ANY:
1214
return "ANY";
1215
case ARG:
1216
return "ARG";
1217
case DIG:
1218
return "DIG";
1219
case NAM:
1220
return "NAM";
1221
case REP:
1222
return "REP";
1223
case SPC:
1224
return "SPC";
1225
case TOK:
1226
return "TOK";
1227
case 0:
1228
return "END";
1229
}
1230
i = 0;
1231
buf[i++] = '\'';
1232
while (i < (sizeof(buf) - 3) && isprint(*s))
1233
buf[i++] = *s++;
1234
buf[i++] = '\'';
1235
buf[i] = 0;
1236
return buf;
1237
}
1238
#endif
1239
1240
/*
1241
* scan fd on file r for patterns compiled in ss
1242
* cons prereqs on p
1243
*/
1244
1245
static List_t*
1246
scanexec(int fd, Rule_t* r, Scan_t* ss, List_t* p)
1247
{
1248
register int c;
1249
register unsigned char* g;
1250
register Scanstate_t* s;
1251
Scanstate_t* m;
1252
unsigned char* pb;
1253
unsigned char* x;
1254
unsigned char* b;
1255
Scanstate_t* rep;
1256
Scanstate_t* per;
1257
char* a;
1258
Hash_table_t* tab;
1259
Hash_position_t* pos;
1260
int d;
1261
int e;
1262
int hit;
1263
int n;
1264
int collect;
1265
int iflev;
1266
int h;
1267
int t;
1268
int typ;
1269
Frame_t frame;
1270
Rule_t* u;
1271
Var_t* v;
1272
struct
1273
{
1274
int arg;
1275
Scanstate_t* state;
1276
unsigned char* buffer;
1277
} any[8], *pop, *pp;
1278
unsigned char buf[2 * SCANBUFFER + 1];
1279
struct
1280
{
1281
int begin;
1282
int end;
1283
int replace;
1284
} arg[SCANARGS];
1285
1286
if (ss->flags & SCAN_macro)
1287
return scanmacro(fd, r, ss, p);
1288
if (ss->external)
1289
{
1290
Sfio_t* sp;
1291
1292
if (!(sp = fapply(r, null, r->name, ss->external, CO_ALWAYS|CO_LOCAL|CO_URGENT)))
1293
error(3, "%s: external scan error", r->name);
1294
parse(sp, NiL, "external-scan", NiL);
1295
sfclose(sp);
1296
p = internal.implicit->prereqs;
1297
internal.implicit->prereqs = 0;
1298
return p;
1299
}
1300
zero(frame);
1301
frame.parent = state.frame;
1302
if (!(frame.previous = r->active))
1303
{
1304
frame.target = r;
1305
state.frame = r->active = &frame;
1306
}
1307
else if (state.frame != r->active)
1308
state.frame = r->active;
1309
tab = ss->classid ? (Hash_table_t*)ss->data : (Hash_table_t*)0;
1310
iflev = (r->property & P_dontcare) ? 1 : 0;
1311
g = buf + 2 * SCANBUFFER;
1312
g[0] = 0;
1313
m = 0;
1314
collect = 0;
1315
for (;;)
1316
{
1317
n = 0;
1318
pop = any;
1319
rep = per = 0;
1320
pb = 0;
1321
hit = 0;
1322
b = g;
1323
if (state.test & 0x00000080)
1324
{
1325
for (x = g; *x && *x != '\n'; x++);
1326
if (x > g)
1327
error(2, "scanexec: NXT \"%-.*s\"", x - g, g);
1328
}
1329
if (s = ss->state)
1330
{
1331
next:
1332
while (!(c = *g++))
1333
{
1334
c = g - b - 1;
1335
g = buf + SCANBUFFER;
1336
if (c && b >= g)
1337
{
1338
memcpy(g - c, b, c);
1339
c += b - g;
1340
b -= c;
1341
if (pb)
1342
pb -= c;
1343
for (pp = any; pp < pop; pp++)
1344
pp->buffer -= c;
1345
}
1346
else
1347
b = g;
1348
if ((c = read(fd, g, SCANBUFFER)) <= 0)
1349
goto done;
1350
g[c] = 0;
1351
if (state.test & 0x00000080)
1352
{
1353
for (x = g; *x && *x != '\n'; x++);
1354
error(2, "scanexec: BUF \"%-.*s\"", x - g, g);
1355
}
1356
}
1357
for (;;)
1358
{
1359
#if DEBUG
1360
if (state.test & 0x00000080)
1361
{
1362
for (x = g - 1; *x && *x != '\n'; x++);
1363
error(2, "scanexec: %s \"%-.*s\"", opname(s), x - (g - 1), g - 1);
1364
}
1365
#endif
1366
/*UNDENT*/
1367
if ((typ = *s) == DIG || typ == SPC || typ == NAM || typ == TOK)
1368
{
1369
h = g == (b + 1);
1370
if (typ == DIG || typ == SPC || typ == NAM && istype(c, C_VARIABLE1) || typ == TOK && istype(c, C_VARIABLE1|C_VARIABLE2))
1371
for (;;)
1372
{
1373
if (typ == SPC ? isspace(c) : typ == DIG ? isdigit(c) : istype(c, C_VARIABLE1|C_VARIABLE2))
1374
{
1375
if (m)
1376
{
1377
m = 0;
1378
if (collect)
1379
{
1380
collect = 0;
1381
arg[n++].end = g - b - 1;
1382
}
1383
}
1384
#if DEBUG
1385
if (!(state.questionable & 0x00000020))
1386
h = 1;
1387
#endif
1388
if (c == '\n')
1389
break;
1390
h = 1;
1391
}
1392
else if (!c)
1393
{
1394
if (b >= buf + SCANBUFFER)
1395
{
1396
c = g - b - 1;
1397
memcpy(buf + SCANBUFFER - c, b, c);
1398
b = buf + SCANBUFFER - c;
1399
}
1400
if ((c = read(fd, g = buf + SCANBUFFER, SCANBUFFER)) <= 0)
1401
goto done;
1402
g[c] = 0;
1403
}
1404
else if (!m)
1405
break;
1406
c = *g++;
1407
}
1408
s += *(s + 1) + 1;
1409
if (!h && !rep && (*s == ANY || *s == ARG || *s == 0))
1410
{
1411
#if DEBUG
1412
if ((state.test & 0x00000080) && *s == 0)
1413
error(2, "scanexec: HIT *s==0");
1414
#endif
1415
m = 0;
1416
collect = 0;
1417
break;
1418
}
1419
}
1420
else if (typ == ANY)
1421
{
1422
if (pop < &any[elementsof(any)])
1423
{
1424
pop->arg = n;
1425
pop->state = s;
1426
pop->buffer = g;
1427
pop++;
1428
}
1429
s += *(s + 1) + 1;
1430
}
1431
else if (typ == ARG)
1432
{
1433
m = s += *(s + 1) + 1;
1434
if (n < elementsof(arg))
1435
{
1436
collect = 1;
1437
arg[n].begin = g - b - 1;
1438
}
1439
}
1440
else if (typ == REP)
1441
{
1442
if (rep)
1443
{
1444
per = s + *(s + 1) + 1;
1445
if (n && arg[0].end > arg[0].begin)
1446
{
1447
x = b + arg[0].begin;
1448
while (x < g)
1449
{
1450
if (*per == SPC)
1451
while (x < g && isspace(*x))
1452
x++;
1453
else
1454
{
1455
if (*x != *per)
1456
break;
1457
x++;
1458
}
1459
per += *(per + 1) + 1;
1460
}
1461
if (x >= g)
1462
break;
1463
}
1464
for (s = per; *s; s += *(s + 1) + 1);
1465
goto rephit;
1466
}
1467
else
1468
rep = s += *(s + 1) + 1;
1469
}
1470
else if (typ == 0)
1471
{
1472
rephit:
1473
if (m)
1474
{
1475
if (c != '\n')
1476
{
1477
s = m;
1478
goto next;
1479
}
1480
m = 0;
1481
if (collect)
1482
{
1483
collect = 0;
1484
arg[n++].end = g - b - 1;
1485
}
1486
}
1487
if (c == '\n')
1488
{
1489
if (per || rep && *rep != ARG && (*rep != SPC || *(rep + *(rep + 1) + 1) != ARG) && (!hit || n))
1490
g++;
1491
else
1492
rep = 0;
1493
}
1494
if (*++s && (!n || arg[0].begin < arg[0].end))
1495
{
1496
if (rep)
1497
hit += n;
1498
if (n < elementsof(arg))
1499
{
1500
arg[n].begin = arg[n].end = g - b - 1;
1501
n++;
1502
}
1503
for (c = 0; c < n; c++)
1504
arg[c].replace = *(b + arg[c].end);
1505
for (c = 0; c < n; c++)
1506
*(b + arg[c].end) = 0;
1507
while (c < elementsof(arg))
1508
arg[c++].begin = arg[n - 1].begin;
1509
#if DEBUG
1510
if (state.test & 0x00000080)
1511
error(2, "scanexec: HIT %s: %c n=%d \"%s\" \"%s\"", r->name, ss->action[*s].type, n - 1, b + arg[0].begin, b + arg[1].begin);
1512
#endif
1513
a = null;
1514
switch (c = ss->action[*s].type)
1515
{
1516
case 'A':
1517
if (state.archive)
1518
{
1519
Time_t date;
1520
1521
if (date = strtol((char*)b + arg[1].begin, NiL, 10))
1522
date = tmxsns(date, 0);
1523
else
1524
date = tmxdate((char*)b + arg[1].begin, NiL, TMX_NOW);
1525
addfile(state.archive, (char*)b + arg[0].begin, date);
1526
}
1527
else
1528
error(2, "%s: `A' scan pattern for non-%s", r->name, internal.archive->name);
1529
a = (char*)b + arg[0].begin;
1530
break;
1531
case 'B':
1532
iflev++;
1533
break;
1534
case 'D':
1535
if (r->property & P_parameter)
1536
p = scandefine((char*)b + arg[0].begin, p);
1537
break;
1538
case 'E':
1539
iflev--;
1540
break;
1541
case 'I':
1542
case 'T':
1543
a = (char*)b + arg[0].begin;
1544
break;
1545
}
1546
p = scanmatch(p, &ss->action[*s], r, (char*)b, a, iflev, c == 'T' ? -1 : a != null && a > (char*)b && (c = *(a - 1)) != '"' && c != '\'' && (c != '<' || arg[0].replace != '>'));
1547
for (c = 0; c < n; c++)
1548
*(b + arg[c].end) = arg[c].replace;
1549
if (pop > any)
1550
pop--;
1551
}
1552
else
1553
{
1554
#if DEBUG
1555
if (state.test & 0x00000080)
1556
error(2, "scanexec: XXX");
1557
#endif
1558
if (hit)
1559
rep = 0;
1560
if (pop > any)
1561
{
1562
pop--;
1563
if (c != '\n')
1564
{
1565
#if DEBUG
1566
if (state.test & 0x00000080)
1567
error(2, "scanexec: POP");
1568
#endif
1569
m = s = pop->state;
1570
g = pop->buffer;
1571
n = pop->arg;
1572
goto next;
1573
}
1574
}
1575
}
1576
if (rep)
1577
{
1578
s = rep;
1579
if ((b = --g) == pb)
1580
goto done;
1581
pb = b;
1582
n = 0;
1583
goto next;
1584
}
1585
break;
1586
}
1587
else if (c == *s++)
1588
{
1589
if (m)
1590
{
1591
m = 0;
1592
if (collect)
1593
{
1594
collect = 0;
1595
arg[n++].end = g - b - 1;
1596
}
1597
}
1598
s += *s;
1599
goto next;
1600
}
1601
else
1602
s++;
1603
/*INDENT*/
1604
}
1605
g = b;
1606
}
1607
n = (ss->flags & SCAN_state) && state.fullscan;
1608
x = ss->type;
1609
while ((c = *g++) != '\n')
1610
{
1611
if (!c)
1612
{
1613
if ((c = read(fd, b = g = buf + SCANBUFFER, SCANBUFFER)) <= 0)
1614
goto done;
1615
g[c] = 0;
1616
}
1617
else if (x[c] & (QUOTE_comment|QUOTE_quote))
1618
{
1619
if (g - 2 >= b)
1620
b = g - 2;
1621
g = scanquote(fd, buf, &b, g, ss->quote, QUOTE_comment|QUOTE_quote);
1622
}
1623
else if (n && istype(c, C_ID1))
1624
{
1625
if (istype(c, C_VARPOS1))
1626
{
1627
h = 1;
1628
t = C_VARPOS1;
1629
}
1630
else
1631
{
1632
h = 0;
1633
t = C_ID1|C_ID2;
1634
}
1635
b = g - 1;
1636
for (;;)
1637
{
1638
while (!(c = *g++))
1639
{
1640
if (b >= buf + SCANBUFFER)
1641
{
1642
c = g - b - 1;
1643
memcpy(buf + SCANBUFFER - c, b, c);
1644
b = buf + SCANBUFFER - c;
1645
}
1646
if ((c = read(fd, g = buf + SCANBUFFER, SCANBUFFER)) <= 0)
1647
goto done;
1648
g[c] = 0;
1649
}
1650
if (t != (C_ID1|C_ID2))
1651
{
1652
if (t == C_VARPOS8)
1653
t = C_ID1|C_ID2;
1654
else
1655
t <<= 1;
1656
}
1657
if (!istype(c, t))
1658
{
1659
if (t == (C_ID1|C_ID2) || !istype(c, C_ID1|C_ID2))
1660
break;
1661
t = C_ID1|C_ID2;
1662
h = 0;
1663
}
1664
}
1665
g--;
1666
if (h)
1667
{
1668
*g = 0;
1669
if ((v = getvar(b)) && (v->property & V_scan))
1670
{
1671
u = staterule(VAR, NiL, (char*)b, 1);
1672
if (!(u->mark & M_scan))
1673
{
1674
u->mark |= M_scan;
1675
p = cons(u, p);
1676
}
1677
}
1678
*g = c;
1679
}
1680
}
1681
else if (tab && istype(c, C_ID1))
1682
{
1683
d = e = 0;
1684
h = 0;
1685
b = g - 1;
1686
for (;;)
1687
{
1688
while (!(c = *g++))
1689
{
1690
if (b >= buf + SCANBUFFER)
1691
{
1692
c = g - b - 1;
1693
memcpy(buf + SCANBUFFER - c, b, c);
1694
b = buf + SCANBUFFER - c;
1695
}
1696
if ((c = read(fd, g = buf + SCANBUFFER, SCANBUFFER)) <= 0)
1697
goto done;
1698
g[c] = 0;
1699
}
1700
if (!istype(c, C_ID1|C_VARIABLE2))
1701
{
1702
if (e && d > 1)
1703
{
1704
h = e;
1705
break;
1706
}
1707
if (!isspace(c))
1708
{
1709
h = 0;
1710
break;
1711
}
1712
if (!h)
1713
h = g - b - 1;
1714
}
1715
else if (c == '.')
1716
{
1717
d++;
1718
e = g - b - 1;
1719
}
1720
else if (h)
1721
break;
1722
}
1723
g--;
1724
if (h)
1725
{
1726
c = b[h];
1727
b[h] = 0;
1728
hashput(tab, b, 1);
1729
b[h] = c;
1730
}
1731
break;
1732
}
1733
}
1734
}
1735
done:
1736
if (tab && (pos = hashscan(tab, 0)))
1737
{
1738
while (hashnext(pos))
1739
if (pos->bucket->value)
1740
{
1741
pos->bucket->value = 0;
1742
p = scanmatch(p, ss->classid, r, pos->bucket->name, pos->bucket->name, 0, 0);
1743
}
1744
hashdone(pos);
1745
}
1746
r->active = frame.previous;
1747
state.frame = frame.parent;
1748
return p;
1749
}
1750
1751
/*
1752
* return list of r's implicit prerequisites
1753
* r must be bound to a file which is then scanned
1754
*/
1755
1756
List_t*
1757
scan(register Rule_t* r, Time_t* tm)
1758
{
1759
register Rule_t* s;
1760
register List_t* oprereqs;
1761
Rule_t* alt;
1762
List_t* p;
1763
Scan_t* ss;
1764
int fd;
1765
1766
if (tm)
1767
*tm = 0;
1768
if ((r->property & (P_attribute|P_state|P_virtual)) || !(r->dynamic & D_regular))
1769
return 0;
1770
s = staterule(RULE, r, NiL, 1);
1771
if ((r->property & P_joint) || (s->dynamic & D_built))
1772
{
1773
alt = s;
1774
s = staterule(PREREQS, r, NiL, 1);
1775
s->property |= P_implicit;
1776
r->preview = r->view;
1777
}
1778
else if (alt = staterule(PREREQS, r, NiL, 0))
1779
{
1780
alt->property &= ~P_implicit;
1781
alt = 0;
1782
}
1783
if (r->scan < SCAN_USER)
1784
{
1785
ss = 0;
1786
if (alt)
1787
s->prereqs = 0;
1788
}
1789
else
1790
{
1791
if (!strategy[r->scan])
1792
{
1793
for (p = internal.scan->prereqs; p; p = p->next)
1794
if (p->rule->scan == r->scan)
1795
{
1796
strategy[r->scan] = scancompile(p->rule, (r->property & P_parameter) ? SCAN_define : 0);
1797
break;
1798
}
1799
if (!p)
1800
error(3, "%s: invalid scan index %d", r->name, r->scan);
1801
}
1802
ss = strategy[r->scan];
1803
}
1804
r->dynamic |= D_scanned;
1805
if (s->dynamic & D_scanned)
1806
return s->prereqs;
1807
oprereqs = s->prereqs;
1808
if (ss)
1809
{
1810
if (!(r->property & P_accept) && !state.accept && !((s->property | (alt ? alt->property : 0L)) & P_force) && r->scan == s->scan)
1811
ss = 0;
1812
else if ((fd = ropen(r->name, O_RDONLY)) < 0)
1813
{
1814
if (state.exec && !(r->property & P_dontcare))
1815
error(1, "cannot read %s", r->name);
1816
return 0;
1817
}
1818
else
1819
{
1820
message((-2, "scanning %s for prerequisites", r->name));
1821
state.savestate = 1;
1822
s->prereqs = scanexec(fd, r, ss, ss->before ? scanmatch(NiL, ss->before, r, null, null, 0, 1) : (List_t*)0);
1823
close(fd);
1824
}
1825
}
1826
s->property &= ~P_force;
1827
s->dynamic |= D_scanned;
1828
s->scan = r->scan;
1829
if (alt)
1830
{
1831
s->event = alt->event;
1832
alt->attribute = r->attribute;
1833
alt->property &= ~P_force;
1834
alt->scan = s->scan;
1835
if (alt->prereqs != r->prereqs)
1836
{
1837
if ((r->property & (P_joint|P_target)) != (P_joint|P_target))
1838
freelist(alt->prereqs);
1839
alt->prereqs = r->prereqs;
1840
}
1841
}
1842
else
1843
s->attribute = r->attribute;
1844
if (ss)
1845
{
1846
if (ss->after)
1847
{
1848
for (p = s->prereqs; p; p = p->next)
1849
if (p->rule->mark & M_scan)
1850
{
1851
p->rule->mark &= ~M_scan;
1852
debug((-5, "%s: implicit prerequisite %s", r->name, p->rule->name));
1853
}
1854
s->prereqs = scanmatch(s->prereqs, ss->after, r, null, null, 0, 1);
1855
}
1856
for (p = s->prereqs; p; p = p->next)
1857
if (p->rule->mark & M_scan)
1858
{
1859
p->rule->mark &= ~M_scan;
1860
debug((-5, "%s: implicit prerequisite %s", r->name, p->rule->name));
1861
}
1862
}
1863
if (tm && prereqchange(r, s->prereqs, r, oprereqs))
1864
*tm = CURTIME;
1865
if (oprereqs != s->prereqs && (r->property & (P_joint|P_target)) != (P_joint|P_target))
1866
freelist(oprereqs);
1867
return s->prereqs;
1868
}
1869
1870