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