Switch license from Intranator license to GPLv2 + linking exception (ACKed by Steffen)
[libi2ncommon] / src / logread.cpp
CommitLineData
0e23f538
TJ
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on this file might be covered by the GNU General Public License.
19*/
7113c4f0
TJ
20#include <stdlib.h>
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <unistd.h>
a74046f1 24#include <stdio.h>
7113c4f0
TJ
25
26#include <stdexcept>
27
28#include "logread.hxx"
29
30using namespace std;
31
32/// Constructor
33logread::logread(string filename, bool _goto_end)
34{
35 this->filename = filename;
36 reset();
37
38 if (_goto_end)
39 goto_end();
40}
41
42/// Reset line state engine
43void logread::reset()
44{
45 logsize = 0;
46 logsize_old = 0;
47
48 line.clear();
49 line_complete = false;
50}
51
52/// Skip initial content. Useful when parsing /var/log/messages
53void logread::goto_end()
54{
55 struct stat my_stat;
56 if (stat(filename.c_str(), &my_stat) == 0) {
57 logsize = my_stat.st_size;
58 logsize_old = logsize;
59 }
60}
61
62/// Main read loop
63void logread::read()
64{
65 // check if size changed
66 if (check_changed()) {
67 if (logsize > logsize_old) {
68 string logChanges = getLogChanges();
69
70 do {
71 extractSingeLine (logChanges);
72 line_complete == true ? processLine() : processUnfinishedLine();
73 } while (!logChanges.empty());
74 } else
75 reset(); // file got truncated
76
77 logsize_old = logsize;
78 }
79}
80
81/// Check if file is modified
82bool logread::check_changed()
83{
84 bool changed = false;
85
86 struct stat my_stat;
87 if (stat(filename.c_str(), &my_stat) == 0
88 && my_stat.st_size != logsize)
89 {
90 logsize = my_stat.st_size;
91 changed = true;
92 }
93
94 return changed;
95}
96
97/// Get changed content since last read
98string logread::getLogChanges()
99{
100 // open logfile
101 FILE *log = fopen (filename.c_str(), "r");
102 if (!log)
103 return "";
104
105 // read logfile
106 int size = logsize-logsize_old;
107
108 char *read_buffer = new char [size+1];
109 if (fseek (log, logsize_old, SEEK_SET) != 0)
110 throw runtime_error("can't seek in file " + filename);
111 fread (read_buffer, size, 1, log);
112 if (ferror(log))
113 throw runtime_error("error reading from file " + filename);
114 fclose (log);
115
116 read_buffer[size] = 0;
117 string changes(read_buffer);
118 delete[] read_buffer;
119
120 return changes;
121}
122
123/// Extract a single line from input buffer
124void logread::extractSingeLine(string &input)
125{
126 string::size_type rtn_pos, copysize;
127
128 // go to next line
129 if (line_complete) {
130 line_complete = false;
131 line.clear();
132 }
133
134 rtn_pos = input.find("\n", 0);
135
136 // complete line or even multi-line
137 if (rtn_pos != string::npos)
138 copysize = rtn_pos;
139 else
140 copysize = input.length();
141
142 line.append (input.c_str(), copysize);
143
144 // Erase data from the input buffer
145 if (rtn_pos == string::npos) // no return found
146 input.erase (0, copysize);
147 else {
148 // also erase the return
149 input.erase (0, copysize+1);
150 line_complete = true;
151 }
152}
153
154/** Short example
155
156#include <iostream>
157class logread_syslog : public logread
158{
159public:
160 logread_syslog() : logread("messages", false) {};
161
162 void processLine()
163 {
164 cout << "finished: " << line << endl;
165 }
166
167 void processUnfinishedLine()
168 {
169 cout << "unfinished: " << line << endl;
170 }
171};
172
173int main(void)
174{
175 logread_syslog messages;
176
177 while (1) {
178 messages.read();
179 sleep(1);
180 }
181
182 return 0;
183}
184*/