replace hash.c; speedup/cleanup from Chris Torek
[unix-history] / usr / src / usr.bin / make / targ.c
CommitLineData
9320ab9e
KB
1/*
2 * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
3 * Copyright (c) 1988, 1989 by Adam de Boor
4 * Copyright (c) 1989 by Berkeley Softworks
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Adam de Boor.
9 *
87198c0c 10 * %sccs.include.redist.c%
9320ab9e
KB
11 */
12
13#ifndef lint
fc46faab 14static char sccsid[] = "@(#)targ.c 5.8 (Berkeley) %G%";
9320ab9e
KB
15#endif /* not lint */
16
ab950546
KB
17/*-
18 * targ.c --
19 * Functions for maintaining the Lst allTargets. Target nodes are
20 * kept in two structures: a Lst, maintained by the list library, and a
21 * hash table, maintained by the hash library.
22 *
ab950546
KB
23 * Interface:
24 * Targ_Init Initialization procedure.
25 *
26 * Targ_NewGN Create a new GNode for the passed target
27 * (string). The node is *not* placed in the
28 * hash table, though all its fields are
29 * initialized.
30 *
31 * Targ_FindNode Find the node for a given target, creating
32 * and storing it if it doesn't exist and the
33 * flags are right (TARG_CREATE)
34 *
35 * Targ_FindList Given a list of names, find nodes for all
36 * of them. If a name doesn't exist and the
37 * TARG_NOCREATE flag was given, an error message
38 * is printed. Else, if a name doesn't exist,
39 * its node is created.
40 *
41 * Targ_Ignore Return TRUE if errors should be ignored when
42 * creating the given target.
43 *
44 * Targ_Silent Return TRUE if we should be silent when
45 * creating the given target.
46 *
47 * Targ_Precious Return TRUE if the target is precious and
48 * should not be removed if we are interrupted.
49 *
50 * Debugging:
51 * Targ_PrintGraph Print out the entire graphm all variables
52 * and statistics for the directory cache. Should
53 * print something for suffixes, too, but...
54 */
ab950546
KB
55
56#include <stdio.h>
57#include <time.h>
58#include "make.h"
59#include "hash.h"
60
61static Lst allTargets; /* the list of all targets found so far */
62static Hash_Table targets; /* a hash table of same */
63
64#define HTSIZE 191 /* initial size of hash table */
65
66/*-
67 *-----------------------------------------------------------------------
68 * Targ_Init --
69 * Initialize this module
70 *
71 * Results:
72 * None
73 *
74 * Side Effects:
75 * The allTargets list and the targets hash table are initialized
76 *-----------------------------------------------------------------------
77 */
78void
79Targ_Init ()
80{
81 allTargets = Lst_Init (FALSE);
fc46faab 82 Hash_InitTable (&targets, HTSIZE);
ab950546 83}
182ca07d 84
ab950546
KB
85/*-
86 *-----------------------------------------------------------------------
87 * Targ_NewGN --
88 * Create and initialize a new graph node
89 *
90 * Results:
91 * An initialized graph node with the name field filled with a copy
92 * of the passed name
93 *
94 * Side Effects:
95 * None.
96 *-----------------------------------------------------------------------
97 */
98GNode *
99Targ_NewGN (name)
100 char *name; /* the name to stick in the new node */
101{
102 register GNode *gn;
103
54527040 104 gn = (GNode *) emalloc (sizeof (GNode));
182ca07d 105 gn->name = strdup (name);
ab950546
KB
106 gn->path = (char *) 0;
107 if (name[0] == '-' && name[1] == 'l') {
108 gn->type = OP_LIB;
109 } else {
110 gn->type = 0;
111 }
112 gn->unmade = 0;
113 gn->make = FALSE;
114 gn->made = UNMADE;
115 gn->childMade = FALSE;
116 gn->mtime = gn->cmtime = 0;
117 gn->iParents = Lst_Init (FALSE);
118 gn->cohorts = Lst_Init (FALSE);
119 gn->parents = Lst_Init (FALSE);
120 gn->children = Lst_Init (FALSE);
121 gn->successors = Lst_Init(FALSE);
122 gn->preds = Lst_Init(FALSE);
123 gn->context = Lst_Init (FALSE);
124 gn->commands = Lst_Init (FALSE);
125
126 return (gn);
127}
182ca07d 128
ab950546
KB
129/*-
130 *-----------------------------------------------------------------------
131 * Targ_FindNode --
132 * Find a node in the list using the given name for matching
133 *
134 * Results:
135 * The node in the list if it was. If it wasn't, return NILGNODE of
136 * flags was TARG_NOCREATE or the newly created and initialized node
137 * if it was TARG_CREATE
138 *
139 * Side Effects:
140 * Sometimes a node is created and added to the list
141 *-----------------------------------------------------------------------
142 */
143GNode *
144Targ_FindNode (name, flags)
145 char *name; /* the name to find */
146 int flags; /* flags governing events when target not
147 * found */
148{
149 GNode *gn; /* node in that element */
150 Hash_Entry *he; /* New or used hash entry for node */
151 Boolean isNew; /* Set TRUE if Hash_CreateEntry had to create */
152 /* an entry for the node */
153
154
155 if (flags & TARG_CREATE) {
156 he = Hash_CreateEntry (&targets, name, &isNew);
157 if (isNew) {
158 gn = Targ_NewGN (name);
159 Hash_SetValue (he, gn);
160 (void) Lst_AtEnd (allTargets, (ClientData)gn);
161 }
162 } else {
163 he = Hash_FindEntry (&targets, name);
164 }
165
166 if (he == (Hash_Entry *) NULL) {
167 return (NILGNODE);
168 } else {
169 return ((GNode *) Hash_GetValue (he));
170 }
171}
182ca07d 172
ab950546
KB
173/*-
174 *-----------------------------------------------------------------------
175 * Targ_FindList --
176 * Make a complete list of GNodes from the given list of names
177 *
178 * Results:
179 * A complete list of graph nodes corresponding to all instances of all
180 * the names in names.
181 *
182 * Side Effects:
183 * If flags is TARG_CREATE, nodes will be created for all names in
184 * names which do not yet have graph nodes. If flags is TARG_NOCREATE,
185 * an error message will be printed for each name which can't be found.
186 * -----------------------------------------------------------------------
187 */
188Lst
189Targ_FindList (names, flags)
190 Lst names; /* list of names to find */
191 int flags; /* flags used if no node is found for a given
192 * name */
193{
194 Lst nodes; /* result list */
195 register LstNode ln; /* name list element */
196 register GNode *gn; /* node in tLn */
197 char *name;
198
199 nodes = Lst_Init (FALSE);
200
201 if (Lst_Open (names) == FAILURE) {
202 return (nodes);
203 }
204 while ((ln = Lst_Next (names)) != NILLNODE) {
205 name = (char *)Lst_Datum(ln);
206 gn = Targ_FindNode (name, flags);
207 if (gn != NILGNODE) {
208 /*
209 * Note: Lst_AtEnd must come before the Lst_Concat so the nodes
210 * are added to the list in the order in which they were
211 * encountered in the makefile.
212 */
213 (void) Lst_AtEnd (nodes, (ClientData)gn);
214 if (gn->type & OP_DOUBLEDEP) {
215 (void)Lst_Concat (nodes, gn->cohorts, LST_CONCNEW);
216 }
217 } else if (flags == TARG_NOCREATE) {
218 Error ("\"%s\" -- target unknown.", name);
219 }
220 }
221 Lst_Close (names);
222 return (nodes);
223}
182ca07d 224
ab950546
KB
225/*-
226 *-----------------------------------------------------------------------
227 * Targ_Ignore --
228 * Return true if should ignore errors when creating gn
229 *
230 * Results:
231 * TRUE if should ignore errors
232 *
233 * Side Effects:
234 * None
235 *-----------------------------------------------------------------------
236 */
237Boolean
238Targ_Ignore (gn)
239 GNode *gn; /* node to check for */
240{
241 if (ignoreErrors || gn->type & OP_IGNORE) {
242 return (TRUE);
243 } else {
244 return (FALSE);
245 }
246}
182ca07d 247
ab950546
KB
248/*-
249 *-----------------------------------------------------------------------
250 * Targ_Silent --
251 * Return true if be silent when creating gn
252 *
253 * Results:
254 * TRUE if should be silent
255 *
256 * Side Effects:
257 * None
258 *-----------------------------------------------------------------------
259 */
260Boolean
261Targ_Silent (gn)
262 GNode *gn; /* node to check for */
263{
264 if (beSilent || gn->type & OP_SILENT) {
265 return (TRUE);
266 } else {
267 return (FALSE);
268 }
269}
182ca07d 270
ab950546
KB
271/*-
272 *-----------------------------------------------------------------------
273 * Targ_Precious --
274 * See if the given target is precious
275 *
276 * Results:
277 * TRUE if it is precious. FALSE otherwise
278 *
279 * Side Effects:
280 * None
281 *-----------------------------------------------------------------------
282 */
283Boolean
284Targ_Precious (gn)
285 GNode *gn; /* the node to check */
286{
287 if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) {
288 return (TRUE);
289 } else {
290 return (FALSE);
291 }
292}
182ca07d 293
ab950546
KB
294/******************* DEBUG INFO PRINTING ****************/
295
296static GNode *mainTarg; /* the main target, as set by Targ_SetMain */
297/*-
298 *-----------------------------------------------------------------------
299 * Targ_SetMain --
300 * Set our idea of the main target we'll be creating. Used for
301 * debugging output.
302 *
303 * Results:
304 * None.
305 *
306 * Side Effects:
307 * "mainTarg" is set to the main target's node.
308 *-----------------------------------------------------------------------
309 */
310void
311Targ_SetMain (gn)
312 GNode *gn; /* The main target we'll create */
313{
314 mainTarg = gn;
315}
316
317static int
318TargPrintName (gn, ppath)
319 GNode *gn;
320 int ppath;
321{
322 printf ("%s ", gn->name);
323#ifdef notdef
324 if (ppath) {
325 if (gn->path) {
326 printf ("[%s] ", gn->path);
327 }
328 if (gn == mainTarg) {
329 printf ("(MAIN NAME) ");
330 }
331 }
332#endif notdef
333 return (0);
334}
335
336
337int
338Targ_PrintCmd (cmd)
339 char *cmd;
340{
341 printf ("\t%s\n", cmd);
342 return (0);
343}
344
345/*-
346 *-----------------------------------------------------------------------
347 * Targ_FmtTime --
348 * Format a modification time in some reasonable way and return it.
349 *
350 * Results:
351 * The time reformatted.
352 *
353 * Side Effects:
354 * The time is placed in a static area, so it is overwritten
355 * with each call.
356 *
357 *-----------------------------------------------------------------------
358 */
359char *
360Targ_FmtTime (time)
361 int time;
362{
363 struct tm *parts;
364 static char buf[40];
365 static char *months[] = {
366 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
367 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
368 };
369
370 parts = localtime(&time);
371
372 sprintf (buf, "%d:%02d:%02d %s %d, 19%d",
373 parts->tm_hour, parts->tm_min, parts->tm_sec,
374 months[parts->tm_mon], parts->tm_mday, parts->tm_year);
375 return(buf);
376}
377
378/*-
379 *-----------------------------------------------------------------------
380 * Targ_PrintType --
381 * Print out a type field giving only those attributes the user can
382 * set.
383 *
384 * Results:
385 *
386 * Side Effects:
387 *
388 *-----------------------------------------------------------------------
389 */
390void
391Targ_PrintType (type)
392 register int type;
393{
394 register int tbit;
395
396#ifdef __STDC__
397#define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break
398#define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break
399#else
400#define PRINTBIT(attr) case CONCAT(OP_,attr): printf(".attr "); break
401#define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf(".attr "); break
402#endif /* __STDC__ */
403
404 type &= ~OP_OPMASK;
405
406 while (type) {
407 tbit = 1 << (ffs(type) - 1);
408 type &= ~tbit;
409
410 switch(tbit) {
ac8c8bba 411 PRINTBIT(OPTIONAL);
ab950546
KB
412 PRINTBIT(USE);
413 PRINTBIT(EXEC);
414 PRINTBIT(IGNORE);
415 PRINTBIT(PRECIOUS);
416 PRINTBIT(SILENT);
417 PRINTBIT(MAKE);
418 PRINTBIT(JOIN);
ab950546
KB
419 PRINTBIT(INVISIBLE);
420 PRINTBIT(NOTMAIN);
421 PRINTDBIT(LIB);
ab950546
KB
422 /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
423 case OP_MEMBER: if (DEBUG(TARG)) printf(".MEMBER "); break;
424 PRINTDBIT(ARCHV);
425 }
426 }
427}
428
429/*-
430 *-----------------------------------------------------------------------
431 * TargPrintNode --
432 * print the contents of a node
433 *-----------------------------------------------------------------------
434 */
435static int
436TargPrintNode (gn, pass)
437 GNode *gn;
438 int pass;
439{
440 if (!OP_NOP(gn->type)) {
441 printf("#\n");
442 if (gn == mainTarg) {
443 printf("# *** MAIN TARGET ***\n");
444 }
445 if (pass == 2) {
446 if (gn->unmade) {
447 printf("# %d unmade children\n", gn->unmade);
448 } else {
449 printf("# No unmade children\n");
450 }
451 if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) {
452 if (gn->mtime != 0) {
453 printf("# last modified %s: %s\n",
454 Targ_FmtTime(gn->mtime),
455 (gn->made == UNMADE ? "unmade" :
456 (gn->made == MADE ? "made" :
457 (gn->made == UPTODATE ? "up-to-date" :
458 "error when made"))));
459 } else if (gn->made != UNMADE) {
460 printf("# non-existent (maybe): %s\n",
461 (gn->made == MADE ? "made" :
462 (gn->made == UPTODATE ? "up-to-date" :
463 (gn->made == ERROR ? "error when made" :
464 "aborted"))));
465 } else {
466 printf("# unmade\n");
467 }
468 }
469 if (!Lst_IsEmpty (gn->iParents)) {
470 printf("# implicit parents: ");
471 Lst_ForEach (gn->iParents, TargPrintName, (ClientData)0);
472 putc ('\n', stdout);
473 }
474 }
475 if (!Lst_IsEmpty (gn->parents)) {
476 printf("# parents: ");
477 Lst_ForEach (gn->parents, TargPrintName, (ClientData)0);
478 putc ('\n', stdout);
479 }
480
481 printf("%-16s", gn->name);
482 switch (gn->type & OP_OPMASK) {
483 case OP_DEPENDS:
484 printf(": "); break;
485 case OP_FORCE:
486 printf("! "); break;
487 case OP_DOUBLEDEP:
488 printf(":: "); break;
489 }
490 Targ_PrintType (gn->type);
491 Lst_ForEach (gn->children, TargPrintName, (ClientData)0);
492 putc ('\n', stdout);
493 Lst_ForEach (gn->commands, Targ_PrintCmd, (ClientData)0);
494 printf("\n\n");
495 if (gn->type & OP_DOUBLEDEP) {
496 Lst_ForEach (gn->cohorts, TargPrintNode, (ClientData)pass);
497 }
498 }
499 return (0);
500}
182ca07d 501
ab950546
KB
502/*-
503 *-----------------------------------------------------------------------
504 * TargPrintOnlySrc --
505 * Print only those targets that are just a source.
506 *
507 * Results:
508 * 0.
509 *
510 * Side Effects:
511 * The name of each file is printed preceeded by #\t
512 *
513 *-----------------------------------------------------------------------
514 */
515static int
516TargPrintOnlySrc(gn)
517 GNode *gn;
518{
519 if (OP_NOP(gn->type)) {
520 printf("#\t%s [%s]\n", gn->name,
521 gn->path ? gn->path : gn->name);
522 }
523 return (0);
524}
182ca07d 525
ab950546
KB
526/*-
527 *-----------------------------------------------------------------------
528 * Targ_PrintGraph --
529 * print the entire graph. heh heh
530 *
531 * Results:
532 * none
533 *
534 * Side Effects:
535 * lots o' output
536 *-----------------------------------------------------------------------
537 */
538Targ_PrintGraph (pass)
539 int pass; /* Which pass this is. 1 => no processing
540 * 2 => processing done */
541{
542 printf("#*** Input graph:\n");
543 Lst_ForEach (allTargets, TargPrintNode, (ClientData)pass);
544 printf("\n\n");
545 printf("#\n# Files that are only sources:\n");
546 Lst_ForEach (allTargets, TargPrintOnlySrc);
547 printf("#*** Global Variables:\n");
548 Var_Dump (VAR_GLOBAL);
549 printf("#*** Command-line Variables:\n");
550 Var_Dump (VAR_CMD);
551 printf("\n");
552 Dir_PrintDirectories();
553 printf("\n");
554 Suff_PrintAll();
555}