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 -m update methodology value: MERGE or COPY
34 -k default -k rcs option to use on import or add
36 and value is a single-quote delimited value.
39 *.nib -f 'gunzipuntar' -t 'targzip' -m 'COPY'
48 WrapMergeMethod mergeMethod
;
51 static WrapperEntry
**wrap_list
=NULL
;
52 static WrapperEntry
**wrap_saved_list
=NULL
;
54 static int wrap_size
=0;
55 static int wrap_count
=0;
56 static int wrap_tempcount
=0;
58 /* FIXME: the relationship between wrap_count, wrap_tempcount,
59 * wrap_saved_count, and wrap_saved_tempcount is not entirely clear;
60 * it is certainly suspicious that wrap_saved_count is never set to a
61 * value other than zero! If the variable isn't being used, it should
62 * be removed. And in general, we should describe how temporary
63 * vs. permanent wrappers are implemented, and then make sure the
64 * implementation is actually doing that.
66 * Right now things seem to be working, but that's no guarantee there
67 * isn't a bug lurking somewhere in the murk.
70 static int wrap_saved_count
=0;
72 static int wrap_saved_tempcount
=0;
74 #define WRAPPER_GROW 8
76 void wrap_add_entry (WrapperEntry
*e
,int temp
);
77 void wrap_kill (void);
78 void wrap_kill_temp (void);
79 void wrap_free_entry (WrapperEntry
*e
);
80 void wrap_free_entry_internal (WrapperEntry
*e
);
81 void wrap_restore_saved (void);
85 /* FIXME-reentrancy: if we do a multithreaded server, will need to
86 move this to a per-connection data structure, or better yet
87 think about a cleaner solution. */
88 static int wrap_setup_already_done
= 0;
91 if (wrap_setup_already_done
!= 0)
94 wrap_setup_already_done
= 1;
96 if (!current_parsed_root
->isremote
)
100 /* Then add entries found in repository, if it exists. */
101 file
= Xasprintf ("%s/%s/%s", current_parsed_root
->directory
,
102 CVSROOTADM
, CVSROOTADM_WRAPPER
);
105 wrap_add_file(file
,0);
110 /* Then add entries found in home dir, (if user has one) and file
112 homedir
= get_homedir ();
113 /* If we can't find a home directory, ignore ~/.cvswrappers. This may
114 make tracking down problems a bit of a pain, but on the other
115 hand it might be obnoxious to complain when CVS will function
116 just fine without .cvswrappers (and many users won't even know what
120 char *file
= strcat_filename_onto_homedir (homedir
, CVSDOTWRAPPER
);
123 wrap_add_file (file
, 0);
128 /* FIXME: calling wrap_add() below implies that the CVSWRAPPERS
129 * environment variable contains exactly one "wrapper" -- a line
132 * FILENAME_PATTERN FLAG OPTS [ FLAG OPTS ...]
134 * This may disagree with the documentation, which states:
137 * A whitespace-separated list of file name patterns that CVS
138 * should treat as wrappers. *Note Wrappers::.
140 * Does this mean the environment variable can hold multiple
141 * wrappers lines? If so, a single call to wrap_add() is
145 /* Then add entries found in CVSWRAPPERS environment variable. */
146 wrap_add (getenv (WRAPPER_ENV
), 0);
149 #ifdef CLIENT_SUPPORT
150 /* Send -W arguments for the wrappers to the server. The command must
151 be one that accepts them (e.g. update, import). */
157 for (i
= 0; i
< wrap_count
+ wrap_tempcount
; ++i
)
159 if (wrap_list
[i
]->tocvsFilter
!= NULL
160 || wrap_list
[i
]->fromcvsFilter
!= NULL
)
161 /* For greater studliness we would print the offending option
162 and (more importantly) where we found it. */
164 -t and -f wrapper options are not supported remotely; ignored");
165 if (wrap_list
[i
]->mergeMethod
== WRAP_COPY
)
166 /* For greater studliness we would print the offending option
167 and (more importantly) where we found it. */
169 -m wrapper option is not supported remotely; ignored");
170 send_to_server ("Argument -W\012Argument ", 0);
171 send_to_server (wrap_list
[i
]->wildCard
, 0);
172 send_to_server (" -k '", 0);
173 if (wrap_list
[i
]->rcsOption
!= NULL
)
174 send_to_server (wrap_list
[i
]->rcsOption
, 0);
176 send_to_server ("kv", 0);
177 send_to_server ("'\012", 0);
180 #endif /* CLIENT_SUPPORT */
182 #if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT)
183 /* Output wrapper entries in the format of cvswrappers lines.
185 * This is useful when one side of a client/server connection wants to
186 * send its wrappers to the other; since the receiving side would like
187 * to use wrap_add() to incorporate the wrapper, it's best if the
188 * entry arrives in this format.
190 * The entries are stored in `line', which is allocated here. Caller
193 * If first_call_p is nonzero, then start afresh. */
195 wrap_unparse_rcs_options (char **line
, int first_call_p
)
197 /* FIXME-reentrancy: we should design a reentrant interface, like
198 a callback which gets handed each wrapper (a multithreaded
199 server being the most concrete reason for this, but the
200 non-reentrant interface is fairly unnecessary/ugly). */
206 if (i
>= wrap_count
+ wrap_tempcount
) {
211 *line
= Xasprintf ("%s -k '%s'",
212 wrap_list
[i
]->wildCard
,
213 wrap_list
[i
]->rcsOption
214 ? wrap_list
[i
]->rcsOption
: "kv");
217 #endif /* SERVER_SUPPORT || CLIENT_SUPPORT */
220 * Remove fmt str specifier other than %% or %s. And allow
221 * only max_s %s specifiers
224 wrap_clean_fmt_str(char *fmt
, int max_s
)
227 if (fmt
[0] == '%' && fmt
[1])
232 if (fmt
[1] == 's' && max_s
> 0)
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 (const char *file
, int temp
)
253 size_t line_allocated
= 0;
255 wrap_restore_saved ();
259 fp
= CVS_FOPEN (file
, "r");
262 if (!existence_error (errno
))
263 error (0, errno
, "cannot open %s", file
);
266 while (getline (&line
, &line_allocated
, fp
) >= 0)
267 wrap_add (line
, temp
);
271 error (0, errno
, "cannot read %s", file
);
272 if (fclose (fp
) == EOF
)
273 error (0, errno
, "cannot close %s", file
);
281 wrap_free_entry(wrap_list
[--wrap_count
]);
287 WrapperEntry
**temps
=wrap_list
+wrap_count
;
289 while(wrap_tempcount
)
290 wrap_free_entry(temps
[--wrap_tempcount
]);
294 wrap_free_entry(WrapperEntry
*e
)
296 wrap_free_entry_internal(e
);
301 wrap_free_entry_internal(WrapperEntry
*e
)
305 free (e
->tocvsFilter
);
306 if (e
->fromcvsFilter
)
307 free (e
->fromcvsFilter
);
313 wrap_restore_saved(void)
322 wrap_list
=wrap_saved_list
;
323 wrap_count
=wrap_saved_count
;
324 wrap_tempcount
=wrap_saved_tempcount
;
326 wrap_saved_list
=NULL
;
328 wrap_saved_tempcount
=0;
332 wrap_add (char *line
, int isTemp
)
339 if (!line
|| line
[0] == '#')
342 memset (&e
, 0, sizeof(e
));
344 /* Search for the wild card */
345 while (*line
&& isspace ((unsigned char) *line
))
348 *line
&& !isspace ((unsigned char) *line
);
357 e
.wildCard
=xstrdup(temp
);
361 /* Search for the option */
362 while(*line
&& *line
!='-')
371 /* Search for the filter commandline */
372 for(++line
;*line
&& *line
!='\'';++line
);
376 for(temp
=++line
;*line
&& (*line
!='\'' || line
[-1]=='\\');++line
)
379 /* This used to "break;" (ignore the option) if there was a
380 single character between the single quotes (I'm guessing
381 that was accidental). Now it "break;"s if there are no
382 characters. I'm not sure either behavior is particularly
383 necessary--the current options might not require ''
384 arguments, but surely some future option legitimately
385 might. Also I'm not sure that ignoring the option is a
386 swift way to handle syntax errors in general. */
394 /* Before this is reenabled, need to address the problem in
396 <http://ximbiot.com/cvs/cvshome/docs/infowrapper.html>). */
398 "-t/-f wrappers not supported by this version of CVS");
401 free(e
.fromcvsFilter
);
402 /* FIXME: error message should say where the bad value
405 expand_path (temp
, current_parsed_root
->directory
, false,
407 if (!e
.fromcvsFilter
)
408 error (1, 0, "Correct above errors first");
411 /* Before this is reenabled, need to address the problem in
413 <http://ximbiot.com/cvs/cvshome/docs/infowrapper.html>). */
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
, current_parsed_root
->directory
,
422 false, "<wrapper>", 0);
424 error (1, 0, "Correct above errors first");
427 if(*temp
=='C' || *temp
=='c')
428 e
.mergeMethod
=WRAP_COPY
;
430 e
.mergeMethod
=WRAP_MERGE
;
435 e
.rcsOption
= strcmp (temp
, "kv") ? xstrdup (temp
) : NULL
;
445 wrap_add_entry(&e
, isTemp
);
449 wrap_add_entry (WrapperEntry
*e
, int temp
)
452 if (wrap_count
+ wrap_tempcount
>= wrap_size
)
454 wrap_size
+= WRAPPER_GROW
;
455 wrap_list
= xnrealloc (wrap_list
, wrap_size
, sizeof (WrapperEntry
*));
458 if (!temp
&& wrap_tempcount
)
460 for (x
= wrap_count
+ wrap_tempcount
- 1; x
>= wrap_count
; --x
)
461 wrap_list
[x
+ 1] = wrap_list
[x
];
464 x
= (temp
? wrap_count
+ (wrap_tempcount
++) : (wrap_count
++));
465 wrap_list
[x
] = xmalloc (sizeof (WrapperEntry
));
469 /* Return 1 if the given filename is a wrapper filename */
471 wrap_name_has (const char *name
, WrapMergeHas has
)
473 int x
,count
=wrap_count
+wrap_tempcount
;
477 if (CVS_FNMATCH (wrap_list
[x
]->wildCard
, name
, 0) == 0){
480 temp
=wrap_list
[x
]->tocvsFilter
;
483 temp
=wrap_list
[x
]->fromcvsFilter
;
486 temp
= wrap_list
[x
]->rcsOption
;
499 static WrapperEntry
*wrap_matching_entry (const char *);
501 static WrapperEntry
*
502 wrap_matching_entry (const char *name
)
504 int x
,count
=wrap_count
+wrap_tempcount
;
507 if (CVS_FNMATCH (wrap_list
[x
]->wildCard
, name
, 0) == 0)
512 /* Return the RCS options for FILENAME in a newly malloc'd string. If
513 ASFLAG, then include "-k" at the beginning (e.g. "-kb"), otherwise
514 just give the option itself (e.g. "b"). */
516 wrap_rcsoption (const char *filename
, int asflag
)
518 WrapperEntry
*e
= wrap_matching_entry (filename
);
520 if (e
== NULL
|| e
->rcsOption
== NULL
|| (*e
->rcsOption
== '\0'))
523 return Xasprintf ("%s%s", asflag
? "-k" : "", e
->rcsOption
);
527 wrap_tocvs_process_file(const char *fileName
)
529 WrapperEntry
*e
=wrap_matching_entry(fileName
);
530 static char *buf
= NULL
;
533 if(e
==NULL
|| e
->tocvsFilter
==NULL
)
538 buf
= cvs_temp_name ();
540 wrap_clean_fmt_str (e
->tocvsFilter
, 2);
541 args
= Xasprintf (e
->tocvsFilter
, fileName
, buf
);
543 run_exec (RUN_TTY
, RUN_TTY
, RUN_TTY
, RUN_NORMAL
| RUN_REALLY
);
550 wrap_merge_is_copy (const char *fileName
)
552 WrapperEntry
*e
=wrap_matching_entry(fileName
);
553 if(e
==NULL
|| e
->mergeMethod
==WRAP_MERGE
)
560 wrap_fromcvs_process_file(const char *fileName
)
563 WrapperEntry
*e
= wrap_matching_entry(fileName
);
565 if (e
!= NULL
&& e
->fromcvsFilter
!= NULL
)
567 wrap_clean_fmt_str (e
->fromcvsFilter
, 1);
568 args
= Xasprintf (e
->fromcvsFilter
, fileName
);
570 run_exec (RUN_TTY
, RUN_TTY
, RUN_TTY
, RUN_NORMAL
);