added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / tools / MetaMake / dirnode.c
blob3b64fdc69e02202ff520fd8983906e942a1dbcf1
1 /* MetaMake - A Make extension
2 Copyright © 1995-2004, 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 #include "config.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <assert.h>
26 #include <errno.h>
27 #ifdef HAVE_STRING_H
28 # include <string.h>
29 #else
30 # include <strings.h>
31 #endif
32 #ifdef HAVE_SYS_STAT_H
33 # include <sys/stat.h>
34 #endif
35 #ifdef HAVE_SYS_TYPES_H
36 # include <sys/types.h>
37 #endif
38 #ifndef PATH_MAX
39 #include <limits.h>
40 #endif
42 #include "dirnode.h"
43 #include "mem.h"
44 #include "var.h"
45 #include "mmake.h"
46 #include "io.h"
48 #define FLAG_VIRTUAL 0x0001
50 static MakefileTarget *
51 newmakefiletarget (char *name, int virtualtarget)
53 MakefileTarget * mftarget;
55 mftarget = newnodesize (name, sizeof(MakefileTarget));
56 mftarget->virtualtarget = virtualtarget;
57 NewList (&mftarget->deps);
59 return mftarget;
62 void
63 freemakefiletarget (MakefileTarget * mftarget)
65 freelist (&mftarget->deps);
66 xfree (mftarget);
69 void
70 freemakefiletargetlist (List * targets)
72 MakefileTarget * mftarget, * mftarget2;
74 ForeachNodeSafe (targets, mftarget, mftarget2)
75 freemakefiletarget (mftarget);
77 NewList (targets);
80 void
81 printdirnode (DirNode * node, int level)
83 DirNode * subdir;
84 int t;
86 for (t=0; t<level; t++)
87 printf (" ");
89 printf ("%s\n", node->node.name);
91 level ++;
93 ForeachNode (&node->subdirs, subdir)
94 printdirnode (subdir, level);
97 void
98 printdirnodemftarget (DirNode * node)
100 Makefile * makefile;
101 MakefileTarget * mftarget;
102 Node * dep;
103 DirNode * subdir;
105 ForeachNode (&node->makefiles, makefile)
107 printf ("%s/%s:\n", buildpath(node), makefile->node.name);
108 ForeachNode (&makefile->targets, mftarget)
110 printf (" %s:", mftarget->node.name);
111 ForeachNode (&mftarget->deps, dep)
112 printf (" %s", dep->name);
113 printf ("\n");
117 ForeachNode (&node->subdirs, subdir)
118 printdirnodemftarget (subdir);
121 void
122 freedirnode (DirNode * node)
124 DirNode * subnode, * subnode2;
126 ForeachNodeSafe (&node->subdirs, subnode, subnode2)
127 freedirnode (subnode);
129 xfree (node->node.name);
130 xfree (node);
133 void
134 freemakefile (Makefile * makefile)
136 freemakefiletargetlist (&makefile->targets);
137 xfree (makefile->node.name);
138 xfree (makefile);
141 DirNode *
142 finddirnode (DirNode * topnode, const char * path)
144 const char * ptr;
145 char dirname[256];
146 int len;
147 DirNode * node = topnode, * subdir;
149 ptr = path+2;
151 if (!*ptr)
152 return node;
154 subdir = NULL;
156 while (*ptr)
158 for (len=0; ptr[len] && ptr[len] != '/'; len++);
160 strncpy (dirname, ptr, len);
161 dirname[len] = 0;
162 ptr += len;
163 while (*ptr == '/')
164 ptr ++;
166 subdir = FindNode (&node->subdirs, dirname);
168 if (!subdir)
169 break;
171 node = subdir;
174 return subdir;
179 scandirnode (DirNode * node, const char * mfname, List * ignoredirs)
181 struct stat st;
182 DIR * dirh;
183 struct dirent * dirent;
185 int mfnamelen = strlen(mfname), scanned = 0;
187 if (stat(".", &st) != 0)
189 error("scandirnode(): scanning %s\n",
190 strlen(node->node.name) == 0
191 ? "topdir"
192 : node->node.name);
194 exit(20);
197 if (st.st_mtime > node->time)
199 List newdirs, newmakefiles;
200 DirNode * subdir = NULL, * subdir2;
201 Makefile * makefile;
203 if (debug)
204 printf("scandirnode(): scanning %s\n",
205 strlen(node->node.name)==0 ? "topdir" : buildpath(node)
208 NewList (&newdirs);
209 NewList (&newmakefiles);
211 node->time = st.st_mtime;
213 dirh = opendir (".");
214 if (!dirh)
216 error("opendir: could not open current dir");
217 exit(20);
220 while ((dirent = readdir (dirh)))
222 /* Add makefile if it present or the file with .src is present */
223 if (strcmp(dirent->d_name, mfname) == 0
224 || (strlen(dirent->d_name) == mfnamelen + 4
225 && strncmp(dirent->d_name, mfname, mfnamelen) == 0
226 && strcmp(dirent->d_name + mfnamelen, ".src") == 0
230 /* Don't add makefile twice */
231 makefile = FindNode (&newmakefiles, mfname);
232 if (makefile == NULL)
234 makefile = FindNode (&node->makefiles, mfname);
235 if (makefile != NULL)
237 Remove (makefile);
239 else
241 makefile = newnodesize (mfname, sizeof (Makefile));
242 makefile->dir = node;
243 makefile->time = (time_t)0;
244 NewList (&makefile->targets);
246 AddTail (&newmakefiles, makefile);
249 else
251 /* If the file is already in the makefiles from the current dirnode
252 * and it is still present in the directory copy it to the new makefiles
253 * list
255 if (strlen (dirent->d_name) > 4
256 && strcmp (dirent->d_name + strlen(dirent->d_name) - 4, ".src") == 0
259 dirent->d_name[strlen(dirent->d_name) - 4] = 0;
260 makefile = FindNode (&node->makefiles, dirent->d_name);
261 dirent->d_name[strlen(dirent->d_name)] = '.';
263 else
264 makefile = FindNode (&node->makefiles, dirent->d_name);
266 if (makefile != NULL)
268 Remove (makefile);
269 AddTail (&newmakefiles, makefile);
273 /* Add file to newsubdirs if it is a directory and it has not to be ignored
275 if (lstat (dirent->d_name, &st) == -1)
277 error ("scandirnode: stat(%s)", dirent->d_name);
278 exit(20);
281 if (S_ISDIR (st.st_mode)
282 && strcmp (dirent->d_name, ".") != 0
283 && strcmp (dirent->d_name, "..") != 0
284 && !S_ISLNK (st.st_mode)
285 && !FindNode (ignoredirs, dirent->d_name)
288 subdir = FindNode (&node->subdirs, dirent->d_name);
290 if (subdir != NULL)
292 Remove (subdir);
294 else
296 subdir = newnodesize (dirent->d_name, sizeof(DirNode));
297 subdir->parent = node;
298 subdir->time = (time_t)0;
299 NewList (&subdir->subdirs);
300 NewList (&subdir->makefiles);
302 AddTail (&newdirs, subdir);
307 closedir (dirh);
309 ForeachNodeSafe (&node->subdirs, subdir, subdir2)
310 freedirnode (subdir);
311 AssignList (&node->subdirs, &newdirs);
313 /* Clear the makefiles that have disappeared */
314 ForeachNode (&node->makefiles, makefile)
316 MakefileTarget * mftarget;
318 ForeachNode (&makefile->targets, mftarget)
319 freelist (&mftarget->deps);
321 freelist (&makefile->targets);
324 freelist (&node->makefiles);
326 AssignList (&node->makefiles, &newmakefiles);
328 scanned = 1;
331 #if 0
332 printf ("scandirnode()\n");
333 printdirnode (node);
334 #endif
336 return scanned;
341 scanmakefiles (DirNode * node, List * vars)
343 Makefile * makefile;
344 struct stat st;
345 static char * line = NULL;
346 static int linelen = 512;
347 int reread = 0;
348 FILE * fh;
350 assert (node);
352 if (line == NULL)
353 line = xmalloc(linelen);
355 ForeachNode (&node->makefiles, makefile)
357 if (stat(makefile->node.name, &st) != 0)
359 error("Could not stat %s", makefile->node.name);
360 exit(20);
363 if (st.st_mtime > makefile->time)
365 int flags = 0;
366 int lineno = 0;
367 MakefileTarget * mftarget = NULL;
369 if (debug)
370 printf("scanmakefiles(): scanning makefile in %s/%s\n",
371 strlen(node->node.name)==0 ? "topdir" : buildpath(node),
372 makefile->node.name
375 #if 0
376 printf ("Opening %s\n", makefile->name);
377 #endif
379 fh = fopen (makefile->node.name, "r");
380 if (!fh)
382 error ("buildtargetlist:fopen(): Opening %s for reading",
383 makefile->node.name
387 /* Free old metatargets when the file is reread */
388 freemakefiletargetlist (&makefile->targets);
389 NewList (&makefile->targets);
391 while (fgets (line, linelen, fh))
393 lineno ++;
395 while (line[strlen(line)-1] != '\n' && !feof(fh))
397 char * ptr;
399 linelen += 512;
400 ptr = xmalloc (linelen);
401 strcpy (ptr, line);
402 xfree (line);
403 line = ptr;
404 fgets (line+strlen(line), linelen-strlen(line), fh);
407 if (line[strlen(line)-1] == '\n')
409 line[strlen(line)-1] = 0;
412 if (strncmp (line, "#MM", 3) == 0)
414 char * ptr;
415 int count, t;
417 #if 0
418 printf ("found #MM in %s\n", makefile->name);
419 #endif
421 /* Read in next lines if there is continuation */
422 while (line[strlen(line)-1] == '\\')
424 ptr = line + strlen(line) - 1;
426 if (!fgets (ptr, linelen-strlen(line)+1, fh))
428 error("%s/%s:unexpected end of makefile",
429 getcwd(NULL, 0),
430 makefile->node.name
432 exit(20);
435 lineno ++;
437 while (line[strlen(line)-1] != '\n' && !feof(fh))
439 int pos = ptr - line;
440 linelen += 512;
441 ptr = xmalloc (linelen);
442 strcpy (ptr, line);
443 xfree (line);
444 line = ptr;
445 fgets (line+strlen(line), linelen-strlen(line), fh);
446 ptr = line + pos;
449 if (line[strlen(line)-1] == '\n')
451 line[strlen(line)-1] = 0;
454 if (strncmp (ptr, "##MM", 3) == 0)
456 *ptr = line[strlen(line)-1];
457 ptr[1] = 0;
458 continue;
461 if (strncmp (ptr, "#MM", 3) != 0)
463 errno = 0;
464 error("%s/%s:%d:continuation line has to start with #MM",
465 getcwd (NULL, 0),
466 makefile->node.name,
467 lineno
469 exit(20);
472 memmove (ptr, ptr+4, strlen(ptr)-4+1);
475 ptr = line+3;
477 if (*ptr == '-')
479 flags |= FLAG_VIRTUAL;
480 ptr ++;
482 else
483 flags &= ~FLAG_VIRTUAL;
485 while (isspace (*ptr))
486 ptr ++;
488 if (!*ptr)
490 /* Line with only #MM, metatarget is on next line */
491 char ** targets;
492 fgets (line, linelen, fh);
493 lineno ++;
495 ptr = line;
496 while (*ptr != ':' && *ptr)
497 ptr ++;
499 *ptr = 0;
501 targets = getargs (line, &count, NULL);
503 if (count != 0)
505 mftarget = FindNode (&makefile->targets, targets[0]);
507 if (mftarget == NULL)
509 mftarget = newmakefiletarget (targets[0], 0);
510 AddTail (&makefile->targets, mftarget);
512 else
513 mftarget->virtualtarget = 0;
515 else
516 printf ("Warning: Can't find metatarget in %s:%d (%s)\n", makefile->node.name, lineno, buildpath(node));
518 else
520 List newtargets;
521 char * ptr2 = ptr, ** tptr;
522 MakefileTarget * mftarget2, * mftarget3;
524 NewList (&newtargets);
526 while (*ptr2 != ':' && *ptr2)
527 ptr2 ++;
528 if (*ptr2)
529 *ptr2 ++ = 0;
531 tptr = getargs (ptr, &count, NULL);
533 for (t = 0; t < count; t++)
535 mftarget = newmakefiletarget (tptr[t], (flags & FLAG_VIRTUAL) != 0);
536 AddTail (&newtargets, mftarget);
539 tptr = getargs (ptr2, &count, NULL);
540 for (t = 0; t < count; t++)
542 ForeachNode (&newtargets, mftarget)
543 addnodeonce (&mftarget->deps, tptr[t]);
546 ForeachNodeSafe (&newtargets, mftarget, mftarget2)
548 mftarget3 = FindNode (&makefile->targets, mftarget->node.name);
550 /* mftarget doesn't exists yet add it to targets */
551 if (mftarget3 == NULL)
553 Remove (mftarget);
554 AddTail (&makefile->targets, mftarget);
556 else
558 /* Merge data in mftarget into mftarget3 */
559 Node * node;
561 mftarget3->virtualtarget = mftarget3->virtualtarget && mftarget->virtualtarget;
563 ForeachNode (&mftarget->deps, node)
564 addnodeonce (&mftarget3->deps, node->name);
566 /* Free the targets from which the data was merged in other targets */
567 freemakefiletargetlist (&newtargets);
570 } /* If this is a MetaMake line in the makefile */
571 } /* For all lines in a makefile */
573 reread ++;
574 makefile->time = st.st_mtime;
575 #if 0
576 printf ("Read %d lines\n", lineno);
577 #endif
579 fclose (fh);
580 } /* If the makefile needed to be scanned */
581 } /* For all makefiles in the project */
583 return reread;
587 Makefile *
588 addmakefile (DirNode * node, const char * filename)
590 static char curdir[PATH_MAX];
591 const char * ptr = filename;
592 char * name;
593 int len = 0;
594 DirNode * subnode;
595 Makefile * makefile = NULL;
597 getcwd(curdir, PATH_MAX);
599 while (ptr != NULL)
601 len = 0;
602 while (ptr[len] != '/' && ptr[len] != 0)
603 len++;
605 name = xmalloc (len+4+1); /* Make room for possibly adding .src at the end */
606 strncpy (name, ptr, len);
607 name[len] = 0;
609 if (ptr[len] == '/')
611 subnode = FindNode (&node->subdirs, name);
612 if (subnode == NULL)
614 xfree(name);
615 chdir (curdir);
616 return NULL;
618 chdir (name);
619 node = subnode;
620 ptr = ptr + len + 1;
622 else
624 if (len >= 4 && strcmp (name+len-4, ".src") == 0)
625 name[len-4] = 0;
627 makefile = FindNode (&node->makefiles, name);
629 if (makefile == NULL)
631 struct stat st;
633 printf ("Trying to stat %s\n", name);
635 if (stat(name, &st) != 0)
637 len = strlen(name);
638 strcat (name, ".src");
639 if (stat (name, &st) != 0)
641 xfree (name);
642 chdir (curdir);
643 return NULL;
645 name[len]=0;
648 makefile = newnodesize (name, sizeof (Makefile));
649 makefile->dir = node;
650 makefile->time = (time_t)0;
651 NewList (&makefile->targets);
652 AddTail (&node->makefiles, makefile);
655 ptr = NULL;
658 xfree (name);
661 chdir (curdir);
663 return makefile;
667 Makefile *
668 findmakefile (DirNode * node, const char *filename)
670 const char * ptr = filename;
671 char * name;
672 int len;
673 DirNode * subnode;
674 Makefile * makefile = NULL;
676 while (ptr != NULL)
678 len = 0;
679 while (ptr[len] != '/' && ptr[len] != 0)
680 len++;
682 name = xstrndup (ptr, len);
683 name[len] = 0;
685 if (ptr[len] == '/')
687 subnode = FindNode (&node->subdirs, name);
689 if (subnode == NULL)
691 xfree(name);
692 return NULL;
694 node = subnode;
695 ptr = ptr + len + 1;
697 else
699 if (len >= 4 && strcmp (name+len-4, ".src") == 0)
700 name[len-4] = 0;
702 makefile = FindNode (&node->makefiles, name);
703 ptr = NULL;
706 xfree (name);
709 return makefile;
712 typedef struct {
713 Node node;
714 DirNode * dirnode;
716 DirNodeRef;
719 const char *
720 buildpath (DirNode * node)
722 static char path[PATH_MAX];
723 List tree;
724 DirNodeRef * ref = NULL;
726 NewList (&tree);
730 if (strlen (node->node.name) > 0)
732 ref = newnodesize ("", sizeof (DirNodeRef));
733 ref->dirnode = node;
734 AddHead (&tree, ref);
736 node = node->parent;
737 } while (node != NULL);
739 strcpy (path, "");
740 ForeachNode (&tree, ref)
742 if (path[0] != 0)
743 strcat (path, "/");
744 strcat (path, ref->dirnode->node.name);
747 freelist (&tree);
749 return path;
752 Makefile *
753 readmakefile (FILE * fh)
755 Makefile * makefile;
756 MakefileTarget * mftarget;
757 Node * n;
758 uint32_t intt;
759 char * s;
761 if (!readstring(fh, &s))
763 error ("readmakefile:readstring():%d", __LINE__);
764 exit (20);
767 if (s == NULL)
768 return NULL;
770 makefile = newnodesize(s, sizeof(Makefile));
771 xfree(s);
772 NewList(&makefile->targets);
774 if (!readuint32 (fh, &intt))
776 error ("readmakefile:fread():%d", __LINE__);
777 exit (20);
779 makefile->time = intt;
781 for (;;)
783 int32_t in;
785 if (!readstring(fh, &s))
787 error ("readmakefile:readstring():%d", __LINE__);
788 exit (20);
791 if (s == NULL)
792 break;
794 mftarget = newnodesize(s, sizeof(MakefileTarget));
795 xfree(s);
796 AddTail (&makefile->targets, mftarget);
797 NewList (&mftarget->deps);
799 if (!readint32 (fh, &in))
801 error ("readmakefile:fread():%d", __LINE__);
802 exit (20);
804 mftarget->virtualtarget = in;
806 for (;;)
808 if (!readstring(fh, &s))
810 error ("readmakefile:readstring():%d", __LINE__);
811 exit (20);
814 if (s == NULL)
815 break;
817 n = newnode(s);
818 xfree(s);
819 AddTail (&mftarget->deps, n);
823 return makefile;
828 writemakefile (FILE * fh, Makefile * makefile)
830 MakefileTarget * mftarget;
831 Node * n;
833 if (makefile == NULL)
835 if (!writestring (fh, NULL))
837 error ("writemakefile/writestring():%d", __LINE__);
838 return 0;
841 return 1;
844 if (!writestring (fh, makefile->node.name))
846 error ("writemakefile/writestring():%d", __LINE__);
847 return 0;
850 if (!writeuint32 (fh, makefile->time))
852 error ("writemakefile/fwrite():%d", __LINE__);
853 return 0;
856 ForeachNode (&makefile->targets, mftarget)
858 if (!writestring (fh, mftarget->node.name))
860 error ("writemakefile/writestring():%d", __LINE__);
861 return 0;
864 if (!writeint32 (fh, mftarget->virtualtarget))
866 error ("writemakefile/fwrite():%d", __LINE__);
867 return 0;
870 ForeachNode (&mftarget->deps, n)
872 if (!writestring (fh, n->name))
874 error ("writemakefile/writestring():%d", __LINE__);
875 return 0;
879 if (!writestring (fh, NULL))
881 error ("writemakefile/writestring():%d", __LINE__);
882 return 0;
886 if (!writestring(fh, NULL))
888 error ("writemakefile/writestring():%d", __LINE__);
889 return 0;
892 return 1;
896 DirNode *
897 readcachedir (FILE * fh)
899 DirNode * node, * subnode;
900 Makefile * makefile;
901 uint32_t intt;
902 char * s;
904 if (!readstring(fh, &s))
906 error ("readcachedir:readstring():%d", __LINE__);
907 return NULL;
910 if (s == NULL)
911 return NULL;
913 node = newnodesize(s, sizeof(DirNode));
914 xfree (s);
915 NewList(&node->makefiles);
916 NewList(&node->subdirs);
918 if (!readuint32 (fh, &intt))
920 error ("readcachedir:fread():%d", __LINE__);
921 free (node);
922 return NULL;
924 node->time = intt;
926 while ((makefile = readmakefile (fh)))
928 makefile->dir = node;
929 AddTail (&node->makefiles, makefile);
932 while ((subnode = readcachedir (fh)))
934 subnode->parent = node;
935 AddTail (&node->subdirs, subnode);
938 return node;
942 writecachedir (FILE * fh, DirNode * node)
944 int out;
945 DirNode * subnode;
946 Makefile * makefile;
948 if (node == NULL)
950 if (!writestring(fh, NULL))
952 error ("writecachedir/writestring():%d", __LINE__);
953 return 0;
956 return 1;
959 if (!writestring(fh, node->node.name))
961 error ("writecachedir/writestring():%d", __LINE__);
962 return 0;
965 if (!writeuint32 (fh, node->time))
967 error ("writecachedir/fwrite():%d", __LINE__);
968 return 0;
971 ForeachNode (&node->makefiles, makefile)
972 writemakefile (fh, makefile);
974 if (!writemakefile (fh, NULL))
975 return 0;
977 ForeachNode (&node->subdirs, subnode)
979 if (!writecachedir (fh, subnode))
980 return 0;
983 return writecachedir (fh, NULL);