| File: | dmake/infer.c |
| Location: | line 224, column 9 |
| Description: | Access to field 'ce_per' results in a dereference of a null pointer (loaded from variable 'infcell') |
| 1 | /* | |||
| 2 | -- | |||
| 3 | -- SYNOPSIS | |||
| 4 | -- Infer how to make a target. | |||
| 5 | -- | |||
| 6 | -- DESCRIPTION | |||
| 7 | -- This file contains the code to infer a recipe, and possibly some new | |||
| 8 | -- prerequisites for a target which dmake does not know how to make, or | |||
| 9 | -- has no explicit recipe. | |||
| 10 | -- | |||
| 11 | -- The inference fails if no path through the inference graph can be | |||
| 12 | -- found by which we can make the target. | |||
| 13 | -- | |||
| 14 | -- AUTHOR | |||
| 15 | -- Dennis Vadura, dvadura@dmake.wticorp.com | |||
| 16 | -- | |||
| 17 | -- WWW | |||
| 18 | -- http://dmake.wticorp.com/ | |||
| 19 | -- | |||
| 20 | -- COPYRIGHT | |||
| 21 | -- Copyright (c) 1996,1997 by WTI Corp. All rights reserved. | |||
| 22 | -- | |||
| 23 | -- This program is NOT free software; you can redistribute it and/or | |||
| 24 | -- modify it under the terms of the Software License Agreement Provided | |||
| 25 | -- in the file <distribution-root>/readme/license.txt. | |||
| 26 | -- | |||
| 27 | -- LOG | |||
| 28 | -- Use cvs log to obtain detailed change logs. | |||
| 29 | */ | |||
| 30 | ||||
| 31 | #include "extern.h" | |||
| 32 | ||||
| 33 | /* attributes that get transfered from the % start cell to the inferred | |||
| 34 | * cells. */ | |||
| 35 | ||||
| 36 | #define A_TRANSFER(0x00008 | 0x00001 | 0x00002 | 0x00800 | 0x00400 | 0x00200 | 0x00004 | 0x00020 | 0x00010 | 0x01000 | 0x04000 | 0x08000 ) (A_EPILOG0x00008 | A_PRECIOUS0x00001 | A_SILENT0x00002 | A_SHELL0x00800 | A_SETDIR0x00400 |\ | |||
| 37 | A_SEQ0x00200 | A_LIBRARY0x00004 | A_IGNORE0x00020 | A_PROLOG0x00010 | A_SWAP0x01000 |\ | |||
| 38 | A_PHONY0x04000 | A_NOSTATE0x08000 ) | |||
| 39 | ||||
| 40 | ||||
| 41 | /* Define local static functions */ | |||
| 42 | static DFALINKPTR dfa_subset ANSI((DFALINKPTR, DFASETPTR))(DFALINKPTR, DFASETPTR); | |||
| 43 | static void free_dfas ANSI((DFALINKPTR))(DFALINKPTR); | |||
| 44 | static int count_dots ANSI((char *))(char *); | |||
| 45 | static char * buildname ANSI((char *, char *, char *))(char *, char *, char *); | |||
| 46 | static void free_icells ANSI((void))(void); | |||
| 47 | static ICELLPTR union_iset ANSI((ICELLPTR, ICELLPTR))(ICELLPTR, ICELLPTR); | |||
| 48 | static ICELLPTR add_iset ANSI((ICELLPTR,ICELLPTR,CELLPTR,DFALINKPTR,(ICELLPTR,ICELLPTR,CELLPTR,DFALINKPTR, CELLPTR,int,int,char * ,char *, int) | |||
| 49 | CELLPTR,int,int,char *,char *, int))(ICELLPTR,ICELLPTR,CELLPTR,DFALINKPTR, CELLPTR,int,int,char * ,char *, int); | |||
| 50 | static ICELLPTR derive_prerequisites ANSI((ICELLPTR, ICELLPTR *))(ICELLPTR, ICELLPTR *); | |||
| 51 | static char * dump_inf_chain ANSI((ICELLPTR, int, int))(ICELLPTR, int, int); | |||
| 52 | ||||
| 53 | #ifdef DBUG | |||
| 54 | static void _dump_dfa_stack ANSI((DFALINKPTR, DFASETPTR))(DFALINKPTR, DFASETPTR); | |||
| 55 | static void _dump_iset ANSI(( char *, ICELLPTR ))( char *, ICELLPTR ); | |||
| 56 | #endif | |||
| 57 | ||||
| 58 | ||||
| 59 | PUBLIC void | |||
| 60 | Infer_recipe( cp, setdirroot )/* | |||
| 61 | ================================ | |||
| 62 | Perform a breadth-first search of the inference graph and return if | |||
| 63 | possible an inferred set of prerequisites for making the current target. */ | |||
| 64 | CELLPTR cp; | |||
| 65 | CELLPTR setdirroot; | |||
| 66 | { | |||
| 67 | ICELLPTR nomatch, match; | |||
| 68 | ||||
| 69 | DB_ENTER("Infer_recipe"); | |||
| 70 | ||||
| 71 | if( cp->ce_attr & A_NOINFER0x00080 ) {DB_VOID_RETURNreturn;} | |||
| ||||
| 72 | ||||
| 73 | DB_PRINT("inf", ("Inferring rule for [%s]", cp->CE_NAME)); | |||
| 74 | ||||
| 75 | match = NIL(ICELL)((ICELL*)((void*)0)); | |||
| 76 | { | |||
| 77 | char *tmp; | |||
| 78 | nomatch = add_iset( NIL(ICELL)((ICELL*)((void*)0)), NIL(ICELL)((ICELL*)((void*)0)), NIL(CELL)((CELL*)((void*)0)), NIL(DFALINK)((DFALINK*)((void*)0)), | |||
| 79 | setdirroot, Prep+count_dots(cp->CE_NAMEce_name->ht_name), 0, | |||
| 80 | tmp = DmStrDup(cp->CE_NAMEce_name->ht_name), NIL(char)((char*)((void*)0)), | |||
| 81 | cp->ce_time != (time_t)0L); | |||
| 82 | FREE(tmp)free((char*)(tmp)); | |||
| 83 | } | |||
| 84 | ||||
| 85 | /* Make sure we try whole heartedly to infer at least one suffix */ | |||
| 86 | if( nomatch->ic_dmax == 0 ) ++nomatch->ic_dmax; | |||
| 87 | ||||
| 88 | DB_EXECUTE( "inf", _dump_iset("nomatch",nomatch); ); | |||
| 89 | ||||
| 90 | /* If nomatch is non-empty there was no match with an existing | |||
| 91 | * prerrequisite, try to derive one. */ | |||
| 92 | while( nomatch != NIL(ICELL)((ICELL*)((void*)0)) ) { | |||
| 93 | ICELLPTR new_nomatch = NIL(ICELL)((ICELL*)((void*)0)); | |||
| 94 | ICELLPTR ic, pmatch, mmatch; | |||
| 95 | CELLPTR prereq; | |||
| 96 | ||||
| 97 | for( ic=nomatch; ic != NIL(ICELL)((ICELL*)((void*)0)); ic=ic->ic_next ) { | |||
| 98 | int ipush = FALSE0; | |||
| 99 | ||||
| 100 | if( ic->ic_dir ) ipush = Push_dir(ic->ic_dir, ic->ic_name, FALSE0); | |||
| 101 | match = union_iset(match, derive_prerequisites(ic, &new_nomatch)); | |||
| 102 | if( ipush ) Pop_dir(FALSE0); | |||
| 103 | } | |||
| 104 | ||||
| 105 | DB_EXECUTE( "inf", _dump_iset("match",match); ); | |||
| 106 | DB_EXECUTE( "inf", _dump_iset("nomatch",new_nomatch); ); | |||
| 107 | ||||
| 108 | /* We have now deduced the two sets MATCH and NOMATCH. MATCH holds the | |||
| 109 | * set of edges that we encountered that matched. If this set is empty | |||
| 110 | * then we can apply transitive closure (if enabled) to the elements of | |||
| 111 | * NOMATCH to see if we can find some other method to make the target. | |||
| 112 | * | |||
| 113 | * If MATCH is non-empty, we have found a method for making the target. | |||
| 114 | * It is the shortest method for doing so (ie. uses fewest number of | |||
| 115 | * steps). If MATCH contains more than one element then we have a | |||
| 116 | * possible ambiguity. | |||
| 117 | */ | |||
| 118 | if( match == NIL(ICELL)((ICELL*)((void*)0)) ) { | |||
| 119 | nomatch = new_nomatch; | |||
| 120 | ||||
| 121 | /* Skip the rest and try one level deeper. */ | |||
| 122 | if( Transitive ) continue; | |||
| 123 | ||||
| 124 | goto all_done; | |||
| 125 | } | |||
| 126 | ||||
| 127 | /* Ok, we have a set of possible matches in MATCH, we should check the | |||
| 128 | * set for ambiguity. If more than one inference path exists of the | |||
| 129 | * same depth, then we may issue an ambiguous inference error message. | |||
| 130 | * | |||
| 131 | * The message is suppressed if MATCH contains two elements and one of | |||
| 132 | * them is the empty-prerequisite-rule. In this case we ignore the | |||
| 133 | * ambiguity and take the rule that infers the prerequisite. | |||
| 134 | * | |||
| 135 | * Also if there are any chains that rely on a non-existant prerequisite | |||
| 136 | * that may get made because it has a recipe then we prefer any that | |||
| 137 | * rely on existing final prerequisites over those that we have to make. | |||
| 138 | */ | |||
| 139 | ||||
| 140 | /* Split out those that have to be made from those that end in | |||
| 141 | * prerequisites that already exist. */ | |||
| 142 | pmatch = mmatch = NIL(ICELL)((ICELL*)((void*)0)); | |||
| 143 | for(; match; match = ic ) { | |||
| 144 | /* This loop checks all possible matches. */ | |||
| 145 | DB_PRINT("inf", ("Target [%s] : prerequisite [%s]", | |||
| 146 | match->ic_meta->CE_NAME, match->ic_name)); | |||
| 147 | ||||
| 148 | ic = match->ic_next; | |||
| 149 | match->ic_next = NIL(ICELL)((ICELL*)((void*)0)); | |||
| 150 | ||||
| 151 | if( match->ic_exists ) | |||
| 152 | pmatch = union_iset(pmatch, match); | |||
| 153 | else | |||
| 154 | mmatch = union_iset(mmatch, match); | |||
| 155 | } | |||
| 156 | ||||
| 157 | /* Prefer %-targets with existing prerequisites. */ | |||
| 158 | if( pmatch ) | |||
| 159 | match = pmatch; | |||
| 160 | else | |||
| 161 | match = mmatch; | |||
| 162 | ||||
| 163 | /* Make sure it is unique. It would be easy to check | |||
| 164 | * match->ic_meta->ce_prq for existence and prefer no prerequisites | |||
| 165 | * over prerequisites that are present, but we are currently not | |||
| 166 | * doing it. */ | |||
| 167 | if( match->ic_next != NIL(ICELL)((ICELL*)((void*)0)) ) { | |||
| 168 | int count = 1; | |||
| 169 | ||||
| 170 | Warning( "Ambiguous inference chains for target '%s'", cp->CE_NAMEce_name->ht_name ); | |||
| 171 | for( ic=match; ic; ic=ic->ic_next ) | |||
| 172 | (void) dump_inf_chain(ic, TRUE1, count++); | |||
| 173 | Warning( "First matching rule is chosen."); | |||
| 174 | } | |||
| 175 | ||||
| 176 | /* MATCH now points at the derived prerequisite chain(s). We must now | |||
| 177 | * take cp, and construct the correct graph so that the make may | |||
| 178 | * proceed. */ | |||
| 179 | ||||
| 180 | /* The folowing shows only the first element, i.e. the last matching | |||
| 181 | * recipe that was found. */ | |||
| 182 | if( Verbose & V_INFER0x08 ) { | |||
| 183 | char *tmp = dump_inf_chain(match, TRUE1, FALSE0); | |||
| 184 | printf("%s: Inferring prerequistes and recipes using:\n%s: ... %s\n", | |||
| 185 | Pname, Pname, tmp ); | |||
| 186 | FREE(tmp)free((char*)(tmp)); | |||
| 187 | } | |||
| 188 | ||||
| 189 | pmatch = NIL(ICELL)((ICELL*)((void*)0)); | |||
| 190 | prereq = NIL(CELL)((CELL*)((void*)0)); | |||
| 191 | ||||
| 192 | /* This loop treats the inferred targets last to first. */ | |||
| 193 | while( match ) { | |||
| 194 | CELLPTR infcell=NIL(CELL)((CELL*)((void*)0)); | |||
| 195 | ||||
| 196 | /* Compute the inferred prerequisite first. */ | |||
| 197 | if( match->ic_name ) { | |||
| 198 | if( match->ic_meta ) | |||
| 199 | infcell = Def_cell( match->ic_name ); | |||
| 200 | else | |||
| 201 | infcell = cp; | |||
| 202 | ||||
| 203 | infcell->ce_flag |= F_TARGET0x0008; | |||
| 204 | ||||
| 205 | if( infcell != cp ) { | |||
| 206 | infcell->ce_flag |= F_INFER0x4000|F_REMOVE0x1000; | |||
| 207 | DB_PRINT("remove", ("Mark for deletion [%s]", | |||
| 208 | infcell->CE_NAME)); | |||
| 209 | } | |||
| 210 | ||||
| 211 | if( !match->ic_flag ) | |||
| 212 | infcell->ce_attr |= A_NOINFER0x00080; | |||
| 213 | } | |||
| 214 | ||||
| 215 | /* Add global prerequisites from previous rule if there are any and | |||
| 216 | * the recipe. */ | |||
| 217 | if( pmatch ) { | |||
| 218 | CELLPTR imeta = pmatch->ic_meta; | |||
| 219 | LINKPTR lp; | |||
| 220 | ||||
| 221 | DB_PRINT("inf", ("%%-target [%s] - infered target [%s]\n", | |||
| 222 | imeta->CE_NAME, infcell->CE_NAME)); | |||
| 223 | ||||
| 224 | infcell->ce_per = pmatch->ic_dfa->dl_per; | |||
| ||||
| 225 | infcell->ce_attr |= (imeta->ce_attr & A_TRANSFER(0x00008 | 0x00001 | 0x00002 | 0x00800 | 0x00400 | 0x00200 | 0x00004 | 0x00020 | 0x00010 | 0x01000 | 0x04000 | 0x08000 )); | |||
| 226 | ||||
| 227 | /* The .PHONY mechanism relies on having phony targets not | |||
| 228 | * being STATed and having a zero time stamp. While inferring | |||
| 229 | * the this target it might have been created and stated | |||
| 230 | * therefore these values need to be reset. */ | |||
| 231 | if( infcell->ce_attr & A_PHONY0x04000 ){ | |||
| 232 | infcell->ce_time = 0L; | |||
| 233 | infcell->ce_flag &= ~F_STAT0x0040; | |||
| 234 | } | |||
| 235 | ||||
| 236 | if( !(infcell->ce_flag & F_RULES0x0010) ) { | |||
| 237 | infcell->ce_flag |= (imeta->ce_flag&(F_SINGLE0x0004|F_GROUP0x0020))|F_RULES0x0010; | |||
| 238 | infcell->ce_recipe = imeta->ce_recipe; | |||
| 239 | } | |||
| 240 | ||||
| 241 | /* Add any conditional macro definitions that may be associated | |||
| 242 | * with the inferred cell. */ | |||
| 243 | if (imeta->ce_cond != NIL(STRING)((STRING*)((void*)0))) { | |||
| 244 | STRINGPTR sp,last; | |||
| 245 | ||||
| 246 | last = infcell->ce_cond; | |||
| 247 | for(sp=imeta->ce_cond; sp; sp=sp->st_next) { | |||
| 248 | STRINGPTR new; | |||
| 249 | TALLOC(new, 1, STRING)if ((new = (STRING*) calloc((unsigned int)(1), (size_t)sizeof (STRING))) == (STRING*)0) {No_ram();}; | |||
| 250 | new->st_string = DmStrDup(sp->st_string); | |||
| 251 | if(last) | |||
| 252 | last->st_next = new; | |||
| 253 | else | |||
| 254 | infcell->ce_cond = new; | |||
| 255 | last = new; | |||
| 256 | } | |||
| 257 | } | |||
| 258 | ||||
| 259 | pmatch->ic_dfa->dl_per = NIL(char)((char*)((void*)0)); | |||
| 260 | ||||
| 261 | /* If infcell already had a .SETDIR directory set then modify it | |||
| 262 | * based on whether it was the original cell or some intermediary. */ | |||
| 263 | if( imeta->ce_dir ) { | |||
| 264 | if( infcell->ce_dir && infcell == cp ) { | |||
| 265 | /* cp->ce_dir was set and we have pushed the directory prior | |||
| 266 | * to calling this routine. | |||
| 267 | * We build a new path by appending imeta->ce_dir to the | |||
| 268 | * current directory of the original cell. | |||
| 269 | * We should therefore pop it and push the new concatenated | |||
| 270 | * directory required by the inference. | |||
| 271 | * This leaks memory as cp->ce_dir is not freed before | |||
| 272 | * setting the new the new infcell->ce_dir value but as | |||
| 273 | * the pointer could be a `A_POOL` member we accept this. */ | |||
| 274 | infcell->ce_dir = DmStrDup(Build_path(infcell->ce_dir, | |||
| 275 | imeta->ce_dir)); | |||
| 276 | } | |||
| 277 | else { | |||
| 278 | /* Inherit a copy of the .SETDIR value. Use a copy because | |||
| 279 | * the original could have been freed in the meantime | |||
| 280 | * in Make() by the FREE() before _pool_lookup(). This can | |||
| 281 | * also leak if infcell->ce_dir was set before. */ | |||
| 282 | infcell->ce_dir = DmStrDup(imeta->ce_dir); | |||
| 283 | } | |||
| 284 | } | |||
| 285 | ||||
| 286 | for( lp=imeta->ce_indprq; lp != NIL(LINK)((LINK*)((void*)0)); lp=lp->cl_next ) { | |||
| 287 | char *name = lp->cl_prq->CE_NAMEce_name->ht_name; | |||
| 288 | CELLPTR tcp; | |||
| 289 | ||||
| 290 | name = buildname( cp->CE_NAMEce_name->ht_name, name, infcell->ce_per ); | |||
| 291 | tcp = Def_cell( name ); | |||
| 292 | tcp->ce_flag |= F_REMOVE0x1000; | |||
| 293 | Add_prerequisite( infcell, tcp, FALSE0, FALSE0 ); | |||
| 294 | ||||
| 295 | if( Verbose & V_INFER0x08 ) | |||
| 296 | printf( "%s: Inferred indirect prerequisite [%s]\n", | |||
| 297 | Pname, name ); | |||
| 298 | FREE(name)free((char*)(name)); | |||
| 299 | } | |||
| 300 | } | |||
| 301 | ||||
| 302 | /* Add the previous cell as the prerequisite */ | |||
| 303 | if( prereq ) | |||
| 304 | (Add_prerequisite(infcell,prereq,FALSE0,FALSE0))->cl_flag |=F_TARGET0x0008; | |||
| 305 | ||||
| 306 | pmatch = match; /* Previous member in inference chain ... */ | |||
| 307 | prereq = infcell; /* is a prerequisite to the next match. */ | |||
| 308 | /* ip->ic_parent is the next target in the inference chain to be | |||
| 309 | * build. If it is empty we are done. */ | |||
| 310 | match = match->ic_parent; | |||
| 311 | } | |||
| 312 | ||||
| 313 | DB_PRINT("inf", ("Terminated due to a match")); | |||
| 314 | break; | |||
| 315 | } | |||
| 316 | ||||
| 317 | all_done: | |||
| 318 | free_icells(); | |||
| 319 | ||||
| 320 | DB_VOID_RETURNreturn; | |||
| 321 | } | |||
| 322 | ||||
| 323 | ||||
| 324 | static ICELLPTR | |||
| 325 | derive_prerequisites( ic, nnmp )/* | |||
| 326 | =================================== | |||
| 327 | Take a cell and derive a set of prerequisites from the cell. Categorize | |||
| 328 | them into those that MATCH (ie. those that we found in the file system), | |||
| 329 | and those that do not match NOMATCH that we may possibly have a look at | |||
| 330 | later. When we process the next level of the breadth-first search. | |||
| 331 | ||||
| 332 | Once MATCH is non-empty we will stop inserting elements into NOMATCH | |||
| 333 | since we know that either MATCH is successful and unique or it will | |||
| 334 | issue an ambiguity error. We will never go on to look at elements | |||
| 335 | in NOMATCH after wards. */ | |||
| 336 | ICELLPTR ic; | |||
| 337 | ICELLPTR *nnmp; | |||
| 338 | { | |||
| 339 | ICELLPTR match = NIL(ICELL)((ICELL*)((void*)0)); | |||
| 340 | DFALINKPTR pdfa; | |||
| 341 | DFALINKPTR dfas; | |||
| 342 | ||||
| 343 | DB_ENTER("derive_prerequisites"); | |||
| 344 | ||||
| 345 | DB_PRINT("inf", ("for [%s]\n", ic->ic_name)); | |||
| 346 | ||||
| 347 | /* If none of the inference nodes match then forget about the inference. | |||
| 348 | * The user did not tell us how to make such a target. We also stop the | |||
| 349 | * Inference if the new set of DFA's is a proper subset of a previous | |||
| 350 | * subset and it's PREP counts exceed the value of Prep. | |||
| 351 | */ | |||
| 352 | dfas = dfa_subset( Match_dfa(ic->ic_name), &ic->ic_dfastack ); | |||
| 353 | ||||
| 354 | DB_EXECUTE("inf", _dump_dfa_stack(dfas, &ic->ic_dfastack); ); | |||
| 355 | ||||
| 356 | /* Ok, we have nothing here to work with so return an empty cell. */ | |||
| 357 | if( dfas == NIL(DFALINK)((DFALINK*)((void*)0)) ) { | |||
| 358 | DB_PRINT( "mem", ("%s:<- mem %ld",ic->ic_name, (long)coreleft())); | |||
| 359 | DB_PRINT( "inf", ("<<< Exit, no dfas, cp = %04x", NIL(CELL)) ); | |||
| 360 | DB_RETURN( NIL(ICELL) )return (((ICELL*)((void*)0))); | |||
| 361 | } | |||
| 362 | ||||
| 363 | /* Save the dfas, we are going to use on the stack for this cell. */ | |||
| 364 | ic->ic_dfastack.df_set = dfas; | |||
| 365 | ||||
| 366 | /* Run through the %-meta cells, build the prerequisite cells. For each | |||
| 367 | * %-meta go through it's list of edges and try to use each in turn to | |||
| 368 | * deduce a likely prerequisite. We perform a breadth-first search | |||
| 369 | * matching the first path that results in a unique method for making the | |||
| 370 | * target. */ | |||
| 371 | for( pdfa = dfas; pdfa != NIL(DFALINK)((DFALINK*)((void*)0)); pdfa = pdfa->dl_next ) { | |||
| 372 | LINK tl; | |||
| 373 | LINKPTR edge; | |||
| 374 | CELLPTR pmeta; | |||
| 375 | ||||
| 376 | pmeta = pdfa->dl_meta; | |||
| 377 | DB_PRINT( "inf", ("Using dfa: [%s]", pmeta->CE_NAME) ); | |||
| 378 | ||||
| 379 | /* If the %-meta is a singleton meta then deal with it differently from | |||
| 380 | * the case when it is a bunch of %-meta's found on the original entries | |||
| 381 | * prerequisite list. */ | |||
| 382 | if( pmeta->ce_flag & F_MULTI0x0002 ) | |||
| 383 | edge = pmeta->ce_prq; | |||
| 384 | else { | |||
| 385 | tl.cl_prq = pmeta; | |||
| 386 | tl.cl_next = NIL(LINK)((LINK*)((void*)0)); | |||
| 387 | edge = &tl; | |||
| 388 | } | |||
| 389 | ||||
| 390 | /* Now run through the list of prerequisite edge's for the %-meta. */ | |||
| 391 | for( ; edge != NIL(LINK)((LINK*)((void*)0)); edge = edge->cl_next ) { | |||
| 392 | HASHPTR thp = 0; /* temporary hash table pointer */ | |||
| 393 | HASH iprqh; /* hash cell for new prerequisite */ | |||
| 394 | CELL iprq; /* inferred prerequisite to look for */ | |||
| 395 | CELLPTR idirroot; /* Inferred prerequisite root */ | |||
| 396 | CELLPTR nidirroot; /* Inferred prerequisite root */ | |||
| 397 | STRINGPTR ircp = 0; /* Inferred prerequisites recipe */ | |||
| 398 | char *idir; /* directory to CD to. */ | |||
| 399 | int ipush = 0; /* flag for push on inferred prereq */ | |||
| 400 | char *name = NIL(char)((char*)((void*)0)); /* prerequisite name */ | |||
| 401 | CELLPTR meta = edge->cl_prq; | |||
| 402 | int trans; | |||
| 403 | int noinf; | |||
| 404 | int exists; | |||
| 405 | ||||
| 406 | /* Name of the prerequisite, can be empty. */ | |||
| 407 | if( meta->ce_prq ) | |||
| 408 | name = meta->ce_prq->cl_prq->CE_NAMEce_name->ht_name; | |||
| 409 | ||||
| 410 | DB_PRINT( "inf", ("Trying edge from [%s] to [%s] for [%s]", | |||
| 411 | meta->CE_NAME, name?name:"(nil)", ic->ic_name) ); | |||
| 412 | ||||
| 413 | /* Set the temp CELL used for building prerequisite candidates to | |||
| 414 | * all zero so that we don't have to keep initializing all the | |||
| 415 | * fields. */ | |||
| 416 | { | |||
| 417 | register char *s = (char *) &iprq; | |||
| 418 | register int n = sizeof(CELL); | |||
| 419 | while( n ) { *s++ = '\0'; n--; } | |||
| 420 | } | |||
| 421 | ||||
| 422 | nidirroot = idirroot = ic->ic_setdirroot; | |||
| 423 | iprq.ce_name = &iprqh; | |||
| 424 | ||||
| 425 | if( name ) { | |||
| 426 | /* Build the prerequisite name from the %-meta prerequisite given | |||
| 427 | * for the %-meta rule. */ | |||
| 428 | int dmax_fix; | |||
| 429 | iprqh.ht_name = buildname( ic->ic_name, name, pdfa->dl_per ); | |||
| 430 | if((dmax_fix = (count_dots(name)-count_dots(meta->CE_NAMEce_name->ht_name))) < 0) | |||
| 431 | dmax_fix = 0; | |||
| 432 | ||||
| 433 | if( !strcmp(ic->ic_name, iprqh.ht_name) || | |||
| 434 | (count_dots(iprqh.ht_name) > ic->ic_dmax + dmax_fix) ) { | |||
| 435 | FREE( iprqh.ht_name )free((char*)(iprqh.ht_name)); | |||
| 436 | continue; | |||
| 437 | } | |||
| 438 | ||||
| 439 | DB_PRINT( "inf", ("Checking prerequisite [%s]", iprqh.ht_name) ); | |||
| 440 | ||||
| 441 | /* See if the prerequisite CELL has been previously defined. If | |||
| 442 | * it has, then make a copy of it into iprq, and use it to try | |||
| 443 | * the inference. We make the copy so that we don't modify the | |||
| 444 | * stat of the inferred cell if the inference fails. | |||
| 445 | */ | |||
| 446 | thp = Get_name( iprqh.ht_name, Defs, FALSE0 ); | |||
| 447 | if(thp != NIL(HASH)((HASH*)((void*)0))) { | |||
| 448 | iprq = *thp->CP_OWNRvar.val.ht.ht_owner; | |||
| 449 | /* Check if a recipe for this target exists. Targets with F_MULTI | |||
| 450 | * set need each cell checked for existing recipes. | |||
| 451 | */ | |||
| 452 | if( iprq.ce_flag & F_MULTI0x0002 ) { | |||
| 453 | /* Walk through all cells of this target. */ | |||
| 454 | LINKPTR mtcp = iprq.ce_prq; | |||
| 455 | ircp = NIL(STRING)((STRING*)((void*)0)); | |||
| 456 | for( ; mtcp != NIL(LINK)((LINK*)((void*)0)); mtcp = mtcp->cl_next ) { | |||
| 457 | /* If a recipe is found stop searching and set ircp to that result. | |||
| 458 | * ircp is not used but only checked if it is set. | |||
| 459 | */ | |||
| 460 | if( mtcp->cl_prq->ce_recipe != NIL(STRING)((STRING*)((void*)0)) ) { | |||
| 461 | ircp = mtcp->cl_prq->ce_recipe; | |||
| 462 | break; | |||
| 463 | } | |||
| 464 | } | |||
| 465 | } | |||
| 466 | else | |||
| 467 | ircp = iprq.ce_recipe; | |||
| 468 | } | |||
| 469 | else | |||
| 470 | ircp = NIL(STRING)((STRING*)((void*)0)); | |||
| 471 | } | |||
| 472 | else | |||
| 473 | iprqh.ht_name = NIL(char)((char*)((void*)0)); | |||
| 474 | ||||
| 475 | ||||
| 476 | /* If the %-meta has a .SETDIR set then we change to the new | |||
| 477 | * directory prior to performing the stat of the new prerequisite. | |||
| 478 | * If the change of directory fails then the rule is droped from | |||
| 479 | * further consideration. | |||
| 480 | */ | |||
| 481 | if( iprq.ce_dir ) { | |||
| 482 | if( (ipush = Push_dir(iprq.ce_dir, iprqh.ht_name, TRUE1)) != 0 ) { | |||
| 483 | nidirroot = thp->CP_OWNRvar.val.ht.ht_owner; | |||
| 484 | idir = Pwd; | |||
| 485 | } | |||
| 486 | else { | |||
| 487 | if( iprqh.ht_name ) FREE( iprqh.ht_name )free((char*)(iprqh.ht_name)); | |||
| 488 | continue; | |||
| 489 | } | |||
| 490 | } | |||
| 491 | else | |||
| 492 | idir = NIL(char)((char*)((void*)0)); | |||
| 493 | ||||
| 494 | ||||
| 495 | /* Stat the inferred prerequisite. | |||
| 496 | */ | |||
| 497 | if( name ) { | |||
| 498 | if( Verbose & V_INFER0x08 ) | |||
| 499 | printf( "%s: Trying prerequisite [%s] for [%s]\n", Pname, | |||
| 500 | iprqh.ht_name, ic->ic_name ); | |||
| 501 | ||||
| 502 | /* irpq is a temporary target cell, a stat will not be remembered. */ | |||
| 503 | if( !(iprq.ce_flag & F_STAT0x0040) ) Stat_target(&iprq, FALSE0, FALSE0); | |||
| 504 | } | |||
| 505 | ||||
| 506 | ||||
| 507 | /* If the STAT succeeded or if the prerequisite has a recipe for | |||
| 508 | * making it then it's a match and a candidate for getting infered. | |||
| 509 | * Otherwise it is not a match, and we cannot yet tell if it is | |||
| 510 | * going to be a successful path to follow, so we save it for | |||
| 511 | * later consideration. | |||
| 512 | */ | |||
| 513 | noinf = ((Glob_attr)&A_NOINFER0x00080); | |||
| 514 | if( meta->ce_prq ) | |||
| 515 | noinf |= ((meta->ce_prq->cl_prq->ce_attr)&A_NOINFER0x00080); | |||
| 516 | trans = Transitive || !noinf; | |||
| 517 | ||||
| 518 | /* If no prereq is given treat it as if it is existing. */ | |||
| 519 | exists = (iprq.ce_time != (time_t)0L) || (name == NIL(char)((char*)((void*)0))); | |||
| 520 | ||||
| 521 | if( exists || (ircp != NIL(STRING)((STRING*)((void*)0))) || !name ) { | |||
| 522 | match = add_iset( match, ic, meta, pdfa, idirroot, ic->ic_dmax, | |||
| 523 | trans, iprq.ce_name->ht_name, idir, exists ); | |||
| 524 | DB_PRINT("inf",("Added to MATCH %s",iprq.ce_name->ht_name)); | |||
| 525 | } | |||
| 526 | else if( !noinf && match == NIL(ICELL)((ICELL*)((void*)0)) ) { | |||
| 527 | *nnmp = add_iset( *nnmp, ic, meta, pdfa, nidirroot, ic->ic_dmax, | |||
| 528 | trans, iprq.ce_name->ht_name, idir, exists ); | |||
| 529 | DB_PRINT("inf",("Added to NOMATCH %s",iprq.ce_name->ht_name)); | |||
| 530 | } | |||
| 531 | ||||
| 532 | /* If we pushed a directory for the inferred prerequisite then | |||
| 533 | * pop it. | |||
| 534 | */ | |||
| 535 | if( ipush ) Pop_dir(FALSE0); | |||
| 536 | if( iprqh.ht_name ) FREE(iprqh.ht_name)free((char*)(iprqh.ht_name)); | |||
| 537 | } | |||
| 538 | } | |||
| 539 | ||||
| 540 | DB_RETURN(match)return (match); | |||
| 541 | } | |||
| 542 | ||||
| 543 | ||||
| 544 | static char * | |||
| 545 | buildname( tg, meta, per )/* | |||
| 546 | ============================ | |||
| 547 | Replace '%' with per in meta. Expand the result and return it. */ | |||
| 548 | char *tg; /* Current target name. */ | |||
| 549 | char *meta; | |||
| 550 | char *per; | |||
| 551 | { | |||
| 552 | char *name; | |||
| 553 | ||||
| 554 | name = Apply_edit( meta, "%", per, FALSE0, FALSE0 ); | |||
| 555 | /* Handle infered dynamic prerequisites. */ | |||
| 556 | if( strchr(name, '$') ) { | |||
| 557 | HASHPTR m_at; | |||
| 558 | char *tmp; | |||
| 559 | ||||
| 560 | /* Set $@ so that a Expand() can use it and remove it afterwards. */ | |||
| 561 | /* Is $@ already expanded? FIXME: Remove this check later. */ | |||
| 562 | if( *DmStrPbrk( tg, "${}" ) != '\0' ) | |||
| 563 | Fatal("$@ [%s] not fully expanded!", tg); | |||
| 564 | m_at = Def_macro( "@", DO_WINPATH(tg)tg, M_MULTI0x0004|M_EXPANDED0x0008 ); | |||
| 565 | tmp = Expand( name ); | |||
| 566 | ||||
| 567 | if( m_at->ht_value != NIL(char)((char*)((void*)0)) ) { | |||
| 568 | FREE( m_at->ht_value )free((char*)(m_at->ht_value)); | |||
| 569 | m_at->ht_value = NIL(char)((char*)((void*)0)); | |||
| 570 | } | |||
| 571 | ||||
| 572 | /* Free name if Apply_edit() did something. */ | |||
| 573 | if( name != meta ) FREE( name )free((char*)(name)); | |||
| 574 | name = tmp; | |||
| 575 | } | |||
| 576 | else if( name == meta ) | |||
| 577 | name = DmStrDup( name ); | |||
| 578 | ||||
| 579 | return(name); | |||
| 580 | } | |||
| 581 | ||||
| 582 | ||||
| 583 | static DFALINKPTR | |||
| 584 | dfa_subset( pdfa, stack )/* | |||
| 585 | ============================ | |||
| 586 | This is the valid DFA subset computation. Whenever a CELL has a Match_dfa | |||
| 587 | subset computed this algorithm is run to see if any of the previously | |||
| 588 | computed sets on the DFA stack are proper subsets of the new set. If they | |||
| 589 | are, then any elements of the matching subset whose Prep counts exceed | |||
| 590 | the allowed maximum given by Prep are removed from the computed DFA set, | |||
| 591 | and hence from consideration, thereby cutting off the cycle in the | |||
| 592 | inference graph. */ | |||
| 593 | DFALINKPTR pdfa; | |||
| 594 | register DFASETPTR stack; | |||
| 595 | { | |||
| 596 | register DFALINKPTR element; | |||
| 597 | DFALINKPTR nelement; | |||
| 598 | ||||
| 599 | DB_ENTER( "dfa_subset" ); | |||
| 600 | ||||
| 601 | DB_PRINT("inf",("Computing DFA subset, PREP = %d",Prep)); | |||
| 602 | DB_EXECUTE("inf", _dump_dfa_stack(pdfa, stack); ); | |||
| 603 | ||||
| 604 | for(; pdfa != NIL(DFALINK)((DFALINK*)((void*)0)) && stack != NIL(DFASET)((DFASET*)((void*)0)); stack = stack->df_next) { | |||
| 605 | int subset = TRUE1; | |||
| 606 | ||||
| 607 | for( element=stack->df_set; subset && element != NIL(DFALINK)((DFALINK*)((void*)0)); | |||
| 608 | element=element->dl_next ) { | |||
| 609 | register DFALINKPTR subel; | |||
| 610 | ||||
| 611 | for( subel = pdfa; | |||
| 612 | subel != NIL(DFALINK)((DFALINK*)((void*)0)) && (subel->dl_meta != element->dl_meta); | |||
| 613 | subel = subel->dl_next ); | |||
| 614 | ||||
| 615 | DB_PRINT("inf",("Looking for %s, (%s)",element->dl_meta->CE_NAME, | |||
| 616 | (subel != NIL(DFALINK))?"succ":"fail")); | |||
| 617 | ||||
| 618 | if( (subset = (subel != NIL(DFALINK)((DFALINK*)((void*)0)))) != 0 ) | |||
| 619 | element->dl_member = subel; | |||
| 620 | } | |||
| 621 | ||||
| 622 | if( subset ) | |||
| 623 | for( element=stack->df_set; element != NIL(DFALINK)((DFALINK*)((void*)0)); | |||
| 624 | element=element->dl_next ) { | |||
| 625 | DFALINKPTR mem = element->dl_member; | |||
| 626 | int npr = element->dl_prep + 1; | |||
| 627 | ||||
| 628 | if( npr > Prep ) | |||
| 629 | mem->dl_delete++; | |||
| 630 | else | |||
| 631 | mem->dl_prep = npr; | |||
| 632 | } | |||
| 633 | } | |||
| 634 | ||||
| 635 | for( element = pdfa; element != NIL(DFALINK)((DFALINK*)((void*)0)); element = nelement ) { | |||
| 636 | nelement = element->dl_next; | |||
| 637 | ||||
| 638 | if( element->dl_delete ) { | |||
| 639 | /* A member of the subset has a PREP count equal to PREP, so | |||
| 640 | * it should not be considered further in the inference, hence | |||
| 641 | * we remove it from the doubly linked set list */ | |||
| 642 | if( element == pdfa ) | |||
| 643 | pdfa = element->dl_next; | |||
| 644 | else | |||
| 645 | element->dl_prev->dl_next = element->dl_next; | |||
| 646 | ||||
| 647 | if( element->dl_next != NIL(DFALINK)((DFALINK*)((void*)0)) ) | |||
| 648 | element->dl_next->dl_prev = element->dl_prev; | |||
| 649 | ||||
| 650 | DB_PRINT("inf", ("deleting dfa [%s]", element->dl_meta->CE_NAME)); | |||
| 651 | FREE( element->dl_per )free((char*)(element->dl_per)); | |||
| 652 | FREE( element )free((char*)(element)); | |||
| 653 | } | |||
| 654 | } | |||
| 655 | ||||
| 656 | DB_RETURN( pdfa )return (pdfa); | |||
| 657 | } | |||
| 658 | ||||
| 659 | ||||
| 660 | ||||
| 661 | static void | |||
| 662 | free_dfas( chain )/* | |||
| 663 | ===================== | |||
| 664 | Free the list of DFA's constructed by Match_dfa, and linked together by | |||
| 665 | LINK cells. FREE the % value as well, as long as it isn't NIL. */ | |||
| 666 | DFALINKPTR chain; | |||
| 667 | { | |||
| 668 | register DFALINKPTR tl; | |||
| 669 | ||||
| 670 | DB_ENTER( "free_dfas" ); | |||
| 671 | ||||
| 672 | for( tl=chain; tl != NIL(DFALINK)((DFALINK*)((void*)0)); chain = tl ) { | |||
| 673 | tl = tl->dl_next; | |||
| 674 | ||||
| 675 | DB_PRINT( "inf", ("Freeing DFA [%s], %% = [%s]", chain->dl_meta->CE_NAME, | |||
| 676 | chain->dl_per) ); | |||
| 677 | ||||
| 678 | if( chain->dl_per != NIL(char)((char*)((void*)0)) ) FREE( chain->dl_per )free((char*)(chain->dl_per)); | |||
| 679 | FREE( chain )free((char*)(chain)); | |||
| 680 | } | |||
| 681 | ||||
| 682 | DB_VOID_RETURNreturn; | |||
| 683 | } | |||
| 684 | ||||
| 685 | ||||
| 686 | static int | |||
| 687 | count_dots( name )/* | |||
| 688 | =====================*/ | |||
| 689 | char *name; | |||
| 690 | { | |||
| 691 | register char *p; | |||
| 692 | register int i = 0; | |||
| 693 | ||||
| 694 | for( p = name; *p; p++ ) if(*p == '.') i++; | |||
| 695 | ||||
| 696 | return( i ); | |||
| 697 | } | |||
| 698 | ||||
| 699 | ||||
| 700 | static ICELLPTR _icells = NIL(ICELL)((ICELL*)((void*)0)); | |||
| 701 | #ifdef DBUG | |||
| 702 | static int _icell_cost = 0; | |||
| 703 | #endif | |||
| 704 | ||||
| 705 | static ICELLPTR | |||
| 706 | add_iset( iset, parent, meta, dfa, setdirroot, dmax, noinf, name, dir, exists) | |||
| 707 | ICELLPTR iset; | |||
| 708 | ICELLPTR parent; | |||
| 709 | CELLPTR meta; | |||
| 710 | DFALINKPTR dfa; | |||
| 711 | CELLPTR setdirroot; | |||
| 712 | int dmax; | |||
| 713 | int noinf; | |||
| 714 | char *name; | |||
| 715 | char *dir; | |||
| 716 | int exists; | |||
| 717 | { | |||
| 718 | ICELLPTR icell; | |||
| 719 | ||||
| 720 | DB_ENTER("add_iset"); | |||
| 721 | TALLOC(icell, 1, ICELL)if ((icell = (ICELL*) calloc((unsigned int)(1), (size_t)sizeof (ICELL))) == (ICELL*)0) {No_ram();}; | |||
| 722 | ||||
| 723 | DB_EXECUTE("inf", _icell_cost+=(sizeof(ICELL)+strlen(dir?dir:"")+strlen(name?name:"")+2);); | |||
| 724 | ||||
| 725 | icell->ic_meta = meta; | |||
| 726 | icell->ic_dfa = dfa; | |||
| 727 | icell->ic_setdirroot = setdirroot; | |||
| 728 | ||||
| 729 | if( parent ) icell->ic_dfastack.df_next = &parent->ic_dfastack; | |||
| 730 | ||||
| 731 | icell->ic_dmax = dmax; | |||
| 732 | icell->ic_dir = DmStrDup(dir); | |||
| 733 | icell->ic_name = DmStrDup(name); | |||
| 734 | icell->ic_parent = parent; | |||
| 735 | icell->ic_next = iset; | |||
| 736 | icell->ic_flag = noinf; | |||
| 737 | icell->ic_exists = exists; | |||
| 738 | ||||
| 739 | icell->ic_link = _icells; | |||
| 740 | _icells = icell; | |||
| 741 | ||||
| 742 | DB_RETURN(icell)return (icell); | |||
| 743 | } | |||
| 744 | ||||
| 745 | ||||
| 746 | static void | |||
| 747 | free_icells() | |||
| 748 | { | |||
| 749 | register ICELLPTR ic; | |||
| 750 | ||||
| 751 | DB_ENTER("free_icells"); | |||
| 752 | ||||
| 753 | for( ; _icells; _icells = ic ) { | |||
| 754 | ic = _icells->ic_link; | |||
| 755 | ||||
| 756 | free_dfas(_icells->ic_dfastack.df_set); | |||
| 757 | if( _icells->ic_dir ) FREE(_icells->ic_dir)free((char*)(_icells->ic_dir)); | |||
| 758 | if( _icells->ic_name) FREE(_icells->ic_name)free((char*)(_icells->ic_name)); | |||
| 759 | FREE(_icells)free((char*)(_icells)); | |||
| 760 | } | |||
| 761 | ||||
| 762 | DB_PRINT("inf",("Used %d memory for icells",_icell_cost)); | |||
| 763 | DB_EXECUTE("inf", _icell_cost=0; ); | |||
| 764 | ||||
| 765 | DB_VOID_RETURNreturn; | |||
| 766 | } | |||
| 767 | ||||
| 768 | ||||
| 769 | static ICELLPTR | |||
| 770 | union_iset( iset, uset ) | |||
| 771 | ICELLPTR iset; | |||
| 772 | ICELLPTR uset; | |||
| 773 | { | |||
| 774 | register ICELLPTR ic; | |||
| 775 | ||||
| 776 | if( iset == NIL(ICELL)((ICELL*)((void*)0)) ) return(uset); | |||
| 777 | ||||
| 778 | for( ic=iset; ic->ic_next != NIL(ICELL)((ICELL*)((void*)0)); ic=ic->ic_next ); | |||
| 779 | ic->ic_next = uset; | |||
| 780 | ||||
| 781 | return(iset); | |||
| 782 | } | |||
| 783 | ||||
| 784 | ||||
| 785 | static char * | |||
| 786 | dump_inf_chain( ip, flag, print )/* | |||
| 787 | =================================== | |||
| 788 | Return string with infered prerequisites. | |||
| 789 | flag == TRUE adds the top of the chain. | |||
| 790 | print == TRUE prints to screen with number "print" and returns NULL. */ | |||
| 791 | ICELLPTR ip; | |||
| 792 | int flag; | |||
| 793 | int print; | |||
| 794 | { | |||
| 795 | char *tmp; | |||
| 796 | ||||
| 797 | if( ip == NIL(ICELL)((ICELL*)((void*)0)) ) return(NIL(char)((char*)((void*)0))); | |||
| 798 | ||||
| 799 | /* ip->ic_parent is the target to be build after ip. */ | |||
| 800 | tmp = dump_inf_chain(ip->ic_parent, FALSE0, FALSE0); | |||
| 801 | ||||
| 802 | if( ip->ic_meta ) { | |||
| 803 | tmp = DmStrJoin(tmp, "(", -1, TRUE1); | |||
| 804 | tmp = DmStrJoin(tmp, ip->ic_meta->CE_NAMEce_name->ht_name, -1, TRUE1); | |||
| 805 | ||||
| 806 | if( ip->ic_dir && !*ip->ic_dir ) { | |||
| 807 | tmp = DmStrJoin(tmp, "[", -1, TRUE1); | |||
| 808 | if( strncmp(Makedir,ip->ic_dir, strlen(Makedir)) ) | |||
| 809 | tmp = DmStrJoin(tmp, ip->ic_dir, -1, TRUE1); | |||
| 810 | else | |||
| 811 | tmp = DmStrJoin(tmp, ip->ic_dir+strlen(Makedir)+1, -1, TRUE1); | |||
| 812 | tmp = DmStrJoin(tmp, "]", -1, TRUE1); | |||
| 813 | } | |||
| 814 | tmp = DmStrJoin(tmp, (ip->ic_name)?") -->":")", -1, TRUE1); | |||
| 815 | } | |||
| 816 | ||||
| 817 | if( ip->ic_name ) tmp = DmStrApp( tmp, ip->ic_name ); | |||
| 818 | ||||
| 819 | if( flag && ip->ic_meta->ce_prq) { | |||
| 820 | tmp = DmStrJoin(tmp, "(", -1, TRUE1); | |||
| 821 | tmp = DmStrJoin(tmp, ip->ic_meta->ce_prq->cl_prq->CE_NAMEce_name->ht_name, -1, TRUE1); | |||
| 822 | tmp = DmStrJoin(tmp, ")", -1, TRUE1); | |||
| 823 | } | |||
| 824 | ||||
| 825 | if( print ) { | |||
| 826 | fprintf( stderrstderr, "%s: %2d. %s\n", Pname, print, tmp ); | |||
| 827 | FREE(tmp)free((char*)(tmp)); | |||
| 828 | tmp = NIL(char)((char*)((void*)0)); | |||
| 829 | } | |||
| 830 | ||||
| 831 | return(tmp); | |||
| 832 | } | |||
| 833 | ||||
| 834 | ||||
| 835 | #ifdef DBUG | |||
| 836 | static void | |||
| 837 | _dump_dfa_stack(dfas, dfa_stack) | |||
| 838 | DFALINKPTR dfas; | |||
| 839 | DFASETPTR dfa_stack; | |||
| 840 | { | |||
| 841 | register DFALINKPTR pdfa; | |||
| 842 | char *tmp = NIL(char)((char*)((void*)0)); | |||
| 843 | DFASETPTR ds; | |||
| 844 | ||||
| 845 | for( pdfa = dfas; pdfa != NIL(DFALINK)((DFALINK*)((void*)0)); pdfa = pdfa->dl_next ) | |||
| 846 | tmp = DmStrApp( tmp, pdfa->dl_meta->CE_NAMEce_name->ht_name ); | |||
| 847 | ||||
| 848 | tmp = DmStrApp( tmp, ":: {" ); | |||
| 849 | for( ds = dfa_stack; ds != NIL(DFASET)((DFASET*)((void*)0)); ds = ds->df_next ) { | |||
| 850 | tmp = DmStrApp( tmp, "[" ); | |||
| 851 | for( pdfa = ds->df_set; pdfa != NIL(DFALINK)((DFALINK*)((void*)0)); pdfa = pdfa->dl_next ) | |||
| 852 | tmp = DmStrApp( tmp, pdfa->dl_meta->CE_NAMEce_name->ht_name ); | |||
| 853 | tmp = DmStrApp( tmp, "]" ); | |||
| 854 | } | |||
| 855 | tmp = DmStrApp( tmp, "}" ); | |||
| 856 | ||||
| 857 | printf( "DFA set and stack contents:\n%s\n", tmp ); | |||
| 858 | FREE(tmp)free((char*)(tmp)); | |||
| 859 | } | |||
| 860 | ||||
| 861 | ||||
| 862 | static void | |||
| 863 | _dump_iset( name, iset ) | |||
| 864 | char *name; | |||
| 865 | ICELLPTR iset; | |||
| 866 | { | |||
| 867 | int cell = 0; | |||
| 868 | ||||
| 869 | printf( "**** ISET for %s\n", name ); | |||
| 870 | for( ; iset != NIL(ICELL)((ICELL*)((void*)0)); iset = iset->ic_next ){ | |||
| 871 | printf( "cell %d\n", cell++ ); | |||
| 872 | if( iset->ic_meta ) | |||
| 873 | printf( "edge: %s --> %s\n", iset->ic_meta->CE_NAMEce_name->ht_name, | |||
| 874 | iset->ic_meta->ce_prq ? | |||
| 875 | iset->ic_meta->ce_prq->cl_prq->CE_NAMEce_name->ht_name : | |||
| 876 | "(nil)" ); | |||
| 877 | else | |||
| 878 | printf( "edge: (nil)\n" ); | |||
| 879 | ||||
| 880 | if( iset->ic_dfa ) | |||
| 881 | printf( "dfa: %s\n", iset->ic_dfa->dl_meta->CE_NAMEce_name->ht_name ); | |||
| 882 | else | |||
| 883 | printf( "dfa: (nil)\n" ); | |||
| 884 | ||||
| 885 | printf( "sdr: %p\n", iset->ic_setdirroot ); | |||
| 886 | _dump_dfa_stack(iset->ic_dfastack.df_set, &iset->ic_dfastack); | |||
| 887 | ||||
| 888 | printf( "dmax: %d\n", iset->ic_dmax ); | |||
| 889 | printf( "name: %s\n", iset->ic_name ); | |||
| 890 | printf( "dir: %s\n", iset->ic_dir?iset->ic_dir:"(nil)" ); | |||
| 891 | ||||
| 892 | printf( "parent: " ); | |||
| 893 | if( iset->ic_parent ) | |||
| 894 | if( iset->ic_parent->ic_meta ) | |||
| 895 | printf( "%s --> %s\n", | |||
| 896 | iset->ic_parent->ic_meta->CE_NAMEce_name->ht_name, | |||
| 897 | iset->ic_parent->ic_meta->ce_prq ? | |||
| 898 | iset->ic_parent->ic_meta->ce_prq->cl_prq->CE_NAMEce_name->ht_name : | |||
| 899 | "(nil)" ); | |||
| 900 | else | |||
| 901 | printf( "(nil)\n" ); | |||
| 902 | else | |||
| 903 | printf( "(nil)\n" ); | |||
| 904 | } | |||
| 905 | printf( "==================================\n" ); | |||
| 906 | } | |||
| 907 | #endif |