138889Sjdp/* depend.c - Handle dependency tracking.
2218822Sdim   Copyright 1997, 1998, 2000, 2001, 2003 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
18218822Sdim   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
19218822Sdim   02110-1301, 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
38130561Sobrienstatic int quote_string_for_make (FILE *, char *);
39130561Sobrienstatic void wrap_output (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
48130561Sobrienstart_dependencies (char *filename)
4938889Sjdp{
5038889Sjdp  dep_file = filename;
5138889Sjdp}
5238889Sjdp
5338889Sjdp/* Noticed a new filename, so try to register it.  */
5438889Sjdp
5538889Sjdpvoid
56130561Sobrienregister_dependency (char *filename)
5738889Sjdp{
5838889Sjdp  struct dependency *dep;
5938889Sjdp
6038889Sjdp  if (dep_file == NULL)
6138889Sjdp    return;
6238889Sjdp
6338889Sjdp  for (dep = dep_chain; dep != NULL; dep = dep->next)
6438889Sjdp    {
6577298Sobrien      if (!strcmp (filename, dep->file))
6638889Sjdp	return;
6738889Sjdp    }
6838889Sjdp
6938889Sjdp  dep = (struct dependency *) xmalloc (sizeof (struct dependency));
7038889Sjdp  dep->file = xstrdup (filename);
7138889Sjdp  dep->next = dep_chain;
7238889Sjdp  dep_chain = dep;
7338889Sjdp}
7438889Sjdp
7538889Sjdp/* Quote a file name the way `make' wants it, and print it to FILE.
7638889Sjdp   If FILE is NULL, do no printing, but return the length of the
7738889Sjdp   quoted string.
7838889Sjdp
7938889Sjdp   This code is taken from gcc with only minor changes.  */
8038889Sjdp
8138889Sjdpstatic int
82130561Sobrienquote_string_for_make (FILE *file, char *src)
8338889Sjdp{
8438889Sjdp  char *p = src;
8538889Sjdp  int i = 0;
8689857Sobrien
8738889Sjdp  for (;;)
8838889Sjdp    {
8938889Sjdp      char c = *p++;
9089857Sobrien
9138889Sjdp      switch (c)
9238889Sjdp	{
9338889Sjdp	case '\0':
9438889Sjdp	case ' ':
9538889Sjdp	case '\t':
9638889Sjdp	  {
9738889Sjdp	    /* GNU make uses a weird quoting scheme for white space.
9838889Sjdp	       A space or tab preceded by 2N+1 backslashes represents
9938889Sjdp	       N backslashes followed by space; a space or tab
10038889Sjdp	       preceded by 2N backslashes represents N backslashes at
10138889Sjdp	       the end of a file name; and backslashes in other
10238889Sjdp	       contexts should not be doubled.  */
10338889Sjdp	    char *q;
10489857Sobrien
10577298Sobrien	    for (q = p - 1; src < q && q[-1] == '\\'; q--)
10638889Sjdp	      {
10738889Sjdp		if (file)
10838889Sjdp		  putc ('\\', file);
10938889Sjdp		i++;
11038889Sjdp	      }
11138889Sjdp	  }
11238889Sjdp	  if (!c)
11338889Sjdp	    return i;
11438889Sjdp	  if (file)
11538889Sjdp	    putc ('\\', file);
11638889Sjdp	  i++;
11738889Sjdp	  goto ordinary_char;
11877298Sobrien
11938889Sjdp	case '$':
12038889Sjdp	  if (file)
12138889Sjdp	    putc (c, file);
12238889Sjdp	  i++;
12338889Sjdp	  /* Fall through.  This can mishandle things like "$(" but
12438889Sjdp	     there's no easy fix.  */
12538889Sjdp	default:
12638889Sjdp	ordinary_char:
12738889Sjdp	  /* This can mishandle characters in the string "\0\n%*?[\\~";
12838889Sjdp	     exactly which chars are mishandled depends on the `make' version.
12938889Sjdp	     We know of no portable solution for this;
13038889Sjdp	     even GNU make 3.76.1 doesn't solve the problem entirely.
13138889Sjdp	     (Also, '\0' is mishandled due to our calling conventions.)  */
13238889Sjdp	  if (file)
13338889Sjdp	    putc (c, file);
13438889Sjdp	  i++;
13538889Sjdp	  break;
13638889Sjdp	}
13738889Sjdp    }
13838889Sjdp}
13938889Sjdp
14038889Sjdp/* Append some output to the file, keeping track of columns and doing
14138889Sjdp   wrapping as necessary.  */
14238889Sjdp
14338889Sjdpstatic void
144130561Sobrienwrap_output (FILE *f, char *string, int spacer)
14538889Sjdp{
14638889Sjdp  int len = quote_string_for_make (NULL, string);
14738889Sjdp
14838889Sjdp  if (len == 0)
14938889Sjdp    return;
15038889Sjdp
15177298Sobrien  if (column
15277298Sobrien      && (MAX_COLUMNS
15377298Sobrien	  - 1 /* spacer */
15477298Sobrien	  - 2 /* ` \'   */
15577298Sobrien	  < column + len))
15638889Sjdp    {
15738889Sjdp      fprintf (f, " \\\n ");
15838889Sjdp      column = 0;
15938889Sjdp      if (spacer == ' ')
16038889Sjdp	spacer = '\0';
16138889Sjdp    }
16238889Sjdp
16338889Sjdp  if (spacer == ' ')
16438889Sjdp    {
16538889Sjdp      putc (spacer, f);
16638889Sjdp      ++column;
16738889Sjdp    }
16838889Sjdp
16938889Sjdp  quote_string_for_make (f, string);
17038889Sjdp  column += len;
17138889Sjdp
17238889Sjdp  if (spacer == ':')
17338889Sjdp    {
17438889Sjdp      putc (spacer, f);
17538889Sjdp      ++column;
17638889Sjdp    }
17738889Sjdp}
17838889Sjdp
17938889Sjdp/* Print dependency file.  */
18038889Sjdp
18138889Sjdpvoid
182130561Sobrienprint_dependencies (void)
18338889Sjdp{
18438889Sjdp  FILE *f;
18538889Sjdp  struct dependency *dep;
18638889Sjdp
18738889Sjdp  if (dep_file == NULL)
18838889Sjdp    return;
18938889Sjdp
19089857Sobrien  f = fopen (dep_file, FOPEN_WT);
19138889Sjdp  if (f == NULL)
19238889Sjdp    {
19389857Sobrien      as_warn (_("can't open `%s' for writing"), dep_file);
19438889Sjdp      return;
19538889Sjdp    }
19638889Sjdp
19738889Sjdp  column = 0;
19838889Sjdp  wrap_output (f, out_file_name, ':');
19938889Sjdp  for (dep = dep_chain; dep != NULL; dep = dep->next)
20038889Sjdp    wrap_output (f, dep->file, ' ');
20138889Sjdp
20238889Sjdp  putc ('\n', f);
20338889Sjdp
20438889Sjdp  if (fclose (f))
20589857Sobrien    as_warn (_("can't close `%s'"), dep_file);
20638889Sjdp}
207