option.c: fixed warnings
[k8jam.git] / src / rules.c
blob986277723c9ecba9feb4f20aa432dcaa876eab7b
1 /*
2 * Copyright 1993, 1995 Christopher Seiwald.
3 * This file is part of Jam - see jam.c for Copyright information.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 * rules.c - access to RULEs, TARGETs, and ACTIONs
20 * External routines:
22 * bindrule() - return pointer to RULE, creating it if necessary
23 * bindtarget() - return pointer to TARGET, creating it if necessary
24 * copytarget() - make a new target with the old target's name
25 * touchtarget() - mark a target to simulate being new
26 * targetlist() - turn list of target names into a TARGET chain
27 * targetentry() - add a TARGET to a chain of TARGETS
28 * targetchain() - append two TARGET chains
29 * actionlist() - append to an ACTION chain
30 * addsettings() - add a deferred "set" command to a target
31 * copysettings() - copy a settings list for temp use
32 * pushsettings() - set all target specific variables
33 * popsettings() - reset target specific variables to their pre-push values
34 * freesettings() - delete a settings list
35 * donerules() - free RULE and TARGET tables
37 #include "jam.h"
38 #include "lists.h"
39 #include "parse.h"
40 #include "variable.h"
41 #include "rules.h"
42 #include "newstr.h"
43 #include "hash.h"
46 static struct hash *rulehash = NULL;
47 static struct hash *targethash = NULL;
50 int iteraterules (hash_iterator_cb itercb, void *udata) {
51 if (!rulehash) return 0;
52 return hashiterate(rulehash, itercb, udata);
56 RULE *findrule (const char *rulename) {
57 RULE rule, *r = &rule;
58 if (!rulehash || !rulename || !rulename[0]) return 0;
59 r->name = rulename;
60 return hashcheck(rulehash, (HASHDATA **)&r) ? r : NULL;
65 * haverule() - return !0 if rule exists
67 int haverule (const char *rulename) {
68 return findrule(rulename) ? 1 : 0;
73 * bindrule() - return pointer to RULE, creating it if necessary
75 RULE *bindrule (const char *rulename) {
76 RULE rule, *r = &rule;
77 if (!rulehash) rulehash = hashinit(sizeof(RULE), "rules");
78 r->name = rulename;
79 if (hashenter(rulehash, (HASHDATA **)&r)) {
80 r->name = newstr(rulename); /* never freed */
81 r->procedure = (PARSE *)0;
82 r->actions = (char *)0;
83 r->bindlist = L0;
84 r->params = L0;
85 r->flags = 0;
87 return r;
92 * bindtarget() - return pointer to TARGET, creating it if necessary
94 TARGET *bindtarget (const char *targetname) {
95 TARGET target, *t = &target;
96 if (!targethash) targethash = hashinit(sizeof(TARGET), "targets");
97 t->name = targetname;
98 if (hashenter(targethash, (HASHDATA **)&t)) {
99 memset((char *)t, '\0', sizeof(*t));
100 t->name = newstr(targetname); /* never freed */
101 t->boundname = t->name; /* default for T_FLAG_NOTFILE */
103 return t;
108 * copytarget() - make a new target with the old target's name
110 * Not entered into hash table -- for internal nodes.
112 TARGET *copytarget (const TARGET *ot) {
113 TARGET *t = (TARGET *)malloc(sizeof(*t));
114 memset((char *)t, '\0', sizeof(*t));
115 t->name = copystr(ot->name);
116 t->boundname = t->name;
117 t->flags |= T_FLAG_NOTFILE|T_FLAG_INTERNAL;
118 return t;
123 * touchtarget() - mark a target to simulate being new
125 void touchtarget (const char *t) {
126 bindtarget(t)->flags |= T_FLAG_TOUCHED;
131 * targetlist() - turn list of target names into a TARGET chain
133 * Inputs:
134 * chain existing TARGETS to append to
135 * targets list of target names
137 TARGETS *targetlist (TARGETS *chain, LIST *targets) {
138 for (; targets; targets = list_next(targets)) chain = targetentry(chain, bindtarget(targets->string));
139 return chain;
144 * targetentry() - add a TARGET to a chain of TARGETS
146 * Inputs:
147 * chain exisitng TARGETS to append to
148 * target new target to append
150 TARGETS *targetentry (TARGETS *chain, TARGET *target) {
151 TARGETS *c = (TARGETS *)malloc(sizeof(TARGETS));
152 c->target = target;
153 if (!chain) chain = c; else chain->tail->next = c;
154 chain->tail = c;
155 c->next = 0;
156 return chain;
161 * targetchain() - append two TARGET chains
163 * Inputs:
164 * chain exisitng TARGETS to append to
165 * target new target to append
167 TARGETS *targetchain (TARGETS *chain, TARGETS *targets) {
168 if (!targets) return chain;
169 if (!chain) return targets;
170 chain->tail->next = targets;
171 chain->tail = targets->tail;
172 return chain;
177 * actionlist() - append to an ACTION chain
179 ACTIONS *actionlist (ACTIONS *chain, ACTION *action) {
180 ACTIONS *actions = (ACTIONS *)malloc(sizeof(ACTIONS));
181 actions->action = action;
182 if (!chain) chain = actions; else chain->tail->next = actions;
183 chain->tail = actions;
184 actions->next = 0;
185 return chain;
190 * addsettings() - add a deferred "set" command to a target
192 * Adds a variable setting (varname=list) onto a chain of settings
193 * for a particular target. Replaces the previous previous value,
194 * if any, unless 'append' says to append the new list onto the old.
195 * Returns the head of the chain of settings.
197 SETTINGS *addsettings (SETTINGS *head, int setflag, const char *symbol, LIST *value) {
198 SETTINGS *v;
199 /* look for previous setting */
200 for (v = head; v; v = v->next) if (!strcmp(v->symbol, symbol)) break;
201 /* if not previously set, alloc a new */
202 /* if appending, do so */
203 /* else free old and set new */
204 if (!v) {
205 v = (SETTINGS *)malloc(sizeof(*v));
206 v->symbol = newstr(symbol);
207 v->value = value;
208 v->next = head;
209 head = v;
210 } else {
211 switch (setflag) {
212 case VAR_SET:
213 /* toss old, set new */
214 list_free(v->value);
215 v->value = value;
216 break;
217 case VAR_APPEND:
218 /* append new to old */
219 v->value = list_append(v->value, value);
220 break;
221 case VAR_REMOVE:
222 v->value = list_removeall(v->value, value);
223 list_free(value);
224 break;
225 case VAR_DEFAULT:
226 /* toss new, old already set */
227 list_free(value);
228 break;
231 /* return (new) head of list */
232 return head;
237 * copysettings() - copy a settings list for temp use
239 * When target-specific variables are pushed into place with pushsettings(),
240 * any global variables with the same name are swapped onto the target's
241 * SETTINGS chain. If that chain gets modified (by using the "on target"
242 * syntax), popsettings() would wrongly swap those modified values back
243 * as the new global values.
245 * copysettings() protects the target's SETTINGS chain by providing a
246 * copy of the chain to pass to pushsettings() and popsettings(), so that
247 * the target's original SETTINGS chain can be modified using the usual
248 * "on target" syntax.
250 SETTINGS *copysettings (SETTINGS *from) {
251 SETTINGS *head = 0;
252 for (; from; from = from->next) {
253 SETTINGS *v = (SETTINGS *)malloc(sizeof(*v));
254 v->symbol = copystr(from->symbol);
255 v->value = list_copy(0, from->value);
256 v->next = head;
257 head = v;
259 return head;
264 * pushsettings() - set all target specific variables
266 void pushsettings (SETTINGS *v) {
267 for (; v; v = v->next) v->value = var_swap(v->symbol, v->value);
272 * popsettings() - reset target specific variables to their pre-push values
274 void popsettings (SETTINGS *v) {
275 pushsettings(v); /* just swap again */
280 * freesettings() - delete a settings list
282 void freesettings (SETTINGS *v) {
283 while (v != NULL) {
284 SETTINGS *n = v->next;
285 freestr(v->symbol);
286 list_free(v->value);
287 free((char *)v);
288 v = n;
294 * donerules() - free RULE and TARGET tables
296 void donerules (void) {
297 hashdone(rulehash);
298 hashdone(targethash);