depend.c revision 89857
1/* depend.c - Handle dependency tracking.
2   Copyright 1997, 1998, 2000, 2001 Free Software Foundation, Inc.
3
4   This file is part of GAS, the GNU Assembler.
5
6   GAS 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.
10
11   GAS 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.
15
16   You should have received a copy of the GNU General Public License
17   along with GAS; see the file COPYING.  If not, write to the Free
18   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.  */
20
21#include "as.h"
22
23/* The file to write to, or NULL if no dependencies being kept.  */
24static char * dep_file = NULL;
25
26struct dependency
27  {
28    char * file;
29    struct dependency * next;
30  };
31
32/* All the files we depend on.  */
33static struct dependency * dep_chain = NULL;
34
35/* Current column in output file.  */
36static int column = 0;
37
38static int quote_string_for_make PARAMS ((FILE *, char *));
39static void wrap_output PARAMS ((FILE *, char *, int));
40
41/* Number of columns allowable.  */
42#define MAX_COLUMNS 72
43
44/* Start saving dependencies, to be written to FILENAME.  If this is
45   never called, then dependency tracking is simply skipped.  */
46
47void
48start_dependencies (filename)
49     char *filename;
50{
51  dep_file = filename;
52}
53
54/* Noticed a new filename, so try to register it.  */
55
56void
57register_dependency (filename)
58     char *filename;
59{
60  struct dependency *dep;
61
62  if (dep_file == NULL)
63    return;
64
65  for (dep = dep_chain; dep != NULL; dep = dep->next)
66    {
67      if (!strcmp (filename, dep->file))
68	return;
69    }
70
71  dep = (struct dependency *) xmalloc (sizeof (struct dependency));
72  dep->file = xstrdup (filename);
73  dep->next = dep_chain;
74  dep_chain = dep;
75}
76
77/* Quote a file name the way `make' wants it, and print it to FILE.
78   If FILE is NULL, do no printing, but return the length of the
79   quoted string.
80
81   This code is taken from gcc with only minor changes.  */
82
83static int
84quote_string_for_make (file, src)
85     FILE *file;
86     char *src;
87{
88  char *p = src;
89  int i = 0;
90
91  for (;;)
92    {
93      char c = *p++;
94
95      switch (c)
96	{
97	case '\0':
98	case ' ':
99	case '\t':
100	  {
101	    /* GNU make uses a weird quoting scheme for white space.
102	       A space or tab preceded by 2N+1 backslashes represents
103	       N backslashes followed by space; a space or tab
104	       preceded by 2N backslashes represents N backslashes at
105	       the end of a file name; and backslashes in other
106	       contexts should not be doubled.  */
107	    char *q;
108
109	    for (q = p - 1; src < q && q[-1] == '\\'; q--)
110	      {
111		if (file)
112		  putc ('\\', file);
113		i++;
114	      }
115	  }
116	  if (!c)
117	    return i;
118	  if (file)
119	    putc ('\\', file);
120	  i++;
121	  goto ordinary_char;
122
123	case '$':
124	  if (file)
125	    putc (c, file);
126	  i++;
127	  /* Fall through.  This can mishandle things like "$(" but
128	     there's no easy fix.  */
129	default:
130	ordinary_char:
131	  /* This can mishandle characters in the string "\0\n%*?[\\~";
132	     exactly which chars are mishandled depends on the `make' version.
133	     We know of no portable solution for this;
134	     even GNU make 3.76.1 doesn't solve the problem entirely.
135	     (Also, '\0' is mishandled due to our calling conventions.)  */
136	  if (file)
137	    putc (c, file);
138	  i++;
139	  break;
140	}
141    }
142}
143
144/* Append some output to the file, keeping track of columns and doing
145   wrapping as necessary.  */
146
147static void
148wrap_output (f, string, spacer)
149     FILE *f;
150     char *string;
151     int spacer;
152{
153  int len = quote_string_for_make (NULL, string);
154
155  if (len == 0)
156    return;
157
158  if (column
159      && (MAX_COLUMNS
160	  - 1 /* spacer */
161	  - 2 /* ` \'   */
162	  < column + len))
163    {
164      fprintf (f, " \\\n ");
165      column = 0;
166      if (spacer == ' ')
167	spacer = '\0';
168    }
169
170  if (spacer == ' ')
171    {
172      putc (spacer, f);
173      ++column;
174    }
175
176  quote_string_for_make (f, string);
177  column += len;
178
179  if (spacer == ':')
180    {
181      putc (spacer, f);
182      ++column;
183    }
184}
185
186/* Print dependency file.  */
187
188void
189print_dependencies ()
190{
191  FILE *f;
192  struct dependency *dep;
193
194  if (dep_file == NULL)
195    return;
196
197  f = fopen (dep_file, FOPEN_WT);
198  if (f == NULL)
199    {
200      as_warn (_("can't open `%s' for writing"), dep_file);
201      return;
202    }
203
204  column = 0;
205  wrap_output (f, out_file_name, ':');
206  for (dep = dep_chain; dep != NULL; dep = dep->next)
207    wrap_output (f, dep->file, ' ');
208
209  putc ('\n', f);
210
211  if (fclose (f))
212    as_warn (_("can't close `%s'"), dep_file);
213}
214