/*
* Routines to gen makefile dependencies for C source
*/
#include <sys/types.h>
#include <stdio.h>
#include <limits.h>
#include <string.h>
#include "ansi.h"
#include "files.h"
#include "hash.h"
#include "buffer.h"
#include "cpp.h"
#include "cpp_hide.h"
#include "allocate.h"
#include "host.h"
#undef NULL
#define NULL 0
#ifndef PATH_MAX
#define PATH_MAX 1024
#endif
#define MAX_SUPPRESS 16
#define MAX_DEPENDS 64
#define MAX_PARENTS 512
#define NOT_A_FILE -1
extern int Num_Errors;
int translate_comments; /* Need for resolving link symbol */
static short depend_graph[MAX_PARENTS][MAX_DEPENDS];
static short parents[MAX_PARENTS];
static int cur_parent;
static char *suppress_list[MAX_SUPPRESS];
static int suppress_index;
static void
init()
{
int i,j;
for (i = 0; i < MAX_PARENTS; i++)
for (j = 0; j < MAX_DEPENDS; j++)
depend_graph[i][j] = NOT_A_FILE;
}
static void
add_suppress(path)
char *path;
{
if (suppress_index >= MAX_SUPPRESS) {
fatal(path,0,"Too many paths to suppress");
}
suppress_list[suppress_index++] = path;
}
static int
suppress(path)
char *path;
{
int i, len;
for (i = 0; i < suppress_index; i++) {
if (path[0] == suppress_list[i][0]) {
len = strlen(suppress_list[i]);
if (len <= strlen(path)) {
if (!strncmp(path,suppress_list[i],len)) {
return 1;
}
}
}
}
return 0;
}
static char*
file_extension(path)
char *path;
{
char *last_dot = NULL;
for (; *path; path++) {
switch (*path) {
case '.':
last_dot = path;
break;
case '/':
last_dot = NULL;
break;
}
}
return last_dot;
}
static void
strcpy_until(s1, s2, stop)
char *s1, *s2, *stop;
{
while (*s2 && s2 != stop) {
*s1++ = *s2++;
}
*s1 = 0;
}
static void
strcpy_root(p, path)
char *p, *path;
{
char *last;
for (last = p; *path; p++, path++) {
*p = *path;
if (*path == '/') {
last = path + 1;
}
}
*last = 0;
}
static char*
output_file(fname)
char *fname;
{
static char output_name[PATH_MAX + 16];
char *ext;
char *p1, *p2;
ext = file_extension(fname);
if (ext == NULL) {
strcpy(output_name, fname);
}
else {
strcpy_until(output_name, fname, ext);
}
strcat(output_name, ".o");
return output_name;
}
static void
get_depends(file, f)
int file;
FILE *f;
{
char *fname;
char *lhs;
char *depend;
int i;
fname = file_name_from_ord(file);
lhs = output_file(fname);
fprintf(f, "%s: %s\n", lhs, fname);
for (i = 0; i < MAX_DEPENDS; i++) {
if (depend_graph[file][i] == NOT_A_FILE) {
return;
}
depend = file_name_from_ord(depend_graph[file][i]);
if (!suppress(depend)) {
fprintf(f, "%s: %s\n", lhs, depend);
}
}
}
static void
dump_depends(f)
FILE *f;
{
int i;
for (i = 0; i < MAX_PARENTS; i++) {
if (parents[i]) {
get_depends(i,f);
}
}
}
static int
patch_copy(mf, tf, tfname)
FILE *mf, *tf;
char *tfname;
{
char buf[2048];
int len;
while (fgets(buf, sizeof(buf), mf)) {
len = strlen(buf);
if (fwrite(buf, 1, len, tf) != len) {
syserr(tfname, 0);
return 1;
}
if (len >= 3 && strncmp(buf, "###", 3) == 0) {
break;
}
}
return 0;
}
static void
patch_mf(makefile)
char *makefile;
{
FILE *mf, *tf;
int tfd;
char tfname[16];
if ((mf = fopen(makefile, "r")) == NULL) {
syserr(makefile,0);
return;
}
strcpy(tfname, "mf_XXXXXX");
if ((tfd = mkstemp(tfname)) == -1) {
fclose(mf);
syserr(tfname,0);
return;
}
tf = fdopen(tfd, "w");
if (tf == NULL) {
fclose(mf);
syserr(tfname,0);
return;
}
if (patch_copy(mf, tf, tfname)) {
fclose(mf);
fclose(tf);
unlink(tfname);
return;
}
dump_depends(tf);
fclose(mf);
fclose(tf);
unlink("makefile.bak");
if (rename(makefile, "makefile.bak") == -1) {
error(0,0,"Can't rename %s as makefile.bak", makefile);
return;
}
if (rename(tfname, makefile) == -1) {
error(0,0,"Can't rename %s as %s", tfname, makefile);
rename("makefile.bak", makefile);
}
}
static void
set_parent(pos)
file_pos_t pos;
{
cur_parent = FILE_ORD(pos);
parents[cur_parent] = 1;
}
static void
set_depend(pos)
file_pos_t pos;
{
int i;
int file = FILE_ORD(pos);
if (file == cur_parent) {
return;
}
for (i = 0; i < MAX_DEPENDS; i++) {
if (depend_graph[cur_parent][i] == file) {
return;
}
else if (depend_graph[cur_parent][i] == NOT_A_FILE) {
depend_graph[cur_parent][i] = file;
return;
}
}
assert(0);
}
static int
usage(prog)
char *prog;
{
fputs("Illegal invocation\n\n", stderr);
fprintf(stderr, "Usage: %s [flags] input files\n", prog);
fputs("\n\tflags:\n\n", stderr);
fputs("\t\t-Dname\n", stderr);
fputs("\t\t-Dname=value\n", stderr);
fputs("\t\t\tDefine a macro with an optional value. By default\n", stderr);
fputs("\t\t\tmacros will be defined with the value 1.\n\n", stderr);
fputs("\t\t-Uname\n", stderr);
fputs("\t\t\tUndefine a builtin macro.\n\n", stderr);
fputs("\t\t-Idir\n", stderr);
fputs("\t\t\tAdd a search path for finding include files.\n\n", stderr);
fputs("\t\t-builtin\n", stderr);
fputs("\t\t\tDisplay all predefined macros.\n", stderr);
fputs("\t\t-Spath\n", stderr);
fputs("\t\t\tSuppress dependencies for path.\n", stderr);
return 1;
}
static void
do_define(name)
char *name;
{
char buf[128];
char *val, *p, *s;
if (name[0] == 0) return;
val = strchr(name, '=');
if (val == NULL) {
macro_def(name, "1", 1, -1, 0);
return;
}
val++;
for (p = buf, s = name; s != val; s++, p++) {
*p = *s;
}
*p = 0;
macro_def(new_string(buf), val, strlen(val), -1, 0);
}
static int
scan_to_end(c)
int c;
{
for (;;) {
if (c == 0 || c == '\n') break;
c = cpp_getc();
}
return c;
}
int
skip_white(c)
int c;
{
while (is_white(c)) {
c = cpp_getc();
}
return c;
}
static int
scan_directive(c)
int c;
{
char fname[256];
int i;
c = skip_white(c);
if (! is_digit(c)) {
return scan_to_end(c);
}
do {
c = cpp_getc();
} while (is_digit(c));
c = skip_white(c);
if (c != '"') {
return scan_to_end(c);
}
for (i = 0; ; i++) {
c = cpp_getc();
if (c == '"' || c == 0 || c == '\n') break;
fname[i] = c;
}
fname[i] = 0;
set_depend(add_file(fname));
return scan_to_end(c);
}
int
main(argc, argv)
int argc;
char *argv[];
{
int i, c;
int fstart = 0;
int show = 0;
char *makefile = NULL;
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
if (fstart != 0) {
fputs("Place flags before files\n", stderr);
return usage(argv[0]);
}
switch (argv[i][1]) {
case 'D':
do_define(&argv[i][2]);
break;
case 'U':
macro_undef(&argv[i][2]);
break;
case 'I':
fprintf(stderr, "%s not yet implemented\n", argv[i]);
return 1;
case 'S':
add_suppress(&argv[i][2]);
break;
case 'M':
if (argv[i][2] == 0) {
return usage(argv[i]);
}
else {
makefile = &argv[i][2];
}
break;
case 'b':
if (strcmp(argv[i], "-builtin")) {
return usage(argv[i]);
}
else {
show = 1;
}
break;
default:
return usage(argv[0]);
}
}
else if (fstart == 0) {
fstart = i;
}
}
if (show) {
cpp_show_predefines();
}
if (fstart == 0) {
return usage(argv[0]);
}
init();
for (i = fstart; i < argc; i++) {
macro_init(1);
if (cpp_open(argv[i]) != 0) {
syserr(argv[i],0);
continue;
}
set_parent(add_file(argv[i]));
c = cpp_getc();
for (;;) {
switch (c) {
case 0:
goto next_file;
case '\n':
c = cpp_getc();
break;
case '#':
c = scan_directive(cpp_getc());
break;
default:
c = scan_to_end(c);
break;
}
}
next_file:
cpp_cleanup();
}
if (makefile != NULL) {
patch_mf(makefile);
}
else {
dump_depends(stdout);
}
return !!Num_Errors;
}
syntax highlighted by Code2HTML, v. 0.9.1