| File: | dmake/dag.c |
| Location: | line 647, column 4 |
| Description: | Access to field 'st_string' results in a dereference of a null pointer (loaded from variable 'nsp') |
| 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 | } |