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