mkjambase now can process '. file' includes; default monolithic Jambase separated...
[k8jam.git] / src / rules.c
blob30712928fc5716562cd991444567ec7949e39eda
1 /*
2 * Copyright 1993, 1995 Christopher Seiwald.
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
6 /*
7 * rules.c - access to RULEs, TARGETs, and ACTIONs
9 * External routines:
11 * bindrule() - return pointer to RULE, creating it if necessary
12 * bindtarget() - return pointer to TARGET, creating it if necessary
13 * copytarget() - make a new target with the old target's name
14 * touchtarget() - mark a target to simulate being new
15 * targetlist() - turn list of target names into a TARGET chain
16 * targetentry() - add a TARGET to a chain of TARGETS
17 * targetchain() - append two TARGET chains
18 * actionlist() - append to an ACTION chain
19 * addsettings() - add a deferred "set" command to a target
20 * copysettings() - copy a settings list for temp use
21 * pushsettings() - set all target specific variables
22 * popsettings() - reset target specific variables to their pre-push values
23 * freesettings() - delete a settings list
24 * donerules() - free RULE and TARGET tables
26 * 04/12/94 (seiwald) - actionlist() now just appends a single action.
27 * 08/23/94 (seiwald) - Support for '+=' (append to variable)
28 * 06/21/02 (seiwald) - support for named parameters
29 * 11/04/02 (seiwald) - const-ing for string literals
30 * 12/03/02 (seiwald) - fix odd includes support by grafting them onto depends
31 * 12/17/02 (seiwald) - new copysettings() to protect target-specific vars
32 * 01/14/03 (seiwald) - fix includes fix with new internal includes TARGET
34 #include "jam.h"
35 #include "lists.h"
36 #include "parse.h"
37 #include "variable.h"
38 #include "rules.h"
39 #include "newstr.h"
40 #include "hash.h"
43 static struct hash *rulehash = NULL;
44 static struct hash *targethash = NULL;
48 * haverule() - return !0 if rule exists
50 int haverule (const char *rulename) {
51 RULE rule, *r = &rule;
53 if (!rulehash) return 0;
54 r->name = rulename;
55 return hashcheck(rulehash, (HASHDATA **)&r) ? 1 : 0; /* just in case */
60 * bindrule() - return pointer to RULE, creating it if necessary
62 RULE *bindrule (const char *rulename) {
63 RULE rule, *r = &rule;
65 if (!rulehash) rulehash = hashinit(sizeof(RULE), "rules");
66 r->name = rulename;
67 if (hashenter(rulehash, (HASHDATA **)&r)) {
68 r->name = newstr(rulename); /* never freed */
69 r->procedure = (PARSE *)0;
70 r->actions = (char *)0;
71 r->bindlist = L0;
72 r->params = L0;
73 r->flags = 0;
75 return r;
80 * bindtarget() - return pointer to TARGET, creating it if necessary
82 TARGET *bindtarget (const char *targetname) {
83 TARGET target, *t = ⌖
85 if (!targethash) targethash = hashinit(sizeof(TARGET), "targets");
86 t->name = targetname;
87 if (hashenter(targethash, (HASHDATA **)&t)) {
88 memset((char *)t, '\0', sizeof(*t));
89 t->name = newstr(targetname); /* never freed */
90 t->boundname = t->name; /* default for T_FLAG_NOTFILE */
92 return t;
97 * copytarget() - make a new target with the old target's name
99 * Not entered into hash table -- for internal nodes.
101 TARGET *copytarget (const TARGET *ot) {
102 TARGET *t = (TARGET *)malloc(sizeof(*t));
103 memset((char *)t, '\0', sizeof(*t));
104 t->name = copystr(ot->name);
105 t->boundname = t->name;
106 t->flags |= T_FLAG_NOTFILE|T_FLAG_INTERNAL;
107 return t;
112 * touchtarget() - mark a target to simulate being new
114 void touchtarget (const char *t) {
115 bindtarget(t)->flags |= T_FLAG_TOUCHED;
120 * targetlist() - turn list of target names into a TARGET chain
122 * Inputs:
123 * chain existing TARGETS to append to
124 * targets list of target names
126 TARGETS *targetlist (TARGETS *chain, LIST *targets) {
127 for (; targets; targets = list_next(targets)) chain = targetentry(chain, bindtarget(targets->string));
128 return chain;
133 * targetentry() - add a TARGET to a chain of TARGETS
135 * Inputs:
136 * chain exisitng TARGETS to append to
137 * target new target to append
139 TARGETS *targetentry (TARGETS *chain, TARGET *target) {
140 TARGETS *c = (TARGETS *)malloc(sizeof(TARGETS));
141 c->target = target;
142 if (!chain) chain = c; else chain->tail->next = c;
143 chain->tail = c;
144 c->next = 0;
145 return chain;
150 * targetchain() - append two TARGET chains
152 * Inputs:
153 * chain exisitng TARGETS to append to
154 * target new target to append
156 TARGETS *targetchain (TARGETS *chain, TARGETS *targets) {
157 if (!targets) return chain;
158 if (!chain) return targets;
159 chain->tail->next = targets;
160 chain->tail = targets->tail;
161 return chain;
166 * actionlist() - append to an ACTION chain
168 ACTIONS *actionlist (ACTIONS *chain, ACTION *action) {
169 ACTIONS *actions = (ACTIONS *)malloc(sizeof(ACTIONS));
170 actions->action = action;
171 if (!chain) chain = actions; else chain->tail->next = actions;
172 chain->tail = actions;
173 actions->next = 0;
174 return chain;
179 * addsettings() - add a deferred "set" command to a target
181 * Adds a variable setting (varname=list) onto a chain of settings
182 * for a particular target. Replaces the previous previous value,
183 * if any, unless 'append' says to append the new list onto the old.
184 * Returns the head of the chain of settings.
186 SETTINGS *addsettings (SETTINGS *head, int setflag, const char *symbol, LIST *value) {
187 SETTINGS *v;
188 /* look for previous setting */
189 for (v = head; v; v = v->next) if (!strcmp(v->symbol, symbol)) break;
190 /* if not previously set, alloc a new */
191 /* if appending, do so */
192 /* else free old and set new */
193 if (!v) {
194 v = (SETTINGS *)malloc(sizeof(*v));
195 v->symbol = newstr(symbol);
196 v->value = value;
197 v->next = head;
198 head = v;
199 } else {
200 switch (setflag) {
201 case VAR_SET:
202 /* toss old, set new */
203 list_free(v->value);
204 v->value = value;
205 break;
206 case VAR_APPEND:
207 /* append new to old */
208 v->value = list_append(v->value, value);
209 break;
210 case VAR_REMOVE:
211 v->value = list_removeall(v->value, value);
212 list_free(value);
213 break;
214 case VAR_DEFAULT:
215 /* toss new, old already set */
216 list_free(value);
217 break;
220 /* return (new) head of list */
221 return head;
226 * copysettings() - copy a settings list for temp use
228 * When target-specific variables are pushed into place with pushsettings(),
229 * any global variables with the same name are swapped onto the target's
230 * SETTINGS chain. If that chain gets modified (by using the "on target"
231 * syntax), popsettings() would wrongly swap those modified values back
232 * as the new global values.
234 * copysettings() protects the target's SETTINGS chain by providing a
235 * copy of the chain to pass to pushsettings() and popsettings(), so that
236 * the target's original SETTINGS chain can be modified using the usual
237 * "on target" syntax.
239 SETTINGS *copysettings (SETTINGS *from) {
240 SETTINGS *head = 0;
242 for (; from; from = from->next) {
243 SETTINGS *v = (SETTINGS *)malloc(sizeof(*v));
244 v->symbol = copystr(from->symbol);
245 v->value = list_copy(0, from->value);
246 v->next = head;
247 head = v;
249 return head;
254 * pushsettings() - set all target specific variables
256 void pushsettings (SETTINGS *v) {
257 for (; v; v = v->next) v->value = var_swap(v->symbol, v->value);
262 * popsettings() - reset target specific variables to their pre-push values
264 void popsettings (SETTINGS *v) {
265 pushsettings(v); /* just swap again */
270 * freesettings() - delete a settings list
272 void freesettings (SETTINGS *v) {
273 while (v != NULL) {
274 SETTINGS *n = v->next;
276 freestr(v->symbol);
277 list_free(v->value);
278 free((char *)v);
279 v = n;
285 * donerules() - free RULE and TARGET tables
287 void donerules (void) {
288 hashdone(rulehash);
289 hashdone(targethash);