A class that keeps track of lines and columns in a text file. I use it in a parser so that when an error occurs, I can print out the line and column at which it occured.
Here's line col.hpp
#ifndef line_col_hpp
#define line_col_hpp
#include <cctype>
#include <cstdio>
#include <cassert>
///Keeps track of lines and columns in text.
///Great for writing error messages in parsers
class LineCol {
public:
using LineType = unsigned int;
using ColType = unsigned int;
static const ColType SIZE_OF_TAB = 8;
static const LineType FIRST_LINE = 1;
static const ColType FIRST_COL = 1;
explicit LineCol(LineType line = FIRST_LINE,
ColType col = FIRST_COL);
///Move line and col according to the char.
///Call this at the end of the loop with the char you just processed
void update(char);
///This calls update(char) for each char in the null terminated string
void update(const char *);
///This calls update(char) for the first n chars in the string
void update(const char *, size_t);
///Sets line to FIRST_LINE and col to FIRST_COL
void reset();
LineType getLine() const;
ColType getCol() const;
const char *getStr() const;
private:
LineType line;
ColType col;
};
#endif
Here's line col.cpp
#include "line col.hpp"
LineCol::LineCol(LineType line, ColType col)
: line(line), col(col) {
assert(line >= FIRST_LINE);
assert(col >= FIRST_COL);
}
void LineCol::update(char c) {
switch (c) {
case '\t':
col += SIZE_OF_TAB;
break;
case '\n':
line++;
col = FIRST_COL;
break;
//vertical tab and form feed do the same thing on my system
case '\v':
case '\f':
line++;
break;
case '\r':
col = FIRST_COL;
break;
case '\b':
//backspace doesn't move up lines
//when backspacing tabs it treats them as spaces so it only
//moves back one char
if (col != FIRST_COL) {
col--;
}
//i don't have to put a break here but should I even though we'll
//fallthrough to another break?
case '\0':
case EOF:
break;
default:
if (std::isprint(c)) {
col++;
}
}
}
void LineCol::update(const char *str) {
assert(str);
while (*str) {
update(*str);
str++;
}
}
void LineCol::update(const char *str, size_t size) {
assert(str);
while (size) {
update(*str);
str++;
size--;
}
}
void LineCol::reset() {
line = FIRST_LINE;
col = FIRST_COL;
}
LineCol::LineType LineCol::getLine() const {
return line;
}
LineCol::ColType LineCol::getCol() const {
return col;
}
const char *LineCol::getStr() const {
//The largest 64 bit integer value is 18446744073709551615 which is
//20 characters. 20 + ':' + 20 + '\0' = 42
static char str[42];
std::snprintf(str, 42, "%u:%u", line, col);
return str;
}
Heres an example of how the class is used.
const char *buf;
size_t size;
LineCol lc;
for (const char *c = buf; c < buf + size; c++) {
//do stuff with the character
//maybe print lc.getStr()
lc.update(*c);
}
How could this be improved? Are there any special characters that I've missed?