1st attempt of Zunification of BHFormat.
[cake.git] / tools / MetaMake / dirnode.c
blob3a511d9c242dc9ad96485177f1c7e96902d820d6
1 /* MetaMake - A Make extension
2 Copyright © 1995-2008, The AROS Development Team. All rights reserved.
4 This file is part of MetaMake.
6 MetaMake is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 MetaMake is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 //#define DEBUG_DIRNODE
23 #include "config.h"
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <assert.h>
28 #include <errno.h>
29 #ifdef HAVE_STRING_H
30 # include <string.h>
31 #else
32 # include <strings.h>
33 #endif
34 #ifdef HAVE_SYS_STAT_H
35 # include <sys/stat.h>
36 #endif
37 #ifdef HAVE_SYS_TYPES_H
38 # include <sys/types.h>
39 #endif
40 #ifndef PATH_MAX
41 #include <limits.h>
42 #endif
44 #include "dirnode.h"
45 #include "mem.h"
46 #include "var.h"
47 #include "mmake.h"
48 #include "io.h"
50 #if defined(DEBUG_DIRNODE)
51 #define debug(a) a
52 #else
53 #define debug(v)
54 #endif
56 #define FLAG_VIRTUAL 0x0001
58 extern char *mm_srcdir;
59 extern char *mm_builddir;
61 static MakefileTarget *
62 newmakefiletarget (char *name, int virtualtarget)
64 MakefileTarget * mftarget;
66 mftarget = newnodesize (name, sizeof(MakefileTarget));
67 mftarget->virtualtarget = virtualtarget;
68 NewList (&mftarget->deps);
70 return mftarget;
73 void
74 freemakefiletarget (MakefileTarget * mftarget)
76 freelist (&mftarget->deps);
77 xfree (mftarget);
80 void
81 freemakefiletargetlist (List * targets)
83 MakefileTarget * mftarget, * mftarget2;
85 ForeachNodeSafe (targets, mftarget, mftarget2)
86 freemakefiletarget (mftarget);
88 NewList (targets);
91 void
92 printdirnode (DirNode * node, int level)
94 DirNode * subdir;
95 int t;
97 for (t=0; t<level; t++)
98 printf (" ");
100 printf ("%s\n", node->node.name);
102 level ++;
104 ForeachNode (&node->subdirs, subdir)
105 printdirnode (subdir, level);
108 void
109 printdirnodemftarget (DirNode * node)
111 Makefile * makefile;
112 MakefileTarget * mftarget;
113 Node * dep;
114 DirNode * subdir;
116 ForeachNode (&node->makefiles, makefile)
118 printf ("%s/%s:\n", buildpath(node), makefile->node.name);
119 ForeachNode (&makefile->targets, mftarget)
121 printf (" %s:", mftarget->node.name);
122 ForeachNode (&mftarget->deps, dep)
123 printf (" %s", dep->name);
124 printf ("\n");
128 ForeachNode (&node->subdirs, subdir)
129 printdirnodemftarget (subdir);
132 void
133 freedirnode (DirNode * node)
135 DirNode * subnode, * subnode2;
137 ForeachNodeSafe (&node->subdirs, subnode, subnode2)
138 freedirnode (subnode);
140 xfree (node->node.name);
141 xfree (node);
144 void
145 freemakefile (Makefile * makefile)
147 freemakefiletargetlist (&makefile->targets);
148 xfree (makefile->node.name);
149 xfree (makefile);
152 DirNode *
153 finddirnode (DirNode * topnode, const char * path)
155 const char * ptr;
156 char dirname[256];
157 int len;
158 DirNode * node = topnode, * subdir;
160 ptr = path+2;
162 if (!*ptr)
163 return node;
165 subdir = NULL;
167 while (*ptr)
169 for (len=0; ptr[len] && ptr[len] != '/'; len++);
171 strncpy (dirname, ptr, len);
172 dirname[len] = 0;
173 ptr += len;
174 while (*ptr == '/')
175 ptr ++;
177 subdir = FindNode (&node->subdirs, dirname);
179 if (!subdir)
180 break;
182 node = subdir;
185 return subdir;
190 scandirnode (DirNode * node, const char * mfname, List * ignoredirs)
192 struct stat st;
193 DIR * dirh;
194 struct dirent * dirent;
196 int mfnamelen = strlen(mfname), scanned = 0;
198 debug(printf("MMAKE:dirnode.c->scandirnode('%s')\n", node->node.name));
200 if (stat(".", &st) != 0)
202 error("scandirnode(): scanning %s\n",
203 strlen(node->node.name) == 0
204 ? "topdir"
205 : node->node.name);
207 exit(20);
210 if (st.st_mtime > node->time)
212 List newdirs, newmakefiles;
213 DirNode * subdir = NULL, * subdir2;
214 Makefile * makefile;
216 debug(printf("MMAKE:dirnode.c->scandirnode dir->time changed .. scanning\n"));
218 if (debug)
219 printf("scandirnode(): scanning %s\n",
220 strlen(node->node.name)==0 ? "topdir" : buildpath(node)
223 NewList (&newdirs);
224 NewList (&newmakefiles);
226 node->time = st.st_mtime;
228 dirh = opendir (".");
229 if (!dirh)
231 error("opendir: could not open current dir");
232 exit(20);
235 while ((dirent = readdir (dirh)))
237 /* Add makefile if it present or the file with .src is present */
238 if (strcmp(dirent->d_name, mfname) == 0
239 || (strlen(dirent->d_name) == mfnamelen + 4
240 && strncmp(dirent->d_name, mfname, mfnamelen) == 0
241 && strcmp(dirent->d_name + mfnamelen, ".src") == 0
245 /* Don't add makefile twice */
246 debug(printf("MMAKE:dirnode.c->scandirnode: %s found ('%s')\n", mfname, dirent->d_name));
248 makefile = FindNode (&newmakefiles, mfname);
249 if (makefile == NULL)
251 debug(printf("MMAKE:dirnode.c->scandirnode: Creating New Makefile node\n"));
252 makefile = FindNode (&node->makefiles, mfname);
253 if (makefile != NULL)
255 Remove (makefile);
257 else
259 makefile = newnodesize (mfname, sizeof (Makefile));
260 makefile->dir = node;
261 debug(printf("MMAKE:dirnode.c->scandirnode: Makefile node dir '%s'\n", node->node.name));
262 makefile->time = (time_t)0;
263 NewList (&makefile->targets);
265 AddTail (&newmakefiles, makefile);
267 if (strcmp(dirent->d_name + mfnamelen, ".src") == 0)
268 makefile->generated = 1;
270 else
272 /* If the file is already in the makefiles from the current dirnode
273 * and it is still present in the directory copy it to the new makefiles
274 * list
276 if (strlen (dirent->d_name) > 4
277 && strcmp (dirent->d_name + strlen(dirent->d_name) - 4, ".src") == 0
280 dirent->d_name[strlen(dirent->d_name) - 4] = 0;
281 makefile = FindNode (&node->makefiles, dirent->d_name);
282 dirent->d_name[strlen(dirent->d_name)] = '.';
284 else
285 makefile = FindNode (&node->makefiles, dirent->d_name);
287 if (makefile != NULL)
289 Remove (makefile);
290 AddTail (&newmakefiles, makefile);
294 /* Add file to newsubdirs if it is a directory and it has not to be ignored
296 if (lstat (dirent->d_name, &st) == -1)
298 error ("scandirnode: stat(%s)", dirent->d_name);
299 exit(20);
302 /* TODO: Add support to MetaMake for going through links
303 * If this feature is to be supported one also has to implement
304 * checks to avoid MetaMake going into infinite loop when circular
305 * linking is present
307 if (S_ISDIR (st.st_mode)
308 && strcmp (dirent->d_name, ".") != 0
309 && strcmp (dirent->d_name, "..") != 0
310 && !S_ISLNK (st.st_mode)
311 && !FindNode (ignoredirs, dirent->d_name)
314 subdir = FindNode (&node->subdirs, dirent->d_name);
316 if (subdir != NULL)
318 Remove (subdir);
320 else
322 subdir = newnodesize (dirent->d_name, sizeof(DirNode));
323 debug(printf("MMAKE:dirnode.c->scandirnode: New SubDir Node '%s' @ %p\n", dirent->d_name, subdir));
324 subdir->parent = node;
325 subdir->time = (time_t)0;
326 NewList (&subdir->subdirs);
327 NewList (&subdir->makefiles);
329 AddTail (&newdirs, subdir);
334 closedir (dirh);
336 ForeachNodeSafe (&node->subdirs, subdir, subdir2)
337 freedirnode (subdir);
338 AssignList (&node->subdirs, &newdirs);
340 /* Clear the makefiles that have disappeared */
341 ForeachNode (&node->makefiles, makefile)
343 MakefileTarget * mftarget;
345 ForeachNode (&makefile->targets, mftarget)
346 freelist (&mftarget->deps);
348 freelist (&makefile->targets);
351 freelist (&node->makefiles);
353 AssignList (&node->makefiles, &newmakefiles);
355 scanned = 1;
358 debug(printf("MMAKE:dirnode.c->scandirnode: Finished scanning dir '%s'\n", node->node.name));
359 if (debug)
361 printf ("scandirnode()\n");
362 printdirnode (node, 1);
365 return scanned;
370 scanmakefiles (DirNode * node, List * vars)
372 Makefile * makefile;
373 struct stat st;
374 static char * line = NULL;
375 static int linelen = 512;
376 int reread = 0;
377 FILE * fh;
379 debug(printf("MMAKE:dirnode.c->scanmakefiles('%s')\n", node->node.name));
381 assert (node);
383 if (line == NULL)
384 line = xmalloc(linelen);
386 ForeachNode (&node->makefiles, makefile)
388 debug(printf("MMAKE:dirnode.c->scanmakefiles: %d '%s'\n", makefile->generated, makefile->node.name));
390 if (makefile->generated == 0)
392 if (chdir(mm_srcdir) < 0)
394 error("Could not change to dir '%s'", mm_srcdir);
395 exit (20);
398 else
400 if (chdir(mm_builddir) < 0)
402 error("Could not change to dir '%s'", mm_builddir);
403 exit (20);
407 if ((strlen(makefile->dir->node.name) != 0) && (strcmp(makefile->dir->node.name, mm_srcdir) != 0))
409 if (chdir(buildpath(makefile->dir)) < 0)
411 error("Could not change to dir '%s'", makefile->dir->node.name);
412 exit (20);
416 if (stat(makefile->node.name, &st) != 0)
418 error("Could not stat %s", makefile->node.name);
419 exit(20);
422 if (st.st_mtime > makefile->time)
424 int flags = 0;
425 int lineno = 0;
426 MakefileTarget * mftarget = NULL;
428 if (debug)
429 printf("scanmakefiles(): scanning makefile in %s/%s\n",
430 strlen(node->node.name)==0 ? "topdir" : buildpath(node),
431 makefile->node.name
434 #if 0
435 printf ("Opening %s\n", makefile->name);
436 #endif
438 fh = fopen (makefile->node.name, "r");
439 if (!fh)
441 error ("buildtargetlist:fopen(): Opening %s for reading",
442 makefile->node.name
446 /* Free old metatargets when the file is reread */
447 freemakefiletargetlist (&makefile->targets);
448 NewList (&makefile->targets);
450 while (fgets (line, linelen, fh))
452 lineno ++;
454 while (line[strlen(line)-1] != '\n' && !feof(fh))
456 char * ptr;
458 linelen += 512;
459 ptr = xmalloc (linelen);
460 strcpy (ptr, line);
461 xfree (line);
462 line = ptr;
463 fgets (line+strlen(line), linelen-strlen(line), fh);
466 if (line[strlen(line)-1] == '\n')
468 line[strlen(line)-1] = 0;
471 if (strncmp (line, "#MM", 3) == 0)
473 char * ptr;
474 int count, t;
476 #if 0
477 printf ("found #MM in %s\n", makefile->name);
478 #endif
480 /* Read in next lines if there is continuation */
481 while (line[strlen(line)-1] == '\\')
483 ptr = line + strlen(line) - 1;
485 if (!fgets (ptr, linelen-strlen(line)+1, fh))
487 error("%s/%s:unexpected end of makefile",
488 getcwd(NULL, 0),
489 makefile->node.name
491 exit(20);
494 lineno ++;
496 while (line[strlen(line)-1] != '\n' && !feof(fh))
498 int pos = ptr - line;
499 linelen += 512;
500 ptr = xmalloc (linelen);
501 strcpy (ptr, line);
502 xfree (line);
503 line = ptr;
504 fgets (line+strlen(line), linelen-strlen(line), fh);
505 ptr = line + pos;
508 if (line[strlen(line)-1] == '\n')
510 line[strlen(line)-1] = 0;
513 if (strncmp (ptr, "##MM", 3) == 0)
515 *ptr = line[strlen(line)-1];
516 ptr[1] = 0;
517 continue;
520 if (strncmp (ptr, "#MM", 3) != 0)
522 errno = 0;
523 error("%s/%s:%d:continuation line has to start with #MM",
524 getcwd (NULL, 0),
525 makefile->node.name,
526 lineno
528 exit(20);
531 memmove (ptr, ptr+4, strlen(ptr)-4+1);
534 ptr = line+3;
536 if (*ptr == '-')
538 flags |= FLAG_VIRTUAL;
539 ptr ++;
541 else
542 flags &= ~FLAG_VIRTUAL;
544 while (isspace (*ptr))
545 ptr ++;
547 if (!*ptr)
549 /* Line with only #MM, metatarget is on next line */
550 char ** targets;
551 fgets (line, linelen, fh);
552 lineno ++;
554 ptr = line;
555 while (*ptr != ':' && *ptr)
556 ptr ++;
558 *ptr = 0;
560 targets = getargs (line, &count, NULL);
562 if (count != 0)
564 mftarget = FindNode (&makefile->targets, targets[0]);
566 if (mftarget == NULL)
568 mftarget = newmakefiletarget (targets[0], 0);
569 AddTail (&makefile->targets, mftarget);
571 else
572 mftarget->virtualtarget = 0;
574 else
575 printf ("Warning: Can't find metatarget in %s:%d (%s)\n", makefile->node.name, lineno, buildpath(node));
577 else
579 List newtargets;
580 char * ptr2 = ptr, ** tptr;
581 MakefileTarget * mftarget2, * mftarget3;
583 NewList (&newtargets);
585 while (*ptr2 != ':' && *ptr2)
586 ptr2 ++;
587 if (*ptr2)
588 *ptr2 ++ = 0;
590 tptr = getargs (ptr, &count, NULL);
592 for (t = 0; t < count; t++)
594 mftarget = newmakefiletarget (tptr[t], (flags & FLAG_VIRTUAL) != 0);
595 AddTail (&newtargets, mftarget);
598 tptr = getargs (ptr2, &count, NULL);
599 for (t = 0; t < count; t++)
601 ForeachNode (&newtargets, mftarget)
602 addnodeonce (&mftarget->deps, tptr[t]);
605 ForeachNodeSafe (&newtargets, mftarget, mftarget2)
607 mftarget3 = FindNode (&makefile->targets, mftarget->node.name);
609 /* mftarget doesn't exists yet add it to targets */
610 if (mftarget3 == NULL)
612 Remove (mftarget);
613 AddTail (&makefile->targets, mftarget);
615 else
617 /* Merge data in mftarget into mftarget3 */
618 Node * node;
620 mftarget3->virtualtarget = mftarget3->virtualtarget && mftarget->virtualtarget;
622 ForeachNode (&mftarget->deps, node)
623 addnodeonce (&mftarget3->deps, node->name);
625 /* Free the targets from which the data was merged in other targets */
626 freemakefiletargetlist (&newtargets);
629 } /* If this is a MetaMake line in the makefile */
630 } /* For all lines in a makefile */
632 reread ++;
633 makefile->time = st.st_mtime;
634 #if 0
635 printf ("Read %d lines\n", lineno);
636 #endif
638 fclose (fh);
639 } /* If the makefile needed to be scanned */
640 } /* For all makefiles in the project */
642 return reread;
646 Makefile *
647 addmakefile (DirNode * node, const char * filename)
649 static char curdir[PATH_MAX];
650 const char * ptr = filename;
651 char * name;
652 int len = 0;
653 DirNode * subnode;
654 Makefile * makefile = NULL;
656 getcwd(curdir, PATH_MAX);
658 while (ptr != NULL)
660 len = 0;
661 while (ptr[len] != '/' && ptr[len] != 0)
662 len++;
664 name = xmalloc (len+4+1); /* Make room for possibly adding .src at the end */
665 strncpy (name, ptr, len);
666 name[len] = 0;
668 if (ptr[len] == '/')
670 subnode = FindNode (&node->subdirs, name);
671 if (subnode == NULL)
673 xfree(name);
674 chdir (curdir);
675 return NULL;
677 chdir (name);
678 node = subnode;
679 ptr = ptr + len + 1;
681 else
683 if (len >= 4 && strcmp (name+len-4, ".src") == 0)
684 name[len-4] = 0;
686 makefile = FindNode (&node->makefiles, name);
688 if (makefile == NULL)
690 struct stat st;
692 printf ("Trying to stat %s\n", name);
694 if (stat(name, &st) != 0)
696 len = strlen(name);
697 strcat (name, ".src");
698 if (stat (name, &st) != 0)
700 xfree (name);
701 chdir (curdir);
702 return NULL;
704 name[len]=0;
707 makefile = newnodesize (name, sizeof (Makefile));
708 makefile->dir = node;
709 makefile->time = (time_t)0;
710 NewList (&makefile->targets);
711 AddTail (&node->makefiles, makefile);
714 ptr = NULL;
717 xfree (name);
720 chdir (curdir);
722 return makefile;
726 Makefile *
727 findmakefile (DirNode * node, const char *filename)
729 const char * ptr = filename;
730 char * name;
731 int len;
732 DirNode * subnode;
733 Makefile * makefile = NULL;
735 while (ptr != NULL)
737 len = 0;
738 while (ptr[len] != '/' && ptr[len] != 0)
739 len++;
741 name = xstrndup (ptr, len);
742 name[len] = 0;
744 if (ptr[len] == '/')
746 subnode = FindNode (&node->subdirs, name);
748 if (subnode == NULL)
750 xfree(name);
751 return NULL;
753 node = subnode;
754 ptr = ptr + len + 1;
756 else
758 if (len >= 4 && strcmp (name+len-4, ".src") == 0)
759 name[len-4] = 0;
761 makefile = FindNode (&node->makefiles, name);
762 ptr = NULL;
765 xfree (name);
768 return makefile;
771 typedef struct {
772 Node node;
773 DirNode * dirnode;
775 DirNodeRef;
778 const char *
779 buildpath (DirNode * node)
781 static char path[PATH_MAX];
782 List tree;
783 DirNodeRef * ref = NULL;
785 NewList (&tree);
789 if ((strlen (node->node.name) > 0) && (strcmp(node->node.name, mm_srcdir) != 0))
791 ref = newnodesize ("", sizeof (DirNodeRef));
792 ref->dirnode = node;
793 AddHead (&tree, ref);
795 node = node->parent;
796 } while (node != NULL);
798 strcpy (path, "");
799 ForeachNode (&tree, ref)
801 if (path[0] != 0)
802 strcat (path, "/");
803 strcat (path, ref->dirnode->node.name);
806 freelist (&tree);
808 return path;
811 Makefile *
812 readmakefile (FILE * fh)
814 Makefile * makefile;
815 MakefileTarget * mftarget;
816 Node * n;
817 uint32_t intt;
818 char * s;
820 if (!readstring(fh, &s))
822 error ("readmakefile:readstring():%d", __LINE__);
823 exit (20);
826 if (s == NULL)
827 return NULL;
829 makefile = newnodesize(s, sizeof(Makefile));
830 xfree(s);
831 NewList(&makefile->targets);
833 if (!readuint32 (fh, &intt))
835 error ("readmakefile:fread():%d", __LINE__);
836 exit (20);
838 makefile->time = intt;
840 for (;;)
842 int32_t in;
844 if (!readstring(fh, &s))
846 error ("readmakefile:readstring():%d", __LINE__);
847 exit (20);
850 if (s == NULL)
851 break;
853 mftarget = newnodesize(s, sizeof(MakefileTarget));
854 xfree(s);
855 AddTail (&makefile->targets, mftarget);
856 NewList (&mftarget->deps);
858 if (!readint32 (fh, &in))
860 error ("readmakefile:fread():%d", __LINE__);
861 exit (20);
863 mftarget->virtualtarget = in;
865 for (;;)
867 if (!readstring(fh, &s))
869 error ("readmakefile:readstring():%d", __LINE__);
870 exit (20);
873 if (s == NULL)
874 break;
876 n = newnode(s);
877 xfree(s);
878 AddTail (&mftarget->deps, n);
882 return makefile;
887 writemakefile (FILE * fh, Makefile * makefile)
889 MakefileTarget * mftarget;
890 Node * n;
892 if (makefile == NULL)
894 if (!writestring (fh, NULL))
896 error ("writemakefile/writestring():%d", __LINE__);
897 return 0;
900 return 1;
903 if (!writestring (fh, makefile->node.name))
905 error ("writemakefile/writestring():%d", __LINE__);
906 return 0;
909 if (!writeuint32 (fh, makefile->time))
911 error ("writemakefile/fwrite():%d", __LINE__);
912 return 0;
915 ForeachNode (&makefile->targets, mftarget)
917 if (!writestring (fh, mftarget->node.name))
919 error ("writemakefile/writestring():%d", __LINE__);
920 return 0;
923 if (!writeint32 (fh, mftarget->virtualtarget))
925 error ("writemakefile/fwrite():%d", __LINE__);
926 return 0;
929 ForeachNode (&mftarget->deps, n)
931 if (!writestring (fh, n->name))
933 error ("writemakefile/writestring():%d", __LINE__);
934 return 0;
938 if (!writestring (fh, NULL))
940 error ("writemakefile/writestring():%d", __LINE__);
941 return 0;
945 if (!writestring(fh, NULL))
947 error ("writemakefile/writestring():%d", __LINE__);
948 return 0;
951 return 1;
955 DirNode *
956 readcachedir (FILE * fh)
958 DirNode * node, * subnode;
959 Makefile * makefile;
960 uint32_t intt;
961 char * s;
963 if (!readstring(fh, &s))
965 error ("readcachedir:readstring():%d", __LINE__);
966 return NULL;
969 if (s == NULL)
970 return NULL;
972 node = newnodesize(s, sizeof(DirNode));
973 xfree (s);
974 NewList(&node->makefiles);
975 NewList(&node->subdirs);
977 if (!readuint32 (fh, &intt))
979 error ("readcachedir:fread():%d", __LINE__);
980 free (node);
981 return NULL;
983 node->time = intt;
985 while ((makefile = readmakefile (fh)))
987 makefile->dir = node;
988 AddTail (&node->makefiles, makefile);
991 while ((subnode = readcachedir (fh)))
993 subnode->parent = node;
994 AddTail (&node->subdirs, subnode);
997 return node;
1001 writecachedir (FILE * fh, DirNode * node)
1003 int out;
1004 DirNode * subnode;
1005 Makefile * makefile;
1007 if (node == NULL)
1009 if (!writestring(fh, NULL))
1011 error ("writecachedir/writestring():%d", __LINE__);
1012 return 0;
1015 return 1;
1018 if (!writestring(fh, node->node.name))
1020 error ("writecachedir/writestring():%d", __LINE__);
1021 return 0;
1024 if (!writeuint32 (fh, node->time))
1026 error ("writecachedir/fwrite():%d", __LINE__);
1027 return 0;
1030 ForeachNode (&node->makefiles, makefile)
1031 writemakefile (fh, makefile);
1033 if (!writemakefile (fh, NULL))
1034 return 0;
1036 ForeachNode (&node->subdirs, subnode)
1038 if (!writecachedir (fh, subnode))
1039 return 0;
1042 return writecachedir (fh, NULL);