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
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
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;
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");
80 if (hashenter(rulehash
, (HASHDATA
**)&r
)) {
81 r
->name
= newstr(rulename
); /* never freed */
82 r
->procedure
= (PARSE
*)0;
83 r
->actions
= (char *)0;
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");
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 */
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
;
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
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
));
145 * targetentry() - add a TARGET to a chain of TARGETS
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
));
154 if (!chain
) chain
= c
; else chain
->tail
->next
= c
;
162 * targetchain() - append two TARGET chains
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
;
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
;
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
) {
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 */
206 v
= (SETTINGS
*)malloc(sizeof(*v
));
207 v
->symbol
= newstr(symbol
);
214 /* toss old, set new */
219 /* append new to old */
220 v
->value
= list_append(v
->value
, value
);
223 v
->value
= list_removeall(v
->value
, value
);
227 /* toss new, old already set */
232 /* return (new) head of list */
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
) {
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
);
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
) {
285 SETTINGS
*n
= v
->next
;
295 * donerules() - free RULE and TARGET tables
297 void donerules (void) {
299 hashdone(targethash
);