1 /*
2  * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
3  *
4  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
5  *                                  and others.
6  *
7  * Portions Copyright (C) 1993 david d zuhn
8  *
9  * Written by david d `zoo' zuhn while at Cygnus Support
10  *
11  * You may distribute under the terms of the GNU General Public License as
12  * specified in the README file that comes with the CVS source distribution.
13  *
14  */
15 
16 
17 #include "cvs.h"
18 #include "getline.h"
19 
20 /* this file is to be found in the user's home directory */
21 
22 #ifndef	CVSRC_FILENAME
23 #define	CVSRC_FILENAME	".cvsrc"
24 #endif
25 char cvsrc[] = CVSRC_FILENAME;
26 
27 #define	GROW	10
28 
29 /* Read cvsrc, processing options matching CMDNAME ("cvs" for global
30    options, and update *ARGC and *ARGV accordingly.  */
31 
32 void
read_cvsrc(int * argc,char *** argv,const char * cmdname)33 read_cvsrc (int *argc, char ***argv, const char *cmdname)
34 {
35     char *homedir;
36     char *homeinit;
37     FILE *cvsrcfile;
38 
39     char *line;
40     int line_length;
41     size_t line_chars_allocated;
42 
43     char *optstart;
44     int white_len;
45 
46     int command_len;
47     int found = 0;
48 
49     int i;
50 
51     int new_argc;
52     int max_new_argv;
53     char **new_argv;
54 
55     /* old_argc and old_argv hold the values returned from the
56        previous invocation of read_cvsrc and are used to free the
57        allocated memory.  The first invocation of read_cvsrc gets argv
58        from the system, this memory must not be free'd.  */
59     static int old_argc = 0;
60     static char **old_argv = NULL;
61 
62     /* don't do anything if argc is -1, since that implies "help" mode */
63     if (*argc == -1)
64 	return;
65 
66     /* determine filename for ~/.cvsrc */
67 
68     homedir = get_homedir ();
69     /* If we can't find a home directory, ignore ~/.cvsrc.  This may
70        make tracking down problems a bit of a pain, but on the other
71        hand it might be obnoxious to complain when CVS will function
72        just fine without .cvsrc (and many users won't even know what
73        .cvsrc is).  */
74     if (!homedir)
75 	return;
76 
77     homeinit = strcat_filename_onto_homedir (homedir, cvsrc);
78 
79     /* if it can't be read, there's no point to continuing */
80 
81     if (!isreadable (homeinit))
82     {
83 	free (homeinit);
84 	return;
85     }
86 
87     /* now scan the file until we find the line for the command in question */
88 
89     line = NULL;
90     line_chars_allocated = 0;
91     command_len = strlen (cmdname);
92     cvsrcfile = xfopen (homeinit, "r");
93     while ((line_length = getline (&line, &line_chars_allocated, cvsrcfile))
94 	   >= 0)
95     {
96 	/* skip over comment lines */
97 	if (line[0] == '#')
98 	    continue;
99 
100     for (white_len=0; isspace(line[white_len]); white_len++)
101         ;
102 
103 	/* stop if we match the current command */
104 	if (!strncmp (line + white_len, cmdname, command_len)
105 	    && isspace ((unsigned char) *(line + white_len + command_len)))
106 	{
107 	    found = 1;
108 	    break;
109 	}
110     }
111 
112     if (line_length < 0 && !feof (cvsrcfile))
113 	error (0, errno, "cannot read %s", homeinit);
114 
115     fclose (cvsrcfile);
116 
117     /* setup the new options list */
118 
119     new_argc = 1;
120     max_new_argv = (*argc) + GROW;
121     new_argv = xnmalloc (max_new_argv, sizeof (char *));
122     new_argv[0] = xstrdup ((*argv)[0]);
123 
124     if (found)
125     {
126 	/* skip over command in the options line */
127 	for (optstart = strtok (line + white_len + command_len, "\t \n");
128 	     optstart;
129 	     optstart = strtok (NULL, "\t \n"))
130 	{
131 	    new_argv [new_argc++] = xstrdup (optstart);
132 
133 	    if (new_argc >= max_new_argv)
134 	    {
135 		max_new_argv += GROW;
136 		new_argv = xnrealloc (new_argv, max_new_argv, sizeof (char *));
137 	    }
138 	}
139     }
140 
141     if (line != NULL)
142 	free (line);
143 
144     /* now copy the remaining arguments */
145 
146     if (new_argc + *argc > max_new_argv)
147     {
148 	max_new_argv = new_argc + *argc;
149 	new_argv = xnrealloc (new_argv, max_new_argv, sizeof (char *));
150     }
151     for (i = 1; i < *argc; i++)
152 	new_argv [new_argc++] = xstrdup ((*argv)[i]);
153 
154     if (old_argv != NULL)
155     {
156 	/* Free the memory which was allocated in the previous
157            read_cvsrc call.  */
158 	free_names (&old_argc, old_argv);
159     }
160 
161     old_argc = *argc = new_argc;
162     old_argv = *argv = new_argv;
163 
164     free (homeinit);
165     return;
166 }
167