argutil.c   [plain text]


/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- 
 *
 * distcc -- A simple distributed compiler system
 *
 * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org>
 *
 * 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
 */



/*
 * Utilities for dealing with argv[]-style strings.
 *
 * These rules might not yet be consistently applied in distcc, but they
 * should be in the future:
 *
 * For simplicity in managing memory we try to keep all argv structures
 * malloc'd, without any shared structure.  It is then possible to just free
 * the whole thing whenever we're finished with it.
 *
 * One exception is of course the argv used to invoke the program, which is
 * treated as read-only.
 */


#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>

#include <sys/stat.h>

#include "distcc.h"
#include "trace.h"
#include "util.h"
#include "exitcode.h"


/**
 * Return true if argv contains needle as an argument.
 **/
int dcc_argv_search(char **a,
                    const char *needle)
{
    for (; *a; a = a++) 
        if (!strcmp(*a, needle))
            return 1;
    return 0;
}


int dcc_argv_len(char **a)
{
    int i;

    for (i = 0; a[i]; i++)
        ;
    return i;
}


/* Free a malloc'd argv structure.  Only safe when the array and all its
 * components were malloc'd. */
void dcc_free_argv(char **argv)
{
    char **a;

    for (a = argv; *a != NULL; a++)
        free(a);
    free(argv);
}


/* Copy an argv array, adding extra NULL elements to the end to allow for
 * adding more arguments later.
 */
int dcc_copy_argv(char **from, char ***out, int delta)
{
    char **b;
    int l, i;

    l = dcc_argv_len(from);
    b = malloc((l+1+delta) * (sizeof from[0]));
    if (b == NULL) {
        rs_log_error("failed to allocate copy of argv");
        exit(EXIT_OUT_OF_MEMORY);
    }
    for (i = 0; i < l; i++) {
        if ((b[i] = strdup(from[i])) == NULL) {
            rs_log_error("failed to duplicate element %d", i);
            return EXIT_OUT_OF_MEMORY;
        }
    }
    b[l] = NULL;
    
    *out = b;

    return 0;
}



/**
 * Convert an argv array to printable form for debugging output.
 *
 * @note The result is not necessarily properly quoted for passing to
 * shells.
 *
 * @return newly-allocated string containing representation of
 * arguments.
 **/
char *dcc_argv_tostr(char **a)
{
    int l, i;
    char *s, *ss;
    
    /* calculate total length */
    for (l = 0, i = 0; a[i]; i++) {
        l += strlen(a[i]) + 3;  /* two quotes and space */
    }

    ss = s = malloc((size_t) l + 1);
    if (!s) {
        rs_log_crit("failed to allocate %d bytes", l+1);
        exit(EXIT_OUT_OF_MEMORY);
    }
    
    for (i = 0; a[i]; i++) {
        /* kind of half-assed quoting; won't handle strings containing
         * quotes properly, but good enough for debug messages for the
         * moment. */
        int needs_quotes = (strpbrk(a[i], " \t\n\"\';") != NULL);
        if (i)
            *ss++ = ' ';
        if (needs_quotes)
            *ss++ = '"';
        strcpy(ss, a[i]);
        ss += strlen(a[i]);
        if (needs_quotes)
            *ss++ = '"';
    }
    *ss = '\0';

    return s;
}