1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
|
/*
# 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 */
|