#include <config.h>
#ifdef XCODE_INTEGRATION
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include "distcc.h"
#include "dopt.h"
#include "exitcode.h"
#include "trace.h"
#include "util.h"
#include "xci.h"
char *arg_xcode_dir = NULL;
char *dcc_xci_read_whole_file(FILE *file, size_t *len) {
char *output = NULL, *new_output = NULL;
const int max_buffer_chunk = 10240;
int buffer_size = 128, pos = 0, count;
output = malloc(buffer_size);
if (!output) {
rs_log_error("malloc(%d) failed: %s", buffer_size, strerror(errno));
goto out_error;
}
while (!feof(file)) {
if (pos == buffer_size - 1) {
if (buffer_size < max_buffer_chunk)
buffer_size *= 2;
else
buffer_size += max_buffer_chunk;
new_output = realloc(output, buffer_size);
if (!new_output) {
rs_log_error("realloc(%d) failed: %s",
buffer_size, strerror(errno));
goto out_error;
}
output = new_output;
}
count = fread(&output[pos], 1, buffer_size - pos - 1, file);
pos += count;
if (!count && ferror(file)) {
if (errno != EINTR) {
rs_log_error("fread failed: %s", strerror(errno));
goto out_error;
}
clearerr(file);
}
}
output[pos] = '\0';
if (pos + 1 < buffer_size) {
buffer_size = pos + 1;
new_output = realloc(output, buffer_size);
if (!new_output) {
rs_log_error("realloc(%d) failed: %s",
buffer_size, strerror(errno));
goto out_error;
}
output = new_output;
}
if (len)
*len = pos;
return output;
out_error:
if (output)
free(output);
return NULL;
}
int dcc_xci_write(FILE *file, const char *buf, size_t len) {
size_t pos = 0, written;
while (pos < len) {
written = fwrite(buf + pos, 1, len - pos, file);
if (written == 0) {
if (errno != EINTR) {
rs_log_error("fwrite() failed: %s", strerror(errno));
return EXIT_DISTCC_FAILED;
}
clearerr(file);
}
pos += written;
}
return 0;
}
char *dcc_xci_run_command(const char *command_line) {
FILE *p = NULL;
char *output = NULL;
int rv;
p = popen(command_line, "r");
if (!p) {
rs_log_error("popen(\"%s\", \"r\") failed", command_line);
goto out_error;
}
output = dcc_xci_read_whole_file(p, NULL);
if (!output) {
rs_log_error("dcc_xci_read_whole_file failed for \"%s\"", command_line);
goto out_error;
}
if ((rv = pclose(p))) {
rs_log_error("pclose returned %d for \"%s\"", rv, command_line);
p = NULL;
goto out_error;
}
return output;
out_error:
if (output)
free(output);
if (p)
pclose(p);
return NULL;
}
const char *dcc_xci_xcodeselect_path(void) {
static const char default_path[] = "/Developer";
static int has_xcodeselect_path = 0;
static const char *xcodeselect_path = NULL;
char *output = NULL;
struct stat statbuf;
if (arg_xcode_dir)
return arg_xcode_dir;
if (!has_xcodeselect_path) {
has_xcodeselect_path = 1;
if (stat("/usr/bin/xcode-select", &statbuf) != 0) {
rs_log_info("no /usr/bin/xcode-select, using \"%s\"",
default_path);
xcodeselect_path = default_path;
} else {
output = dcc_xci_run_command("/usr/bin/xcode-select -print-path");
if (!output)
goto out_error;
if (output[0] == '\0' || output[0] == '\n') {
rs_log_error("no output from xcode-select");
goto out_error;
}
char *newline = strchr(output + 1, '\n');
if (!newline || newline[1] != '\0') {
rs_log_error("malformed output from xcode-select");
goto out_error;
}
*newline = '\0';
xcodeselect_path = output;
}
}
return xcodeselect_path;
out_error:
if (output)
free(output);
return NULL;
}
static const char xci_dev_dir_token[] = "/_^_XCODE_DEV_DIRECTORY_^_";
char *dcc_xci_mask_developer_dir(const char *path) {
const char *xci_dev_dir = dcc_xci_xcodeselect_path();
char *result = dcc_replace_substring(path, xci_dev_dir, xci_dev_dir_token);
if (!result) {
rs_log_error("failed to create new string for developer dir processing "
"\"%s\".", path);
}
return result;
}
char *dcc_xci_unmask_developer_dir(const char *path) {
const char *xci_dev_dir = dcc_xci_xcodeselect_path();
char *result = dcc_replace_substring(path, xci_dev_dir_token, xci_dev_dir);
if (!result) {
rs_log_error("failed to create new string for developer dir processing "
"\"%s\".", path);
}
return result;
}
#endif