Chameleon

Chameleon Svn Source Tree

Root/branches/cparm/i386/util/md.c

1/* ************************************************************************ *\
2 * *
3 * File: md.c *
4 * *
5 * Updates makefiles from the .n dependency files generated by the *
6 * -MD option to "cc" (and "cpp"). *
7 * *
8 * Abstract: *
9 * *
10 * Basically, "md" does two things: *
11 * 1) It processes the raw dependency files produced by the cpp -MD *
12 * option. There is one line in the file for every #include *
13 * encountered, but there are repeats and patterns like *
14 * .../dir1/../dir2 appear which should reduce to .../dir2 *
15 * Md canonicalizes and flushes repeats from the dependency *
16 * list. It also sorts the file names and "fills" them to a 78 *
17 * character line. *
18 * 2) Md also updates the makefile directly with the dependency *
19 * information, so the .d file can be thrown away (-- -d option) *
20 * This is done to save space. Md assumes that dependency *
21 * information in the makefile is sorted by .o file name and it *
22 * procedes to merge in (add/or replace [as appropriate]) the new *
23 * dependency lines that it has generated. For time effeciency, *
24 * Md assumes that any .d files it is given that were created *
25 * before the creation date of the "makefile" were processed *
26 * already. It ignores them unless the force flag (-f) is given. *
27 * *
28 * Arguments: *
29 * *
30 * -d delete the .d file after it is processed *
31 * -f force an update of the dependencies in the makefile *
32 * even though the makefile is more recent than the .n file *
33 * (This implies that md has been run already.) *
34 * -m specify the makefile to be upgraded. The defaults are *
35 * "makefile" and then "Makefile". *
36 * -u like -m above, but the file will be created if necessary *
37 * -o specify an output file for the dependencies other than a *
38 * makefile *
39 * -v set the verbose flag *
40 * -x expunge old dependency info from makefile *
41 * -D subswitch for debugging. can be followed by any of *
42 * "c", "d", "m", "o", "t", "D" meaning: *
43 * c show file contents *
44 * d show new dependency crunching *
45 * m show generation of makefile *
46 * o show files being opened *
47 * t show time comparisons *
48 * D show very low level debugging *
49 * *
50 * Author: Robert V. Baron *
51 * Copyright (c) 1986 by Robert V. Baron *
52 * *
53 * HISTORY *
54 * 29-Apr-87 Robert Baron (rvb) at Carnegie-Mellon University
55 * If specified -u file does not exist, assume it is empty and
56 * generate one. As a sanity check, it must be possible to create
57 * the output file.
58 * Also, generalized fix below to handle any case of . as a
59 * file name.
60 *
61 * 25-Mar-87 Mary Thompson (mrt) at Carnegie Mellon
62 * Fixed up pathnamecanonicalization to recognize .// and
63 * drop the second / as well. mmax cpp generates this form.
64 *
65 * 6-Jan-87 Robert Baron (rvb) at Carnegie-Mellon University
66 * Fixed up pathname canonicalization to that ../../, etc would be
67 * handled correctly.
68 * Also made "force" on by default.
69 *
70 * 16-Mar-86 Robert Baron (rvb) at Carnegie-Mellon University
71 * Created 4/16/86 *
72 * *
73 \* ************************************************************************ */
74
75/* cleaned and adapted for Chameleon by cparm */
76
77#include <sys/types.h>
78#include <sys/stat.h>
79#include <stdio.h>
80#include <stdlib.h>
81#include <string.h>
82#include <unistd.h>
83#include <fcntl.h>
84
85#define LINESIZE 65536 // NeXT_MOD
86
87#define OUTLINELEN 79
88#define IObuffer 50000
89#define SALUTATION "# Dependencies for File:"
90#define SALUTATIONLEN (sizeof SALUTATION - 1)
91#define OLDSALUTATION "# DO NOT DELETE THIS LINE"
92#define OLDSALUTATIONLEN (sizeof OLDSALUTATION - 1)
93
94static char file_array[IObuffer]; /* read file and store crunched names */
95static char dep_line[LINESIZE]; /* line being processed */
96static char dot_o[LINESIZE]; /* <foo.o>: prefix */
97static char *path_component[100]; /* stores components for a path while being
98 crunched */
99
100static struct dep { /* stores paths that a file depends on */
101 int len;
102 char *str;
103} dep_files[1000];
104static int dep_file_index;
105
106static int qsort_strcmp(struct dep *a, struct dep *b)
107{
108 extern int strcmp();
109 return strcmp(a->str, b->str);
110}
111
112static char *outfile = (char *) 0; /* generate dependency file */
113static FILE *out;
114
115static char *makefile = (char *) 0; /* user supplied makefile name */
116static char *real_mak_name; /* actual makefile name (if not supplied) */
117static char shadow_mak_name[LINESIZE]; /* changes done here then renamed */
118static FILE *mak; /* for reading makefile */
119static FILE *makout; /* for writing shadow */
120static char makbuf[LINESIZE]; /* one line buffer for makefile */
121static struct stat makstat; /* stat of makefile for time comparisons */
122static int mak_eof = 0; /* eof seen on makefile */
123
124static int delete = 0; /* -d delete dependency file */
125static int debug = 0;
126static int D_contents = 0; /* print file contents */
127static int D_depend = 0; /* print dependency processing info */
128static int D_make = 0; /* print makefile processing info */
129static int D_open = 0; /* print after succesful open */
130static int D_time = 0; /* print time comparison info */
131static int force = 1; /* always update dependency info */
132static int update = 0; /* it's ok if the -m file does not exist */
133static int verbose = 0; /* tell me something */
134static int expunge = 0; /* first flush dependency stuff from makefile */
135
136
137static char *name;
138static int read_dep(register char *file);
139static void save_dot_o(void);
140static void parse_dep(void);
141static void output_dep(FILE *out);
142static FILE *find_mak(char *file);
143static FILE *temp_mak(void);
144static void scan_mak(FILE *, FILE *, char *);
145static void expunge_mak(register FILE *makin, register FILE *makout);
146static void skip_mak(register FILE *makin, register FILE *makout);
147static void finish_mak(FILE *, FILE *);
148
149int main(int argc, register char **argv)
150{
151 int size;
152
153 name = *argv;
154 {
155 register char *cp =name;
156 while (*cp) if (*cp++ == '/') name = cp;
157 }
158
159 for ( argv++ ; --argc ; argv++ )
160 {
161
162 register char *token = *argv;
163 if (*token++ != '-' || !*token)
164 break;
165 else
166 {
167 register int flag;
168 for ( ; (flag = *token++) ; )
169 {
170 switch (flag)
171 {
172 case 'd':
173 delete++;
174 break;
175 case 'f':
176 force++;
177 break;
178 case 'u':
179 update++;
180 case 'm':
181 makefile = *++argv;
182 if (--argc < 0) goto usage;
183 break;
184 case 'o':
185 outfile = *++argv;
186 if (--argc < 0) goto usage;
187 break;
188 case 'v':
189 verbose++;
190 break;
191 case 'x':
192 expunge++;
193 break;
194 case 'D':
195 for ( ; (flag = *token++) ; )
196 switch (flag)
197 {
198 case 'c':
199 D_contents++;
200 break;
201 case 'd':
202 D_depend++;
203 break;
204 case 'm':
205 D_make++;
206 break;
207 case 'o':
208 D_open++;
209 break;
210 case 't':
211 D_time++;
212 break;
213 case 'D':
214 debug++;
215 break;
216 default:
217 goto letters;
218
219 }
220 goto newtoken;
221 default:
222 goto usage;
223 }
224 letters: ;
225 }
226 }
227 newtoken: ;
228 }
229
230 if (!expunge && argc < 1) goto usage;
231 if ((int) outfile && (int) makefile) /* not both */
232 goto usage;
233
234 if ((int) outfile)
235 {
236 /*
237 * NeXT_MOD, For SGS stuff, in case still linked to master version
238 */
239 unlink(outfile);
240
241 if ((out = fopen(outfile, "w")) == NULL)
242 {
243 fprintf(stderr, "%s: outfile = \"%s\" ", name, outfile);
244 perror("fopen");
245 fflush(stdout), fflush(stderr);
246 exit(1);
247 }
248 else if (D_open)
249 printf("%s: opened outfile \"%s\"\n", name, outfile);
250 }
251 else if ((mak = find_mak(makefile)))
252 {
253 makout = temp_mak();
254 out = makout;
255 if (expunge)
256 expunge_mak(mak, makout);
257 else
258 skip_mak(mak, makout);
259 }
260 else if (mak_eof && /* non existent file == mt file */
261 (int)(makout = temp_mak()))
262 { /* but we need to be able */
263 out = makout; /* to write here */
264 }
265 else if (makefile)
266 {
267 fprintf(stderr, "%s: makefile \"%s\" can not be opened or stat'ed\n",
268 name, makefile);
269 exit(2);
270 }
271
272 for (; argc--; argv++)
273 {
274 dep_file_index = 0;
275
276 if ((size = read_dep(*argv)))
277 {
278
279 save_dot_o();
280 if (D_depend) printf("%s: dot_o = \"%s\"\n", name, dot_o);
281
282 parse_dep();
283 if (mak) scan_mak(mak, makout, dot_o);
284 if (out) output_dep(out);
285
286 if (delete)
287 unlink(*argv);
288 }
289 }
290
291 if (mak) finish_mak(mak, makout);
292 rename(shadow_mak_name, real_mak_name);
293 exit(0);
294usage:
295 fprintf(stderr, "usage: md -f -Dcdmot -m makefile -o outputfile -v <file1> ... <filen>\n");
296 exit(1);
297 return 1;
298}
299
300
301static int read_dep(register char *file)
302{
303 register int fd;
304 register int size;
305 struct stat statbuf;
306
307 if ((fd = open(file, 0)) < 0)
308 {
309 fprintf(stderr, "%s: file = \"%s\" ", name, file);
310 perror("open");
311 fflush(stdout), fflush(stderr);
312 return 0;
313 }
314 if (D_open)
315 printf("%s: opened dependency file \"%s\"\n", name, file);
316
317 if (fstat(fd, &statbuf) < 0)
318 {
319 fprintf(stderr, "%s: file = \"%s\" ", name, file);
320 perror("stat");
321 fflush(stdout), fflush(stderr);
322 goto out;
323 }
324 switch(statbuf.st_mode & S_IFMT)
325 {
326 case S_IFREG:
327 if (D_time)
328 printf("%s: file time = %ld\n", name, statbuf.st_mtime);
329
330 if (statbuf.st_size > IObuffer)
331 {
332 fprintf(stderr, "%s: file \"%s\" tooo big for IObuffer\n",
333 name, file);
334 goto out;
335 } else if (force)
336 break;
337 else if ((int) mak && statbuf.st_mtime < makstat.st_mtime)
338 {
339 if (verbose || D_time)
340 fprintf(stderr, "%s: skipping \"%s\" %ld < %ld \"%s\"\n",
341 name, file, statbuf.st_mtime, makstat.st_mtime,
342 real_mak_name);
343 goto out;
344 } else /* >= =>ok */
345 break;
346 case S_IFDIR:
347 case S_IFLNK:
348 case S_IFCHR:
349 case S_IFBLK:
350 case S_IFSOCK:
351 default:
352 fprintf(stderr, "%s: bad mode: 0%o on \"%s\"\n",
353 name, statbuf.st_mode, file);
354 fflush(stdout), fflush(stderr);
355 goto out;
356 }
357
358 if ((size = read(fd, file_array, sizeof (file_array))) < 0)
359 {
360 fprintf(stderr, "%s: file = \"%s\" ", name, file);
361 perror("read");
362 fflush(stdout), fflush(stderr);
363 goto out;
364 }
365 file_array[size] = 0;
366
367 if (close(fd) < 0)
368 {
369 fprintf(stderr, "%s: file = \"%s\" ", name, file);
370 perror("close");
371 fflush(stdout), fflush(stderr);
372 return 0;
373 }
374
375 if (D_depend && D_contents)
376 printf("file_array: \"%s\"\n", file_array);
377 return size;
378out: ;
379 close(fd);
380 return 0;
381}
382
383static void save_dot_o(void)
384{
385 register char *cp = file_array;
386 register char *svp = dot_o;
387 register int c;
388
389 while ((*svp++ = (c = *cp++)) && c != ':');
390 *svp = 0;
391}
392
393static void parse_dep(void)
394{
395 register char *lp = file_array;
396 register int c;
397
398 while (*lp)
399 {
400 register char *tlp = lp;
401 register char *cp = dep_line;
402 register int i = 0;
403 int abspath = 0;
404 char oldc;
405 char *oldcp;
406
407 /* get a line to process */
408 while ((c = *lp++) && c != '\n')
409 {
410 if (c == '\\')
411 lp++; /* skip backslash newline */
412 else
413 *cp++ = c;
414 }
415 if (!c)
416 break;
417 *cp = 0;
418 cp = dep_line;
419 lp[-1] = 0;
420 /* skip .o file name */
421 while ((c = *cp++) && c != ':'); if (!c) continue;
422 next_filename:
423 i = 0;
424 abspath = 0;
425 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; if (!c) continue;
426
427 /* canonicalization processing */
428
429 /* initial / is remembered */
430 if (c == '/')
431 abspath++;
432
433 while (c && c != ' ' && c != '\t')
434 {
435 if (D_depend) printf("i = %d going \"%s\"\n", i, cp);
436 /* kill \'s */
437 while ((c = *cp) && c == '/') cp++; if (!c) break;
438 path_component[i] = cp;
439 /* swallow chars till next / or null */
440 while ((c = *cp++) && c != '/' && c != ' ' && c != '\t');
441 if (c) cp[-1]=0;/* end component C style */
442
443 /* ignore . */;
444 if (!strncmp(path_component[i], ".", sizeof(".")))
445 ; /* if "component" != .. */
446 else /* don't reduce /component/.. to nothing */
447 i++; /* there could be symbolic links! */
448 }
449 /* reassemble components */
450 oldc = c; /* save c */
451 oldcp = cp; /* save cp */
452 cp = tlp; /* overwrite line in buffer */
453 if (abspath)
454 *cp++ = '/';
455 for (c=0; c<i; c++) {register char *ccp = path_component[c];
456 while ((*cp++ = *ccp++));
457 *--cp = '/';
458 cp++;
459 }
460 *--cp = 0;
461
462 c=dep_file_index++;
463 dep_files[c].str = tlp;
464 dep_files[c].len = cp - tlp;
465 if (D_depend)
466 printf("%s: dep_file[%d] = \"%s\" Len %ld\n",
467 name, dep_file_index - 1, tlp, (long)(cp - tlp));
468 tlp = cp + 1;
469 if (oldc)
470 {
471 cp = oldcp;
472 goto next_filename;
473 }
474 }
475}
476
477static void output_dep(FILE *out)
478{
479 register int j;
480 register int size = 1000;
481 register int dot_o_len = strlen(dot_o);
482 register struct dep *dp = dep_files;
483 int written = 0;
484
485 if (D_depend && debug)
486 for(j = 0; j < dep_file_index; j++)
487 {
488 printf("dep_files[%d] = %s\n", j, dep_files[j].str);
489 }
490 typedef int (*qsort_strcmp_fixer)(const void *, const void *);
491
492 int (*qsort_strcmp_fix)(const void *, const void *) = (qsort_strcmp_fixer)qsort_strcmp;
493
494 qsort(dep_files, dep_file_index, sizeof (struct dep), qsort_strcmp_fix);
495
496 if (D_depend && debug)
497 for(j = 0; j < dep_file_index; j++)
498 {
499 printf("dep_files[%d] = %s\n", j, dep_files[j].str);
500 }
501
502 fprintf(out, "%s %s", SALUTATION, dot_o);
503 for(j = 0; j < dep_file_index; j++, dp++)
504 {
505 register int len = dp->len;
506 register char *str = dp->str;
507 if (j && len == (dp-1)->len && !strcmp(str, (dp-1)->str))
508 continue;
509 written++;
510 if (size + len + 1 > OUTLINELEN)
511 {
512 fprintf(out, "\n%s %s", dot_o, str);
513 size = dot_o_len + len + 1;
514 }
515 else
516 {
517 fprintf(out, " %s", str);
518 size += len + 1;
519 }
520 }
521 fprintf(out, "\n");
522 if (verbose)
523 fprintf(stdout, "%s: \"%s\" %d => %d\n", name, dot_o, dep_file_index, written);
524}
525
526/* process makefile */
527static FILE *find_mak(char *file)
528{
529 FILE *mak;
530
531 if ((int) file)
532 {
533 if ((mak = fopen(file, "r")) != NULL)
534 {
535 real_mak_name = file;
536 }
537 else if (update)
538 {
539 mak_eof = 1;
540 real_mak_name = file;
541 return NULL;
542 }
543 else
544 {
545 fprintf(stderr, "%s: file = \"%s\" ", name, file);
546 perror("fopen");
547 fflush(stdout), fflush(stderr);
548 return NULL;
549 }
550 }
551 else
552 {
553 if ((mak = fopen("makefile", "r")) != NULL)
554 {
555 real_mak_name = "makefile";
556 }
557 else if ((mak = fopen("Makefile", "r")) != NULL)
558 {
559 real_mak_name = "Makefile";
560 }
561 else return NULL;
562 }
563
564 if (fstat(fileno(mak), &makstat) < 0)
565 {
566 fprintf(stderr, "%s: file = \"%s\" ", name, real_mak_name);
567 perror("stat");
568 fflush(stdout), fflush(stderr);
569fclose(mak);
570 return NULL;
571 }
572 if (D_open)
573 printf("%s: opened makefile \"%s\"\n", name, real_mak_name);
574 if (D_time)
575 printf("%s: makefile time = %ld\n", name, makstat.st_mtime);
576
577 return mak;
578}
579
580static FILE *temp_mak(void)
581{
582 FILE *mak;
583
584 strlcpy(shadow_mak_name, real_mak_name, sizeof(shadow_mak_name));
585 strlcat(shadow_mak_name, ".md", sizeof(shadow_mak_name));
586
587 /*
588 * For SGS stuff, in case still linked to master version
589 */
590 unlink(shadow_mak_name);
591 if ((mak = fopen(shadow_mak_name, "w")) == NULL)
592 {
593 fprintf(stderr, "%s: file = \"%s\" ", name, shadow_mak_name);
594 perror("fopen");
595 fflush(stdout), fflush(stderr);
596 return NULL;
597 }
598 if (D_open)
599 printf("%s: opened makefile.md \"%s\"\n", name, shadow_mak_name);
600
601 return mak;
602}
603
604static void skip_mak(register FILE *makin, register FILE *makout)
605{
606 register int len = SALUTATIONLEN;
607
608 if (D_make)
609 printf("skipping in \"%s\" ", real_mak_name);
610
611 while (fgets(makbuf, LINESIZE, makin) != NULL)
612 {
613 if (D_make && D_contents)
614 printf("%s: \"%s\"\n", real_mak_name, makbuf);
615 if (strncmp(makbuf, SALUTATION, len))
616 {
617 fputs(makbuf, makout);
618 }
619 else
620 break;
621 }
622 mak_eof = feof(makin);
623 if (mak_eof)
624 fclose(makin);
625 if (D_make)
626 printf("eof = %d str = \"%s\"", mak_eof, makbuf);
627}
628
629static void expunge_mak(register FILE *makin, register FILE *makout)
630{
631 register int len = SALUTATIONLEN;
632 register int oldlen = OLDSALUTATIONLEN;
633
634 if (D_make)
635 printf("expunging in \"%s\" ", real_mak_name);
636
637 while (fgets(makbuf, LINESIZE, makin) != NULL)
638 {
639 if (D_make && D_contents)
640 printf("%s: \"%s\"\n", real_mak_name, makbuf);
641 if (! strncmp(makbuf, SALUTATION, len) ||
642 ! strncmp(makbuf, OLDSALUTATION, oldlen))
643 break;
644 else
645 fputs(makbuf, makout);
646 }
647 mak_eof = 1;
648 if (mak_eof)
649 fclose(makin);
650 if (D_make)
651 printf("eof = %d str = \"%s\"", mak_eof, makbuf);
652}
653
654static void
655scan_mak(FILE *makin, FILE *makout, char *file)
656{
657 register char *cp = &makbuf[SALUTATIONLEN+1];
658 register int len = strlen(file);
659 register int ret;
660
661 if (D_make)
662 printf("scanning in \"%s\" for \"%s\"\n", real_mak_name, file);
663
664 do {
665 if (mak_eof) /* don't scan any more */
666 return;
667
668 ret = strncmp(cp, file, len);
669 if (D_make)
670 printf("saw \"%s\" ret = %d\n", cp, ret);
671
672 if (ret < 0) { /* skip forward till match or greater */
673 fputs(makbuf, makout); /* line we're looking at */
674 while (fgets(makbuf, LINESIZE, makin) != NULL)
675 {
676 if (strncmp(makbuf, SALUTATION, SALUTATIONLEN))
677 {
678 fputs(makbuf, makout);
679 }
680 else
681 break;
682 }
683 mak_eof = feof(makin);
684
685 if (mak_eof)
686 fclose(makin);
687
688 continue;
689 }
690 else if (ret == 0)
691 { /* flush match */
692 while (fgets(makbuf, LINESIZE, makin) != NULL)
693 {
694 if (strncmp(makbuf, SALUTATION, SALUTATIONLEN))
695 {
696 ; /* flush old stuff */
697 }
698 else
699 break;
700 }
701 mak_eof = feof(makin);
702 if (mak_eof)
703 fclose(makin);
704 break;
705 }
706 else
707 { /* no luck this time */
708 break;
709 }
710 } while (1);
711}
712
713static void
714finish_mak(FILE *makin, FILE *makout)
715{
716 if (mak_eof) /* don't scan any more */
717 return;
718
719 if (D_make)
720 printf("finishing in \"%s\"\n", real_mak_name);
721
722 fputs(makbuf, makout); /* line we're looking at */
723 while (fgets(makbuf, LINESIZE, makin) != NULL)
724 {
725 fputs(makbuf, makout);
726 }
727}
728

Archive Download this file

Revision: 2118