| graph.c - 9base - revived minimalist port of Plan 9 userland to Unix | |
| git clone git://git.suckless.org/9base | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| graph.c (5833B) | |
| --- | |
| 1 #include "mk.h" | |
| 2 | |
| 3 static Node *applyrules(char *, char *); | |
| 4 static void togo(Node *); | |
| 5 static int vacuous(Node *); | |
| 6 static Node *newnode(char *); | |
| 7 static void trace(char *, Arc *); | |
| 8 static void cyclechk(Node *); | |
| 9 static void ambiguous(Node *); | |
| 10 static void attribute(Node *); | |
| 11 | |
| 12 Node * | |
| 13 graph(char *target) | |
| 14 { | |
| 15 Node *node; | |
| 16 char *cnt; | |
| 17 | |
| 18 cnt = rulecnt(); | |
| 19 node = applyrules(target, cnt); | |
| 20 free(cnt); | |
| 21 cyclechk(node); | |
| 22 node->flags |= PROBABLE; /* make sure it doesn't get dele… | |
| 23 vacuous(node); | |
| 24 ambiguous(node); | |
| 25 attribute(node); | |
| 26 return(node); | |
| 27 } | |
| 28 | |
| 29 static Node * | |
| 30 applyrules(char *target, char *cnt) | |
| 31 { | |
| 32 Symtab *sym; | |
| 33 Node *node; | |
| 34 Rule *r; | |
| 35 Arc head, *a = &head; | |
| 36 Word *w; | |
| 37 char stem[NAMEBLOCK], buf[NAMEBLOCK]; | |
| 38 Resub rmatch[NREGEXP]; | |
| 39 | |
| 40 /* print("applyrules(%lux='%s')\n", target, target); */ | |
| 41 sym = symlook(target, S_NODE, 0); | |
| 42 if(sym) | |
| 43 return sym->u.ptr; | |
| 44 target = strdup(target); | |
| 45 node = newnode(target); | |
| 46 head.n = 0; | |
| 47 head.next = 0; | |
| 48 sym = symlook(target, S_TARGET, 0); | |
| 49 memset((char*)rmatch, 0, sizeof(rmatch)); | |
| 50 for(r = sym? sym->u.ptr:0; r; r = r->chain){ | |
| 51 if(r->attr&META) continue; | |
| 52 if(strcmp(target, r->target)) continue; | |
| 53 if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail-… | |
| 54 if(cnt[r->rule] >= nreps) continue; | |
| 55 cnt[r->rule]++; | |
| 56 node->flags |= PROBABLE; | |
| 57 | |
| 58 /* if(r->attr&VIR) | |
| 59 * node->flags |= VIRTUAL; | |
| 60 * if(r->attr&NOREC) | |
| 61 * node->flags |= NORECIPE; | |
| 62 * if(r->attr&DEL) | |
| 63 * node->flags |= DELETE; | |
| 64 */ | |
| 65 if(!r->tail || !r->tail->s || !*r->tail->s) { | |
| 66 a->next = newarc((Node *)0, r, "", rmatch); | |
| 67 a = a->next; | |
| 68 } else | |
| 69 for(w = r->tail; w; w = w->next){ | |
| 70 a->next = newarc(applyrules(w->s, cnt), … | |
| 71 a = a->next; | |
| 72 } | |
| 73 cnt[r->rule]--; | |
| 74 head.n = node; | |
| 75 } | |
| 76 for(r = metarules; r; r = r->next){ | |
| 77 if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail-… | |
| 78 if ((r->attr&NOVIRT) && a != &head && (a->r->attr&VIR)) | |
| 79 continue; | |
| 80 if(r->attr®EXP){ | |
| 81 stem[0] = 0; | |
| 82 patrule = r; | |
| 83 memset((char*)rmatch, 0, sizeof(rmatch)); | |
| 84 if(regexec(r->pat, node->name, rmatch, NREGEXP) … | |
| 85 continue; | |
| 86 } else { | |
| 87 if(!match(node->name, r->target, stem, r->shellt… | |
| 88 } | |
| 89 if(cnt[r->rule] >= nreps) continue; | |
| 90 cnt[r->rule]++; | |
| 91 | |
| 92 /* if(r->attr&VIR) | |
| 93 * node->flags |= VIRTUAL; | |
| 94 * if(r->attr&NOREC) | |
| 95 * node->flags |= NORECIPE; | |
| 96 * if(r->attr&DEL) | |
| 97 * node->flags |= DELETE; | |
| 98 */ | |
| 99 | |
| 100 if(!r->tail || !r->tail->s || !*r->tail->s) { | |
| 101 a->next = newarc((Node *)0, r, stem, rmatch); | |
| 102 a = a->next; | |
| 103 } else | |
| 104 for(w = r->tail; w; w = w->next){ | |
| 105 if(r->attr®EXP) | |
| 106 regsub(w->s, buf, sizeof buf, rm… | |
| 107 else | |
| 108 subst(stem, w->s, buf); | |
| 109 a->next = newarc(applyrules(buf, cnt), r… | |
| 110 a = a->next; | |
| 111 } | |
| 112 cnt[r->rule]--; | |
| 113 } | |
| 114 a->next = node->prereqs; | |
| 115 node->prereqs = head.next; | |
| 116 return(node); | |
| 117 } | |
| 118 | |
| 119 static void | |
| 120 togo(Node *node) | |
| 121 { | |
| 122 Arc *la, *a; | |
| 123 | |
| 124 /* delete them now */ | |
| 125 la = 0; | |
| 126 for(a = node->prereqs; a; la = a, a = a->next) | |
| 127 if(a->flag&TOGO){ | |
| 128 if(a == node->prereqs) | |
| 129 node->prereqs = a->next; | |
| 130 else | |
| 131 la->next = a->next, a = la; | |
| 132 } | |
| 133 } | |
| 134 | |
| 135 static int | |
| 136 vacuous(Node *node) | |
| 137 { | |
| 138 Arc *la, *a; | |
| 139 int vac = !(node->flags&PROBABLE); | |
| 140 | |
| 141 if(node->flags&READY) | |
| 142 return(node->flags&VACUOUS); | |
| 143 node->flags |= READY; | |
| 144 for(a = node->prereqs; a; a = a->next) | |
| 145 if(a->n && vacuous(a->n) && (a->r->attr&META)) | |
| 146 a->flag |= TOGO; | |
| 147 else | |
| 148 vac = 0; | |
| 149 /* if a rule generated arcs that DON'T go; no others from that r… | |
| 150 for(a = node->prereqs; a; a = a->next) | |
| 151 if((a->flag&TOGO) == 0) | |
| 152 for(la = node->prereqs; la; la = la->next) | |
| 153 if((la->flag&TOGO) && (la->r == a->r)){ | |
| 154 la->flag &= ~TOGO; | |
| 155 } | |
| 156 togo(node); | |
| 157 if(vac) | |
| 158 node->flags |= VACUOUS; | |
| 159 return(vac); | |
| 160 } | |
| 161 | |
| 162 static Node * | |
| 163 newnode(char *name) | |
| 164 { | |
| 165 register Node *node; | |
| 166 | |
| 167 node = (Node *)Malloc(sizeof(Node)); | |
| 168 symlook(name, S_NODE, (void *)node); | |
| 169 node->name = name; | |
| 170 node->time = timeof(name, 0); | |
| 171 node->prereqs = 0; | |
| 172 node->flags = node->time? PROBABLE : 0; | |
| 173 node->next = 0; | |
| 174 return(node); | |
| 175 } | |
| 176 | |
| 177 void | |
| 178 dumpn(char *s, Node *n) | |
| 179 { | |
| 180 char buf[1024]; | |
| 181 Arc *a; | |
| 182 | |
| 183 snprint(buf, sizeof buf, "%s ", (*s == ' ')? s:""); | |
| 184 Bprint(&bout, "%s%s@%ld: time=%ld flags=0x%x next=%ld\n", | |
| 185 s, n->name, n, n->time, n->flags, n->next); | |
| 186 for(a = n->prereqs; a; a = a->next) | |
| 187 dumpa(buf, a); | |
| 188 } | |
| 189 | |
| 190 static void | |
| 191 trace(char *s, Arc *a) | |
| 192 { | |
| 193 fprint(2, "\t%s", s); | |
| 194 while(a){ | |
| 195 fprint(2, " <-(%s:%d)- %s", a->r->file, a->r->line, | |
| 196 a->n? a->n->name:""); | |
| 197 if(a->n){ | |
| 198 for(a = a->n->prereqs; a; a = a->next) | |
| 199 if(*a->r->recipe) break; | |
| 200 } else | |
| 201 a = 0; | |
| 202 } | |
| 203 fprint(2, "\n"); | |
| 204 } | |
| 205 | |
| 206 static void | |
| 207 cyclechk(Node *n) | |
| 208 { | |
| 209 Arc *a; | |
| 210 | |
| 211 if((n->flags&CYCLE) && n->prereqs){ | |
| 212 fprint(2, "mk: cycle in graph detected at target %s\n", … | |
| 213 Exit(); | |
| 214 } | |
| 215 n->flags |= CYCLE; | |
| 216 for(a = n->prereqs; a; a = a->next) | |
| 217 if(a->n) | |
| 218 cyclechk(a->n); | |
| 219 n->flags &= ~CYCLE; | |
| 220 } | |
| 221 | |
| 222 static void | |
| 223 ambiguous(Node *n) | |
| 224 { | |
| 225 Arc *a; | |
| 226 Rule *r = 0; | |
| 227 Arc *la; | |
| 228 int bad = 0; | |
| 229 | |
| 230 la = 0; | |
| 231 for(a = n->prereqs; a; a = a->next){ | |
| 232 if(a->n) | |
| 233 ambiguous(a->n); | |
| 234 if(*a->r->recipe == 0) continue; | |
| 235 if(r == 0) | |
| 236 r = a->r, la = a; | |
| 237 else{ | |
| 238 if(r->recipe != a->r->recipe){ | |
| 239 if((r->attr&META) && !(a->r->attr&META)){ | |
| 240 la->flag |= TOGO; | |
| 241 r = a->r, la = a; | |
| 242 } else if(!(r->attr&META) && (a->r->attr… | |
| 243 a->flag |= TOGO; | |
| 244 continue; | |
| 245 } | |
| 246 } | |
| 247 if(r->recipe != a->r->recipe){ | |
| 248 if(bad == 0){ | |
| 249 fprint(2, "mk: ambiguous recipes… | |
| 250 bad = 1; | |
| 251 trace(n->name, la); | |
| 252 } | |
| 253 trace(n->name, a); | |
| 254 } | |
| 255 } | |
| 256 } | |
| 257 if(bad) | |
| 258 Exit(); | |
| 259 togo(n); | |
| 260 } | |
| 261 | |
| 262 static void | |
| 263 attribute(Node *n) | |
| 264 { | |
| 265 register Arc *a; | |
| 266 | |
| 267 for(a = n->prereqs; a; a = a->next){ | |
| 268 if(a->r->attr&VIR) | |
| 269 n->flags |= VIRTUAL; | |
| 270 if(a->r->attr&NOREC) | |
| 271 n->flags |= NORECIPE; | |
| 272 if(a->r->attr&DEL) | |
| 273 n->flags |= DELETE; | |
| 274 if(a->n) | |
| 275 attribute(a->n); | |
| 276 } | |
| 277 if(n->flags&VIRTUAL) | |
| 278 n->time = 0; | |
| 279 } |