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
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
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;
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");
79 if (hashenter(rulehash
, (HASHDATA
**)&r
)) {
80 r
->name
= newstr(rulename
); /* never freed */
81 r
->procedure
= (PARSE
*)0;
82 r
->actions
= (char *)0;
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");
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 */
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
;
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
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
));
144 * targetentry() - add a TARGET to a chain of TARGETS
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
));
153 if (!chain
) chain
= c
; else chain
->tail
->next
= c
;
161 * targetchain() - append two TARGET chains
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
;
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
;
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
) {
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 */
205 v
= (SETTINGS
*)malloc(sizeof(*v
));
206 v
->symbol
= newstr(symbol
);
213 /* toss old, set new */
218 /* append new to old */
219 v
->value
= list_append(v
->value
, value
);
222 v
->value
= list_removeall(v
->value
, value
);
226 /* toss new, old already set */
231 /* return (new) head of list */
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
) {
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
);
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
) {
284 SETTINGS
*n
= v
->next
;
294 * donerules() - free RULE and TARGET tables
296 void donerules (void) {
298 hashdone(targethash
);