1 /* This program is free software; you can redistribute it and/or modify
2 it under the terms of the GNU General Public License as published by
3 the Free Software Foundation; either version 2, or (at your option)
6 This program is distributed in the hope that it will be useful,
7 but WITHOUT ANY WARRANTY; without even the implied warranty of
8 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 GNU General Public License for more details. */
15 Original Author: athan@morgan.com <Andrew C. Athan> 2/1/94
16 Modified By: vdemarco@bou.shl.com
18 This package was written to support the NEXTSTEP concept of
19 "wrappers." These are essentially directories that are to be
20 treated as "files." This package allows such wrappers to be
21 "processed" on the way in and out of CVS. The intended use is to
22 wrap up a wrapper into a single tar, such that that tar can be
23 treated as a single binary file in CVS. To solve the problem
24 effectively, it was also necessary to be able to prevent rcsmerge
25 application at appropriate times.
28 Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers)
30 wildcard [option value][option value]...
32 where option is one of
33 -f from cvs filter value: path to filter
34 -t to cvs filter value: path to filter
35 -m update methodology value: MERGE or COPY
36 -k default -k rcs option to use on import or add
38 and value is a single-quote delimited value.
41 *.nib -f 'gunzipuntar' -t 'targzip' -m 'COPY'
50 WrapMergeMethod mergeMethod;
53 static WrapperEntry **wrap_list=NULL;
54 static WrapperEntry **wrap_saved_list=NULL;
56 static int wrap_size=0;
57 static int wrap_count=0;
58 static int wrap_tempcount=0;
60 /* FIXME: the relationship between wrap_count, wrap_tempcount,
61 * wrap_saved_count, and wrap_saved_tempcount is not entirely clear;
62 * it is certainly suspicious that wrap_saved_count is never set to a
63 * value other than zero! If the variable isn't being used, it should
64 * be removed. And in general, we should describe how temporary
65 * vs. permanent wrappers are implemented, and then make sure the
66 * implementation is actually doing that.
68 * Right now things seem to be working, but that's no guarantee there
69 * isn't a bug lurking somewhere in the murk.
72 static int wrap_saved_count=0;
74 static int wrap_saved_tempcount=0;
76 #define WRAPPER_GROW 8
78 void wrap_add_entry PROTO((WrapperEntry *e,int temp));
79 void wrap_kill PROTO((void));
80 void wrap_kill_temp PROTO((void));
81 void wrap_free_entry PROTO((WrapperEntry *e));
82 void wrap_free_entry_internal PROTO((WrapperEntry *e));
83 void wrap_restore_saved PROTO((void));
87 /* FIXME-reentrancy: if we do a multithreaded server, will need to
88 move this to a per-connection data structure, or better yet
89 think about a cleaner solution. */
90 static int wrap_setup_already_done = 0;
93 if (wrap_setup_already_done != 0)
96 wrap_setup_already_done = 1;
104 file = xmalloc (strlen (CVSroot_directory)
105 + sizeof (CVSROOTADM)
106 + sizeof (CVSROOTADM_WRAPPER)
108 /* Then add entries found in repository, if it exists. */
109 (void) sprintf (file, "%s/%s/%s", CVSroot_directory, CVSROOTADM,
113 wrap_add_file(file,0);
118 /* Then add entries found in home dir, (if user has one) and file
120 homedir = get_homedir ();
121 /* If we can't find a home directory, ignore ~/.cvswrappers. This may
122 make tracking down problems a bit of a pain, but on the other
123 hand it might be obnoxious to complain when CVS will function
124 just fine without .cvswrappers (and many users won't even know what
130 file = xmalloc (strlen (homedir) + sizeof (CVSDOTWRAPPER) + 10);
131 (void) sprintf (file, "%s/%s", homedir, CVSDOTWRAPPER);
134 wrap_add_file (file, 0);
139 /* FIXME: calling wrap_add() below implies that the CVSWRAPPERS
140 * environment variable contains exactly one "wrapper" -- a line
143 * FILENAME_PATTERN FLAG OPTS [ FLAG OPTS ...]
145 * This may disagree with the documentation, which states:
148 * A whitespace-separated list of file name patterns that CVS
149 * should treat as wrappers. *Note Wrappers::.
151 * Does this mean the environment variable can hold multiple
152 * wrappers lines? If so, a single call to wrap_add() is
156 /* Then add entries found in CVSWRAPPERS environment variable. */
157 wrap_add (getenv (WRAPPER_ENV), 0);
160 #ifdef CLIENT_SUPPORT
161 /* Send -W arguments for the wrappers to the server. The command must
162 be one that accepts them (e.g. update, import). */
168 for (i = 0; i < wrap_count + wrap_tempcount; ++i)
170 if (wrap_list[i]->tocvsFilter != NULL
171 || wrap_list[i]->fromcvsFilter != NULL)
172 /* For greater studliness we would print the offending option
173 and (more importantly) where we found it. */
175 -t and -f wrapper options are not supported remotely; ignored");
176 if (wrap_list[i]->mergeMethod == WRAP_COPY)
177 /* For greater studliness we would print the offending option
178 and (more importantly) where we found it. */
180 -m wrapper option is not supported remotely; ignored");
181 if (wrap_list[i]->rcsOption != NULL)
183 send_to_server ("Argument -W\012Argument ", 0);
184 send_to_server (wrap_list[i]->wildCard, 0);
185 send_to_server (" -k '", 0);
186 send_to_server (wrap_list[i]->rcsOption, 0);
187 send_to_server ("'\012", 0);
191 #endif /* CLIENT_SUPPORT */
193 #if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT)
194 /* Output wrapper entries in the format of cvswrappers lines.
196 * This is useful when one side of a client/server connection wants to
197 * send its wrappers to the other; since the receiving side would like
198 * to use wrap_add() to incorporate the wrapper, it's best if the
199 * entry arrives in this format.
201 * The entries are stored in `line', which is allocated here. Caller
204 * If first_call_p is nonzero, then start afresh. */
206 wrap_unparse_rcs_options (line, first_call_p)
210 /* FIXME-reentrancy: we should design a reentrant interface, like
211 a callback which gets handed each wrapper (a multithreaded
212 server being the most concrete reason for this, but the
213 non-reentrant interface is fairly unnecessary/ugly). */
219 for (; i < wrap_count + wrap_tempcount; ++i)
221 if (wrap_list[i]->rcsOption != NULL)
223 *line = xmalloc (strlen (wrap_list[i]->wildCard)
226 + strlen (wrap_list[i]->rcsOption)
228 + 1); /* leave room for '\0' */
230 strcpy (*line, wrap_list[i]->wildCard);
231 strcat (*line, " -k '");
232 strcat (*line, wrap_list[i]->rcsOption);
235 /* We're going to miss the increment because we return, so
246 #endif /* SERVER_SUPPORT || CLIENT_SUPPORT */
249 * Open a file and read lines, feeding each line to a line parser. Arrange
250 * for keeping a temporary list of wrappers at the end, if the "temp"
254 wrap_add_file (file, temp)
260 size_t line_allocated = 0;
262 wrap_restore_saved ();
266 fp = CVS_FOPEN (file, "r");
269 if (!existence_error (errno))
270 error (0, errno, "cannot open %s", file);
273 while (getline (&line, &line_allocated, fp) >= 0)
274 wrap_add (line, temp);
278 error (0, errno, "cannot read %s", file);
279 if (fclose (fp) == EOF)
280 error (0, errno, "cannot close %s", file);
288 wrap_free_entry(wrap_list[--wrap_count]);
294 WrapperEntry **temps=wrap_list+wrap_count;
296 while(wrap_tempcount)
297 wrap_free_entry(temps[--wrap_tempcount]);
304 wrap_free_entry_internal(e);
309 wrap_free_entry_internal(e)
314 free (e->tocvsFilter);
315 if (e->fromcvsFilter)
316 free (e->fromcvsFilter);
331 wrap_list=wrap_saved_list;
332 wrap_count=wrap_saved_count;
333 wrap_tempcount=wrap_saved_tempcount;
335 wrap_saved_list=NULL;
337 wrap_saved_tempcount=0;
341 wrap_add (line, isTemp)
350 if (!line || line[0] == '#')
353 memset (&e, 0, sizeof(e));
355 /* Search for the wild card */
356 while (*line && isspace ((unsigned char) *line))
359 *line && !isspace ((unsigned char) *line);
368 e.wildCard=xstrdup(temp);
372 /* Search for the option */
373 while(*line && *line!='-')
382 /* Search for the filter commandline */
383 for(++line;*line && *line!='\'';++line);
387 for(temp=++line;*line && (*line!='\'' || line[-1]=='\\');++line)
390 /* This used to "break;" (ignore the option) if there was a
391 single character between the single quotes (I'm guessing
392 that was accidental). Now it "break;"s if there are no
393 characters. I'm not sure either behavior is particularly
394 necessary--the current options might not require ''
395 arguments, but surely some future option legitimately
396 might. Also I'm not sure that ignoring the option is a
397 swift way to handle syntax errors in general. */
405 /* Before this is reenabled, need to address the problem in
406 commit.c (see http://www.cyclic.com/cvs/dev-wrap.txt). */
408 "-t/-f wrappers not supported by this version of CVS");
411 free(e.fromcvsFilter);
412 /* FIXME: error message should say where the bad value
414 e.fromcvsFilter=expand_path (temp, "<wrapper>", 0);
415 if (!e.fromcvsFilter)
416 error (1, 0, "Correct above errors first");
419 /* Before this is reenabled, need to address the problem in
420 commit.c (see http://www.cyclic.com/cvs/dev-wrap.txt). */
422 "-t/-f wrappers not supported by this version of CVS");
426 /* FIXME: error message should say where the bad value
428 e.tocvsFilter=expand_path (temp, "<wrapper>", 0);
430 error (1, 0, "Correct above errors first");
433 if(*temp=='C' || *temp=='c')
434 e.mergeMethod=WRAP_COPY;
436 e.mergeMethod=WRAP_MERGE;
441 e.rcsOption = xstrdup (temp);
451 wrap_add_entry(&e, isTemp);
455 wrap_add_entry(e, temp)
460 if(wrap_count+wrap_tempcount>=wrap_size){
461 wrap_size += WRAPPER_GROW;
462 wrap_list = (WrapperEntry **) xrealloc ((char *) wrap_list,
464 sizeof (WrapperEntry *));
467 if(!temp && wrap_tempcount){
468 for(x=wrap_count+wrap_tempcount-1;x>=wrap_count;--x)
469 wrap_list[x+1]=wrap_list[x];
472 x=(temp ? wrap_count+(wrap_tempcount++):(wrap_count++));
473 wrap_list[x]=(WrapperEntry *)xmalloc(sizeof(WrapperEntry));
474 wrap_list[x]->wildCard=e->wildCard;
475 wrap_list[x]->fromcvsFilter=e->fromcvsFilter;
476 wrap_list[x]->tocvsFilter=e->tocvsFilter;
477 wrap_list[x]->mergeMethod=e->mergeMethod;
478 wrap_list[x]->rcsOption = e->rcsOption;
481 /* Return 1 if the given filename is a wrapper filename */
483 wrap_name_has (name,has)
487 int x,count=wrap_count+wrap_tempcount;
491 if (CVS_FNMATCH (wrap_list[x]->wildCard, name, 0) == 0){
494 temp=wrap_list[x]->tocvsFilter;
497 temp=wrap_list[x]->fromcvsFilter;
500 temp = wrap_list[x]->rcsOption;
513 static WrapperEntry *wrap_matching_entry PROTO ((const char *));
515 static WrapperEntry *
516 wrap_matching_entry (name)
519 int x,count=wrap_count+wrap_tempcount;
522 if (CVS_FNMATCH (wrap_list[x]->wildCard, name, 0) == 0)
524 return (WrapperEntry *)NULL;
527 /* Return the RCS options for FILENAME in a newly malloc'd string. If
528 ASFLAG, then include "-k" at the beginning (e.g. "-kb"), otherwise
529 just give the option itself (e.g. "b"). */
531 wrap_rcsoption (filename, asflag)
532 const char *filename;
535 WrapperEntry *e = wrap_matching_entry (filename);
538 if (e == NULL || e->rcsOption == NULL || (*e->rcsOption == '\0'))
541 buf = xmalloc (strlen (e->rcsOption) + 3);
545 strcat (buf, e->rcsOption);
549 strcpy (buf, e->rcsOption);
555 wrap_tocvs_process_file(fileName)
556 const char *fileName;
558 WrapperEntry *e=wrap_matching_entry(fileName);
559 static char *buf = NULL;
562 if(e==NULL || e->tocvsFilter==NULL)
567 buf = cvs_temp_name ();
569 args = xmalloc (strlen (e->tocvsFilter)
572 /* FIXME: sprintf will blow up if the format string contains items other
573 than %s, or contains too many %s's. We should instead be parsing
574 e->tocvsFilter ourselves and giving a real error. */
575 sprintf (args, e->tocvsFilter, fileName, buf);
577 run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY );
584 wrap_merge_is_copy (fileName)
585 const char *fileName;
587 WrapperEntry *e=wrap_matching_entry(fileName);
588 if(e==NULL || e->mergeMethod==WRAP_MERGE)
595 wrap_fromcvs_process_file(fileName)
596 const char *fileName;
599 WrapperEntry *e=wrap_matching_entry(fileName);
601 if(e==NULL || e->fromcvsFilter==NULL)
604 args = xmalloc (strlen (e->fromcvsFilter)
605 + strlen (fileName));
606 /* FIXME: sprintf will blow up if the format string contains items other
607 than %s, or contains too many %s's. We should instead be parsing
608 e->fromcvsFilter ourselves and giving a real error. */
609 sprintf (args, e->fromcvsFilter, fileName);
611 run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL );