Bug Summary

File:dmake/dag.c
Location:line 80, column 13
Description:Dereference of null pointer (loaded from variable 'Buffer')

Annotated Source Code

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
30static void
31set_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*/
36HASHPTR hp;
37{
38 switch( hp->ht_flag & M_VAR_MASK0xf000 ) /* only one var type per var */
12
Control jumps to 'case 32768:' at line 65
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 */
13
Taking false branch
68
69 tvalue = atoi(hp->ht_value);
70 if( hp->MV_IVARvar.val.mv_ivar == &Buffer_size ) {
14
Taking true branch
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;
15
'?' condition is false
77 if( Buffer_size == tvalue ) break;
16
Taking false branch
78 if( Buffer ) FREE(Buffer)free((char*)(Buffer));
17
Assuming 'Buffer' is null
18
Taking false branch
79 if((Buffer=MALLOC(tvalue, char)(char*) malloc((unsigned int)(tvalue)*(size_t)sizeof(char))) == NIL(char)((char*)((void*)0))) No_ram();
19
Value assigned to 'Buffer'
20
Assuming pointer value is null
21
Taking true branch
80 *Buffer = '\0';
22
Dereference of null pointer (loaded from variable 'Buffer')
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
138PUBLIC HASHPTR
139Get_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
145char *name; /* name we are looking for */
146HASHPTR *tab; /* the hash table to look in */
147int 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
181PUBLIC HASHPTR
182Search_table( tab, name, phv, phkey )
183HASHPTR *tab;
184char *name;
185uint16 *phv;
186uint32 *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
201PUBLIC HASHPTR
202Push_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*/
209HASHPTR 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
249PUBLIC HASHPTR
250Pop_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
256HASHPTR 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)
1
Loop condition is true. Entering loop body
266 if (cur == hp)
2
Taking true branch
267 break;
3
Execution continues on line 270
268
269 /* If cur == NIL macros was not found. */
270 if (cur == NIL(HASH)((HASH*)((void*)0)))
4
Taking false branch
271 return(NIL(HASH)((HASH*)((void*)0)));
272
273 /* Remove hp from the linked list. */
274 if (prev)
5
Taking false branch
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)
6
Loop condition is true. Entering loop body
7
Loop condition is true. Entering loop body
281 if( cur->ht_hash == key
8
Taking true branch
282 && !strcmp(cur->ht_name, hp->ht_name) )
283 break;
9
Execution continues on line 286
284
285 /* If one was found we restore the typecast values. */
286 if (cur)
10
Taking true branch
287 set_macro_value(cur);
11
Calling 'set_macro_value'
288
289 hp->ht_next = NIL(HASH)((HASH*)((void*)0));
290 return(hp);
291}
292
293
294
295PUBLIC HASHPTR
296Def_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
318char *name; /* macro name to define */
319char *value; /* macro value to set */
320int 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
431PUBLIC CELLPTR
432Def_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. */
438char *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
510PUBLIC LINKPTR
511Add_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. */
517CELLPTR cell;
518CELLPTR prq;
519int head;
520int 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
565PUBLIC void
566Clear_prerequisites( cell )/*
567=============================
568 Clear out the list of prerequisites, freeing all of the LINK nodes,
569 and setting the list to NULL */
570CELLPTR 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
590PUBLIC int
591Test_circle( cp, fail )/*
592=========================
593 Actually run through the graph */
594CELLPTR cp;
595int 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
620PUBLIC STRINGPTR
621Def_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. */
629char *rcp;
630STRINGPTR sp;
631int white_too;
632int 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
658PUBLIC t_attr
659Rcp_attribute( rp )/*
660======================
661 Look at the recipe and return the set of attributes that it defines. */
662char *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}