Logo Search packages:      
Sourcecode: viewcvs version File versions  Download package

tparse.h

/*
# Copyright (C) 2000-2002 The ViewCVS Group. All Rights Reserved.
# This file has been rewritten in C++ from the rcsparse.py file by
# Lucas Bruand <lucas.bruand@ecl2002.ec-lyon.fr>
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewCVS
# distribution or at http://viewcvs.sourceforge.net/license-1.html.
#
# Contact information:
#   Greg Stein, PO Box 760, Palo Alto, CA, 94302
#   gstein@lyra.org, http://viewcvs.sourceforge.net/
#
# -----------------------------------------------------------------------
#
# This software is being maintained as part of the ViewCVS project.
# Information is available at:
#    http://viewcvs.sourceforge.net/
#
# This file was originally based on portions of the blame.py script by
# Curt Hagenlocher.
#
# -----------------------------------------------------------------------
#
*/

/*
   This C++ library offers an API to a performance-oriented RCSFILE parser.
   It does little syntax checking.
 
   Version: $Id: tparse.h,v 1.7 2004/04/06 02:52:08 cmpilato Exp $
 */
#define CHUNK_SIZE 30000
#ifndef __PARSE_H
#define __PARSE_H
#include <iostream.h>
#include <strstream.h>
#include <stdio.h>
#include <fstream.h>
#include <string.h>
#include <stdlib.h>
#define delstr(a) if (a != NULL) { delete [] a; a=NULL; };

/* This class represents a exception that occured during the parsing
   of a file */
class RCSParseError
{
  public:
    char *value;
    RCSParseError() {};
    RCSParseError(char *myvalue)
    {
      value = myvalue;
    };
    char *getvalue()
    {
      return value;
    };
};

class RCSIllegalCharacter : public RCSParseError
{
  public:
    RCSIllegalCharacter(char *myvalue)
    {
      value = myvalue;
    };
};

class RCSExpected : public RCSParseError
{
  public:
    char *got;
    char *wanted;
    RCSExpected(char *mygot, char *mywanted)
    {
      got = mygot;
      wanted = mywanted;
    }
    char *getvalue()
    {
      ostrstream *out = new ostrstream();
      (*out) << "RCSExcepted: " << wanted << " Got: " << got << endl;
      out->put('\0');
      return out->str();
    };
};

/* This class is used to store a list of the branches of a revision */
class Branche
{
  public:
    char *name;
    Branche *next;
    Branche(char *myname, Branche *mynext)
    {
      name = myname;
      next = mynext;
    };
    ~Branche()
    {
      delstr(name);
      name = NULL;
      if (next != NULL)
        delete next;
      next = NULL;
    };
};

/* This class is a handler that receive the event generated by the parser
   i.e.: When we reach the head revision tag, etc... */
class Sink
{
  public:
    Sink() {};
    virtual int set_head_revision(char * revision) = 0;
    virtual int set_principal_branch(char *branch_name) = 0;
    virtual int define_tag(char *name, char *revision) = 0;
    virtual int set_comment(char *comment) = 0;
    virtual int set_description(char *description) = 0;
    virtual int define_revision(char *revision, long timestamp, 
                                char *author, char *state, 
                                Branche *branches, char *next) = 0;
    virtual int set_revision_info(char *revision, char *log, char *text) = 0;
    virtual int tree_completed() = 0;
    virtual int parse_completed() = 0;
};

/* The class is used to get one by one every token in the file. */
class TokenParser
{
  private:
    istream *input;
    char buf[CHUNK_SIZE];
    int buflength;
    int idx;
    char *backget;
  public:
    char *semicol;
    char *get();
    void unget(char *token);
    int eof()
    {
      return (input->gcount() == 0);
    };
    void matchsemicol()
    {
      char *ptr = get();
      if (ptr != semicol)
        throw RCSExpected(ptr, semicol);
    };
    void match(char *token)
    {
      char *ptr;
      if (strcmp(ptr = get(), token) != 0)
        throw RCSExpected(ptr, token);
      delstr( ptr);
    };
    TokenParser(istream *myinput)
    {
      input = myinput;
      backget = NULL;
      idx = 0;
      semicol = ";";
      input->read(buf, CHUNK_SIZE);
      if ( (buflength = input->gcount()) == 0 )
        throw RCSParseError("Non-existing file or empty file");
    };
    ~TokenParser()
    {
      if (input != NULL)
      {
        delete input;
        input = NULL;
      };
      if (backget != NULL)
      {
        delstr(backget);
        backget = NULL;
      };
    };
};

/* this is the class that does the actual job: by reading each part of
   the file and thus generate events to a sink event-handler*/
class tparseParser
{
  private:
    TokenParser *tokenstream;
    Sink *sink;
    int parse_rcs_admin();
    int parse_rcs_tree();
    int parse_rcs_description();
    int parse_rcs_deltatext();
  public:
    tparseParser(istream *myinput, Sink* mysink)
    {
      sink = mysink;
      tokenstream = new TokenParser(myinput);

      if (parse_rcs_admin())
        return;
      if (parse_rcs_tree())
        return;

      // many sinks want to know when the tree has been completed so they can
      // do some work to prepare for the arrival of the deltatext
      if (sink->tree_completed())
        return;

      if (parse_rcs_description())
        return;
      if (parse_rcs_deltatext())
        return;

      // easiest for us to tell the sink it is done, rather than worry about
      // higher level software doing it.
      if (sink->parse_completed())
        return;
    }
    ~tparseParser()
    {
      delete tokenstream;
      delete sink;
    }
};

#endif /* __PARSE_H */

Generated by  Doxygen 1.6.0   Back to index