summaryrefslogtreecommitdiff
path: root/distcc/src/filename.c
diff options
context:
space:
mode:
Diffstat (limited to 'distcc/src/filename.c')
-rw-r--r--distcc/src/filename.c315
1 files changed, 315 insertions, 0 deletions
diff --git a/distcc/src/filename.c b/distcc/src/filename.c
new file mode 100644
index 0000000..bd78f69
--- /dev/null
+++ b/distcc/src/filename.c
@@ -0,0 +1,315 @@
+/* -*- c-file-style: "java"; indent-tabs-mode: nil -*-
+ *
+ * distcc -- A simple distributed compiler system
+ *
+ * Copyright (C) 2002, 2003, 2004 by Martin Pool
+ *
+ * This program 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 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include "distcc.h"
+#include "trace.h"
+#include "util.h"
+#include "exitcode.h"
+
+
+
+/**
+ * @file
+ *
+ * Everything we know about C filenames.
+ *
+ * We need to have some heuristics about input and output filenames to
+ * understand command lines, because that's what cc does.
+ *
+ * @note As of 0.10, .s and .S files are never distributed, because
+ * they might contain '.include' pseudo-operations, which are resolved
+ * by the assembler.
+ */
+
+
+
+/**
+ * Return a pointer to the extension, including the dot, or NULL.
+ **/
+char * dcc_find_extension(char *sfile)
+{
+ char *dot;
+
+ dot = strrchr(sfile, '.');
+ if (dot == NULL || dot[1] == '\0') {
+ /* make sure there's space for one more character after the
+ * dot */
+ return NULL;
+ }
+ return dot;
+}
+
+
+/**
+ * Return a pointer to the basename of the file (everything after the
+ * last slash.) If there is no slash, return the whole filename,
+ * which is presumably in the current directory.
+ **/
+const char * dcc_find_basename(const char *sfile)
+{
+ char *slash;
+
+ if (!sfile)
+ return sfile;
+
+ slash = strrchr(sfile, '/');
+
+ if (slash == NULL || slash[1] == '\0')
+ return sfile;
+
+ return slash+1;
+}
+
+/** Truncate the filename to its dirname (everything before the last slash).
+ * If the filename ends with a slash, just lop off the last slash.
+ * Note: this is destructive.
+ */
+void dcc_truncate_to_dirname(char *file)
+{
+ char *slash = 0;
+
+ slash = strrchr(file, '/');
+
+ if (slash == NULL) {
+ file[0] = '\0';
+ } else {
+ *slash = '\0';
+ }
+}
+
+
+static int dcc_set_file_extension(const char *sfile,
+ const char *new_ext,
+ char **ofile)
+{
+ char *dot, *o;
+
+ o = strdup(sfile);
+ dot = dcc_find_extension((char *) o);
+ if (!dot) {
+ rs_log_error("couldn't find extension in \"%s\"", o);
+ return EXIT_DISTCC_FAILED;
+ }
+ if (strlen(dot) < strlen(new_ext)) {
+ rs_log_error("not enough space for new extension");
+ return EXIT_DISTCC_FAILED;
+ }
+ strcpy(dot, new_ext);
+ *ofile = o;
+
+ return 0;
+}
+
+
+/*
+ * Apple extensions:
+ * file.mm, file.M
+ * Objective-C++ source code which must be preprocessed. (APPLE ONLY)
+ *
+ * file.mii Objective-C++ source code which should not be
+ * preprocessed. (APPLE ONLY)
+ *
+ * http://developer.apple.com/techpubs/macosx/DeveloperTools/gcc3/gcc/Overall-Options.html
+ */
+
+
+
+/**
+ * If you preprocessed a file with extension @p e, what would you get?
+ *
+ * @param e original extension (e.g. ".c")
+ *
+ * @returns preprocessed extension, (e.g. ".i"), or NULL if
+ * unrecognized.
+ **/
+const char * dcc_preproc_exten(const char *e)
+{
+ if (e[0] != '.')
+ return NULL;
+ e++;
+ if (!strcmp(e, "i") || !strcmp(e, "c")) {
+ return ".i";
+ } else if (!strcmp(e, "c") || !strcmp(e, "cc")
+ || !strcmp(e, "cpp") || !strcmp(e, "cxx")
+ || !strcmp(e, "cp") || !strcmp(e, "c++")
+ || !strcmp(e, "C") || !strcmp(e, "ii")) {
+ return ".ii";
+ } else if(!strcmp(e,"mi") || !strcmp(e, "m")) {
+ return ".mi";
+ } else if(!strcmp(e,"mii") || !strcmp(e,"mm")
+ || !strcmp(e,"M")) {
+ return ".mii";
+ } else if (!strcasecmp(e, "s")) {
+ return ".s";
+ } else {
+ return NULL;
+ }
+}
+
+
+/**
+ * Does the extension of this file indicate that it is already
+ * preprocessed?
+ **/
+int dcc_is_preprocessed(const char *sfile)
+{
+ const char *dot, *ext;
+ dot = dcc_find_extension((char *) sfile);
+ if (!dot)
+ return 0;
+ ext = dot+1;
+
+ switch (ext[0]) {
+#ifdef ENABLE_REMOTE_ASSEMBLE
+ case 's':
+ /* .S needs to be run through cpp; .s does not */
+ return !strcmp(ext, "s");
+#endif
+ case 'i':
+ return !strcmp(ext, "i")
+ || !strcmp(ext, "ii");
+ case 'm':
+ return !strcmp(ext, "mi")
+ || !strcmp(ext, "mii");
+ default:
+ return 0;
+ }
+}
+
+
+/**
+ * Work out whether @p sfile is source based on extension
+ **/
+int dcc_is_source(const char *sfile)
+{
+ const char *dot, *ext;
+ dot = dcc_find_extension((char *) sfile);
+ if (!dot)
+ return 0;
+ ext = dot+1;
+
+ /* you could expand this out further into a RE-like set of case
+ * statements, but i'm not sure it's that important. */
+
+ switch (ext[0]) {
+ case 'i':
+ return !strcmp(ext, "i")
+ || !strcmp(ext, "ii");
+ case 'c':
+ return !strcmp(ext, "c")
+ || !strcmp(ext, "cc")
+ || !strcmp(ext, "cpp")
+ || !strcmp(ext, "cxx")
+ || !strcmp(ext, "cp")
+ || !strcmp(ext, "c++");
+ case 'C':
+ return !strcmp(ext, "C");
+ case 'm':
+ return !strcmp(ext,"m")
+ || !strcmp(ext,"mm")
+ || !strcmp(ext,"mi")
+ || !strcmp(ext,"mii");
+ case 'M':
+ return !strcmp(ext, "M");
+#ifdef ENABLE_REMOTE_ASSEMBLE
+ case 's':
+ return !strcmp(ext, "s");
+ case 'S':
+ return !strcmp(ext, "S");
+#endif
+ default:
+ return 0;
+ }
+}
+
+
+
+/**
+ * Decide whether @p filename is an object file, based on its
+ * extension.
+ **/
+int dcc_is_object(const char *filename)
+{
+ const char *dot;
+ dot = dcc_find_extension((char *) filename);
+ if (!dot)
+ return 0;
+
+ return !strcmp(dot, ".o");
+}
+
+
+/* Some files should always be built locally... */
+int
+dcc_source_needs_local(const char *filename)
+{
+ const char *p;
+
+ p = dcc_find_basename(filename);
+
+ if (str_startswith("conftest.", p) || str_startswith("tmp.conftest.", p)) {
+ rs_trace("autoconf tests are run locally: %s", filename);
+ return EXIT_DISTCC_FAILED;
+ }
+
+ return 0;
+}
+
+
+
+/**
+ * Work out the default object file name the compiler would use if -o
+ * was not specified. We don't need to worry about "a.out" because
+ * we've already determined that -c or -S was specified.
+ *
+ * However, the compiler does put the output file in the current
+ * directory even if the source file is elsewhere, so we need to strip
+ * off all leading directories.
+ *
+ * @param sfile Source filename. Assumed to match one of the
+ * recognized patterns, otherwise bad things might happen.
+ **/
+int dcc_output_from_source(const char *sfile,
+ const char *out_extn,
+ char **ofile)
+{
+ char *slash;
+
+ if ((slash = strrchr(sfile, '/')))
+ sfile = slash+1;
+ if (strlen(sfile) < 3) {
+ rs_log_error("source file %s is bogus", sfile);
+ return EXIT_DISTCC_FAILED;
+ }
+
+ return dcc_set_file_extension(sfile, out_extn, ofile);
+}
+