File: | dmake/dag.c |
Location: | line 80, column 13 |
Description: | Dereference of null pointer (loaded from variable 'Buffer') |
1 | /* | |||
2 | -- | |||
3 | -- SYNOPSIS | |||
4 | -- Routines to construct the internal dag. | |||
5 | -- | |||
6 | -- DESCRIPTION | |||
7 | -- This file contains all the routines that are responsible for | |||
8 | -- defining and manipulating all objects used by the make facility. | |||
9 | -- | |||
10 | -- AUTHOR | |||
11 | -- Dennis Vadura, dvadura@dmake.wticorp.com | |||
12 | -- | |||
13 | -- WWW | |||
14 | -- http://dmake.wticorp.com/ | |||
15 | -- | |||
16 | -- COPYRIGHT | |||
17 | -- Copyright (c) 1996,1997 by WTI Corp. All rights reserved. | |||
18 | -- | |||
19 | -- This program is NOT free software; you can redistribute it and/or | |||
20 | -- modify it under the terms of the Software License Agreement Provided | |||
21 | -- in the file <distribution-root>/readme/license.txt. | |||
22 | -- | |||
23 | -- LOG | |||
24 | -- Use cvs log to obtain detailed change logs. | |||
25 | */ | |||
26 | ||||
27 | #include "extern.h" | |||
28 | ||||
29 | ||||
30 | static void | |||
31 | set_macro_value(hp)/* | |||
32 | ===================== | |||
33 | Set the macro according to its type. In addition to the string value | |||
34 | in hp->ht_value a macro can stores a value casted with its type. | |||
35 | */ | |||
36 | HASHPTR hp; | |||
37 | { | |||
38 | switch( hp->ht_flag & M_VAR_MASK0xf000 ) /* only one var type per var */ | |||
39 | { | |||
40 | case M_VAR_STRING0x4000: | |||
41 | *hp->MV_SVARvar.val.mv_svar = hp->ht_value; | |||
42 | /* Add special treatment for PWD/MAKEDIR for .WINPATH. */ | |||
43 | if( hp->MV_SVARvar.val.mv_svar == &Pwd_macval ) { | |||
44 | if( Pwd ) | |||
45 | FREE(Pwd)free((char*)(Pwd)); | |||
46 | Pwd = hp->ht_value; | |||
47 | /* Use the "DOSified" path for the macro. */ | |||
48 | *hp->MV_SVARvar.val.mv_svar = hp->ht_value = DmStrDup(DO_WINPATH(hp->ht_value)hp->ht_value); | |||
49 | DB_PRINT( "smv", ("PWD: %s/%s", Pwd_macval, Pwd) ); | |||
50 | } else if( hp->MV_SVARvar.val.mv_svar == &Makedir_macval ) { | |||
51 | if( Makedir ) | |||
52 | FREE(Makedir)free((char*)(Makedir)); | |||
53 | Makedir = hp->ht_value; | |||
54 | /* Use the "DOSified" path for the macro. */ | |||
55 | *hp->MV_SVARvar.val.mv_svar = hp->ht_value = DmStrDup(DO_WINPATH(hp->ht_value)hp->ht_value); | |||
56 | DB_PRINT( "smv", ("MAKEDIR: %s/%s", Makedir_macval, Makedir) ); | |||
57 | } | |||
58 | /* No special treatment for TMD needed. */ | |||
59 | break; | |||
60 | ||||
61 | case M_VAR_CHAR0x2000: | |||
62 | *hp->MV_CVARvar.val.mv_cvar = (hp->ht_value == NIL(char)((char*)((void*)0))) ? '\0':*hp->ht_value; | |||
63 | break; | |||
64 | ||||
65 | case M_VAR_INT0x8000: { | |||
66 | int tvalue; | |||
67 | if( hp->MV_IVARvar.val.mv_ivar == NIL(int)((int*)((void*)0)) ) break; /* first time */ | |||
68 | ||||
69 | tvalue = atoi(hp->ht_value); | |||
70 | if( hp->MV_IVARvar.val.mv_ivar == &Buffer_size ) { | |||
71 | /* If Buffer_size (MAXLINELENGTH) is modified then make sure | |||
72 | * you change the size of the real buffer as well. As the | |||
73 | * value will at least be BUFSIZ this might lead to the | |||
74 | * situation that the (string) value of MAXLINELENGTH is | |||
75 | * smaller than the integer value. */ | |||
76 | tvalue = (tvalue < (BUFSIZ8192-2)) ? BUFSIZ8192 : tvalue+2; | |||
77 | if( Buffer_size == tvalue ) break; | |||
78 | if( Buffer ) FREE(Buffer)free((char*)(Buffer)); | |||
79 | if((Buffer=MALLOC(tvalue, char)(char*) malloc((unsigned int)(tvalue)*(size_t)sizeof(char))) == NIL(char)((char*)((void*)0))) No_ram(); | |||
80 | *Buffer = '\0'; | |||
| ||||
81 | } | |||
82 | *hp->MV_IVARvar.val.mv_ivar = tvalue; | |||
83 | ||||
84 | if( hp->MV_IVARvar.val.mv_ivar == &Max_proc || hp->MV_IVARvar.val.mv_ivar == &Max_proclmt ) { | |||
85 | if( tvalue < 1 ) | |||
86 | Fatal( "Process limit value must be > 1" ); | |||
87 | ||||
88 | #if defined(USE_CREATEPROCESS) | |||
89 | if( Max_proclmt > MAXIMUM_WAIT_OBJECTS ) | |||
90 | Fatal( "Specified maximum # of processes (MAXPROCESSLIMIT)" | |||
91 | " exceeds OS limit of [%d].", MAXIMUM_WAIT_OBJECTS ); | |||
92 | #endif | |||
93 | ||||
94 | if( Max_proc > Max_proclmt ) | |||
95 | Fatal( "Specified # of processes exceeds limit of [%d]", | |||
96 | Max_proclmt ); | |||
97 | ||||
98 | /* Don't change MAXPROCESS value if .SEQUENTIAL is set. */ | |||
99 | if( (Glob_attr & A_SEQ0x00200) && (Max_proc != 1) ) { | |||
100 | Warning( "Macro MAXPROCESS set to 1 because .SEQUENTIAL is set." ); | |||
101 | Max_proc = 1; | |||
102 | if( hp->ht_value != NIL(char)((char*)((void*)0)) ) FREE(hp->ht_value)free((char*)(hp->ht_value)); | |||
103 | hp->ht_value = DmStrDup( "1" ); | |||
104 | } | |||
105 | } | |||
106 | } break; | |||
107 | ||||
108 | case M_VAR_BIT0x1000: | |||
109 | /* Bit variables are set to 1 if ht_value is not NULL and 0 | |||
110 | * otherwise */ | |||
111 | ||||
112 | if( hp->ht_value == NIL(char)((char*)((void*)0)) ) | |||
113 | *hp->MV_BVARvar.val.mv_bvar &= ~hp->MV_MASKvar.mv_mask; | |||
114 | else { | |||
115 | *hp->MV_BVARvar.val.mv_bvar |= hp->MV_MASKvar.mv_mask; | |||
116 | /* If we're setting .SEQUENTIAL set MAXPROCESS=1. */ | |||
117 | if( (hp->MV_MASKvar.mv_mask & A_SEQ0x00200) && (Max_proc != 1) ) | |||
118 | Def_macro( "MAXPROCESS", "1", M_MULTI0x0004|M_EXPANDED0x0008); | |||
119 | } | |||
120 | ||||
121 | #if defined(__CYGWIN__) | |||
122 | /* Global .WINPATH change. Only needed for cygwin. */ | |||
123 | if(hp->MV_MASKvar.mv_mask & A_WINPATH0x01000) { | |||
124 | UseWinpath = ((Glob_attr&A_WINPATH0x01000) != 0); | |||
125 | /* Change MAKEDIR, PWD according to .WINPATH. During | |||
126 | * makefile evaluation this cannot change TMD (it is "." | |||
127 | * and later TMD is set in Make() according to the | |||
128 | * .WINPATH attribute. */ | |||
129 | Def_macro( "MAKEDIR", Makedir, M_FORCE0x0080 | M_EXPANDED0x0008 ); | |||
130 | Def_macro( "PWD", Pwd, M_FORCE0x0080 | M_EXPANDED0x0008 ); | |||
131 | } | |||
132 | #endif | |||
133 | break; | |||
134 | } | |||
135 | } | |||
136 | ||||
137 | ||||
138 | PUBLIC HASHPTR | |||
139 | Get_name( name, tab, define )/* | |||
140 | =============================== | |||
141 | Look to see if the name is defined, if it is then return | |||
142 | a pointer to its node, if not return NIL(HASH). | |||
143 | If define is TRUE and the name is not found it will be added. */ | |||
144 | ||||
145 | char *name; /* name we are looking for */ | |||
146 | HASHPTR *tab; /* the hash table to look in */ | |||
147 | int define; /* TRUE => add to table */ | |||
148 | { | |||
149 | register HASHPTR hp; | |||
150 | register char *p; | |||
151 | uint16 hv; | |||
152 | uint32 hash_key; | |||
153 | ||||
154 | DB_ENTER( "Get_name" ); | |||
155 | DB_PRINT( "name", ("Looking for %s", name) ); | |||
156 | ||||
157 | hp = Search_table( tab, name, &hv, &hash_key ); | |||
158 | ||||
159 | if( hp == NIL(HASH)((HASH*)((void*)0)) && define ) { | |||
160 | /* Check to make sure that CELL name contains only printable chars */ | |||
161 | for( p=name; *p; p++ ) | |||
162 | if( !isprint(*p)((*__ctype_b_loc ())[(int) ((*p))] & (unsigned short int) _ISprint) && !iswhite(*p)((*p == ' ') || (*p == '\t')) && *p != '\n' ) | |||
163 | Fatal( "Name contains non-printable character [0x%02x]", *p ); | |||
164 | ||||
165 | TALLOC( hp, 1, HASH )if ((hp = (HASH*) calloc((unsigned int)(1), (size_t)sizeof(HASH ))) == (HASH*)0) {No_ram();}; /* allocate a cell and add it in */ | |||
166 | ||||
167 | hp->ht_name = DmStrDup( name ); | |||
168 | hp->ht_hash = hash_key; | |||
169 | hp->ht_next = tab[ hv ]; | |||
170 | tab[ hv ] = hp; | |||
171 | ||||
172 | DB_PRINT( "name", ("Adding %s", name) ); | |||
173 | } | |||
174 | ||||
175 | DB_PRINT( "name",("Returning: [%s,%lu]", | |||
176 | (hp == NIL(HASH)) ? "":hp->ht_name, hv) ); | |||
177 | DB_RETURN( hp )return (hp); | |||
178 | } | |||
179 | ||||
180 | ||||
181 | PUBLIC HASHPTR | |||
182 | Search_table( tab, name, phv, phkey ) | |||
183 | HASHPTR *tab; | |||
184 | char *name; | |||
185 | uint16 *phv; | |||
186 | uint32 *phkey; | |||
187 | { | |||
188 | HASHPTR hp; | |||
189 | ||||
190 | *phv = Hash( name, phkey ); | |||
191 | ||||
192 | for( hp = tab[ *phv ]; hp != NIL(HASH)((HASH*)((void*)0)); hp = hp->ht_next ) | |||
193 | if( hp->ht_hash == *phkey | |||
194 | && !strcmp(hp->ht_name, name) ) | |||
195 | break; | |||
196 | ||||
197 | return( hp ); | |||
198 | } | |||
199 | ||||
200 | ||||
201 | PUBLIC HASHPTR | |||
202 | Push_macro(hp)/* | |||
203 | ================ | |||
204 | This function pushes hp into the hash of all macros. If a previous | |||
205 | instance of the macro exists it is hidden by the new one. If one | |||
206 | existed before the new instance inherits some values from the preexisting | |||
207 | macro (see below for details). | |||
208 | */ | |||
209 | HASHPTR hp; | |||
210 | { | |||
211 | HASHPTR cur,prev; | |||
212 | uint16 hv; | |||
213 | uint32 key; | |||
214 | ||||
215 | hv = Hash(hp->ht_name, &key); | |||
216 | ||||
217 | /* Search for an existing instance of hp->ht_name, if found cur will point | |||
218 | * to it. */ | |||
219 | for(prev=NIL(HASH)((HASH*)((void*)0)),cur=Macs[hv]; cur!=NIL(HASH)((HASH*)((void*)0)); prev=cur,cur=cur->ht_next) | |||
220 | if( cur->ht_hash == key | |||
221 | && !strcmp(cur->ht_name, hp->ht_name) ) | |||
222 | break; | |||
223 | ||||
224 | if (cur == NIL(HASH)((HASH*)((void*)0)) || prev == NIL(HASH)((HASH*)((void*)0))) { | |||
225 | /* If no match or was found or the first element of Macs[hv] was | |||
226 | * the match insert hp at the beginning. */ | |||
227 | hp->ht_next = Macs[hv]; | |||
228 | Macs[hv] = hp; | |||
229 | } | |||
230 | else { | |||
231 | /* otherwise insert hp in the chain. */ | |||
232 | hp->ht_next = prev->ht_next; | |||
233 | prev->ht_next = hp; | |||
234 | } | |||
235 | ||||
236 | /* Inherit some parts of the former instance. Copying cur->var to hp->var | |||
237 | * copies the old value. Keeping the M_VAR_MASK (variable type) makes sure | |||
238 | * the type stays the same keeping M_PRECIOUS assures that the old values | |||
239 | * cannot be overridden if it is/was set. */ | |||
240 | if (cur) { | |||
241 | memcpy((void *)&hp->var, (void *)&cur->var, sizeof(hp->var)); | |||
242 | hp->ht_flag |= ((M_VAR_MASK0xf000|M_PRECIOUS0x0002) & cur->ht_flag); | |||
243 | } | |||
244 | ||||
245 | return(hp); | |||
246 | } | |||
247 | ||||
248 | ||||
249 | PUBLIC HASHPTR | |||
250 | Pop_macro(hp)/* | |||
251 | ================ | |||
252 | This function pops (removes) hp from the hash of all macros. If a previous | |||
253 | instance of the macro existed it becomes accessible again. | |||
254 | */ | |||
255 | ||||
256 | HASHPTR hp; | |||
257 | { | |||
258 | HASHPTR cur,prev; | |||
259 | uint16 hv; | |||
260 | uint32 key; | |||
261 | ||||
262 | hv = Hash(hp->ht_name, &key); | |||
263 | ||||
264 | /* Try to find hp. */ | |||
265 | for(prev=NIL(HASH)((HASH*)((void*)0)),cur=Macs[hv]; cur != NIL(HASH)((HASH*)((void*)0));prev=cur,cur=cur->ht_next) | |||
| ||||
266 | if (cur == hp) | |||
267 | break; | |||
268 | ||||
269 | /* If cur == NIL macros was not found. */ | |||
270 | if (cur == NIL(HASH)((HASH*)((void*)0))) | |||
271 | return(NIL(HASH)((HASH*)((void*)0))); | |||
272 | ||||
273 | /* Remove hp from the linked list. */ | |||
274 | if (prev) | |||
275 | prev->ht_next = cur->ht_next; | |||
276 | else | |||
277 | Macs[hv] = cur->ht_next; | |||
278 | ||||
279 | /* Look for a previous (older) instance of hp->ht_name. */ | |||
280 | for(cur=cur->ht_next; cur != NIL(HASH)((HASH*)((void*)0)); cur=cur->ht_next) | |||
281 | if( cur->ht_hash == key | |||
282 | && !strcmp(cur->ht_name, hp->ht_name) ) | |||
283 | break; | |||
284 | ||||
285 | /* If one was found we restore the typecast values. */ | |||
286 | if (cur) | |||
287 | set_macro_value(cur); | |||
288 | ||||
289 | hp->ht_next = NIL(HASH)((HASH*)((void*)0)); | |||
290 | return(hp); | |||
291 | } | |||
292 | ||||
293 | ||||
294 | ||||
295 | PUBLIC HASHPTR | |||
296 | Def_macro( name, value, flags )/* | |||
297 | ================================= | |||
298 | This routine is used to define a macro, and it's value. A copy of | |||
299 | the content of value is stored and not the pointer to the value. | |||
300 | The flags indicates if it is a permanent macro or if it's value | |||
301 | can be redefined. A flags of M_PRECIOUS means it is a precious | |||
302 | macro and cannot be further redefined unless M_FORCE is used. | |||
303 | If the flags flag contains the M_MULTI bit it means that the macro | |||
304 | can be redefined multiple times and no warning of the redefinitions | |||
305 | should be issued. | |||
306 | Once a macro's VAR flags are set they are preserved through all future | |||
307 | macro definitions. | |||
308 | ||||
309 | Macro definitions that have one of the variable bits set are treated | |||
310 | specially. In each case the hash table entry var field points at the | |||
311 | global variable that can be set by assigning to the macro. | |||
312 | ||||
313 | bit valued global vars must be computed when the macro value is changed. | |||
314 | char valued global vars must have the first char of ht_value copied to | |||
315 | them. string valued global vars have the same value as ht_value and should | |||
316 | just have the new value of ht_value copied to them. */ | |||
317 | ||||
318 | char *name; /* macro name to define */ | |||
319 | char *value; /* macro value to set */ | |||
320 | int flags; /* initial ht_flags */ | |||
321 | { | |||
322 | register HASHPTR hp; | |||
323 | register char *p, *q; | |||
324 | ||||
325 | DB_ENTER( "Def_macro" ); | |||
326 | DB_PRINT( "mac", ("Defining macro %s = %s, %x", name, value, flags) ); | |||
327 | ||||
328 | /* check to see if name is in the table, if so then just overwrite | |||
329 | the previous definition. Otherwise allocate a new node, and | |||
330 | stuff it in the hash table, at the front of any linked list */ | |||
331 | ||||
332 | if( Readenv ) flags |= M_LITERAL0x0020|M_EXPANDED0x0008; | |||
333 | ||||
334 | hp = Get_name( name, Macs, TRUE1 ); | |||
335 | ||||
336 | if ((flags & M_PUSH0x0100) && hp->ht_name != NIL(char)((char*)((void*)0))) { | |||
337 | HASHPTR thp=hp; | |||
338 | TALLOC(hp,1,HASH)if ((hp = (HASH*) calloc((unsigned int)(1), (size_t)sizeof(HASH ))) == (HASH*)0) {No_ram();}; | |||
339 | hp->ht_name = DmStrDup(thp->ht_name); | |||
340 | hp->ht_hash = thp->ht_hash; | |||
341 | Push_macro(hp); | |||
342 | flags |= hp->ht_flag; | |||
343 | } | |||
344 | flags &= ~M_PUSH0x0100; | |||
345 | ||||
346 | if( (hp->ht_flag & M_PRECIOUS0x0002) && !(flags & M_FORCE0x0080) ) { | |||
347 | if (Verbose & V_WARNALL0x40) | |||
348 | Warning( "Macro `%s' cannot be redefined", name ); | |||
349 | DB_RETURN( hp )return (hp); | |||
350 | } | |||
351 | ||||
352 | /* Make sure we don't export macros whose names contain legal macro | |||
353 | * assignment operators, since we can't do proper quoting in the | |||
354 | * environment. */ | |||
355 | if( *DmStrPbrk(name, "*+:=") != '\0' ) flags |= M_NOEXPORT0x0040; | |||
356 | ||||
357 | if( hp->ht_value != NIL(char)((char*)((void*)0)) ) FREE( hp->ht_value )free((char*)(hp->ht_value)); | |||
358 | ||||
359 | if( (hp->ht_flag & M_USED0x0010) && !((flags | hp->ht_flag) & M_MULTI0x0004) ) | |||
360 | Warning( "Macro `%s' redefined after use", name ); | |||
361 | ||||
362 | /* If an empty string ("") is given set ht_value to NIL(char) */ | |||
363 | if( (value != NIL(char)((char*)((void*)0))) && (*value) ) { | |||
364 | ||||
365 | if( !(flags & M_LITERAL0x0020) ) { | |||
366 | q = DmStrDup(value); | |||
367 | /* strip out any \<nl> combinations where \ is the current | |||
368 | * CONTINUATION char */ | |||
369 | for(p=q; (p=strchr(p,CONTINUATION_CHAR'\\'))!=NIL(char)((char*)((void*)0)); ) | |||
370 | if( p[1] == '\n' ) { | |||
371 | size_t len = strlen(p+2)+1; | |||
372 | memmove ( p, p+2, len ); | |||
373 | } | |||
374 | else | |||
375 | p++; | |||
376 | ||||
377 | p = DmStrSpn(q ," \t"); /* Strip white space before ... */ | |||
378 | if( p != q ) { | |||
379 | size_t len = strlen(p)+1; | |||
380 | memmove( q, p, len ); | |||
381 | p = q; | |||
382 | } | |||
383 | ||||
384 | if( *p ) { /* ... and after the value. */ | |||
385 | for(q=p+strlen(p)-1; ((*q == ' ')||(*q == '\t')); q--); | |||
386 | *++q = '\0'; | |||
387 | } | |||
388 | flags &= ~M_LITERAL0x0020; | |||
389 | } | |||
390 | else | |||
391 | p = DmStrDup( value ); /* take string literally */ | |||
392 | ||||
393 | if( !*p ) { /* check if result is "" */ | |||
394 | FREE( p )free((char*)(p)); | |||
395 | p = NIL(char)((char*)((void*)0)); | |||
396 | flags |= M_EXPANDED0x0008; | |||
397 | } | |||
398 | else if( *DmStrPbrk( p, "${}" ) == '\0' ) | |||
399 | flags |= M_EXPANDED0x0008; | |||
400 | ||||
401 | hp->ht_value = p; | |||
402 | } | |||
403 | else { | |||
404 | hp->ht_value = NIL(char)((char*)((void*)0)); | |||
405 | flags |= M_EXPANDED0x0008; | |||
406 | } | |||
407 | ||||
408 | /* Assign the hash table flag less the M_MULTI flag, it is used only | |||
409 | * to silence the warning. But carry it over if it was previously | |||
410 | * defined in ht_flag, as this is a permanent M_MULTI variable. Keep | |||
411 | * the M_PRECIOUS flag and strip the M_INIT flag. */ | |||
412 | ||||
413 | hp->ht_flag = ((flags & ~(M_MULTI0x0004|M_FORCE0x0080)) | | |||
414 | (hp->ht_flag & (M_VAR_MASK0xf000|M_MULTI0x0004|M_PRECIOUS0x0002))) & ~M_INIT0x0200; | |||
415 | ||||
416 | /* Check for macro variables and make the necessary adjustment in the | |||
417 | * corresponding global variables */ | |||
418 | ||||
419 | if( hp->ht_flag & M_VAR_MASK0xf000 ) { | |||
420 | if( !(flags & M_EXPANDED0x0008) ) | |||
421 | Error( "Macro variable '%s' must be assigned with :=", name ); | |||
422 | else | |||
423 | set_macro_value(hp); | |||
424 | } | |||
425 | ||||
426 | DB_RETURN( hp )return (hp); | |||
427 | } | |||
428 | ||||
429 | ||||
430 | ||||
431 | PUBLIC CELLPTR | |||
432 | Def_cell( name )/* | |||
433 | ================== | |||
434 | Check if a cell for "name" already exists, if not create a new cell. | |||
435 | The value of name is normalized before checking/creating the cell to | |||
436 | avoid creating multiple cells for the same target file. | |||
437 | The function returns a pointer to the cell. */ | |||
438 | char *name; | |||
439 | { | |||
440 | register HASHPTR hp; | |||
441 | register CELLPTR cp; | |||
442 | register CELLPTR lib; | |||
443 | char *member; | |||
444 | char *end; | |||
445 | ||||
446 | DB_ENTER( "Def_cell" ); | |||
447 | ||||
448 | /* Check to see if the cell is a member of the form lib(member) or | |||
449 | * lib((symbol)) and handle the cases appropriately. | |||
450 | * What we do is we look at the target, if it is of the above two | |||
451 | * forms we get the lib, and add the member/symbol to the list of | |||
452 | * prerequisites for the library. If this is a symbol name def'n | |||
453 | * we additionally add the attribute A_SYMBOL, so that stat can | |||
454 | * try to do the right thing. */ | |||
455 | ||||
456 | if( ((member = strchr(name, '(')) != NIL(char)((char*)((void*)0))) && | |||
457 | ((end = strrchr(member, ')')) != NIL(char)((char*)((void*)0))) && | |||
458 | (member > name) && (member[-1] != '$') && | |||
459 | (end > member+1) && (end[1] == '\0') ) | |||
460 | { | |||
461 | *member++ = *end = '\0'; | |||
462 | ||||
463 | if( (*member == '(') && (member[strlen(member)-1] == ')') ) { | |||
464 | member[ strlen(member)-1 ] = '\0'; | |||
465 | cp = Def_cell( member+1 ); | |||
466 | cp->ce_attr |= A_SYMBOL0x00040; | |||
467 | } | |||
468 | else | |||
469 | cp = Def_cell( member ); | |||
470 | ||||
471 | lib = Def_cell( name ); | |||
472 | ||||
473 | Add_prerequisite( lib, cp, FALSE0, FALSE0 ); | |||
474 | lib->ce_attr |= A_LIBRARY0x00004 | A_COMPOSITE0x200000; | |||
475 | ||||
476 | if( !Def_targets ) cp = lib; | |||
477 | } | |||
478 | else { | |||
479 | /* Normalize the name. */ | |||
480 | DB_PRINT( "path", ("Normalizing [%s]", name) ); | |||
481 | ||||
482 | /* The normalizing function returns a pointer to a static buffer. */ | |||
483 | name = normalize_path(name); | |||
484 | ||||
485 | hp = Get_name( name, Defs, TRUE1 );/* get the name from hash table */ | |||
486 | ||||
487 | if( hp->CP_OWNRvar.val.ht.ht_owner == NIL(CELL)((CELL*)((void*)0)) ) /* was it previously defined */ | |||
488 | { /* NO, so define a new cell */ | |||
489 | DB_PRINT( "cell", ("Defining cell [%s]", name) ); | |||
490 | ||||
491 | TALLOC( cp, 1, CELL )if ((cp = (CELL*) calloc((unsigned int)(1), (size_t)sizeof(CELL ))) == (CELL*)0) {No_ram();}; | |||
492 | hp->CP_OWNRvar.val.ht.ht_owner = cp; | |||
493 | cp->ce_name = hp; | |||
494 | cp->ce_fname = hp->ht_name; | |||
495 | cp->ce_all.cl_prq = cp; | |||
496 | } | |||
497 | else /* YES, so return the old cell */ | |||
498 | { | |||
499 | DB_PRINT( "cell", ("Getting cell [%s]", hp->ht_name) ); | |||
500 | cp = hp->CP_OWNRvar.val.ht.ht_owner; | |||
501 | } | |||
502 | } | |||
503 | ||||
504 | DB_RETURN( cp )return (cp); | |||
505 | } | |||
506 | ||||
507 | ||||
508 | ||||
509 | ||||
510 | PUBLIC LINKPTR | |||
511 | Add_prerequisite( cell, prq, head, force )/* | |||
512 | ============================================ | |||
513 | Add a dependency node to the dag. It adds it to the prerequisites, | |||
514 | if any, of the cell and makes certain they are in linear order. | |||
515 | If head == 1, then add to head of the prerequisite list, else | |||
516 | add to tail. */ | |||
517 | CELLPTR cell; | |||
518 | CELLPTR prq; | |||
519 | int head; | |||
520 | int force; | |||
521 | { | |||
522 | register LINKPTR lp, tlp; | |||
523 | ||||
524 | DB_ENTER( "Add_prerequisite" ); | |||
525 | DB_PRINT( "cell", ("Defining prerequisite %s", prq->CE_NAME) ); | |||
526 | ||||
527 | if( (prq->ce_flag & (F_MAGIC0x2000 | F_PERCENT0x0800)) && !force ) | |||
528 | Fatal( "Special target [%s] cannot be a prerequisite", | |||
529 | prq->CE_NAMEce_name->ht_name ); | |||
530 | ||||
531 | if( cell->ce_prq == NIL(LINK)((LINK*)((void*)0)) ) { /* it's the first one */ | |||
532 | TALLOC( lp, 1, LINK )if ((lp = (LINK*) calloc((unsigned int)(1), (size_t)sizeof(LINK ))) == (LINK*)0) {No_ram();}; | |||
533 | lp->cl_prq = prq; | |||
534 | cell->ce_prq = lp; | |||
535 | } | |||
536 | else { /* search the list, checking for duplicates */ | |||
537 | for( lp = cell->ce_prq; | |||
538 | (lp->cl_next != NIL(LINK)((LINK*)((void*)0))) && (lp->cl_prq != prq); | |||
539 | lp = lp->cl_next ); | |||
540 | ||||
541 | /* If the prq is not found and we are at the last prq in the list, | |||
542 | * allocate a new prq and place it into the list, insert it at the | |||
543 | * head if head == 1, else we add it to the end. */ | |||
544 | ||||
545 | if( lp->cl_prq != prq ) { | |||
546 | TALLOC( tlp, 1, LINK )if ((tlp = (LINK*) calloc((unsigned int)(1), (size_t)sizeof(LINK ))) == (LINK*)0) {No_ram();}; | |||
547 | tlp->cl_prq = prq; | |||
548 | ||||
549 | if( head ) { | |||
550 | tlp->cl_next = cell->ce_prq; | |||
551 | cell->ce_prq = tlp; | |||
552 | } | |||
553 | else | |||
554 | lp->cl_next = tlp; | |||
555 | ||||
556 | lp = tlp; | |||
557 | } | |||
558 | } | |||
559 | ||||
560 | DB_RETURN( lp )return (lp); | |||
561 | } | |||
562 | ||||
563 | ||||
564 | ||||
565 | PUBLIC void | |||
566 | Clear_prerequisites( cell )/* | |||
567 | ============================= | |||
568 | Clear out the list of prerequisites, freeing all of the LINK nodes, | |||
569 | and setting the list to NULL */ | |||
570 | CELLPTR cell; | |||
571 | { | |||
572 | LINKPTR lp, tlp; | |||
573 | ||||
574 | DB_ENTER( "Clear_prerequisites" ); | |||
575 | DB_PRINT( "cell", ("Nuking prerequisites") ); | |||
576 | ||||
577 | if( cell == NIL(CELL)((CELL*)((void*)0)) ) { DB_VOID_RETURNreturn; } | |||
578 | ||||
579 | for( lp=cell->ce_prq; lp != NIL(LINK)((LINK*)((void*)0)); lp=tlp ) { | |||
580 | tlp=lp->cl_next; | |||
581 | FREE( lp )free((char*)(lp)); | |||
582 | } | |||
583 | ||||
584 | cell->ce_prq = NIL(LINK)((LINK*)((void*)0)); | |||
585 | ||||
586 | DB_VOID_RETURNreturn; | |||
587 | } | |||
588 | ||||
589 | ||||
590 | PUBLIC int | |||
591 | Test_circle( cp, fail )/* | |||
592 | ========================= | |||
593 | Actually run through the graph */ | |||
594 | CELLPTR cp; | |||
595 | int fail; | |||
596 | { | |||
597 | register LINKPTR lp; | |||
598 | int res = 0; | |||
599 | ||||
600 | DB_ENTER( "Test_circle" ); | |||
601 | DB_PRINT( "tc", ("checking [%s]", cp->CE_NAME) ); | |||
602 | ||||
603 | if( cp->ce_flag & F_MARK0x0001 ) { | |||
604 | if( fail ) | |||
605 | Fatal("Detected circular dependency in graph at [%s]", cp->CE_NAMEce_name->ht_name); | |||
606 | else | |||
607 | DB_RETURN( 1 )return (1); | |||
608 | } | |||
609 | ||||
610 | cp->ce_flag |= F_MARK0x0001; | |||
611 | for( lp = cp->ce_prq; !res && lp != NIL(LINK)((LINK*)((void*)0)); lp = lp->cl_next ) | |||
612 | res = Test_circle( lp->cl_prq, fail ); | |||
613 | cp->ce_flag ^= F_MARK0x0001; | |||
614 | ||||
615 | DB_RETURN( res )return (res); | |||
616 | } | |||
617 | ||||
618 | ||||
619 | ||||
620 | PUBLIC STRINGPTR | |||
621 | Def_recipe( rcp, sp, white_too, no_check )/* | |||
622 | ============================================= | |||
623 | Take the recipe (rcp) and add it to the list of recipes pointed to by | |||
624 | sp (sp points to the last element). If white_too == TRUE add the recipe | |||
625 | even if it contains only white space or an empty string. | |||
626 | Return a pointer to the new recipe (or sp if it was discarded). | |||
627 | If no_check is true then don't look for -@ at the start of the recipe | |||
628 | line. */ | |||
629 | char *rcp; | |||
630 | STRINGPTR sp; | |||
631 | int white_too; | |||
632 | int no_check; | |||
633 | { | |||
634 | register STRINGPTR nsp; | |||
635 | register char *rp; | |||
636 | ||||
637 | DB_ENTER( "Def_recipe" ); | |||
638 | DB_PRINT( "rul", ("Defining recipe %s", rcp) ); | |||
639 | ||||
640 | if( !white_too ) rcp = DmStrSpn( rcp, " \t" ); | |||
641 | if( (rcp == NIL(char)((char*)((void*)0))) || (*rcp == 0 && !white_too) ) | |||
642 | DB_RETURN( sp )return (sp); /* return last recipe when new recipe not added */ | |||
643 | ||||
644 | rp = no_check ? rcp : DmStrSpn( rcp, " \t@-+%" ); | |||
645 | ||||
646 | TALLOC(nsp, 1, STRING)if ((nsp = (STRING*) calloc((unsigned int)(1), (size_t)sizeof (STRING))) == (STRING*)0) {No_ram();}; | |||
647 | nsp->st_string = DmStrDup( rp ); | |||
648 | ||||
649 | if( sp != NIL(STRING)((STRING*)((void*)0)) ) sp->st_next = nsp; | |||
650 | nsp->st_next = NIL(STRING)((STRING*)((void*)0)); | |||
651 | ||||
652 | if( !no_check ) nsp->st_attr |= Rcp_attribute( rcp ); | |||
653 | ||||
654 | DB_RETURN( nsp )return (nsp); | |||
655 | } | |||
656 | ||||
657 | ||||
658 | PUBLIC t_attr | |||
659 | Rcp_attribute( rp )/* | |||
660 | ====================== | |||
661 | Look at the recipe and return the set of attributes that it defines. */ | |||
662 | char *rp; | |||
663 | { | |||
664 | t_attr flag = A_DEFAULT0x00000; | |||
665 | int done = FALSE0; | |||
666 | int atcount = 0; | |||
667 | ||||
668 | while( !done ) | |||
669 | switch( *rp++ ) | |||
670 | { | |||
671 | case '@' : ++atcount; break; | |||
672 | case '-' : flag |= A_IGNORE0x00020; break; | |||
673 | case '+' : flag |= A_SHELL0x00800; break; | |||
674 | case '%' : | |||
675 | #if defined(MSDOS) | |||
676 | /* Ignore % in the non-MSDOS case. */ | |||
677 | flag |= A_SWAP0x01000; | |||
678 | #endif | |||
679 | break; | |||
680 | ||||
681 | case ' ' : | |||
682 | case '\t': break; | |||
683 | ||||
684 | default: done = TRUE1; break; | |||
685 | } | |||
686 | ||||
687 | if( !(Verbose & V_FORCEECHO0x80) && atcount-- ) { | |||
688 | flag |= A_SILENT0x00002; | |||
689 | /* hide output if more than one @ are encountered. */ | |||
690 | if( atcount ) | |||
691 | flag |= A_MUTE0x80000000; | |||
692 | } | |||
693 | ||||
694 | return(flag); | |||
695 | } |