depend.c revision 89857
138889Sjdp/* depend.c - Handle dependency tracking.
289857Sobrien   Copyright 1997, 1998, 2000, 2001 Free Software Foundation, Inc.
338889Sjdp
438889Sjdp   This file is part of GAS, the GNU Assembler.
538889Sjdp
638889Sjdp   GAS is free software; you can redistribute it and/or modify
738889Sjdp   it under the terms of the GNU General Public License as published by
838889Sjdp   the Free Software Foundation; either version 2, or (at your option)
938889Sjdp   any later version.
1038889Sjdp
1138889Sjdp   GAS is distributed in the hope that it will be useful,
1238889Sjdp   but WITHOUT ANY WARRANTY; without even the implied warranty of
1338889Sjdp   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1438889Sjdp   GNU General Public License for more details.
1538889Sjdp
1638889Sjdp   You should have received a copy of the GNU General Public License
1738889Sjdp   along with GAS; see the file COPYING.  If not, write to the Free
1838889Sjdp   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
1938889Sjdp   02111-1307, USA.  */
2038889Sjdp
2138889Sjdp#include "as.h"
2238889Sjdp
2338889Sjdp/* The file to write to, or NULL if no dependencies being kept.  */
2489857Sobrienstatic char * dep_file = NULL;
2538889Sjdp
2689857Sobrienstruct dependency
2789857Sobrien  {
2889857Sobrien    char * file;
2989857Sobrien    struct dependency * next;
3089857Sobrien  };
3138889Sjdp
3238889Sjdp/* All the files we depend on.  */
3389857Sobrienstatic struct dependency * dep_chain = NULL;
3438889Sjdp
3538889Sjdp/* Current column in output file.  */
3638889Sjdpstatic int column = 0;
3738889Sjdp
3838889Sjdpstatic int quote_string_for_make PARAMS ((FILE *, char *));
3938889Sjdpstatic void wrap_output PARAMS ((FILE *, char *, int));
4038889Sjdp
4138889Sjdp/* Number of columns allowable.  */
4238889Sjdp#define MAX_COLUMNS 72
4338889Sjdp
4438889Sjdp/* Start saving dependencies, to be written to FILENAME.  If this is
4538889Sjdp   never called, then dependency tracking is simply skipped.  */
4638889Sjdp
4738889Sjdpvoid
4838889Sjdpstart_dependencies (filename)
4938889Sjdp     char *filename;
5038889Sjdp{
5138889Sjdp  dep_file = filename;
5238889Sjdp}
5338889Sjdp
5438889Sjdp/* Noticed a new filename, so try to register it.  */
5538889Sjdp
5638889Sjdpvoid
5738889Sjdpregister_dependency (filename)
5838889Sjdp     char *filename;
5938889Sjdp{
6038889Sjdp  struct dependency *dep;
6138889Sjdp
6238889Sjdp  if (dep_file == NULL)
6338889Sjdp    return;
6438889Sjdp
6538889Sjdp  for (dep = dep_chain; dep != NULL; dep = dep->next)
6638889Sjdp    {
6777298Sobrien      if (!strcmp (filename, dep->file))
6838889Sjdp	return;
6938889Sjdp    }
7038889Sjdp
7138889Sjdp  dep = (struct dependency *) xmalloc (sizeof (struct dependency));
7238889Sjdp  dep->file = xstrdup (filename);
7338889Sjdp  dep->next = dep_chain;
7438889Sjdp  dep_chain = dep;
7538889Sjdp}
7638889Sjdp
7738889Sjdp/* Quote a file name the way `make' wants it, and print it to FILE.
7838889Sjdp   If FILE is NULL, do no printing, but return the length of the
7938889Sjdp   quoted string.
8038889Sjdp
8138889Sjdp   This code is taken from gcc with only minor changes.  */
8238889Sjdp
8338889Sjdpstatic int
8438889Sjdpquote_string_for_make (file, src)
8538889Sjdp     FILE *file;
8638889Sjdp     char *src;
8738889Sjdp{
8838889Sjdp  char *p = src;
8938889Sjdp  int i = 0;
9089857Sobrien
9138889Sjdp  for (;;)
9238889Sjdp    {
9338889Sjdp      char c = *p++;
9489857Sobrien
9538889Sjdp      switch (c)
9638889Sjdp	{
9738889Sjdp	case '\0':
9838889Sjdp	case ' ':
9938889Sjdp	case '\t':
10038889Sjdp	  {
10138889Sjdp	    /* GNU make uses a weird quoting scheme for white space.
10238889Sjdp	       A space or tab preceded by 2N+1 backslashes represents
10338889Sjdp	       N backslashes followed by space; a space or tab
10438889Sjdp	       preceded by 2N backslashes represents N backslashes at
10538889Sjdp	       the end of a file name; and backslashes in other
10638889Sjdp	       contexts should not be doubled.  */
10738889Sjdp	    char *q;
10889857Sobrien
10977298Sobrien	    for (q = p - 1; src < q && q[-1] == '\\'; q--)
11038889Sjdp	      {
11138889Sjdp		if (file)
11238889Sjdp		  putc ('\\', file);
11338889Sjdp		i++;
11438889Sjdp	      }
11538889Sjdp	  }
11638889Sjdp	  if (!c)
11738889Sjdp	    return i;
11838889Sjdp	  if (file)
11938889Sjdp	    putc ('\\', file);
12038889Sjdp	  i++;
12138889Sjdp	  goto ordinary_char;
12277298Sobrien
12338889Sjdp	case '$':
12438889Sjdp	  if (file)
12538889Sjdp	    putc (c, file);
12638889Sjdp	  i++;
12738889Sjdp	  /* Fall through.  This can mishandle things like "$(" but
12838889Sjdp	     there's no easy fix.  */
12938889Sjdp	default:
13038889Sjdp	ordinary_char:
13138889Sjdp	  /* This can mishandle characters in the string "\0\n%*?[\\~";
13238889Sjdp	     exactly which chars are mishandled depends on the `make' version.
13338889Sjdp	     We know of no portable solution for this;
13438889Sjdp	     even GNU make 3.76.1 doesn't solve the problem entirely.
13538889Sjdp	     (Also, '\0' is mishandled due to our calling conventions.)  */
13638889Sjdp	  if (file)
13738889Sjdp	    putc (c, file);
13838889Sjdp	  i++;
13938889Sjdp	  break;
14038889Sjdp	}
14138889Sjdp    }
14238889Sjdp}
14338889Sjdp
14438889Sjdp/* Append some output to the file, keeping track of columns and doing
14538889Sjdp   wrapping as necessary.  */
14638889Sjdp
14738889Sjdpstatic void
14838889Sjdpwrap_output (f, string, spacer)
14938889Sjdp     FILE *f;
15038889Sjdp     char *string;
15138889Sjdp     int spacer;
15238889Sjdp{
15338889Sjdp  int len = quote_string_for_make (NULL, string);
15438889Sjdp
15538889Sjdp  if (len == 0)
15638889Sjdp    return;
15738889Sjdp
15877298Sobrien  if (column
15977298Sobrien      && (MAX_COLUMNS
16077298Sobrien	  - 1 /* spacer */
16177298Sobrien	  - 2 /* ` \'   */
16277298Sobrien	  < column + len))
16338889Sjdp    {
16438889Sjdp      fprintf (f, " \\\n ");
16538889Sjdp      column = 0;
16638889Sjdp      if (spacer == ' ')
16738889Sjdp	spacer = '\0';
16838889Sjdp    }
16938889Sjdp
17038889Sjdp  if (spacer == ' ')
17138889Sjdp    {
17238889Sjdp      putc (spacer, f);
17338889Sjdp      ++column;
17438889Sjdp    }
17538889Sjdp
17638889Sjdp  quote_string_for_make (f, string);
17738889Sjdp  column += len;
17838889Sjdp
17938889Sjdp  if (spacer == ':')
18038889Sjdp    {
18138889Sjdp      putc (spacer, f);
18238889Sjdp      ++column;
18338889Sjdp    }
18438889Sjdp}
18538889Sjdp
18638889Sjdp/* Print dependency file.  */
18738889Sjdp
18838889Sjdpvoid
18938889Sjdpprint_dependencies ()
19038889Sjdp{
19138889Sjdp  FILE *f;
19238889Sjdp  struct dependency *dep;
19338889Sjdp
19438889Sjdp  if (dep_file == NULL)
19538889Sjdp    return;
19638889Sjdp
19789857Sobrien  f = fopen (dep_file, FOPEN_WT);
19838889Sjdp  if (f == NULL)
19938889Sjdp    {
20089857Sobrien      as_warn (_("can't open `%s' for writing"), dep_file);
20138889Sjdp      return;
20238889Sjdp    }
20338889Sjdp
20438889Sjdp  column = 0;
20538889Sjdp  wrap_output (f, out_file_name, ':');
20638889Sjdp  for (dep = dep_chain; dep != NULL; dep = dep->next)
20738889Sjdp    wrap_output (f, dep->file, ' ');
20838889Sjdp
20938889Sjdp  putc ('\n', f);
21038889Sjdp
21138889Sjdp  if (fclose (f))
21289857Sobrien    as_warn (_("can't close `%s'"), dep_file);
21338889Sjdp}
214