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 ();
125 file = xmalloc (strlen (homedir) + sizeof (CVSDOTWRAPPER) + 10);
126 (void) sprintf (file, "%s/%s", homedir, CVSDOTWRAPPER);
129 wrap_add_file (file, 0);
134 /* FIXME: calling wrap_add() below implies that the CVSWRAPPERS
135 * environment variable contains exactly one "wrapper" -- a line
138 * FILENAME_PATTERN FLAG OPTS [ FLAG OPTS ...]
140 * This may disagree with the documentation, which states:
143 * A whitespace-separated list of file name patterns that CVS
144 * should treat as wrappers. *Note Wrappers::.
146 * Does this mean the environment variable can hold multiple
147 * wrappers lines? If so, a single call to wrap_add() is
151 /* Then add entries found in CVSWRAPPERS environment variable. */
152 wrap_add (getenv (WRAPPER_ENV), 0);
155 #ifdef CLIENT_SUPPORT
156 /* Send -W arguments for the wrappers to the server. The command must
157 be one that accepts them (e.g. update, import). */
163 for (i = 0; i < wrap_count + wrap_tempcount; ++i)
165 if (wrap_list[i]->tocvsFilter != NULL
166 || wrap_list[i]->fromcvsFilter != NULL)
167 /* For greater studliness we would print the offending option
168 and (more importantly) where we found it. */
170 -t and -f wrapper options are not supported remotely; ignored");
171 if (wrap_list[i]->mergeMethod == WRAP_COPY)
172 /* For greater studliness we would print the offending option
173 and (more importantly) where we found it. */
175 -m wrapper option is not supported remotely; ignored");
176 if (wrap_list[i]->rcsOption != NULL)
178 send_to_server ("Argument -W\012Argument ", 0);
179 send_to_server (wrap_list[i]->wildCard, 0);
180 send_to_server (" -k '", 0);
181 send_to_server (wrap_list[i]->rcsOption, 0);
182 send_to_server ("'\012", 0);
186 #endif /* CLIENT_SUPPORT */
188 #if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT)
189 /* Output wrapper entries in the format of cvswrappers lines.
191 * This is useful when one side of a client/server connection wants to
192 * send its wrappers to the other; since the receiving side would like
193 * to use wrap_add() to incorporate the wrapper, it's best if the
194 * entry arrives in this format.
196 * The entries are stored in `line', which is allocated here. Caller
199 * If first_call_p is nonzero, then start afresh. */
201 wrap_unparse_rcs_options (line, first_call_p)
205 /* FIXME-reentrancy: we should design a reentrant interface, like
206 a callback which gets handed each wrapper (a multithreaded
207 server being the most concrete reason for this, but the
208 non-reentrant interface is fairly unnecessary/ugly). */
214 for (; i < wrap_count + wrap_tempcount; ++i)
216 if (wrap_list[i]->rcsOption != NULL)
218 *line = xmalloc (strlen (wrap_list[i]->wildCard)
221 + strlen (wrap_list[i]->rcsOption)
223 + 1); /* leave room for '\0' */
225 strcpy (*line, wrap_list[i]->wildCard);
226 strcat (*line, " -k '");
227 strcat (*line, wrap_list[i]->rcsOption);
230 /* We're going to miss the increment because we return, so
241 #endif /* SERVER_SUPPORT || CLIENT_SUPPORT */
244 * Open a file and read lines, feeding each line to a line parser. Arrange
245 * for keeping a temporary list of wrappers at the end, if the "temp"
249 wrap_add_file (file, temp)
255 size_t line_allocated = 0;
257 wrap_restore_saved ();
261 fp = CVS_FOPEN (file, "r");
264 if (!existence_error (errno))
265 error (0, errno, "cannot open %s", file);
268 while (getline (&line, &line_allocated, fp) >= 0)
269 wrap_add (line, temp);
273 error (0, errno, "cannot read %s", file);
274 if (fclose (fp) == EOF)
275 error (0, errno, "cannot close %s", file);
283 wrap_free_entry(wrap_list[--wrap_count]);
289 WrapperEntry **temps=wrap_list+wrap_count;
291 while(wrap_tempcount)
292 wrap_free_entry(temps[--wrap_tempcount]);
299 wrap_free_entry_internal(e);
304 wrap_free_entry_internal(e)
309 free (e->tocvsFilter);
310 if (e->fromcvsFilter)
311 free (e->fromcvsFilter);
326 wrap_list=wrap_saved_list;
327 wrap_count=wrap_saved_count;
328 wrap_tempcount=wrap_saved_tempcount;
330 wrap_saved_list=NULL;
332 wrap_saved_tempcount=0;
336 wrap_add (line, isTemp)
345 if (!line || line[0] == '#')
348 memset (&e, 0, sizeof(e));
350 /* Search for the wild card */
351 while(*line && isspace(*line))
353 for(temp=line;*line && !isspace(*line);++line)
361 e.wildCard=xstrdup(temp);
365 /* Search for the option */
366 while(*line && *line!='-')
375 /* Search for the filter commandline */
376 for(++line;*line && *line!='\'';++line);
380 for(temp=++line;*line && (*line!='\'' || line[-1]=='\\');++line)
383 /* This used to "break;" (ignore the option) if there was a
384 single character between the single quotes (I'm guessing
385 that was accidental). Now it "break;"s if there are no
386 characters. I'm not sure either behavior is particularly
387 necessary--the current options might not require ''
388 arguments, but surely some future option legitimately
389 might. Also I'm not sure that ignoring the option is a
390 swift way to handle syntax errors in general. */
398 /* Before this is reenabled, need to address the problem in
399 commit.c (see http://www.cyclic.com/cvs/dev-wrap.txt). */
401 "-t/-f wrappers not supported by this version of CVS");
404 free(e.fromcvsFilter);
405 /* FIXME: error message should say where the bad value
407 e.fromcvsFilter=expand_path (temp, "<wrapper>", 0);
408 if (!e.fromcvsFilter)
409 error (1, 0, "Correct above errors first");
412 /* Before this is reenabled, need to address the problem in
413 commit.c (see http://www.cyclic.com/cvs/dev-wrap.txt). */
415 "-t/-f wrappers not supported by this version of CVS");
419 /* FIXME: error message should say where the bad value
421 e.tocvsFilter=expand_path (temp, "<wrapper>", 0);
423 error (1, 0, "Correct above errors first");
426 /* FIXME: look into whether this option is still relevant given
427 the 24 Jun 96 change to merge_file. */
428 if(*temp=='C' || *temp=='c')
429 e.mergeMethod=WRAP_COPY;
431 e.mergeMethod=WRAP_MERGE;
436 e.rcsOption = xstrdup (temp);
446 wrap_add_entry(&e, isTemp);
450 wrap_add_entry(e, temp)
455 if(wrap_count+wrap_tempcount>=wrap_size){
456 wrap_size += WRAPPER_GROW;
457 wrap_list = (WrapperEntry **) xrealloc ((char *) wrap_list,
459 sizeof (WrapperEntry *));
462 if(!temp && wrap_tempcount){
463 for(x=wrap_count+wrap_tempcount-1;x>=wrap_count;--x)
464 wrap_list[x+1]=wrap_list[x];
467 x=(temp ? wrap_count+(wrap_tempcount++):(wrap_count++));
468 wrap_list[x]=(WrapperEntry *)xmalloc(sizeof(WrapperEntry));
469 wrap_list[x]->wildCard=e->wildCard;
470 wrap_list[x]->fromcvsFilter=e->fromcvsFilter;
471 wrap_list[x]->tocvsFilter=e->tocvsFilter;
472 wrap_list[x]->mergeMethod=e->mergeMethod;
473 wrap_list[x]->rcsOption = e->rcsOption;
476 /* Return 1 if the given filename is a wrapper filename */
478 wrap_name_has (name,has)
482 int x,count=wrap_count+wrap_tempcount;
486 if (CVS_FNMATCH (wrap_list[x]->wildCard, name, 0) == 0){
489 temp=wrap_list[x]->tocvsFilter;
492 temp=wrap_list[x]->fromcvsFilter;
495 temp = wrap_list[x]->rcsOption;
508 static WrapperEntry *wrap_matching_entry PROTO ((const char *));
510 static WrapperEntry *
511 wrap_matching_entry (name)
514 int x,count=wrap_count+wrap_tempcount;
517 if (CVS_FNMATCH (wrap_list[x]->wildCard, name, 0) == 0)
519 return (WrapperEntry *)NULL;
522 /* Return the RCS options for FILENAME in a newly malloc'd string. If
523 ASFLAG, then include "-k" at the beginning (e.g. "-kb"), otherwise
524 just give the option itself (e.g. "b"). */
526 wrap_rcsoption (filename, asflag)
527 const char *filename;
530 WrapperEntry *e = wrap_matching_entry (filename);
533 if (e == NULL || e->rcsOption == NULL || (*e->rcsOption == '\0'))
536 buf = xmalloc (strlen (e->rcsOption) + 3);
540 strcat (buf, e->rcsOption);
544 strcpy (buf, e->rcsOption);
550 wrap_tocvs_process_file(fileName)
551 const char *fileName;
553 WrapperEntry *e=wrap_matching_entry(fileName);
554 static char *buf = NULL;
557 if(e==NULL || e->tocvsFilter==NULL)
562 buf = cvs_temp_name ();
564 args = xmalloc (strlen (e->tocvsFilter)
567 /* FIXME: sprintf will blow up if the format string contains items other
568 than %s, or contains too many %s's. We should instead be parsing
569 e->tocvsFilter ourselves and giving a real error. */
570 sprintf (args, e->tocvsFilter, fileName, buf);
572 run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY );
579 wrap_merge_is_copy (fileName)
580 const char *fileName;
582 WrapperEntry *e=wrap_matching_entry(fileName);
583 if(e==NULL || e->mergeMethod==WRAP_MERGE)
590 wrap_fromcvs_process_file(fileName)
591 const char *fileName;
594 WrapperEntry *e=wrap_matching_entry(fileName);
596 if(e==NULL || e->fromcvsFilter==NULL)
599 args = xmalloc (strlen (e->fromcvsFilter)
600 + strlen (fileName));
601 /* FIXME: sprintf will blow up if the format string contains items other
602 than %s, or contains too many %s's. We should instead be parsing
603 e->fromcvsFilter ourselves and giving a real error. */
604 sprintf (args, e->fromcvsFilter, fileName);
606 run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL );