1 /*
2     Copyright (c) 2009 Andrew Caudwell (acaudwell@gmail.com)
3     All rights reserved.
4 
5     Redistribution and use in source and binary forms, with or without
6     modification, are permitted provided that the following conditions
7     are met:
8     1. Redistributions of source code must retain the above copyright
9        notice, this list of conditions and the following disclaimer.
10     2. Redistributions in binary form must reproduce the above copyright
11        notice, this list of conditions and the following disclaimer in the
12        documentation and/or other materials provided with the distribution.
13     3. The name of the author may not be used to endorse or promote products
14        derived from this software without specific prior written permission.
15 
16     THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 
28 #include "seeklog.h"
29 #include "sdlapp.h"
30 
31 long long gSeekLogMaxBufferSize = 104857600;
32 
33 //StreamLog
34 
StreamLog()35 StreamLog::StreamLog() {
36     this->stream = &std::cin;
37 
38     fcntl_fail = false;
39 
40 #ifdef _WIN32
41     stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
42 #else
43     int ret = fcntl(STDIN_FILENO, F_GETFL, 0);
44 
45     if (fcntl (STDIN_FILENO, F_SETFL, ret | O_NONBLOCK) < 0) {
46         debugLog("fcntl(stdin) failed");
47         fcntl_fail = true;
48     }
49 #endif
50 }
51 
~StreamLog()52 StreamLog::~StreamLog() {
53 }
54 
getNextLine(std::string & line)55 bool StreamLog::getNextLine(std::string& line) {
56 
57     //try and fix the stream
58     if(isFinished()) stream->clear();
59 
60 #ifdef _WIN32
61 
62     DWORD available_bytes;
63 
64     if (!PeekNamedPipe(stdin_handle, 0, 0, 0,
65         &available_bytes, 0)) return false;
66 
67     if(available_bytes==0) return false;
68 
69 #endif
70 
71     std::getline(*stream, line);
72 
73     //remove carriage returns
74     if (line.size() > 0 && line[line.size()-1] == '\r') {
75         line.resize(line.size() - 1);
76     }
77 
78     if(isFinished()) {
79         return false;
80     }
81 
82     return true;
83 }
84 
isFinished()85 bool StreamLog::isFinished() {
86 
87     if(fcntl_fail || stream->fail() || stream->eof()) {
88         return true;
89     }
90 
91     return false;
92 }
93 
94 // SeekLog
95 
SeekLog(std::string logfile)96 SeekLog::SeekLog(std::string logfile) {
97     this->logfile = logfile;
98 
99     this->stream = 0;
100 
101     if(!readFully()) {
102         throw SeekLogException(logfile);
103     }
104 }
105 
readFully()106 bool SeekLog::readFully() {
107 
108     if(stream!=0) delete stream;
109 
110     std::ifstream* file = new std::ifstream(logfile.c_str(), std::ios::in | std::ios::binary | std::ios::ate);
111 
112     file_size = file->tellg();
113 
114     if(!file->is_open()) {
115         delete file;
116         return false;
117     }
118 
119     file->seekg (0, std::ios::beg);
120 
121     //dont load into memory if larger than
122     if(file_size > gSeekLogMaxBufferSize) {
123         stream = file;
124         return true;
125     }
126 
127 
128     //buffer entire file into memory
129     char* filebuffer = new char[file_size+1];
130 
131     if(!file->read(filebuffer, file_size)) {
132         file->close();
133         delete file;
134         delete [] filebuffer;
135         return false;
136     }
137     filebuffer[file_size] = '\0';
138 
139     file->close();
140     delete file;
141 
142     stream = new std::istringstream(std::string(filebuffer));
143 
144     delete[] filebuffer;
145 
146     return true;
147 }
148 
~SeekLog()149 SeekLog::~SeekLog() {
150     if(stream!=0) delete stream;
151 }
152 
getPercent()153 float SeekLog::getPercent() {
154     return current_percent;
155 }
156 
setPointer(std::streampos pointer)157 void SeekLog::setPointer(std::streampos pointer) {
158     stream->seekg(pointer);
159 }
160 
getPointer()161 std::streampos SeekLog::getPointer() {
162     return stream->tellg();
163 }
164 
seekTo(float percent)165 void SeekLog::seekTo(float percent) {
166 
167     if(isFinished()) stream->clear();
168 
169     std::streampos mem_offset = (std::streampos) (percent * file_size);
170 
171     setPointer(mem_offset);
172 
173     //throw away end of line
174     if(mem_offset != (std::streampos)0) {
175         std::string eol;
176         getNextLine(eol);
177     }
178 }
179 
getNextLine(std::string & line)180 bool SeekLog::getNextLine(std::string& line) {
181 
182     //try and fix the stream
183     if(isFinished()) stream->clear();
184 
185     std::getline(*stream, line);
186 
187     //remove carriage returns
188     if (line.size() > 0 && line[line.size()-1] == '\r') {
189         line.resize(line.size() - 1);
190     }
191 
192     if(stream->fail()) {
193         return false;
194     }
195 
196     current_percent = (float) stream->tellg() / file_size;
197     //debugLog("current_percent = %.2f\n", current_percent);
198 
199     return true;
200 }
201 
202 // temporarily move the file pointer to get a line somewhere else in the file
getNextLineAt(std::string & line,float percent)203 bool SeekLog::getNextLineAt(std::string& line, float percent) {
204     stream->clear();
205 
206     std::streampos currpointer = getPointer();
207 
208     seekTo(percent);
209 
210     bool success = getNextLine(line);
211 
212     stream->clear();
213 
214     //set the pointer back
215     setPointer(currpointer);
216 
217     return success;
218 }
219 
isFinished()220 bool SeekLog::isFinished() {
221     bool finished = false;
222 
223     if(stream->fail() || stream->eof()) {
224         //debugLog("stream is finished");
225         finished=true;
226     }
227 
228     return finished;
229 }
230