| /* depend.c - Handle dependency tracking. |
| Copyright (C) 1997-2016 Free Software Foundation, Inc. |
| |
| This file is part of GAS, the GNU Assembler. |
| |
| GAS is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3, or (at your option) |
| any later version. |
| |
| GAS is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GAS; see the file COPYING. If not, write to the Free |
| Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA |
| 02110-1301, USA. */ |
| |
| #include "as.h" |
| #include "filenames.h" |
| |
| /* The file to write to, or NULL if no dependencies being kept. */ |
| static char * dep_file = NULL; |
| |
| struct dependency |
| { |
| char * file; |
| struct dependency * next; |
| }; |
| |
| /* All the files we depend on. */ |
| static struct dependency * dep_chain = NULL; |
| |
| /* Current column in output file. */ |
| static int column = 0; |
| |
| static int quote_string_for_make (FILE *, const char *); |
| static void wrap_output (FILE *, const char *, int); |
| |
| /* Number of columns allowable. */ |
| #define MAX_COLUMNS 72 |
| |
| /* Start saving dependencies, to be written to FILENAME. If this is |
| never called, then dependency tracking is simply skipped. */ |
| |
| void |
| start_dependencies (char *filename) |
| { |
| dep_file = filename; |
| } |
| |
| /* Noticed a new filename, so try to register it. */ |
| |
| void |
| register_dependency (const char *filename) |
| { |
| struct dependency *dep; |
| |
| if (dep_file == NULL) |
| return; |
| |
| for (dep = dep_chain; dep != NULL; dep = dep->next) |
| { |
| if (!filename_cmp (filename, dep->file)) |
| return; |
| } |
| |
| dep = XNEW (struct dependency); |
| dep->file = xstrdup (filename); |
| dep->next = dep_chain; |
| dep_chain = dep; |
| } |
| |
| /* Quote a file name the way `make' wants it, and print it to FILE. |
| If FILE is NULL, do no printing, but return the length of the |
| quoted string. |
| |
| This code is taken from gcc with only minor changes. */ |
| |
| static int |
| quote_string_for_make (FILE *file, const char *src) |
| { |
| const char *p = src; |
| int i = 0; |
| |
| for (;;) |
| { |
| char c = *p++; |
| |
| switch (c) |
| { |
| case '\0': |
| case ' ': |
| case '\t': |
| { |
| /* GNU make uses a weird quoting scheme for white space. |
| A space or tab preceded by 2N+1 backslashes represents |
| N backslashes followed by space; a space or tab |
| preceded by 2N backslashes represents N backslashes at |
| the end of a file name; and backslashes in other |
| contexts should not be doubled. */ |
| const char *q; |
| |
| for (q = p - 1; src < q && q[-1] == '\\'; q--) |
| { |
| if (file) |
| putc ('\\', file); |
| i++; |
| } |
| } |
| if (!c) |
| return i; |
| if (file) |
| putc ('\\', file); |
| i++; |
| goto ordinary_char; |
| |
| case '$': |
| if (file) |
| putc (c, file); |
| i++; |
| /* Fall through. */ |
| /* This can mishandle things like "$(" but there's no easy fix. */ |
| default: |
| ordinary_char: |
| /* This can mishandle characters in the string "\0\n%*?[\\~"; |
| exactly which chars are mishandled depends on the `make' version. |
| We know of no portable solution for this; |
| even GNU make 3.76.1 doesn't solve the problem entirely. |
| (Also, '\0' is mishandled due to our calling conventions.) */ |
| if (file) |
| putc (c, file); |
| i++; |
| break; |
| } |
| } |
| } |
| |
| /* Append some output to the file, keeping track of columns and doing |
| wrapping as necessary. */ |
| |
| static void |
| wrap_output (FILE *f, const char *string, int spacer) |
| { |
| int len = quote_string_for_make (NULL, string); |
| |
| if (len == 0) |
| return; |
| |
| if (column |
| && (MAX_COLUMNS |
| - 1 /* spacer */ |
| - 2 /* ` \' */ |
| < column + len)) |
| { |
| fprintf (f, " \\\n "); |
| column = 0; |
| if (spacer == ' ') |
| spacer = '\0'; |
| } |
| |
| if (spacer == ' ') |
| { |
| putc (spacer, f); |
| ++column; |
| } |
| |
| quote_string_for_make (f, string); |
| column += len; |
| |
| if (spacer == ':') |
| { |
| putc (spacer, f); |
| ++column; |
| } |
| } |
| |
| /* Print dependency file. */ |
| |
| void |
| print_dependencies (void) |
| { |
| FILE *f; |
| struct dependency *dep; |
| |
| if (dep_file == NULL) |
| return; |
| |
| f = fopen (dep_file, FOPEN_WT); |
| if (f == NULL) |
| { |
| as_warn (_("can't open `%s' for writing"), dep_file); |
| return; |
| } |
| |
| column = 0; |
| wrap_output (f, out_file_name, ':'); |
| for (dep = dep_chain; dep != NULL; dep = dep->next) |
| wrap_output (f, dep->file, ' '); |
| |
| putc ('\n', f); |
| |
| if (fclose (f)) |
| as_warn (_("can't close `%s'"), dep_file); |
| } |