200 lines
3.4 KiB
C++
200 lines
3.4 KiB
C++
// 21 may 2018
|
|
#ifdef _WIN32
|
|
#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
|
|
#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 1
|
|
#include <io.h>
|
|
#include <sys/stat.h>
|
|
#define openfunc _open
|
|
#define openflags (_O_RDONLY | _O_BINARY)
|
|
#define openmode (_S_IREAD)
|
|
#define readfunc _read
|
|
#define readtype int
|
|
#define closefunc _close
|
|
#else
|
|
#endif
|
|
#include <typeinfo>
|
|
#include <algorithm>
|
|
#include "lib.hpp"
|
|
|
|
class eofError : public Error {
|
|
public:
|
|
virtual ~eofError(void);
|
|
|
|
virtual const char *String(void) const;
|
|
};
|
|
|
|
eofError::~eofError(void)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
const char *eofError::String(void) const
|
|
{
|
|
return "EOF";
|
|
}
|
|
|
|
class shortWriteError : public Error {
|
|
public:
|
|
virtual ~shortWriteError(void);
|
|
|
|
virtual const char *String(void) const;
|
|
};
|
|
|
|
shortWriteError::~shortWriteError(void)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
const char *shortWriteError::String(void) const
|
|
{
|
|
return "short write";
|
|
}
|
|
|
|
Error *NewEOF(void)
|
|
{
|
|
return new eofError;
|
|
}
|
|
|
|
Error *NewErrShortWrite(void)
|
|
{
|
|
return new shortWriteError;
|
|
}
|
|
|
|
bool IsEOF(Error *e)
|
|
{
|
|
// typeid does not work directly with pointers, alas (see https://stackoverflow.com/questions/4202877/typeid-for-polymorphic-types)
|
|
return typeid (*e) == typeid (eofError);
|
|
}
|
|
|
|
Error *WriteVector(WriteCloser *w, std::vector<char> *v)
|
|
{
|
|
return w->Write(v->data(), v->size());
|
|
}
|
|
|
|
#define nbuf 1024
|
|
|
|
Scanner::Scanner(ReadCloser *r)
|
|
{
|
|
this->r = r;
|
|
this->buf = new char[nbuf];
|
|
this->p = this->buf;
|
|
this->n = 0;
|
|
this->line = new std::vector<char>;
|
|
this->err = NULL;
|
|
}
|
|
|
|
Scanner::~Scanner(void)
|
|
{
|
|
if (this->err != NULL)
|
|
delete this->err;
|
|
delete this->line;
|
|
delete[] this->buf;
|
|
}
|
|
|
|
bool Scanner::Scan(void)
|
|
{
|
|
size_t n;
|
|
|
|
if (this->err != NULL)
|
|
return false;
|
|
this->line->clear();
|
|
for (;;) {
|
|
if (this->n > 0) {
|
|
size_t j;
|
|
bool haveline;
|
|
|
|
haveline = false;
|
|
for (j = 0; j < this->n; j++)
|
|
if (this->p[j] == '\n') {
|
|
haveline = true;
|
|
break;
|
|
}
|
|
this->line->insert(this->line->end(), this->p, this->p + j);
|
|
this->p += j;
|
|
this->n -= j;
|
|
if (haveline) {
|
|
// swallow the \n for the next time through
|
|
this->p++;
|
|
this->n--;
|
|
return true;
|
|
}
|
|
// otherwise, the buffer was exhausted in the middle of a line, so fall through
|
|
}
|
|
// need to refill the buffer
|
|
this->err = this->r->Read(this->buf, nbuf * sizeof (char), &n);
|
|
if (this->err != NULL)
|
|
return false;
|
|
this->p = this->buf;
|
|
this->n = n;
|
|
}
|
|
}
|
|
|
|
const char *Scanner::Bytes(void) const
|
|
{
|
|
return this->line->data();
|
|
}
|
|
|
|
size_t Scanner::Len(void) const
|
|
{
|
|
return this->line->size();
|
|
}
|
|
|
|
Error *Scanner::Err(void) const
|
|
{
|
|
if (!IsEOF(this->err))
|
|
return this->err;
|
|
return NULL;
|
|
}
|
|
|
|
Slice::Slice(const char *p, size_t n)
|
|
{
|
|
this->p = p;
|
|
this->n = n;
|
|
}
|
|
|
|
const char *Slice::Data(void) const
|
|
{
|
|
return this->p;
|
|
}
|
|
|
|
size_t Slice::Len(void) const
|
|
{
|
|
return this->n;
|
|
}
|
|
|
|
std::vector<Slice *> *TokenizeWhitespace(const char *buf, size_t n)
|
|
{
|
|
std::vector<Slice *> *ret;
|
|
const char *p, *q;
|
|
const char *end;
|
|
|
|
ret = new std::vector<Slice *>;
|
|
p = buf;
|
|
end = buf + n;
|
|
while (p < end) {
|
|
if (*p == ' ' || *p == '\t') {
|
|
p++;
|
|
continue;
|
|
}
|
|
for (q = p; q < end; q++)
|
|
if (*q == ' ' || *q == '\t')
|
|
break;
|
|
ret->push_back(new Slice(p, q - p));
|
|
p = q;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void FreeTokenized(std::vector<Slice *> *v)
|
|
{
|
|
std::for_each(v->begin(), v->end(), [](Slice *s) {
|
|
delete s;
|
|
});
|
|
delete v;
|
|
}
|
|
|
|
void AppendSlice(std::vector<char> *v, Slice *s)
|
|
{
|
|
v->insert(v->end(), s->Data(), s->Data() + s->Len());
|
|
}
|