Import KDE4.3.1 from wip
[pkgsrc.git] / bootstrap / bmake / targ.c
1 /*      $NetBSD: targ.c,v 1.1.1.1 2002/09/19 10:40:12 agc Exp $ */
2
3 /*
4  * Copyright (c) 1988, 1989, 1990, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  * Copyright (c) 1989 by Berkeley Softworks
7  * All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * Adam de Boor.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *      This product includes software developed by the University of
23  *      California, Berkeley and its contributors.
24  * 4. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  */
40
41 #ifdef MAKE_BOOTSTRAP
42 static char rcsid[] = "$NetBSD: targ.c,v 1.1.1.1 2002/09/19 10:40:12 agc Exp $";
43 #else
44 #include <sys/cdefs.h>
45 #ifndef lint
46 #if 0
47 static char sccsid[] = "@(#)targ.c      8.2 (Berkeley) 3/19/94";
48 #else
49 __RCSID("$NetBSD: targ.c,v 1.1.1.1 2002/09/19 10:40:12 agc Exp $");
50 #endif
51 #endif /* not lint */
52 #endif
53
54 /*-
55  * targ.c --
56  *      Functions for maintaining the Lst allTargets. Target nodes are
57  * kept in two structures: a Lst, maintained by the list library, and a
58  * hash table, maintained by the hash library.
59  *
60  * Interface:
61  *      Targ_Init               Initialization procedure.
62  *
63  *      Targ_End                Cleanup the module
64  *
65  *      Targ_List               Return the list of all targets so far.
66  *
67  *      Targ_NewGN              Create a new GNode for the passed target
68  *                              (string). The node is *not* placed in the
69  *                              hash table, though all its fields are
70  *                              initialized.
71  *
72  *      Targ_FindNode           Find the node for a given target, creating
73  *                              and storing it if it doesn't exist and the
74  *                              flags are right (TARG_CREATE)
75  *
76  *      Targ_FindList           Given a list of names, find nodes for all
77  *                              of them. If a name doesn't exist and the
78  *                              TARG_NOCREATE flag was given, an error message
79  *                              is printed. Else, if a name doesn't exist,
80  *                              its node is created.
81  *
82  *      Targ_Ignore             Return TRUE if errors should be ignored when
83  *                              creating the given target.
84  *
85  *      Targ_Silent             Return TRUE if we should be silent when
86  *                              creating the given target.
87  *
88  *      Targ_Precious           Return TRUE if the target is precious and
89  *                              should not be removed if we are interrupted.
90  *
91  * Debugging:
92  *      Targ_PrintGraph         Print out the entire graphm all variables
93  *                              and statistics for the directory cache. Should
94  *                              print something for suffixes, too, but...
95  */
96
97 #include          <stdio.h>
98 #include          <time.h>
99 #include          "make.h"
100 #include          "hash.h"
101 #include          "dir.h"
102
103 static Lst        allTargets;   /* the list of all targets found so far */
104 #ifdef CLEANUP
105 static Lst        allGNs;       /* List of all the GNodes */
106 #endif
107 static Hash_Table targets;      /* a hash table of same */
108
109 #define HTSIZE  191             /* initial size of hash table */
110
111 static int TargPrintOnlySrc __P((ClientData, ClientData));
112 static int TargPrintName __P((ClientData, ClientData));
113 static int TargPrintNode __P((ClientData, ClientData));
114 #ifdef CLEANUP
115 static void TargFreeGN __P((ClientData));
116 #endif
117 static int TargPropagateCohort __P((ClientData, ClientData));
118 static int TargPropagateNode __P((ClientData, ClientData));
119
120 /*-
121  *-----------------------------------------------------------------------
122  * Targ_Init --
123  *      Initialize this module
124  *
125  * Results:
126  *      None
127  *
128  * Side Effects:
129  *      The allTargets list and the targets hash table are initialized
130  *-----------------------------------------------------------------------
131  */
132 void
133 Targ_Init ()
134 {
135     allTargets = Lst_Init (FALSE);
136     Hash_InitTable (&targets, HTSIZE);
137 }
138
139 /*-
140  *-----------------------------------------------------------------------
141  * Targ_End --
142  *      Finalize this module
143  *
144  * Results:
145  *      None
146  *
147  * Side Effects:
148  *      All lists and gnodes are cleared
149  *-----------------------------------------------------------------------
150  */
151 void
152 Targ_End ()
153 {
154 #ifdef CLEANUP
155     Lst_Destroy(allTargets, NOFREE);
156     if (allGNs)
157         Lst_Destroy(allGNs, TargFreeGN);
158     Hash_DeleteTable(&targets);
159 #endif
160 }
161
162 /*-
163  *-----------------------------------------------------------------------
164  * Targ_List --
165  *      Return the list of all targets
166  *
167  * Results:
168  *      The list of all targets.
169  *
170  * Side Effects:
171  *      None
172  *-----------------------------------------------------------------------
173  */
174 Lst
175 Targ_List ()
176 {
177     return allTargets;
178 }
179
180 /*-
181  *-----------------------------------------------------------------------
182  * Targ_NewGN  --
183  *      Create and initialize a new graph node
184  *
185  * Results:
186  *      An initialized graph node with the name field filled with a copy
187  *      of the passed name
188  *
189  * Side Effects:
190  *      The gnode is added to the list of all gnodes.
191  *-----------------------------------------------------------------------
192  */
193 GNode *
194 Targ_NewGN (name)
195     char           *name;       /* the name to stick in the new node */
196 {
197     register GNode *gn;
198
199     gn = (GNode *) emalloc (sizeof (GNode));
200     gn->name = estrdup (name);
201     gn->uname = NULL;
202     gn->path = (char *) 0;
203     if (name[0] == '-' && name[1] == 'l') {
204         gn->type = OP_LIB;
205     } else {
206         gn->type = 0;
207     }
208     gn->unmade =        0;
209     gn->made =          UNMADE;
210     gn->flags =         0;
211     gn->order =         0;
212     gn->mtime = gn->cmtime = 0;
213     gn->iParents =      Lst_Init (FALSE);
214     gn->cohorts =       Lst_Init (FALSE);
215     gn->parents =       Lst_Init (FALSE);
216     gn->children =      Lst_Init (FALSE);
217     gn->successors =    Lst_Init (FALSE);
218     gn->preds =         Lst_Init (FALSE);
219     Hash_InitTable(&gn->context, 0);
220     gn->commands =      Lst_Init (FALSE);
221     gn->suffix =        NULL;
222     gn->lineno =        0;
223     gn->fname =         NULL;
224
225 #ifdef CLEANUP
226     if (allGNs == NULL)
227         allGNs = Lst_Init(FALSE);
228     Lst_AtEnd(allGNs, (ClientData) gn);
229 #endif
230
231     return (gn);
232 }
233
234 #ifdef CLEANUP
235 /*-
236  *-----------------------------------------------------------------------
237  * TargFreeGN  --
238  *      Destroy a GNode
239  *
240  * Results:
241  *      None.
242  *
243  * Side Effects:
244  *      None.
245  *-----------------------------------------------------------------------
246  */
247 static void
248 TargFreeGN (gnp)
249     ClientData gnp;
250 {
251     GNode *gn = (GNode *) gnp;
252
253
254     free(gn->name);
255     if (gn->uname)
256         free(gn->uname);
257     if (gn->path)
258         free(gn->path);
259     if (gn->fname)
260         free(gn->fname);
261
262     Lst_Destroy(gn->iParents, NOFREE);
263     Lst_Destroy(gn->cohorts, NOFREE);
264     Lst_Destroy(gn->parents, NOFREE);
265     Lst_Destroy(gn->children, NOFREE);
266     Lst_Destroy(gn->successors, NOFREE);
267     Lst_Destroy(gn->preds, NOFREE);
268     Hash_DeleteTable(&gn->context);
269     Lst_Destroy(gn->commands, NOFREE);
270     free((Address)gn);
271 }
272 #endif
273
274
275 /*-
276  *-----------------------------------------------------------------------
277  * Targ_FindNode  --
278  *      Find a node in the list using the given name for matching
279  *
280  * Results:
281  *      The node in the list if it was. If it wasn't, return NILGNODE of
282  *      flags was TARG_NOCREATE or the newly created and initialized node
283  *      if it was TARG_CREATE
284  *
285  * Side Effects:
286  *      Sometimes a node is created and added to the list
287  *-----------------------------------------------------------------------
288  */
289 GNode *
290 Targ_FindNode (name, flags)
291     char           *name;       /* the name to find */
292     int             flags;      /* flags governing events when target not
293                                  * found */
294 {
295     GNode         *gn;        /* node in that element */
296     Hash_Entry    *he;        /* New or used hash entry for node */
297     Boolean       isNew;      /* Set TRUE if Hash_CreateEntry had to create */
298                               /* an entry for the node */
299
300
301     if (flags & TARG_CREATE) {
302         he = Hash_CreateEntry (&targets, name, &isNew);
303         if (isNew) {
304             gn = Targ_NewGN (name);
305             Hash_SetValue (he, gn);
306             (void) Lst_AtEnd (allTargets, (ClientData)gn);
307         }
308     } else {
309         he = Hash_FindEntry (&targets, name);
310     }
311
312     if (he == (Hash_Entry *) NULL) {
313         return (NILGNODE);
314     } else {
315         return ((GNode *) Hash_GetValue (he));
316     }
317 }
318
319 /*-
320  *-----------------------------------------------------------------------
321  * Targ_FindList --
322  *      Make a complete list of GNodes from the given list of names
323  *
324  * Results:
325  *      A complete list of graph nodes corresponding to all instances of all
326  *      the names in names.
327  *
328  * Side Effects:
329  *      If flags is TARG_CREATE, nodes will be created for all names in
330  *      names which do not yet have graph nodes. If flags is TARG_NOCREATE,
331  *      an error message will be printed for each name which can't be found.
332  * -----------------------------------------------------------------------
333  */
334 Lst
335 Targ_FindList (names, flags)
336     Lst            names;       /* list of names to find */
337     int            flags;       /* flags used if no node is found for a given
338                                  * name */
339 {
340     Lst            nodes;       /* result list */
341     register LstNode  ln;               /* name list element */
342     register GNode *gn;         /* node in tLn */
343     char          *name;
344
345     nodes = Lst_Init (FALSE);
346
347     if (Lst_Open (names) == FAILURE) {
348         return (nodes);
349     }
350     while ((ln = Lst_Next (names)) != NILLNODE) {
351         name = (char *)Lst_Datum(ln);
352         gn = Targ_FindNode (name, flags);
353         if (gn != NILGNODE) {
354             /*
355              * Note: Lst_AtEnd must come before the Lst_Concat so the nodes
356              * are added to the list in the order in which they were
357              * encountered in the makefile.
358              */
359             (void) Lst_AtEnd (nodes, (ClientData)gn);
360         } else if (flags == TARG_NOCREATE) {
361             Error ("\"%s\" -- target unknown.", name);
362         }
363     }
364     Lst_Close (names);
365     return (nodes);
366 }
367
368 /*-
369  *-----------------------------------------------------------------------
370  * Targ_Ignore  --
371  *      Return true if should ignore errors when creating gn
372  *
373  * Results:
374  *      TRUE if should ignore errors
375  *
376  * Side Effects:
377  *      None
378  *-----------------------------------------------------------------------
379  */
380 Boolean
381 Targ_Ignore (gn)
382     GNode          *gn;         /* node to check for */
383 {
384     if (ignoreErrors || gn->type & OP_IGNORE) {
385         return (TRUE);
386     } else {
387         return (FALSE);
388     }
389 }
390
391 /*-
392  *-----------------------------------------------------------------------
393  * Targ_Silent  --
394  *      Return true if be silent when creating gn
395  *
396  * Results:
397  *      TRUE if should be silent
398  *
399  * Side Effects:
400  *      None
401  *-----------------------------------------------------------------------
402  */
403 Boolean
404 Targ_Silent (gn)
405     GNode          *gn;         /* node to check for */
406 {
407     if (beSilent || gn->type & OP_SILENT) {
408         return (TRUE);
409     } else {
410         return (FALSE);
411     }
412 }
413
414 /*-
415  *-----------------------------------------------------------------------
416  * Targ_Precious --
417  *      See if the given target is precious
418  *
419  * Results:
420  *      TRUE if it is precious. FALSE otherwise
421  *
422  * Side Effects:
423  *      None
424  *-----------------------------------------------------------------------
425  */
426 Boolean
427 Targ_Precious (gn)
428     GNode          *gn;         /* the node to check */
429 {
430     if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) {
431         return (TRUE);
432     } else {
433         return (FALSE);
434     }
435 }
436
437 /******************* DEBUG INFO PRINTING ****************/
438
439 static GNode      *mainTarg;    /* the main target, as set by Targ_SetMain */
440 /*-
441  *-----------------------------------------------------------------------
442  * Targ_SetMain --
443  *      Set our idea of the main target we'll be creating. Used for
444  *      debugging output.
445  *
446  * Results:
447  *      None.
448  *
449  * Side Effects:
450  *      "mainTarg" is set to the main target's node.
451  *-----------------------------------------------------------------------
452  */
453 void
454 Targ_SetMain (gn)
455     GNode   *gn;        /* The main target we'll create */
456 {
457     mainTarg = gn;
458 }
459
460 static int
461 TargPrintName (gnp, ppath)
462     ClientData     gnp;
463     ClientData      ppath;
464 {
465     GNode *gn = (GNode *) gnp;
466     printf ("%s ", gn->name);
467 #ifdef notdef
468     if (ppath) {
469         if (gn->path) {
470             printf ("[%s]  ", gn->path);
471         }
472         if (gn == mainTarg) {
473             printf ("(MAIN NAME)  ");
474         }
475     }
476 #endif /* notdef */
477     return (ppath ? 0 : 0);
478 }
479
480
481 int
482 Targ_PrintCmd (cmd, dummy)
483     ClientData cmd;
484     ClientData dummy;
485 {
486     printf ("\t%s\n", (char *) cmd);
487     return (dummy ? 0 : 0);
488 }
489
490 /*-
491  *-----------------------------------------------------------------------
492  * Targ_FmtTime --
493  *      Format a modification time in some reasonable way and return it.
494  *
495  * Results:
496  *      The time reformatted.
497  *
498  * Side Effects:
499  *      The time is placed in a static area, so it is overwritten
500  *      with each call.
501  *
502  *-----------------------------------------------------------------------
503  */
504 char *
505 Targ_FmtTime (time)
506     time_t    time;
507 {
508     struct tm           *parts;
509     static char         buf[128];
510
511     parts = localtime(&time);
512     (void)strftime(buf, sizeof buf, "%k:%M:%S %b %d, %Y", parts);
513     return(buf);
514 }
515
516 /*-
517  *-----------------------------------------------------------------------
518  * Targ_PrintType --
519  *      Print out a type field giving only those attributes the user can
520  *      set.
521  *
522  * Results:
523  *
524  * Side Effects:
525  *
526  *-----------------------------------------------------------------------
527  */
528 void
529 Targ_PrintType (type)
530     register int    type;
531 {
532     register int    tbit;
533
534 #ifdef __STDC__
535 #define PRINTBIT(attr)  case CONCAT(OP_,attr): printf("." #attr " "); break
536 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break
537 #else
538 #define PRINTBIT(attr)  case CONCAT(OP_,attr): printf(".attr "); break
539 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf(".attr "); break
540 #endif /* __STDC__ */
541
542     type &= ~OP_OPMASK;
543
544     while (type) {
545         tbit = 1 << (ffs(type) - 1);
546         type &= ~tbit;
547
548         switch(tbit) {
549             PRINTBIT(OPTIONAL);
550             PRINTBIT(USE);
551             PRINTBIT(EXEC);
552             PRINTBIT(IGNORE);
553             PRINTBIT(PRECIOUS);
554             PRINTBIT(SILENT);
555             PRINTBIT(MAKE);
556             PRINTBIT(JOIN);
557             PRINTBIT(INVISIBLE);
558             PRINTBIT(NOTMAIN);
559             PRINTDBIT(LIB);
560             /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
561             case OP_MEMBER: if (DEBUG(TARG)) printf(".MEMBER "); break;
562             PRINTDBIT(ARCHV);
563         }
564     }
565 }
566
567 /*-
568  *-----------------------------------------------------------------------
569  * TargPrintNode --
570  *      print the contents of a node
571  *-----------------------------------------------------------------------
572  */
573 static int
574 TargPrintNode (gnp, passp)
575     ClientData   gnp;
576     ClientData   passp;
577 {
578     GNode         *gn = (GNode *) gnp;
579     int           pass = *(int *) passp;
580     if (!OP_NOP(gn->type)) {
581         printf("#\n");
582         if (gn == mainTarg) {
583             printf("# *** MAIN TARGET ***\n");
584         }
585         if (pass == 2) {
586             if (gn->unmade) {
587                 printf("# %d unmade children\n", gn->unmade);
588             } else {
589                 printf("# No unmade children\n");
590             }
591             if (! (gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC))) {
592                 if (gn->mtime != 0) {
593                     printf("# last modified %s: %s\n",
594                               Targ_FmtTime(gn->mtime),
595                               (gn->made == UNMADE ? "unmade" :
596                                (gn->made == MADE ? "made" :
597                                 (gn->made == UPTODATE ? "up-to-date" :
598                                  "error when made"))));
599                 } else if (gn->made != UNMADE) {
600                     printf("# non-existent (maybe): %s\n",
601                               (gn->made == MADE ? "made" :
602                                (gn->made == UPTODATE ? "up-to-date" :
603                                 (gn->made == ERROR ? "error when made" :
604                                  "aborted"))));
605                 } else {
606                     printf("# unmade\n");
607                 }
608             }
609             if (!Lst_IsEmpty (gn->iParents)) {
610                 printf("# implicit parents: ");
611                 Lst_ForEach (gn->iParents, TargPrintName, (ClientData)0);
612                 fputc ('\n', stdout);
613             }
614         }
615         if (!Lst_IsEmpty (gn->parents)) {
616             printf("# parents: ");
617             Lst_ForEach (gn->parents, TargPrintName, (ClientData)0);
618             fputc ('\n', stdout);
619         }
620
621         printf("%-16s", gn->name);
622         switch (gn->type & OP_OPMASK) {
623             case OP_DEPENDS:
624                 printf(": "); break;
625             case OP_FORCE:
626                 printf("! "); break;
627             case OP_DOUBLEDEP:
628                 printf(":: "); break;
629         }
630         Targ_PrintType (gn->type);
631         Lst_ForEach (gn->children, TargPrintName, (ClientData)0);
632         fputc ('\n', stdout);
633         Lst_ForEach (gn->commands, Targ_PrintCmd, (ClientData)0);
634         printf("\n\n");
635         if (gn->type & OP_DOUBLEDEP) {
636             Lst_ForEach (gn->cohorts, TargPrintNode, (ClientData)&pass);
637         }
638     }
639     return (0);
640 }
641
642 /*-
643  *-----------------------------------------------------------------------
644  * TargPrintOnlySrc --
645  *      Print only those targets that are just a source.
646  *
647  * Results:
648  *      0.
649  *
650  * Side Effects:
651  *      The name of each file is printed preceded by #\t
652  *
653  *-----------------------------------------------------------------------
654  */
655 static int
656 TargPrintOnlySrc(gnp, dummy)
657     ClientData    gnp;
658     ClientData    dummy;
659 {
660     GNode         *gn = (GNode *) gnp;
661     if (OP_NOP(gn->type))
662         printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name);
663
664     return (dummy ? 0 : 0);
665 }
666
667 /*-
668  *-----------------------------------------------------------------------
669  * Targ_PrintGraph --
670  *      print the entire graph. heh heh
671  *
672  * Results:
673  *      none
674  *
675  * Side Effects:
676  *      lots o' output
677  *-----------------------------------------------------------------------
678  */
679 void
680 Targ_PrintGraph (pass)
681     int     pass;       /* Which pass this is. 1 => no processing
682                          * 2 => processing done */
683 {
684     printf("#*** Input graph:\n");
685     Lst_ForEach (allTargets, TargPrintNode, (ClientData)&pass);
686     printf("\n\n");
687     printf("#\n#   Files that are only sources:\n");
688     Lst_ForEach (allTargets, TargPrintOnlySrc, (ClientData) 0);
689     printf("#*** Global Variables:\n");
690     Var_Dump (VAR_GLOBAL);
691     printf("#*** Command-line Variables:\n");
692     Var_Dump (VAR_CMD);
693     printf("\n");
694     Dir_PrintDirectories();
695     printf("\n");
696     Suff_PrintAll();
697 }
698
699 static int
700 TargPropagateCohort (cgnp, pgnp)
701     ClientData   cgnp;
702     ClientData   pgnp;
703 {
704     GNode         *cgn = (GNode *) cgnp;
705     GNode         *pgn = (GNode *) pgnp;
706
707     cgn->type |= pgn->type & ~OP_OPMASK;
708     return (0);
709 }
710
711 static int
712 TargPropagateNode (gnp, junk)
713     ClientData   gnp;
714     ClientData   junk;
715 {
716     GNode         *gn = (GNode *) gnp;
717     if (gn->type & OP_DOUBLEDEP)
718         Lst_ForEach (gn->cohorts, TargPropagateCohort, gnp);
719     return (0);
720 }
721
722 void
723 Targ_Propagate ()
724 {
725     Lst_ForEach (allTargets, TargPropagateNode, (ClientData)0);
726 }