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

FileTokenizer.cpp

// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
// -- FileTokenizer.cpp --
// Copyright (c) 2001 - 2003 Jason 'vanRijn' Kasper <vR at movingparts dot net>
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// E_O_H_VR

#include "FileTokenizer.h"

static unsigned int keywordLookup(const KeywordMap& keys, const string& tag) {
    const KeywordMap::const_iterator it = keys.find(tag);
    if (it != keys.end())
        return it->second;
    return 0;
}


static char tabToSpace(char c) {
    if (c == '\t')
        return ' ';
    return c;
}


/* read a line into the string 'line', if it is continued then keep reading
 * until we have the whole line
 * returns the number of lines read and the line via the reference
 */
static unsigned int getFullLine(ifstream& file, string& line) {
    if (! file.good()) return 0;

    getline(file, line);
    unsigned int count = 1;
    while (file.good() && line[line.length() - 1] == '\\') {
        string tmp;
        getline(file, tmp);
        line.erase(line.length() - 1);
        line += tmp;
        ++count;
    }
    transform(line.begin(), line.end(), line.begin(), tabToSpace);
    return count;
}



FileTokenizer::FileTokenizer(const KeywordMap& keys, const char* fname,
                       TokenError errhandler): filename(fname),
                                         keywords(keys),
                                         error(errhandler),
                                         lineno(0l),
                                         state(WANT_TAG) {
    file.open(filename.c_str());

    if (! file.good()) {
        cerr << BBTOOL << ": " << "FileTokenizer::constructor: couldn't open file: [" << filename << "]" << endl;
    }
}


FileTokenizer::~FileTokenizer(void) {
    file.close();
}


TokenBlock* FileTokenizer::next(void) {
    string line;

 TOP:
    unsigned int count;
    if ((count = getFullLine(file, line)) == 0)
        return (TokenBlock*) 0;
    lineno += count;

    TokenBlock* block = new TokenBlock;
    block->lineno = lineno;

    string::size_type pos = 0, len = line.length();
    for (; state != WANT_NOTHING && pos < len; ++pos) {
        if (isspace(line[pos])) continue;

        if (state == WANT_TAG && line[pos] == '[') {
            string::size_type start = ++pos;
            while (pos < len && line[pos] != ']') ++pos; // no escapes allowed

            string tag(line, start, pos - start);
            transform(tag.begin(), tag.end(), tag.begin(), ::tolower);
            unsigned int value = keywordLookup(keywords, tag);
            if (value == 0) {
                if (! error(filename, "unknown tag: " + tag, lineno))
                    goto ERR_EXIT;
                goto TOP;
            }
            block->tag = value;
            state = WANT_NAME;
        } else if (state == WANT_NAME && line[pos] == '(') {
            string::size_type start = ++pos;
            while (pos < len && line[pos] != ')') {
                if (line[pos++] == '\\') ++pos;
            }

            block->name.assign(line, start, pos - start);
            state = WANT_DATA;
        } else if (state == WANT_DATA && line[pos] == '{') {
            string::size_type start = ++pos;
            while (pos < len && line[pos] != '}') {
                if (line[pos++] == '\\') ++pos;
            }

            block->data.assign(line, start, pos - start);
            state = WANT_NOTHING;
        } else {
            if (line[pos] != '#') { // this isn't a comment, complain
                const string e = "invalid input: " + string(line, pos, line.length());
                if (! error(filename, e, lineno))
                    goto ERR_EXIT;
            }
            break;
        }
    }
    if (state == WANT_TAG) {
        // we never found what we wanted, so let's get a new line and try again
        delete block;
        goto TOP;
    }

    state = WANT_TAG; // reset state for next call

    return block;

 ERR_EXIT:
    delete block;
    return (TokenBlock*) 0;
}


Generated by  Doxygen 1.6.0   Back to index