@@ -127,73 +127,79 @@ void LLLogChat::saveHistory(std::string const& filename, std::string line)
127127 }
128128}
129129
130- const std::streamoff BUFFER_SIZE ( 4096 ) ;
130+ static long const LOG_RECALL_BUFSIZ = 2048 ;
131131
132- // Read a chunk of size from pos in ifstr and prepend it to data
133- // return that chunk's newline count
134- U32 read_chunk (llifstream& ifstr, const std::streamoff& pos, U32 size, std::string& data)
132+ void LLLogChat::loadHistory (std::string const & filename , void (*callback)(ELogLineType, std::string, void *), void* userdata)
135133{
136- char buffer[BUFFER_SIZE];
137- ifstr.seekg (pos);
138- ifstr.read (buffer, size);
139- data.insert (0 , buffer, size);
140- return std::count (buffer, buffer + size, ' \n ' );
141- }
142-
143- void LLLogChat::loadHistory (std::string const & filename , void (*callback)(ELogLineType,std::string,void *), void* userdata)
144- {
145- if (!filename.size ())
146- {
147- llwarns << " Filename is Empty!" << llendl;
148- return ;
149- }
150-
151- llifstream ifstr (makeLogFileName (filename));
152- if (!ifstr.is_open ())
134+ bool filename_empty = filename.empty ();
135+ if (filename_empty)
153136 {
154- callback (LOG_EMPTY,LLStringUtil::null,userdata) ;
137+ llwarns << " filename is empty! " << llendl ;
155138 }
156- else
139+ else while ( 1 ) // So we can use break.
157140 {
141+ // The number of lines to return.
158142 static const LLCachedControl<U32> lines (" LogShowHistoryLines" , 32 );
159- ifstr.seekg (-1 , std::ios_base::end);
160- if (!lines || !ifstr)
161- {
162- callback (LOG_EMPTY,LLStringUtil::null,userdata);
163- return ;
164- }
143+ if (lines == 0 ) break ;
165144
166- std::string data;
167- U32 nlines = 0 ;
168- if (ifstr.get () != ' \n ' ) // in case file doesn't end with a newline
169- {
170- data.push_back (' \n ' );
171- ++nlines;
172- }
145+ // Open the log file.
146+ LLFILE* fptr = LLFile::fopen (makeLogFileName (filename), " rb" );
147+ if (!fptr) break ;
173148
174- // Read BUFFER_SIZE byte chunks until we have enough endlines accumulated
175- for (std::streamoff pos = ifstr.tellg () - BUFFER_SIZE; nlines < lines+1 ; pos -= BUFFER_SIZE)
149+ // Set pos to point to the last character of the file, if any.
150+ if (fseek (fptr, 0 , SEEK_END)) break ;
151+ long pos = ftell (fptr) - 1 ;
152+ if (pos < 0 ) break ;
153+
154+ char buffer[LOG_RECALL_BUFSIZ];
155+ bool error = false ;
156+ int nlines = 0 ;
157+ while (pos > 0 && nlines < lines)
176158 {
177- if (pos > 0 )
178- {
179- nlines += read_chunk (ifstr, pos, BUFFER_SIZE, data);
180- }
181- else // Ran out of file read the remaining from the start
159+ // Read the LOG_RECALL_BUFSIZ characters before pos.
160+ size_t size = llmin (LOG_RECALL_BUFSIZ, pos);
161+ pos -= size;
162+ fseek (fptr, pos, SEEK_SET);
163+ size_t len = fread (buffer, 1 , size, fptr);
164+ error = len != size;
165+ if (error) break ;
166+ // Count the number of newlines in it and set pos to the beginning of the first line to return when we found enough.
167+ for (char const * p = buffer + size - 1 ; p >= buffer; --p)
182168 {
183- nlines += read_chunk (ifstr, 0 , pos + BUFFER_SIZE, data);
184- break ;
169+ if (*p == ' \n ' )
170+ {
171+ if (++nlines == lines)
172+ {
173+ pos += p - buffer + 1 ;
174+ break ;
175+ }
176+ }
185177 }
186178 }
179+ if (error)
180+ {
181+ fclose (fptr);
182+ break ;
183+ }
184+
185+ // Set the file pointer at the first line to return.
186+ fseek (fptr, pos, SEEK_SET);
187187
188- // Break data into lines
189- std::istringstream sstr (data);
190- for (std::string line; nlines > 0 && getline (sstr, line); --nlines)
188+ // Read lines from the file one by one until we reach the end of the file.
189+ while (fgets (buffer, LOG_RECALL_BUFSIZ, fptr))
191190 {
192- if (nlines <= lines)
193- {
194- callback (LOG_LINE, line, userdata);
195- }
191+ size_t len = strlen (buffer);
192+ if (buffer[len - 1 ] == ' \n ' ) // In case the log file doesn't end on a new-line (is that even possible?)
193+ {
194+ buffer[len - 1 ] = ' \0 ' ;
195+ }
196+ callback (LOG_LINE, buffer, userdata);
196197 }
197- callback (LOG_END,LLStringUtil::null,userdata);
198+
199+ fclose (fptr);
200+ callback (LOG_END, LLStringUtil::null, userdata);
201+ return ;
198202 }
203+ callback (LOG_EMPTY, LLStringUtil::null, userdata);
199204}
205+
0 commit comments