#include "config.h" #include #include #include #include "rec.h" #define FIELD_TYPES \ FIELD(X, "x") \ FIELD(Y, "y") \ FIELD(State, "state") \ FIELD(Detail, "detail") \ FIELD(Window, "win") \ FIELD(Width, "w") \ FIELD(Height, "h") \ FIELD(Keysym, "keysym") const char *Record::get_field_name(FieldsType type) { #define FIELD(t,n) case t: return n; switch (type) { FIELD_TYPES } #undef FIELD return ""; } Record::FieldsType Record::get_field_type(const char *name) { #define FIELD(t,n) if (strcmp(name, n) == 0) return t; FIELD_TYPES #undef FIELD fprintf(stderr, "Invalid field type %s\n", name); exit(EXIT_FAILURE); } #define RECORD_TYPES \ RECORD(KeyDown, "key_down") \ RECORD(KeyUp, "key_up") \ RECORD(ButtonDown, "button_down") \ RECORD(ButtonUp, "button_up") \ RECORD(MouseMotion, "mouse_move") \ RECORD(WindowMove, "window_move") \ RECORD(TargetWindow, "target_window") const char *Record::get_record_name(RecordType type) { #define RECORD(t,n) case t: return n; switch (type) { RECORD_TYPES } #undef RECORD return ""; } Record::RecordType Record::get_record_type(const char *name) { #define RECORD(t,n) if (strcmp(name, n) == 0) return t; RECORD_TYPES #undef RECORD fprintf(stderr, "Invalid record type\n"); exit(EXIT_FAILURE); } RecordsFile::RecordsFile(FILE *_f): f(_f) { if (!f) { fprintf(stderr, "unable to open file\n"); exit(EXIT_FAILURE); } } ReadRecordsFile::ReadRecordsFile(const char *fn): RecordsFile(fopen(fn, "r")), eof(false) { get_line(); } #define SPACES " \t\v\r\n" void ReadRecordsFile::get_line() { if (eof) { fprintf(stderr, "trying to read past EOF\n"); exit(EXIT_FAILURE); } while (fgets(next_line, sizeof(next_line), f)) { const char *p = next_line; // skip initial spaces p += strspn(p, SPACES); // detect comments if (!*p || *p == '#') continue; // got line return; } if (!feof(f)) { fprintf (stderr, "error reading input file\n"); exit(EXIT_FAILURE); } eof = true; } Record ReadRecordsFile::get() { char *line = next_line; // skip initial spaces line += strspn(line, SPACES); // read time and command int got = 0; unsigned time; char cmd[64]; if (sscanf(line, "@%u %60[^" SPACES "]%n", &time, cmd, &got) < 2) { fprintf (stderr, "error reading time: %s\n", next_line); exit(EXIT_FAILURE); } Record::RecordType type = Record::get_record_type(cmd); Record rec(type, time); char *p = line + got; for (;;) { char field[64]; unsigned value; p += strspn(p, SPACES); if (!*p) break; got = 0; if (sscanf(p, "%60[^:]:%u%n", field, &value, &got) < 2 || got == 0) { fprintf(stderr, "expected a field: %s\n", next_line); exit(EXIT_FAILURE); } p += got; Record::FieldsType type = Record::get_field_type(field); rec.set_field(type, value); } get_line(); return rec; } WriteRecordsFile::WriteRecordsFile(const char *fn): RecordsFile(fopen(fn, "w")) { } void WriteRecordsFile::put(const Record &rec) { fprintf(f, "@%u %s", rec.get_time(), rec.get_record_name(rec.get_type())); for (unsigned n = 0; n < Record::MAX_FIELD; ++n) { Record::FieldsType type = (Record::FieldsType) n; if (!rec.has_field(type)) continue; fprintf(f, " %s:%u", rec.get_field_name(type), rec.get_field(type)); } fprintf(f, "\n"); }