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
94char file_array[IObuffer]; /* read file and store crunched names */
95char dep_line[LINESIZE]; /* line being processed */
96char dot_o[LINESIZE]; /* <foo.o>: prefix */
97char *path_component[100]; /* stores components for a path while being
98 crunched */
99
100struct dep { /* stores paths that a file depends on */
101 int len;
102 char *str;
103} dep_files[1000];
104int dep_file_index;
105
106int qsort_strcmp(struct dep *a, struct dep *b)
107{
108 extern int strcmp();
109 return strcmp(a->str, b->str);
110}
111
112char *outfile = (char *) 0; /* generate dependency file */
113FILE *out;
114
115char *makefile = (char *) 0; /* user supplied makefile name */
116char *real_mak_name; /* actual makefile name (if not supplied) */
117char shadow_mak_name[LINESIZE]; /* changes done here then renamed */
118FILE *mak; /* for reading makefile */
119FILE *makout; /* for writing shadow */
120char makbuf[LINESIZE]; /* one line buffer for makefile */
121struct stat makstat; /* stat of makefile for time comparisons */
122int mak_eof = 0; /* eof seen on makefile */
123FILE *find_mak(), *temp_mak();
124
125int delete = 0; /* -d delete dependency file */
126int debug = 0;
127int D_contents = 0; /* print file contents */
128int D_depend = 0; /* print dependency processing info */
129int D_make = 0; /* print makefile processing info */
130int D_open = 0; /* print after succesful open */
131int D_time = 0; /* print time comparison info */
132int force = 1; /* always update dependency info */
133int update = 0; /* it's ok if the -m file does not exist */
134int verbose = 0; /* tell me something */
135int expunge = 0; /* first flush dependency stuff from makefile */
136
137
138char *name;
139
140static void scan_mak(FILE *, FILE *, char *);
141static void finish_mak(FILE *, FILE *);
142static void output_dep(FILE *out);
143static void parse_dep(void);
144static void save_dot_o(void);
145static int read_dep(register char *file);
146static void skip_mak(register FILE *makin, register FILE *makout);
147static void expunge_mak(register FILE *makin, register FILE *makout);
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}
298
299
300static int read_dep(register char *file)
301{
302 register int fd;
303 register int size;
304 struct stat statbuf;
305
306 if ((fd = open(file, 0)) < 0)
307 {
308 fprintf(stderr, "%s: file = \"%s\" ", name, file);
309 perror("open");
310 fflush(stdout), fflush(stderr);
311 return 0;
312 }
313 if (D_open)
314 printf("%s: opened dependency file \"%s\"\n", name, file);
315
316 if (fstat(fd, &statbuf) < 0)
317 {
318 fprintf(stderr, "%s: file = \"%s\" ", name, file);
319 perror("stat");
320 fflush(stdout), fflush(stderr);
321 goto out;
322 }
323 switch(statbuf.st_mode & S_IFMT)
324 {
325 case S_IFREG:
326 if (D_time)
327 printf("%s: file time = %ld\n", name, statbuf.st_mtime);
328
329 if (statbuf.st_size > IObuffer)
330 {
331 fprintf(stderr, "%s: file \"%s\" tooo big for IObuffer\n",
332 name, file);
333 goto out;
334 } else if (force)
335 break;
336 else if ((int) mak && statbuf.st_mtime < makstat.st_mtime)
337 {
338 if (verbose || D_time)
339 fprintf(stderr, "%s: skipping \"%s\" %ld < %ld \"%s\"\n",
340 name, file, statbuf.st_mtime, makstat.st_mtime,
341 real_mak_name);
342 goto out;
343 } else /* >= =>ok */
344 break;
345 case S_IFDIR:
346 case S_IFLNK:
347 case S_IFCHR:
348 case S_IFBLK:
349 case S_IFSOCK:
350 default:
351 fprintf(stderr, "%s: bad mode: 0%o on \"%s\"\n",
352 name, statbuf.st_mode, file);
353 fflush(stdout), fflush(stderr);
354 goto out;
355 }
356
357 if ((size = read(fd, file_array, sizeof (file_array))) < 0)
358 {
359 fprintf(stderr, "%s: file = \"%s\" ", name, file);
360 perror("read");
361 fflush(stdout), fflush(stderr);
362 goto out;
363 }
364 file_array[size] = 0;
365
366 if (close(fd) < 0)
367 {
368 fprintf(stderr, "%s: file = \"%s\" ", name, file);
369 perror("close");
370 fflush(stdout), fflush(stderr);
371 return 0;
372 }
373
374 if (D_depend && D_contents)
375 printf("file_array: \"%s\"\n", file_array);
376 return size;
377out: ;
378 close(fd);
379 return 0;
380}
381
382static void save_dot_o(void)
383{
384 register char *cp = file_array;
385 register char *svp = dot_o;
386 register int c;
387
388 while ((*svp++ = (c = *cp++)) && c != ':');
389 *svp = 0;
390}
391
392static void parse_dep(void)
393{
394 register char *lp = file_array;
395 register int c;
396
397 while (*lp)
398 {
399 register char *tlp = lp;
400 register char *cp = dep_line;
401 register int i = 0;
402 int abspath = 0;
403 char oldc;
404 char *oldcp;
405
406 /* get a line to process */
407 while ((c = *lp++) && c != '\n')
408 {
409 if (c == '\\')
410 lp++; /* skip backslash newline */
411 else
412 *cp++ = c;
413 }
414 if (!c)
415 break;
416 *cp = 0;
417 cp = dep_line;
418 lp[-1] = 0;
419 /* skip .o file name */
420 while ((c = *cp++) && c != ':'); if (!c) continue;
421 next_filename:
422 i = 0;
423 abspath = 0;
424 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; if (!c) continue;
425
426 /* canonicalization processing */
427
428 /* initial / is remembered */
429 if (c == '/')
430 abspath++;
431
432 while (c && c != ' ' && c != '\t')
433 {
434 if (D_depend) printf("i = %d going \"%s\"\n", i, cp);
435 /* kill \'s */
436 while ((c = *cp) && c == '/') cp++; if (!c) break;
437 path_component[i] = cp;
438 /* swallow chars till next / or null */
439 while ((c = *cp++) && c != '/' && c != ' ' && c != '\t');
440 if (c) cp[-1]=0;/* end component C style */
441
442 /* ignore . */;
443 if (!strcmp(path_component[i], "."))
444 ; /* if "component" != .. */
445 else /* don't reduce /component/.. to nothing */
446 i++; /* there could be symbolic links! */
447 }
448 /* reassemble components */
449 oldc = c; /* save c */
450 oldcp = cp; /* save cp */
451 cp = tlp; /* overwrite line in buffer */
452 if (abspath)
453 *cp++ = '/';
454 for (c=0; c<i; c++) {register char *ccp = path_component[c];
455 while ((*cp++ = *ccp++));
456 *--cp = '/';
457 cp++;
458 }
459 *--cp = 0;
460
461 c=dep_file_index++;
462 dep_files[c].str = tlp;
463 dep_files[c].len = cp - tlp;
464 if (D_depend)
465 printf("%s: dep_file[%d] = \"%s\" Len %ld\n",
466 name, dep_file_index - 1, tlp, (long)(cp - tlp));
467 tlp = cp + 1;
468 if (oldc)
469 {
470 cp = oldcp;
471 goto next_filename;
472 }
473 }
474}
475
476static void output_dep(FILE *out)
477{
478 register int j;
479 register int size = 1000;
480 register int dot_o_len = strlen(dot_o);
481 register struct dep *dp = dep_files;
482 int written = 0;
483
484 if (D_depend && debug)
485 for(j = 0; j < dep_file_index; j++)
486 {
487 printf("dep_files[%d] = %s\n", j, dep_files[j].str);
488 }
489 typedef int (*qsort_strcmp_fixer)(const void *, const void *);
490
491 int (*qsort_strcmp_fix)(const void *, const void *) = (qsort_strcmp_fixer)qsort_strcmp;
492
493 qsort(dep_files, dep_file_index, sizeof (struct dep), qsort_strcmp_fix);
494
495 if (D_depend && debug)
496 for(j = 0; j < dep_file_index; j++)
497 {
498 printf("dep_files[%d] = %s\n", j, dep_files[j].str);
499 }
500
501 fprintf(out, "%s %s", SALUTATION, dot_o);
502 for(j = 0; j < dep_file_index; j++, dp++)
503 {
504 register int len = dp->len;
505 register char *str = dp->str;
506 if (j && len == (dp-1)->len && !strcmp(str, (dp-1)->str))
507 continue;
508 written++;
509 if (size + len + 1 > OUTLINELEN)
510 {
511 fprintf(out, "\n%s %s", dot_o, str);
512 size = dot_o_len + len + 1;
513 }
514 else
515 {
516 fprintf(out, " %s", str);
517 size += len + 1;
518 }
519 }
520 fprintf(out, "\n");
521 if (verbose)
522 fprintf(stdout, "%s: \"%s\" %d => %d\n", name, dot_o, dep_file_index, written);
523}
524
525/* process makefile */
526FILE *
527find_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);
569 return NULL;
570 }
571 if (D_open)
572 printf("%s: opened makefile \"%s\"\n", name, real_mak_name);
573 if (D_time)
574 printf("%s: makefile time = %ld\n", name, makstat.st_mtime);
575
576 return mak;
577}
578
579FILE *
580temp_mak()
581{
582 FILE *mak;
583
584 strcpy(shadow_mak_name, real_mak_name);
585 strcat(shadow_mak_name, ".md");
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: 2043