added "jammod" command and "genman" module
[k8jam.git] / src / rules.c
blobd9e2ccd4cbce3f843552ca5bee1736484acd49ac
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, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 * rules.c - access to RULEs, TARGETs, and ACTIONs
21 * External routines:
23 * bindrule() - return pointer to RULE, creating it if necessary
24 * bindtarget() - return pointer to TARGET, creating it if necessary
25 * copytarget() - make a new target with the old target's name
26 * touchtarget() - mark a target to simulate being new
27 * targetlist() - turn list of target names into a TARGET chain
28 * targetentry() - add a TARGET to a chain of TARGETS
29 * targetchain() - append two TARGET chains
30 * actionlist() - append to an ACTION chain
31 * addsettings() - add a deferred "set" command to a target
32 * copysettings() - copy a settings list for temp use
33 * pushsettings() - set all target specific variables
34 * popsettings() - reset target specific variables to their pre-push values
35 * freesettings() - delete a settings list
36 * donerules() - free RULE and TARGET tables
38 #include "jam.h"
39 #include "lists.h"
40 #include "parse.h"
41 #include "variable.h"
42 #include "rules.h"
43 #include "newstr.h"
44 #include "hash.h"
47 static struct hash *rulehash = NULL;
48 static struct hash *targethash = NULL;
51 int iteraterules (hash_iterator_cb itercb, void *udata) {
52 if (!rulehash) return 0;
53 return hashiterate(rulehash, itercb, udata);
57 RULE *findrule (const char *rulename) {
58 RULE rule, *r = &rule;
59 if (!rulehash || !rulename || !rulename[0]) return 0;
60 r->name = rulename;
61 return hashcheck(rulehash, (HASHDATA **)&r) ? r : NULL;
66 * haverule() - return !0 if rule exists
68 int haverule (const char *rulename) {
69 return findrule(rulename) ? 1 : 0;
74 * bindrule() - return pointer to RULE, creating it if necessary
76 RULE *bindrule (const char *rulename) {
77 RULE rule, *r = &rule;
78 if (!rulehash) rulehash = hashinit(sizeof(RULE), "rules");
79 r->name = rulename;
80 if (hashenter(rulehash, (HASHDATA **)&r)) {
81 r->name = newstr(rulename); /* never freed */
82 r->procedure = (PARSE *)0;
83 r->actions = (char *)0;
84 r->bindlist = L0;
85 r->params = L0;
86 r->flags = 0;
88 return r;
93 * bindtarget() - return pointer to TARGET, creating it if necessary
95 TARGET *bindtarget (const char *targetname) {
96 TARGET target, *t = &target;
97 if (!targethash) targethash = hashinit(sizeof(TARGET), "targets");
98 t->name = targetname;
99 if (hashenter(targethash, (HASHDATA **)&t)) {
100 memset((char *)t, '\0', sizeof(*t));
101 t->name = newstr(targetname); /* never freed */
102 t->boundname = t->name; /* default for T_FLAG_NOTFILE */
104 return t;
109 * copytarget() - make a new target with the old target's name
111 * Not entered into hash table -- for internal nodes.
113 TARGET *copytarget (const TARGET *ot) {
114 TARGET *t = (TARGET *)malloc(sizeof(*t));
115 memset((char *)t, '\0', sizeof(*t));
116 t->name = copystr(ot->name);
117 t->boundname = t->name;
118 t->flags |= T_FLAG_NOTFILE|T_FLAG_INTERNAL;
119 return t;
124 * touchtarget() - mark a target to simulate being new
126 void touchtarget (const char *t) {
127 bindtarget(t)->flags |= T_FLAG_TOUCHED;
132 * targetlist() - turn list of target names into a TARGET chain
134 * Inputs:
135 * chain existing TARGETS to append to
136 * targets list of target names
138 TARGETS *targetlist (TARGETS *chain, LIST *targets) {
139 for (; targets; targets = list_next(targets)) chain = targetentry(chain, bindtarget(targets->string));
140 return chain;
145 * targetentry() - add a TARGET to a chain of TARGETS
147 * Inputs:
148 * chain exisitng TARGETS to append to
149 * target new target to append
151 TARGETS *targetentry (TARGETS *chain, TARGET *target) {
152 TARGETS *c = (TARGETS *)malloc(sizeof(TARGETS));
153 c->target = target;
154 if (!chain) chain = c; else chain->tail->next = c;
155 chain->tail = c;
156 c->next = 0;
157 return chain;
162 * targetchain() - append two TARGET chains
164 * Inputs:
165 * chain exisitng TARGETS to append to
166 * target new target to append
168 TARGETS *targetchain (TARGETS *chain, TARGETS *targets) {
169 if (!targets) return chain;
170 if (!chain) return targets;
171 chain->tail->next = targets;
172 chain->tail = targets->tail;
173 return chain;
178 * actionlist() - append to an ACTION chain
180 ACTIONS *actionlist (ACTIONS *chain, ACTION *action) {
181 ACTIONS *actions = (ACTIONS *)malloc(sizeof(ACTIONS));
182 actions->action = action;
183 if (!chain) chain = actions; else chain->tail->next = actions;
184 chain->tail = actions;
185 actions->next = 0;
186 return chain;
191 * addsettings() - add a deferred "set" command to a target
193 * Adds a variable setting (varname=list) onto a chain of settings
194 * for a particular target. Replaces the previous previous value,
195 * if any, unless 'append' says to append the new list onto the old.
196 * Returns the head of the chain of settings.
198 SETTINGS *addsettings (SETTINGS *head, int setflag, const char *symbol, LIST *value) {
199 SETTINGS *v;
200 /* look for previous setting */
201 for (v = head; v; v = v->next) if (!strcmp(v->symbol, symbol)) break;
202 /* if not previously set, alloc a new */
203 /* if appending, do so */
204 /* else free old and set new */
205 if (!v) {
206 v = (SETTINGS *)malloc(sizeof(*v));
207 v->symbol = newstr(symbol);
208 v->value = value;
209 v->next = head;
210 head = v;
211 } else {
212 switch (setflag) {
213 case VAR_SET:
214 /* toss old, set new */
215 list_free(v->value);
216 v->value = value;
217 break;
218 case VAR_APPEND:
219 /* append new to old */
220 v->value = list_append(v->value, value);
221 break;
222 case VAR_REMOVE:
223 v->value = list_removeall(v->value, value);
224 list_free(value);
225 break;
226 case VAR_DEFAULT:
227 /* toss new, old already set */
228 list_free(value);
229 break;
232 /* return (new) head of list */
233 return head;
238 * copysettings() - copy a settings list for temp use
240 * When target-specific variables are pushed into place with pushsettings(),
241 * any global variables with the same name are swapped onto the target's
242 * SETTINGS chain. If that chain gets modified (by using the "on target"
243 * syntax), popsettings() would wrongly swap those modified values back
244 * as the new global values.
246 * copysettings() protects the target's SETTINGS chain by providing a
247 * copy of the chain to pass to pushsettings() and popsettings(), so that
248 * the target's original SETTINGS chain can be modified using the usual
249 * "on target" syntax.
251 SETTINGS *copysettings (SETTINGS *from) {
252 SETTINGS *head = 0;
253 for (; from; from = from->next) {
254 SETTINGS *v = (SETTINGS *)malloc(sizeof(*v));
255 v->symbol = copystr(from->symbol);
256 v->value = list_copy(0, from->value);
257 v->next = head;
258 head = v;
260 return head;
265 * pushsettings() - set all target specific variables
267 void pushsettings (SETTINGS *v) {
268 for (; v; v = v->next) v->value = var_swap(v->symbol, v->value);
273 * popsettings() - reset target specific variables to their pre-push values
275 void popsettings (SETTINGS *v) {
276 pushsettings(v); /* just swap again */
281 * freesettings() - delete a settings list
283 void freesettings (SETTINGS *v) {
284 while (v != NULL) {
285 SETTINGS *n = v->next;
286 freestr(v->symbol);
287 list_free(v->value);
288 free((char *)v);
289 v = n;
295 * donerules() - free RULE and TARGET tables
297 void donerules (void) {
298 hashdone(rulehash);
299 hashdone(targethash);