2018-05-21 21:42:19 -05:00
|
|
|
// 21 may 2018
|
|
|
|
#include <vector>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2018-05-22 20:03:54 -05:00
|
|
|
class Scanner {
|
|
|
|
FILE *fin;
|
|
|
|
char *buf;
|
|
|
|
const char *p;
|
|
|
|
size_t n;
|
|
|
|
std::vector<char> *line;
|
|
|
|
bool eof;
|
2018-05-21 21:42:19 -05:00
|
|
|
bool error;
|
2018-05-22 20:03:54 -05:00
|
|
|
public:
|
|
|
|
Scanner(FILE *fin);
|
|
|
|
~Scanner(void);
|
|
|
|
|
|
|
|
bool Scan(void);
|
2018-05-22 20:19:54 -05:00
|
|
|
const char *Bytes(void) const;
|
|
|
|
size_t Len(void) const;
|
2018-05-22 20:03:54 -05:00
|
|
|
bool Error(void) const;
|
2018-05-21 21:42:19 -05:00
|
|
|
};
|
|
|
|
|
2018-05-22 20:03:54 -05:00
|
|
|
#define nbuf 1024
|
|
|
|
|
|
|
|
Scanner::Scanner(FILE *fin)
|
2018-05-21 21:42:19 -05:00
|
|
|
{
|
2018-05-22 20:03:54 -05:00
|
|
|
this->fin = fin;
|
|
|
|
this->buf = new char[nbuf];
|
|
|
|
this->p = this->buf;
|
|
|
|
this->n = 0;
|
|
|
|
this->line = new std::vector<char>;
|
|
|
|
this->eof = false;
|
|
|
|
this->error = false;
|
2018-05-21 21:42:19 -05:00
|
|
|
}
|
|
|
|
|
2018-05-22 20:03:54 -05:00
|
|
|
Scanner::~Scanner(void)
|
2018-05-21 21:42:19 -05:00
|
|
|
{
|
2018-05-22 20:03:54 -05:00
|
|
|
delete this->line;
|
|
|
|
delete[] this->buf;
|
2018-05-21 21:42:19 -05:00
|
|
|
}
|
|
|
|
|
2018-05-22 20:03:54 -05:00
|
|
|
bool Scanner::Scan(void)
|
2018-05-21 21:42:19 -05:00
|
|
|
{
|
2018-05-22 20:03:54 -05:00
|
|
|
if (this->eof || this->error)
|
|
|
|
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
|
2018-05-21 21:42:19 -05:00
|
|
|
}
|
2018-05-22 20:03:54 -05:00
|
|
|
// need to refill the buffer
|
|
|
|
this->n = fread(this->buf, sizeof (char), nbuf, this->fin);
|
|
|
|
if (this->n < nbuf) {
|
|
|
|
// TODO what if this->eof && this->error? the C standard does not expressly disallow this
|
|
|
|
this->eof = feof(this->fin) != 0;
|
|
|
|
this->error = ferror(this->fin) != 0;
|
|
|
|
if (this->eof || this->error)
|
|
|
|
return false;
|
|
|
|
// otherwise process this last chunk of the file
|
|
|
|
}
|
|
|
|
this->p = this->buf;
|
2018-05-21 21:42:19 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-22 20:19:54 -05:00
|
|
|
const char *Scanner::Bytes(void) const
|
2018-05-21 21:42:19 -05:00
|
|
|
{
|
2018-05-22 20:19:54 -05:00
|
|
|
return this->line->data();
|
2018-05-21 21:42:19 -05:00
|
|
|
}
|
|
|
|
|
2018-05-22 20:19:54 -05:00
|
|
|
size_t Scanner::Len(void) const
|
2018-05-21 21:42:19 -05:00
|
|
|
{
|
2018-05-22 20:19:54 -05:00
|
|
|
return this->line->size();
|
2018-05-21 21:42:19 -05:00
|
|
|
}
|
|
|
|
|
2018-05-22 20:03:54 -05:00
|
|
|
bool Scanner::Error(void) const
|
2018-05-21 21:42:19 -05:00
|
|
|
{
|
2018-05-22 20:03:54 -05:00
|
|
|
return this->error;
|
2018-05-21 21:42:19 -05:00
|
|
|
}
|
|
|
|
|
2018-05-22 20:19:54 -05:00
|
|
|
bool generate(const char *line, size_t n, FILE *fout)
|
|
|
|
{
|
|
|
|
std::vector<char> genout;
|
|
|
|
size_t nw;
|
|
|
|
|
|
|
|
genout.push_back('/');
|
|
|
|
genout.push_back('/');
|
|
|
|
genout.push_back(' ');
|
|
|
|
genout.insert(genout.end(), line, line + n);
|
|
|
|
genout.push_back('\n');
|
|
|
|
|
|
|
|
genout.push_back('\n');
|
|
|
|
nw = fwrite(genout.data(), sizeof (char), genout.size(), fout);
|
|
|
|
return nw == genout.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool process(const char *line, size_t n, FILE *fout)
|
|
|
|
{
|
|
|
|
size_t nw;
|
|
|
|
|
|
|
|
if (n > 0 && line[0] == '@')
|
|
|
|
return generate(line + 1, n - 1, fout);
|
|
|
|
nw = fwrite(line, sizeof (char), n, fout);
|
|
|
|
if (nw != n)
|
|
|
|
return false;
|
|
|
|
return fwrite("\n", sizeof (char), 1, fout) == 1;
|
|
|
|
}
|
|
|
|
|
2018-05-21 21:42:19 -05:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
FILE *fin = NULL, *fout = NULL;
|
2018-05-22 20:19:54 -05:00
|
|
|
Scanner *s = NULL;
|
2018-05-21 21:42:19 -05:00
|
|
|
int ret = 1;
|
|
|
|
|
|
|
|
if (argc != 3) {
|
|
|
|
fprintf(stderr, "usage: %s infile outfile\n", argv[0]);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fin = fopen(argv[1], "rb");
|
|
|
|
if (fin == NULL) {
|
|
|
|
fprintf(stderr, "error opening %s\n", argv[1]);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
fout = fopen(argv[2], "wb");
|
|
|
|
if (fout == NULL) {
|
|
|
|
fprintf(stderr, "error creating %s\n", argv[2]);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2018-05-22 20:19:54 -05:00
|
|
|
s = new Scanner(fin);
|
|
|
|
while (s->Scan()) {
|
|
|
|
const char *line;
|
|
|
|
size_t n;
|
|
|
|
|
|
|
|
line = s->Bytes();
|
|
|
|
n = s->Len();
|
|
|
|
if (!process(line, n, fout)) {
|
2018-05-21 21:42:19 -05:00
|
|
|
fprintf(stderr, "error writing to %s\n", argv[2]);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
2018-05-22 20:19:54 -05:00
|
|
|
if (s->Error()) {
|
2018-05-21 21:42:19 -05:00
|
|
|
fprintf(stderr, "error reading from %s\n", argv[1]);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
done:
|
2018-05-22 20:19:54 -05:00
|
|
|
if (s != NULL)
|
|
|
|
delete s;
|
2018-05-21 21:42:19 -05:00
|
|
|
if (fout != NULL)
|
|
|
|
fclose(fout);
|
2018-05-22 20:19:54 -05:00
|
|
|
if (fin != NULL)
|
|
|
|
fclose(fin);
|
2018-05-21 21:42:19 -05:00
|
|
|
return ret;
|
|
|
|
}
|