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