예제 #1
0
/** Find an arbitrary number of delimited strings at the end of a file.  This
 * function provides the core of our last-lines-loader implementation.
 *
 * @param fd File descriptor to operate on.  This must be opened for reading.
 *
 * @param bytes Delimiter sequence.
 *
 * @param bytes_length Number of significant bytes in @p bytes.
 *
 * @param count Number of tail sequences to find.
 *
 * @param out Destination string array.
 */
static inline size_t
find_tail_sequences(int fd, const char* bytes, size_t bytes_length, size_t count, wxArrayString& out)
{
    size_t count_added ( 0 );

    /* We overlap the file reads a little to avoid splitting (and thus missing) the
       delimiter sequence.  */
    const size_t read_overlap ( bytes_length - 1 );
    const size_t read_size ( BUFSIZ );

    const off_t log_length ( lseek(fd, 0, SEEK_END) );
    bool have_last_pos ( false );
    char buf[read_size];
    off_t last_found_pos ( 0 );
    off_t last_read_position ( log_length + read_overlap );

    /* We read `read_size'-byte blocks of the file, starting at the end and working backwards. */
    while ( count_added < count && last_read_position > 0 ) {
        off_t read_position ( next_read_position(last_read_position, read_size, read_overlap) );
        size_t bytes_read ( pread(fd, buf, std::min(static_cast<off_t>(read_size), last_read_position - read_position), read_position) );

        /* In each block, we search for `bytes', starting at the end.  */
        for ( ssize_t i = bytes_read - read_overlap - 1; i >= 0; i-- ) {
            if ( !strncmp((buf + i), bytes, bytes_length) ) {
                off_t this_found_pos ( read_position + i );

                if ( have_last_pos && count_added < count ) {
                    size_t line_length ( last_found_pos - this_found_pos - bytes_length );

                    if ( line_length > 0 ) {
                        char* source ( NULL );

                        if ( last_found_pos >= read_position + (off_t) bytes_read ) {
                            source = new char[ line_length + 1];
                            memset(source, 0, line_length + 1);

                            if ( pread(fd, source, line_length, this_found_pos + bytes_length) < (ssize_t) line_length ) {
                                wxLogWarning(_T("ChatLog::find_tail_sequences: Read-byte count less than expected"));
                            }
                        } else {
                            source = buf + i + bytes_length;
                        }

                        if (  strncmp(source, "##", 2) != 0 ) {
                            out.Insert(wxString(L'\0', 0), 0);
                            wxLogMessage(_T("ChatLog::find_tail_sequences: fetching write buffer for %lu bytes"), sizeof(wxChar) * (line_length + 1));
#if !defined(HAVE_WX28) || defined(SL_QT_MODE)
                            wxStringBufferLength outzero_buf(out[0], sizeof(wxChar) * (line_length + 1));
                            wxConvUTF8.ToWChar(outzero_buf, line_length, source);
                            outzero_buf.SetLength(line_length);
#else
                            wxConvUTF8.MB2WC(out[0].GetWriteBuf(sizeof(wxChar) * (line_length + 1)), source, line_length);
                            out[0].UngetWriteBuf(line_length);
#endif

                            ++count_added;
                        }

                        if ( last_found_pos >= read_position + (off_t) bytes_read )
                            delete[] source;

                        if ( count_added >= count )
                            i = -1; /* short-circuit the `for' loop. */
                    }
                }
                last_found_pos = this_found_pos;
                have_last_pos = true;
                i -= bytes_length - 1;
            }
        }

        last_read_position = read_position;
    }

    return count_added;
}
예제 #2
0
/** Find an arbitrary number of delimited strings at the end of a file.  This
 * function provides the core of our last-lines-loader implementation.
 *
 * @param fd File descriptor to operate on.  This must be opened for reading.
 *
 * @param bytes Delimiter sequence.
 *
 * @param bytes_length Number of significant bytes in @p bytes.
 *
 * @param count Number of tail sequences to find.
 *
 * @param out Destination string array.
 */
static size_t find_tail_sequences(wxFile& fd, const char* bytes, size_t bytes_length, size_t count, wxArrayString& out)
{
	size_t count_added(0);

	/* We overlap the file reads a little to avoid splitting (and thus missing) the
	   delimiter sequence.  */
	const size_t read_overlap = bytes_length - 1;
	const size_t read_size = BUFSIZ;

	const off_t log_length = fd.SeekEnd();
	bool have_last_pos = false;
	char buf[read_size];
	off_t last_found_pos = 0;
	off_t last_read_position = log_length + read_overlap;

	/* We read `read_size'-byte blocks of the file, starting at the end and working backwards. */
	while (count_added < count && last_read_position > 0) {
		const off_t read_position = next_read_position(last_read_position, read_size, read_overlap);
		const size_t bytes_read = readblock(fd, buf, std::min(static_cast<off_t>(read_size), last_read_position - read_position), read_position);

		/* In each block, we search for `bytes', starting at the end.  */
		for (ssize_t i = bytes_read - read_overlap - 1; i >= 0; i--) {
			if (strncmp((buf + i), bytes, bytes_length) == 0) {
				const off_t this_found_pos = read_position + i;

				if (have_last_pos) {
					const size_t line_length = last_found_pos - this_found_pos - bytes_length;

					if (line_length > 0) {
						char* source = NULL;

						if (last_found_pos >= read_position + (off_t)bytes_read) {
							source = new char[line_length + 1];
							memset(source, 0, line_length + 1);

							if (readblock(fd, source, line_length, this_found_pos + bytes_length) < (ssize_t)line_length) {
								wxLogWarning(_T("ChatLog::find_tail_sequences: Read-byte count less than expected"));
							}
						} else {
							source = buf + i + bytes_length;
						}
						source[line_length] = 0;
						wxString tmp = wxString::FromUTF8(source);
						out.Insert(tmp, 0);
						if (last_found_pos >= read_position + (off_t)bytes_read)
							delete[] source;

						count_added++;
						if (count_added >= count)
							break;
					}
				}
				last_found_pos = this_found_pos;
				have_last_pos = true;
				i -= bytes_length - 1;
			}
		}

		last_read_position = read_position;
	}

	return count_added;
}