/*
 * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
 *
 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
 *                                  and others.
 *
 * Portions Copyright (C) 1993 david d zuhn
 * 
 * Written by david d `zoo' zuhn while at Cygnus Support
 * 
 * You may distribute under the terms of the GNU General Public License as
 * specified in the README file that comes with the CVS source distribution.
 *
 */


#include "cvs.h"
#include "getline.h"

/* this file is to be found in the user's home directory */

#ifndef	CVSRC_FILENAME
#define	CVSRC_FILENAME	".cvsrc"
#endif
char cvsrc[] = CVSRC_FILENAME;

#define	GROW	10

/* Read cvsrc, processing options matching CMDNAME ("cvs" for global
   options, and update *ARGC and *ARGV accordingly.  */

void
read_cvsrc (int *argc, char ***argv, const char *cmdname)
{
    char *homedir;
    char *homeinit;
    FILE *cvsrcfile;

    char *line;
    int line_length;
    size_t line_chars_allocated;

    char *optstart;

    int command_len;
    int found = 0;

    int i;

    int new_argc;
    int max_new_argv;
    char **new_argv;

    /* old_argc and old_argv hold the values returned from the
       previous invocation of read_cvsrc and are used to free the
       allocated memory.  The first invocation of read_cvsrc gets argv
       from the system, this memory must not be free'd.  */
    static int old_argc = 0;
    static char **old_argv = NULL;

    /* don't do anything if argc is -1, since that implies "help" mode */
    if (*argc == -1)
	return;

    /* determine filename for ~/.cvsrc */

    homedir = get_homedir ();
    /* If we can't find a home directory, ignore ~/.cvsrc.  This may
       make tracking down problems a bit of a pain, but on the other
       hand it might be obnoxious to complain when CVS will function
       just fine without .cvsrc (and many users won't even know what
       .cvsrc is).  */
    if (!homedir)
	return;

    homeinit = strcat_filename_onto_homedir (homedir, cvsrc);

    /* if it can't be read, there's no point to continuing */

    if (!isreadable (homeinit))
    {
	free (homeinit);
	return;
    }

    /* now scan the file until we find the line for the command in question */

    line = NULL;
    line_chars_allocated = 0;
    command_len = strlen (cmdname);
    cvsrcfile = xfopen (homeinit, "r");
    while ((line_length = getline (&line, &line_chars_allocated, cvsrcfile))
	   >= 0)
    {
	/* skip over comment lines */
	if (line[0] == '#')
	    continue;

	/* stop if we match the current command */
	if (!strncmp (line, cmdname, command_len)
	    && isspace ((unsigned char) *(line + command_len)))
	{
	    found = 1;
	    break;
	}
    }

    if (line_length < 0 && !feof (cvsrcfile))
	error (0, errno, "cannot read %s", homeinit);

    fclose (cvsrcfile);

    /* setup the new options list */

    new_argc = 1;
    max_new_argv = (*argc) + GROW;
    new_argv = xnmalloc (max_new_argv, sizeof (char *));
    new_argv[0] = xstrdup ((*argv)[0]);

    if (found)
    {
	/* skip over command in the options line */
	for (optstart = strtok (line + command_len, "\t \n");
	     optstart;
	     optstart = strtok (NULL, "\t \n"))
	{
	    new_argv [new_argc++] = xstrdup (optstart);
	  
	    if (new_argc >= max_new_argv)
	    {
		max_new_argv += GROW;
		new_argv = xnrealloc (new_argv, max_new_argv, sizeof (char *));
	    }
	}
    }

    if (line != NULL)
	free (line);

    /* now copy the remaining arguments */
  
    if (new_argc + *argc > max_new_argv)
    {
	max_new_argv = new_argc + *argc;
	new_argv = xnrealloc (new_argv, max_new_argv, sizeof (char *));
    }
    for (i = 1; i < *argc; i++)
	new_argv [new_argc++] = xstrdup ((*argv)[i]);

    if (old_argv != NULL)
    {
	/* Free the memory which was allocated in the previous
           read_cvsrc call.  */
	free_names (&old_argc, old_argv);
    }

    old_argc = *argc = new_argc;
    old_argv = *argv = new_argv;

    free (homeinit);
    return;
}
