"Fossies" - the Fresh Open Source Software Archive

Member "cvs-1.11.23/src/wrapper.c" (7 May 2008, 15836 Bytes) of package /linux/misc/old/cvs-1.11.23.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "wrapper.c" see the Fossies "Dox" file reference documentation.

    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)
    4    any later version.
    5 
    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.  */
   10 
   11 #include "cvs.h"
   12 #include "getline.h"
   13 
   14 /*
   15   Original Author:  athan@morgan.com <Andrew C. Athan> 2/1/94
   16   Modified By:      vdemarco@bou.shl.com
   17 
   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.
   26 
   27   ------------------
   28   Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers)
   29 
   30   wildcard  [option value][option value]...
   31 
   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
   35 
   36   and value is a single-quote delimited value.
   37 
   38   E.g:
   39   *.nib     -f 'gunzipuntar' -t 'targzip' -m 'COPY'
   40 */
   41 
   42 
   43 typedef struct {
   44     char *wildCard;
   45     char *tocvsFilter;
   46     char *fromcvsFilter;
   47     char *rcsOption;
   48     WrapMergeMethod mergeMethod;
   49 } WrapperEntry;
   50 
   51 static WrapperEntry **wrap_list=NULL;
   52 static WrapperEntry **wrap_saved_list=NULL;
   53 
   54 static int wrap_size=0;
   55 static int wrap_count=0;
   56 static int wrap_tempcount=0;
   57 
   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.
   65  *
   66  * Right now things seem to be working, but that's no guarantee there
   67  * isn't a bug lurking somewhere in the murk.
   68  */
   69 
   70 static int wrap_saved_count=0;
   71 
   72 static int wrap_saved_tempcount=0;
   73 
   74 #define WRAPPER_GROW    8
   75 
   76 void wrap_add_entry PROTO((WrapperEntry *e,int temp));
   77 void wrap_kill PROTO((void));
   78 void wrap_kill_temp PROTO((void));
   79 void wrap_free_entry PROTO((WrapperEntry *e));
   80 void wrap_free_entry_internal PROTO((WrapperEntry *e));
   81 void wrap_restore_saved PROTO((void));
   82 
   83 void wrap_setup()
   84 {
   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;
   89     char *homedir;
   90 
   91     if (wrap_setup_already_done != 0)
   92         return;
   93     else
   94         wrap_setup_already_done = 1;
   95 
   96     if (!current_parsed_root->isremote)
   97     {
   98     char *file;
   99 
  100     file = xmalloc (strlen (current_parsed_root->directory)
  101             + sizeof (CVSROOTADM)
  102             + sizeof (CVSROOTADM_WRAPPER)
  103             + 3);
  104     /* Then add entries found in repository, if it exists.  */
  105     (void) sprintf (file, "%s/%s/%s", current_parsed_root->directory, CVSROOTADM,
  106             CVSROOTADM_WRAPPER);
  107     if (isfile (file))
  108     {
  109         wrap_add_file(file,0);
  110     }
  111     free (file);
  112     }
  113 
  114     /* Then add entries found in home dir, (if user has one) and file
  115        exists.  */
  116     homedir = get_homedir ();
  117     /* If we can't find a home directory, ignore ~/.cvswrappers.  This may
  118        make tracking down problems a bit of a pain, but on the other
  119        hand it might be obnoxious to complain when CVS will function
  120        just fine without .cvswrappers (and many users won't even know what
  121        .cvswrappers is).  */
  122     if (homedir != NULL)
  123     {
  124     char *file = strcat_filename_onto_homedir (homedir, CVSDOTWRAPPER);
  125     if (isfile (file))
  126     {
  127         wrap_add_file (file, 0);
  128     }
  129     free (file);
  130     }
  131 
  132     /* FIXME: calling wrap_add() below implies that the CVSWRAPPERS
  133      * environment variable contains exactly one "wrapper" -- a line
  134      * of the form
  135      * 
  136      *    FILENAME_PATTERN  FLAG  OPTS [ FLAG OPTS ...]
  137      *
  138      * This may disagree with the documentation, which states:
  139      * 
  140      *   `$CVSWRAPPERS'
  141      *      A whitespace-separated list of file name patterns that CVS
  142      *      should treat as wrappers. *Note Wrappers::.
  143      *
  144      * Does this mean the environment variable can hold multiple
  145      * wrappers lines?  If so, a single call to wrap_add() is
  146      * insufficient.
  147      */
  148 
  149     /* Then add entries found in CVSWRAPPERS environment variable. */
  150     wrap_add (getenv (WRAPPER_ENV), 0);
  151 }
  152 
  153 #ifdef CLIENT_SUPPORT
  154 /* Send -W arguments for the wrappers to the server.  The command must
  155    be one that accepts them (e.g. update, import).  */
  156 void
  157 wrap_send ()
  158 {
  159     int i;
  160 
  161     for (i = 0; i < wrap_count + wrap_tempcount; ++i)
  162     {
  163     if (wrap_list[i]->tocvsFilter != NULL
  164         || wrap_list[i]->fromcvsFilter != NULL)
  165         /* For greater studliness we would print the offending option
  166            and (more importantly) where we found it.  */
  167         error (0, 0, "\
  168 -t and -f wrapper options are not supported remotely; ignored");
  169     if (wrap_list[i]->mergeMethod == WRAP_COPY)
  170         /* For greater studliness we would print the offending option
  171            and (more importantly) where we found it.  */
  172         error (0, 0, "\
  173 -m wrapper option is not supported remotely; ignored");
  174     send_to_server ("Argument -W\012Argument ", 0);
  175     send_to_server (wrap_list[i]->wildCard, 0);
  176     send_to_server (" -k '", 0);
  177     if (wrap_list[i]->rcsOption != NULL)
  178         send_to_server (wrap_list[i]->rcsOption, 0);
  179     else
  180         send_to_server ("kv", 0);
  181     send_to_server ("'\012", 0);
  182     }
  183 }
  184 #endif /* CLIENT_SUPPORT */
  185 
  186 #if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT)
  187 /* Output wrapper entries in the format of cvswrappers lines.
  188  *
  189  * This is useful when one side of a client/server connection wants to
  190  * send its wrappers to the other; since the receiving side would like
  191  * to use wrap_add() to incorporate the wrapper, it's best if the
  192  * entry arrives in this format.
  193  *
  194  * The entries are stored in `line', which is allocated here.  Caller
  195  * can free() it.
  196  *
  197  * If first_call_p is nonzero, then start afresh.  */
  198 void
  199 wrap_unparse_rcs_options (line, first_call_p)
  200     char **line;
  201     int first_call_p;
  202 {
  203     /* FIXME-reentrancy: we should design a reentrant interface, like
  204        a callback which gets handed each wrapper (a multithreaded
  205        server being the most concrete reason for this, but the
  206        non-reentrant interface is fairly unnecessary/ugly).  */
  207     static int i;
  208 
  209     if (first_call_p)
  210         i = 0;
  211 
  212     if (i >= wrap_count + wrap_tempcount) {
  213         *line = NULL;
  214         return;
  215     }
  216 
  217     *line = xmalloc (strlen (wrap_list[i]->wildCard)
  218                      + strlen ("\t")
  219                      + strlen (" -k '")
  220                      + (wrap_list[i]->rcsOption != NULL ? 
  221                            strlen (wrap_list[i]->rcsOption) : 2)
  222                      + strlen ("'")
  223                      + 1);  /* leave room for '\0' */
  224 
  225     strcpy (*line, wrap_list[i]->wildCard);
  226     strcat (*line, " -k '");
  227     if (wrap_list[i]->rcsOption != NULL)
  228         strcat (*line, wrap_list[i]->rcsOption);
  229     else
  230         strcat (*line, "kv");
  231     strcat (*line, "'");
  232 
  233     ++i;
  234 }
  235 #endif /* SERVER_SUPPORT || CLIENT_SUPPORT */
  236 
  237 /*
  238  * Remove fmt str specifier other than %% or %s. And allow
  239  * only max_s %s specifiers
  240  */
  241 void
  242 wrap_clean_fmt_str(char *fmt, int max_s)
  243 {
  244     while (*fmt) {
  245     if (fmt[0] == '%' && fmt[1])
  246     {
  247         if (fmt[1] == '%') 
  248         fmt++;
  249         else
  250         if (fmt[1] == 's' && max_s > 0)
  251         {
  252             max_s--;
  253             fmt++;
  254         } else 
  255             *fmt = ' ';
  256     }
  257     fmt++;
  258     }
  259 }
  260 
  261 /*
  262  * Open a file and read lines, feeding each line to a line parser. Arrange
  263  * for keeping a temporary list of wrappers at the end, if the "temp"
  264  * argument is set.
  265  */
  266 void
  267 wrap_add_file (file, temp)
  268     const char *file;
  269     int temp;
  270 {
  271     FILE *fp;
  272     char *line = NULL;
  273     size_t line_allocated = 0;
  274 
  275     wrap_restore_saved ();
  276     wrap_kill_temp ();
  277 
  278     /* Load the file.  */
  279     errno = 0; /* Standard C doesn't require errno be set on error */
  280     fp = CVS_FOPEN (file, "r");
  281     if (fp == NULL)
  282     {
  283     if (!existence_error (errno))
  284         error (0, errno, "cannot open %s", file);
  285     return;
  286     }
  287     while (getline (&line, &line_allocated, fp) >= 0)
  288     wrap_add (line, temp);
  289     if (line)
  290         free (line);
  291     if (ferror (fp))
  292     error (0, errno, "cannot read %s", file);
  293     if (fclose (fp) == EOF)
  294     error (0, errno, "cannot close %s", file);
  295 }
  296 
  297 void
  298 wrap_kill()
  299 {
  300     wrap_kill_temp();
  301     while(wrap_count)
  302     wrap_free_entry(wrap_list[--wrap_count]);
  303 }
  304 
  305 void
  306 wrap_kill_temp()
  307 {
  308     WrapperEntry **temps=wrap_list+wrap_count;
  309 
  310     while(wrap_tempcount)
  311     wrap_free_entry(temps[--wrap_tempcount]);
  312 }
  313 
  314 void
  315 wrap_free_entry(e)
  316      WrapperEntry *e;
  317 {
  318     wrap_free_entry_internal(e);
  319     free(e);
  320 }
  321 
  322 void
  323 wrap_free_entry_internal(e)
  324     WrapperEntry *e;
  325 {
  326     free (e->wildCard);
  327     if (e->tocvsFilter)
  328     free (e->tocvsFilter);
  329     if (e->fromcvsFilter)
  330     free (e->fromcvsFilter);
  331     if (e->rcsOption)
  332     free (e->rcsOption);
  333 }
  334 
  335 void
  336 wrap_restore_saved()
  337 {
  338     if(!wrap_saved_list)
  339     return;
  340 
  341     wrap_kill();
  342 
  343     free(wrap_list);
  344 
  345     wrap_list=wrap_saved_list;
  346     wrap_count=wrap_saved_count;
  347     wrap_tempcount=wrap_saved_tempcount;
  348 
  349     wrap_saved_list=NULL;
  350     wrap_saved_count=0;
  351     wrap_saved_tempcount=0;
  352 }
  353 
  354 void
  355 wrap_add (line, isTemp)
  356    char *line;
  357    int         isTemp;
  358 {
  359     char *temp;
  360     char ctemp;
  361     WrapperEntry e;
  362     char opt;
  363 
  364     if (!line || line[0] == '#')
  365     return;
  366 
  367     memset (&e, 0, sizeof(e));
  368 
  369     /* Search for the wild card */
  370     while (*line && isspace ((unsigned char) *line))
  371     ++line;
  372     for (temp = line;
  373      *line && !isspace ((unsigned char) *line);
  374      ++line)
  375     ;
  376     if(temp==line)
  377     return;
  378 
  379     ctemp=*line;
  380     *line='\0';
  381 
  382     e.wildCard=xstrdup(temp);
  383     *line=ctemp;
  384 
  385     while(*line){
  386         /* Search for the option */
  387     while(*line && *line!='-')
  388         ++line;
  389     if(!*line)
  390         break;
  391     ++line;
  392     if(!*line)
  393         break;
  394     opt=*line;
  395 
  396         /* Search for the filter commandline */
  397     for(++line;*line && *line!='\'';++line);
  398     if(!*line)
  399         break;
  400 
  401     for(temp=++line;*line && (*line!='\'' || line[-1]=='\\');++line)
  402         ;
  403 
  404     /* This used to "break;" (ignore the option) if there was a
  405        single character between the single quotes (I'm guessing
  406        that was accidental).  Now it "break;"s if there are no
  407        characters.  I'm not sure either behavior is particularly
  408        necessary--the current options might not require ''
  409        arguments, but surely some future option legitimately
  410        might.  Also I'm not sure that ignoring the option is a
  411        swift way to handle syntax errors in general.  */
  412     if (line==temp)
  413         break;
  414 
  415     ctemp=*line;
  416     *line='\0';
  417     switch(opt){
  418     case 'f':
  419         /* Before this is reenabled, need to address the problem in
  420            commit.c (see
  421            http://ximbiot.com/cvs/cvshome/docs/infowrapper.html).  */
  422         error (1, 0,
  423            "-t/-f wrappers not supported by this version of CVS");
  424 
  425         if(e.fromcvsFilter)
  426         free(e.fromcvsFilter);
  427         /* FIXME: error message should say where the bad value
  428            came from.  */
  429         e.fromcvsFilter=expand_path (temp, "<wrapper>", 0);
  430             if (!e.fromcvsFilter)
  431         error (1, 0, "Correct above errors first");
  432         break;
  433     case 't':
  434         /* Before this is reenabled, need to address the problem in
  435            commit.c (see
  436            http://ximbiot.com/cvs/cvshome/docs/infowrapper.html).  */
  437         error (1, 0,
  438            "-t/-f wrappers not supported by this version of CVS");
  439 
  440         if(e.tocvsFilter)
  441         free(e.tocvsFilter);
  442         /* FIXME: error message should say where the bad value
  443            came from.  */
  444         e.tocvsFilter=expand_path (temp, "<wrapper>", 0);
  445             if (!e.tocvsFilter)
  446         error (1, 0, "Correct above errors first");
  447         break;
  448     case 'm':
  449         if(*temp=='C' || *temp=='c')
  450         e.mergeMethod=WRAP_COPY;
  451         else
  452         e.mergeMethod=WRAP_MERGE;
  453         break;
  454     case 'k':
  455         if (e.rcsOption)
  456         free (e.rcsOption);
  457         e.rcsOption = strcmp (temp, "kv") ? xstrdup (temp) : NULL;
  458         break;
  459     default:
  460         break;
  461     }
  462     *line=ctemp;
  463     if(!*line)break;
  464     ++line;
  465     }
  466 
  467     wrap_add_entry(&e, isTemp);
  468 }
  469 
  470 void
  471 wrap_add_entry(e, temp)
  472     WrapperEntry *e;
  473     int temp;
  474 {
  475     int x;
  476     if(wrap_count+wrap_tempcount>=wrap_size){
  477     wrap_size += WRAPPER_GROW;
  478     wrap_list = (WrapperEntry **) xrealloc ((char *) wrap_list,
  479                         wrap_size *
  480                         sizeof (WrapperEntry *));
  481     }
  482 
  483     if(!temp && wrap_tempcount){
  484     for(x=wrap_count+wrap_tempcount-1;x>=wrap_count;--x)
  485         wrap_list[x+1]=wrap_list[x];
  486     }
  487 
  488     x=(temp ? wrap_count+(wrap_tempcount++):(wrap_count++));
  489     wrap_list[x]=(WrapperEntry *)xmalloc(sizeof(WrapperEntry));
  490     *wrap_list[x]=*e;
  491 }
  492 
  493 /* Return 1 if the given filename is a wrapper filename */
  494 int
  495 wrap_name_has (name,has)
  496     const char   *name;
  497     WrapMergeHas  has;
  498 {
  499     int x,count=wrap_count+wrap_tempcount;
  500     char *temp;
  501 
  502     for(x=0;x<count;++x)
  503     if (CVS_FNMATCH (wrap_list[x]->wildCard, name, 0) == 0){
  504         switch(has){
  505         case WRAP_TOCVS:
  506         temp=wrap_list[x]->tocvsFilter;
  507         break;
  508         case WRAP_FROMCVS:
  509         temp=wrap_list[x]->fromcvsFilter;
  510         break;
  511         case WRAP_RCSOPTION:
  512         temp = wrap_list[x]->rcsOption;
  513         break;
  514         default:
  515             abort ();
  516         }
  517         if(temp==NULL)
  518         return (0);
  519         else
  520         return (1);
  521     }
  522     return (0);
  523 }
  524 
  525 static WrapperEntry *wrap_matching_entry PROTO ((const char *));
  526 
  527 static WrapperEntry *
  528 wrap_matching_entry (name)
  529     const char *name;
  530 {
  531     int x,count=wrap_count+wrap_tempcount;
  532 
  533     for(x=0;x<count;++x)
  534     if (CVS_FNMATCH (wrap_list[x]->wildCard, name, 0) == 0)
  535         return wrap_list[x];
  536     return (WrapperEntry *)NULL;
  537 }
  538 
  539 /* Return the RCS options for FILENAME in a newly malloc'd string.  If
  540    ASFLAG, then include "-k" at the beginning (e.g. "-kb"), otherwise
  541    just give the option itself (e.g. "b").  */
  542 char *
  543 wrap_rcsoption (filename, asflag)
  544     const char *filename;
  545     int asflag;
  546 {
  547     WrapperEntry *e = wrap_matching_entry (filename);
  548     char *buf;
  549 
  550     if (e == NULL || e->rcsOption == NULL || (*e->rcsOption == '\0'))
  551     return NULL;
  552 
  553     buf = xmalloc (strlen (e->rcsOption) + 3);
  554     if (asflag)
  555     {
  556     strcpy (buf, "-k");
  557     strcat (buf, e->rcsOption);
  558     }
  559     else
  560     {
  561     strcpy (buf, e->rcsOption);
  562     }
  563     return buf;
  564 }
  565 
  566 char *
  567 wrap_tocvs_process_file(fileName)
  568     const char *fileName;
  569 {
  570     WrapperEntry *e=wrap_matching_entry(fileName);
  571     static char *buf = NULL;
  572     char *args;
  573 
  574     if(e==NULL || e->tocvsFilter==NULL)
  575     return NULL;
  576 
  577     if (buf != NULL)
  578     free (buf);
  579     buf = cvs_temp_name ();
  580 
  581     args = xmalloc (strlen (e->tocvsFilter)
  582             + strlen (fileName)
  583             + strlen (buf));
  584 
  585     wrap_clean_fmt_str(e->tocvsFilter, 2);
  586     sprintf (args, e->tocvsFilter, fileName, buf);
  587     run_setup (args);
  588     run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY );
  589     free (args);
  590 
  591     return buf;
  592 }
  593 
  594 int
  595 wrap_merge_is_copy (fileName)
  596     const char *fileName;
  597 {
  598     WrapperEntry *e=wrap_matching_entry(fileName);
  599     if(e==NULL || e->mergeMethod==WRAP_MERGE)
  600     return 0;
  601 
  602     return 1;
  603 }
  604 
  605 void
  606 wrap_fromcvs_process_file(fileName)
  607     const char *fileName;
  608 {
  609     char *args;
  610     WrapperEntry *e=wrap_matching_entry(fileName);
  611 
  612     if(e==NULL || e->fromcvsFilter==NULL)
  613     return;
  614 
  615     args = xmalloc (strlen (e->fromcvsFilter)
  616             + strlen (fileName));
  617 
  618     wrap_clean_fmt_str(e->fromcvsFilter, 1);
  619     sprintf (args, e->fromcvsFilter, fileName);
  620     run_setup (args);
  621     run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL );
  622     free (args);
  623     return;
  624 }