Files
mlpack/fastlib/file/textfile.h
T
2007-03-26 04:56:04 +00:00

385 lines
7.0 KiB
C++

// Copyright 2007 Georgia Institute of Technology. All rights reserved.
// ABSOLUTELY NOT FOR DISTRIBUTION
/**
* @file textfile.h
*
* Small wrappers for text files.
* The most useful thing here is the ReadLine function.
*/
#ifndef FILE_TEXTFILE_H
#define FILE_TEXTFILE_H
#include "base/common.h"
#include "col/string.h"
#include <cstdio>
#include <ctype.h>
#include <stdarg.h>
/**
* Helper for reading text files.
*
* Files are closed automatically when they fall out of scope, though
* you may choose to close it yourself at no harm.
*/
class TextLineReader {
FORBID_COPY(TextLineReader);
private:
FILE *f_;
String line_;
int line_num_;
bool has_line_;
public:
/** Creates an unitialized object. */
TextLineReader() {
f_ = NULL;
}
/**
* Automatically closes the file.
*/
~TextLineReader() {
if (f_) {
::fclose(f_);
}
}
/**
* Opens a file.
*
* @return success value
*/
success_t Open(const char *fname);
/**
* Closes the file.
*
* (No need for a return value since you are only reading the file.)
*/
void Close() {
(void)fclose(f_);
f_ = NULL;
}
/**
* Are there more lines left?
*/
bool MoreLines() {
return has_line_;
}
int line_num() const {
return line_num_;
}
/**
* Gets the current line.
*/
String& Peek() {
return line_;
}
/**
* Gets the current line.
*/
const String& Peek() const {
return line_;
}
/**
* Tries to read one line from a file.
*
* @param result the string
* @return true if a line was returned, false if end of file
*/
bool Gobble();
/**
* Prints a formatted error message with line number info.
*/
COMPILER_PRINTF(2, 3)
void Error(const char *msg, ...);
private:
char *ReadLine_();
};
/**
* Simple text tokenizer.
*
* This tokenizes the input stream. It will identify the general type of
* token, and ignore whitespace and different kinds of comments.
*
* This has the concept of 'next' token which you can peek at, and the
* current token. The current token is always initialized to empty at
* the very beginning, because you are encouraged to peek ahead one token.
*
* Example:
*
* @code
* TextTokenizer tokenizer;
* tokenizer.Open("file.txt");
*
* if (tokenizer->Match("count")) {
* if (tokenizer->Match(TextTokenizer::INTEGER)) {
* printf("Found number: %d\n", atoi(tokenizer->Current()));
* } else { Error(); }
* } else { Error(); }
* @endcode
*/
class TextTokenizer {
FORBID_COPY(TextTokenizer);
public:
enum TokenType {
INVALID = -1,
END,
PUNCT,
IDENTIFIER,
STRING,
DOUBLE,
INTEGER
};
enum Features {
WANT_NEWLINE = 0x01
};
private:
FILE *f_;
String next_;
TokenType next_type_;
String cur_;
TokenType cur_type_;
const char *comment_start_;
const char *ident_extra_;
int features_;
int line_;
public:
TextTokenizer() {
f_ = NULL;
}
~TextTokenizer() {
if (unlikely(f_ != NULL)) {
(void) fclose(f_);
}
DEBUG_POISON_PTR(f_);
}
success_t Open(const char *fname,
const char *comment_chars = "", const char *ident_extra = "",
int features = 0);
const String& Peek() const {
return next_;
}
TokenType PeekType() const {
return next_type_;
}
const String& Current() const {
return cur_;
}
TokenType CurrentType() const {
return cur_type_;
}
void Gobble();
bool MoreTokens() const {
return next_type_ != END;
}
bool Match(const char *exact) {
if (next_ == exact) {
Gobble();
return true;
} else {
return false;
}
}
bool MatchNoCase(const char *str) {
if (next_.EqualsNoCase(str)) {
Gobble();
return true;
} else {
return false;
}
}
bool MatchInteger() {
return MatchType(INTEGER);
}
bool MatchDouble() {
return MatchType(DOUBLE);
}
bool MatchNumber() {
return MatchInteger() || MatchDouble();
}
bool MatchIdentifier() {
return MatchType(IDENTIFIER);
}
bool MatchQuasiIdentifier() {
return MatchIdentifier() || MatchNumber();
}
bool MatchString() {
return MatchType(STRING);
}
bool MatchPunct() {
return MatchType(PUNCT);
}
bool MatchType(TokenType type) {
if (next_type_ == type) {
Gobble();
return true;
} else {
return false;
}
}
int line() const {
return line_;
}
COMPILER_PRINTF(2, 3)
void Error(const char *msg, ...);
private:
int GetChar_() {
return ::getc(f_);
}
void Unget_(int c) {
::ungetc(c, f_);
}
bool IsEOF_() {
return ::feof(f_);
}
char Skip_(ArrayList<char> *token);
char NextChar_(ArrayList<char> *token);
char NextChar_();
void UndoNextChar_(ArrayList<char> *token);
void Error_(const char *msg, const ArrayList<char>& token);
bool isident_begin_(int c) const {
return isalpha(c) || unlikely(c == '_');
}
bool isident_rest_(int c) const {
return isalnum(c) || unlikely(c == '_') || (c != 0 && strchr(ident_extra_, c));
}
void ScanNumber_(char c, ArrayList<char> *token);
void ScanString_(char ending, ArrayList<char> *token);
void Scan_(ArrayList<char> *token);
};
/**
* Helper for writing text fo a file.
*/
class TextWriter {
FORBID_COPY(TextWriter);
private:
FILE *f_;
public:
/**
* Creates an uninitialized text writer (you must initialize it).
*/
TextWriter() {
f_ = NULL;
}
/**
* Automatically closes the file when it gets out of scope; for
* best error handling, you should call Close first.
*
* If you do not explicitly close the file beforehand, this will abort the
* program on a write error.
*/
~TextWriter() {
if (f_) {
ASSERT_PASS(::fclose(f_));
}
DEBUG_POISON_PTR(f_);
}
/**
* Opens a file by name (initializer).
*
* @return success or failure
*/
success_t Open(const char *fname) {
f_ = ::fopen(fname, "w");
return (unlikely(!f_)) ? SUCCESS_FAIL : SUCCESS_PASS;
}
/**
* Explicitly closes the file.
*/
success_t Close() {
int rv = fclose(f_);
f_ = NULL;
return unlikely(rv < 0) ? SUCCESS_FAIL : SUCCESS_PASS;
}
success_t Printf(const char *format, ...);
success_t Write(const char *s) {
return SUCCESS_FROM_INT(fputs(s, f_));
}
success_t Write(int i) {
return SUCCESS_FROM_INT(fprintf(f_, "%d", i));
}
success_t Write(unsigned int i) {
return SUCCESS_FROM_INT(fprintf(f_, "%u", i));
}
success_t Write(long i) {
return SUCCESS_FROM_INT(fprintf(f_, "%ld", i));
}
success_t Write(unsigned long i) {
return SUCCESS_FROM_INT(fprintf(f_, "%lu", i));
}
success_t Write(long long i) {
return SUCCESS_FROM_INT(fprintf(f_, "%lld", i));
}
success_t Write(unsigned long long i) {
return SUCCESS_FROM_INT(fprintf(f_, "%llu", i));
}
success_t Write(double d) {
return SUCCESS_FROM_INT(fprintf(f_, "%.15e", d));
}
};
#endif