Updated Spanish translation
[gnome-utils.git] / logview / logview-log.c
blobcc744a2bff7041e35d783ad639aa0ecd79a0ee5e
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
2 /* logview-log.c - object representation of a logfile
4 * Copyright (C) 1998 Cesar Miquel <miquel@df.uba.ar>
5 * Copyright (C) 2008 Cosimo Cecchi <cosimoc@gnome.org>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 551 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20 * USA.
23 #include "config.h"
25 #include <glib.h>
26 #include <glib/gi18n.h>
27 #include <gio/gio.h>
29 #ifdef HAVE_ZLIB
30 #include <zlib.h>
31 #endif
33 #include "logview-log.h"
34 #include "logview-utils.h"
36 G_DEFINE_TYPE (LogviewLog, logview_log, G_TYPE_OBJECT);
38 #define GET_PRIVATE(o) \
39 (G_TYPE_INSTANCE_GET_PRIVATE ((o), LOGVIEW_TYPE_LOG, LogviewLogPrivate))
41 enum {
42 LOG_CHANGED,
43 LAST_SIGNAL
46 static guint signals [LAST_SIGNAL] = { 0 };
48 struct _LogviewLogPrivate {
49 /* file and monitor */
50 GFile *file;
51 GFileMonitor *mon;
53 /* stats about the file */
54 time_t file_time;
55 goffset file_size;
56 char *display_name;
57 gboolean has_days;
59 /* lines and relative days */
60 GSList *days;
61 GPtrArray *lines;
62 guint lines_no;
64 /* stream poiting to the log */
65 GDataInputStream *stream;
66 gboolean has_new_lines;
69 typedef struct {
70 LogviewLog *log;
71 GError *err;
72 LogviewCreateCallback callback;
73 gpointer user_data;
74 } LoadJob;
76 typedef struct {
77 LogviewLog *log;
78 GError *err;
79 const char **lines;
80 GSList *new_days;
81 LogviewNewLinesCallback callback;
82 gpointer user_data;
83 } NewLinesJob;
85 typedef struct {
86 GInputStream *parent_str;
87 guchar * buffer;
88 GFile *file;
90 gboolean last_str_result;
91 int last_z_result;
92 z_stream zstream;
93 } GZHandle;
95 static void
96 do_finalize (GObject *obj)
98 LogviewLog *log = LOGVIEW_LOG (obj);
99 char ** lines;
101 if (log->priv->stream) {
102 g_object_unref (log->priv->stream);
103 log->priv->stream = NULL;
106 if (log->priv->file) {
107 g_object_unref (log->priv->file);
108 log->priv->file = NULL;
111 if (log->priv->mon) {
112 g_object_unref (log->priv->mon);
113 log->priv->mon = NULL;
116 if (log->priv->days) {
117 g_slist_foreach (log->priv->days,
118 (GFunc) logview_utils_day_free, NULL);
119 g_slist_free (log->priv->days);
120 log->priv->days = NULL;
123 if (log->priv->lines) {
124 lines = (char **) g_ptr_array_free (log->priv->lines, FALSE);
125 g_strfreev (lines);
126 log->priv->lines = NULL;
129 G_OBJECT_CLASS (logview_log_parent_class)->finalize (obj);
132 static void
133 logview_log_class_init (LogviewLogClass *klass)
135 GObjectClass *object_class = G_OBJECT_CLASS (klass);
137 object_class->finalize = do_finalize;
139 signals[LOG_CHANGED] = g_signal_new ("log-changed",
140 G_OBJECT_CLASS_TYPE (object_class),
141 G_SIGNAL_RUN_LAST,
142 G_STRUCT_OFFSET (LogviewLogClass, log_changed),
143 NULL, NULL,
144 g_cclosure_marshal_VOID__VOID,
145 G_TYPE_NONE, 0);
147 g_type_class_add_private (klass, sizeof (LogviewLogPrivate));
150 static void
151 logview_log_init (LogviewLog *self)
153 self->priv = GET_PRIVATE (self);
155 self->priv->lines = NULL;
156 self->priv->lines_no = 0;
157 self->priv->days = NULL;
158 self->priv->file = NULL;
159 self->priv->mon = NULL;
160 self->priv->has_new_lines = FALSE;
161 self->priv->has_days = FALSE;
164 static void
165 monitor_changed_cb (GFileMonitor *monitor,
166 GFile *file,
167 GFile *unused,
168 GFileMonitorEvent event,
169 gpointer user_data)
171 LogviewLog *log = user_data;
173 if (event == G_FILE_MONITOR_EVENT_CHANGED) {
174 log->priv->has_new_lines = TRUE;
175 g_signal_emit (log, signals[LOG_CHANGED], 0, NULL);
177 /* TODO: handle the case where the log is deleted? */
180 static void
181 setup_file_monitor (LogviewLog *log)
183 GError *err = NULL;
185 log->priv->mon = g_file_monitor (log->priv->file,
186 0, NULL, &err);
187 if (err) {
188 /* it'd be strange to get this error at this point but whatever */
189 g_warning ("Impossible to monitor the log file: the changes won't be notified");
190 g_error_free (err);
191 return;
194 /* set the rate to 1sec, as I guess it's not unusual to have more than
195 * one line written consequently or in a short time, being a log file.
197 g_file_monitor_set_rate_limit (log->priv->mon, 1000);
198 g_signal_connect (log->priv->mon, "changed",
199 G_CALLBACK (monitor_changed_cb), log);
202 static GSList *
203 add_new_days_to_cache (LogviewLog *log, const char **new_lines, guint lines_offset)
205 GSList *new_days, *l, *last_cached;
206 int res;
207 Day *day, *last;
209 new_days = log_read_dates (new_lines, log->priv->file_time);
211 /* the days are stored in chronological order, so we compare the last cached
212 * one with the new we got.
214 last_cached = g_slist_last (log->priv->days);
216 if (!last_cached) {
217 /* this means the day list is empty (i.e. we're on the first read */
218 log->priv->days = logview_utils_day_list_copy (new_days);
219 return new_days;
222 for (l = new_days; l; l = l->next) {
223 res = days_compare (l->data, last_cached->data);
224 day = l->data;
226 if (res > 0) {
227 /* this day in the list is newer than the last one, append to
228 * the cache.
230 day->first_line += lines_offset;
231 day->last_line += lines_offset;
232 log->priv->days = g_slist_append (log->priv->days, logview_utils_day_copy (day));
233 } else if (res == 0) {
234 last = last_cached->data;
236 /* update the lines number */
237 last->last_line += day->last_line;
241 return new_days;
244 static gboolean
245 new_lines_job_done (gpointer data)
247 NewLinesJob *job = data;
249 if (job->err) {
250 job->callback (job->log, NULL, NULL, job->err, job->user_data);
251 g_error_free (job->err);
252 } else {
253 job->callback (job->log, job->lines, job->new_days, job->err, job->user_data);
256 g_slist_foreach (job->new_days, (GFunc) logview_utils_day_free, NULL);
257 g_slist_free (job->new_days);
259 /* drop the reference we acquired before */
260 g_object_unref (job->log);
262 g_slice_free (NewLinesJob, job);
264 return FALSE;
267 static gboolean
268 do_read_new_lines (GIOSchedulerJob *io_job,
269 GCancellable *cancellable,
270 gpointer user_data)
272 /* this runs in a separate thread */
273 NewLinesJob *job = user_data;
274 LogviewLog *log = job->log;
275 char *line;
276 GError *err = NULL;
277 GPtrArray *lines;
279 g_assert (LOGVIEW_IS_LOG (log));
280 g_assert (log->priv->stream != NULL);
282 if (!log->priv->lines) {
283 log->priv->lines = g_ptr_array_new ();
284 g_ptr_array_add (log->priv->lines, NULL);
287 lines = log->priv->lines;
289 /* remove the NULL-terminator */
290 g_ptr_array_remove_index (lines, lines->len - 1);
292 while ((line = g_data_input_stream_read_line (log->priv->stream, NULL,
293 NULL, &err)) != NULL)
295 g_ptr_array_add (lines, (gpointer) line);
298 if (err) {
299 job->err = err;
300 goto out;
303 /* NULL-terminate the array again */
304 g_ptr_array_add (lines, NULL);
306 log->priv->has_new_lines = FALSE;
308 /* we'll return only the new lines in the callback */
309 line = g_ptr_array_index (lines, log->priv->lines_no);
310 job->lines = (const char **) lines->pdata + log->priv->lines_no;
312 /* save the new number of days and lines */
313 job->new_days = add_new_days_to_cache (log, job->lines, log->priv->lines_no);
314 log->priv->lines_no = (lines->len - 1);
316 out:
317 g_io_scheduler_job_send_to_mainloop_async (io_job,
318 new_lines_job_done,
319 job, NULL);
320 return FALSE;
323 static gboolean
324 log_load_done (gpointer user_data)
326 LoadJob *job = user_data;
328 if (job->err) {
329 /* the callback will have NULL as log, and the error set */
330 g_object_unref (job->log);
331 job->callback (NULL, job->err, job->user_data);
332 g_error_free (job->err);
333 } else {
334 job->callback (job->log, NULL, job->user_data);
335 setup_file_monitor (job->log);
338 g_slice_free (LoadJob, job);
340 return FALSE;
343 #ifdef HAVE_ZLIB
345 /* GZip functions adapted for GIO from gnome-vfs/gzip-method.c */
347 #define Z_BUFSIZE 16384
349 #define GZIP_HEADER_SIZE 10
350 #define GZIP_MAGIC_1 0x1f
351 #define GZIP_MAGIC_2 0x8b
352 #define GZIP_FLAG_ASCII 0x01 /* bit 0 set: file probably ascii text */
353 #define GZIP_FLAG_HEAD_CRC 0x02 /* bit 1 set: header CRC present */
354 #define GZIP_FLAG_EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
355 #define GZIP_FLAG_ORIG_NAME 0x08 /* bit 3 set: original file name present */
356 #define GZIP_FLAG_COMMENT 0x10 /* bit 4 set: file comment present */
357 #define GZIP_FLAG_RESERVED 0xE0 /* bits 5..7: reserved */
359 static gboolean
360 skip_string (GInputStream *is)
362 guchar c;
363 gssize bytes_read;
365 do {
366 bytes_read = g_input_stream_read (is, &c, 1, NULL, NULL);
368 if (bytes_read != 1) {
369 return FALSE;
371 } while (c != 0);
373 return TRUE;
376 static gboolean
377 read_gzip_header (GInputStream *is,
378 time_t *modification_time)
380 gboolean res;
381 guchar buffer[GZIP_HEADER_SIZE];
382 gssize bytes, to_skip;
383 guint mode;
384 guint flags;
386 bytes = g_input_stream_read (is, buffer, GZIP_HEADER_SIZE,
387 NULL, NULL);
388 if (bytes == -1) {
389 return FALSE;
392 if (bytes != GZIP_HEADER_SIZE)
393 return FALSE;
395 if (buffer[0] != GZIP_MAGIC_1 || buffer[1] != GZIP_MAGIC_2)
396 return FALSE;
398 mode = buffer[2];
399 if (mode != 8) /* Mode: deflate */
400 return FALSE;
402 flags = buffer[3];
404 if (flags & GZIP_FLAG_RESERVED)
405 return FALSE;
407 if (flags & GZIP_FLAG_EXTRA_FIELD) {
408 guchar tmp[2];
410 bytes = g_input_stream_read (is, tmp, 2, NULL, NULL);
412 if (bytes != 2) {
413 return FALSE;
416 to_skip = tmp[0] | (tmp[0] << 8);
417 bytes = g_input_stream_skip (is, to_skip, NULL, NULL);
418 if (bytes != to_skip) {
419 return FALSE;
423 if (flags & GZIP_FLAG_ORIG_NAME) {
424 if (!skip_string (is)) {
425 return FALSE;
429 if (flags & GZIP_FLAG_COMMENT) {
430 if (!skip_string (is)) {
431 return FALSE;
435 if (flags & GZIP_FLAG_HEAD_CRC) {
436 bytes = g_input_stream_skip (is, 2, NULL, NULL);
437 if (bytes != 2) {
438 return FALSE;
442 *modification_time = (buffer[4] | (buffer[5] << 8)
443 | (buffer[6] << 16) | (buffer[7] << 24));
445 return TRUE;
448 static GZHandle *
449 gz_handle_new (GFile *file,
450 GInputStream *parent_stream)
452 GZHandle *ret;
454 ret = g_new (GZHandle, 1);
455 ret->parent_str = g_object_ref (parent_stream);
456 ret->file = g_object_ref (file);
457 ret->buffer = NULL;
459 return ret;
462 static gboolean
463 gz_handle_init (GZHandle *gz)
465 gz->zstream.zalloc = NULL;
466 gz->zstream.zfree = NULL;
467 gz->zstream.opaque = NULL;
469 g_free (gz->buffer);
470 gz->buffer = g_malloc (Z_BUFSIZE);
471 gz->zstream.next_in = gz->buffer;
472 gz->zstream.avail_in = 0;
474 if (inflateInit2 (&gz->zstream, -MAX_WBITS) != Z_OK) {
475 return FALSE;
478 gz->last_z_result = Z_OK;
479 gz->last_str_result = TRUE;
481 return TRUE;
484 static void
485 gz_handle_free (GZHandle *gz)
487 g_object_unref (gz->parent_str);
488 g_object_unref (gz->file);
489 g_free (gz->buffer);
490 g_free (gz);
493 static gboolean
494 fill_buffer (GZHandle *gz,
495 gsize num_bytes)
497 gboolean res;
498 gsize count;
500 z_stream * zstream = &gz->zstream;
502 if (zstream->avail_in > 0) {
503 return TRUE;
506 count = g_input_stream_read (gz->parent_str,
507 gz->buffer,
508 Z_BUFSIZE,
509 NULL, NULL);
510 if (count == -1) {
511 if (zstream->avail_out == num_bytes) {
512 return FALSE;
514 gz->last_str_result = FALSE;
515 } else {
516 zstream->next_in = gz->buffer;
517 zstream->avail_in = count;
520 return TRUE;
523 static gboolean
524 result_from_z_result (int z_result)
526 switch (z_result) {
527 case Z_OK:
528 case Z_STREAM_END:
529 return TRUE;
530 case Z_DATA_ERROR:
531 return FALSE;
532 default:
533 return FALSE;
537 static gboolean
538 gz_handle_read (GZHandle *gz,
539 guchar *buffer,
540 gsize num_bytes,
541 gsize * bytes_read)
543 z_stream *zstream;
544 gboolean res;
545 int z_result;
547 *bytes_read = 0;
548 zstream = &gz->zstream;
550 if (gz->last_z_result != Z_OK) {
551 if (gz->last_z_result == Z_STREAM_END) {
552 *bytes_read = 0;
553 return TRUE;
554 } else {
555 return result_from_z_result (gz->last_z_result);
557 } else if (gz->last_str_result == FALSE) {
558 return FALSE;
561 zstream->next_out = buffer;
562 zstream->avail_out = num_bytes;
564 while (zstream->avail_out != 0) {
565 res = fill_buffer (gz, num_bytes);
567 if (!res) {
568 return res;
571 z_result = inflate (zstream, Z_NO_FLUSH);
572 if (z_result == Z_STREAM_END) {
573 gz->last_z_result = z_result;
574 break;
575 } else if (z_result != Z_OK) {
576 gz->last_z_result = z_result;
579 if (gz->last_z_result != Z_OK && zstream->avail_out == num_bytes) {
580 return result_from_z_result (gz->last_z_result);
584 *bytes_read = num_bytes - zstream->avail_out;
586 return TRUE;
589 static GError *
590 create_zlib_error (void)
592 GError *err;
594 err = g_error_new_literal (LOGVIEW_ERROR_QUARK, LOGVIEW_ERROR_ZLIB,
595 _("Error while uncompressing the GZipped log. The file "
596 "might be corrupt."));
597 return err;
600 #endif /* HAVE_ZLIB */
602 static gboolean
603 log_load (GIOSchedulerJob *io_job,
604 GCancellable *cancellable,
605 gpointer user_data)
607 /* this runs in a separate i/o thread */
608 LoadJob *job = user_data;
609 LogviewLog *log = job->log;
610 GFile *f = log->priv->file;
611 GFileInfo *info;
612 GInputStream *is;
613 const char *peeked_buffer;
614 const char * parse_data[2];
615 GSList *days;
616 const char *content_type;
617 GFileType type;
618 GError *err = NULL;
619 GTimeVal timeval;
620 gboolean is_archive, can_read;
622 info = g_file_query_info (f,
623 G_FILE_ATTRIBUTE_ACCESS_CAN_READ ","
624 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
625 G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME ","
626 G_FILE_ATTRIBUTE_STANDARD_TYPE ","
627 G_FILE_ATTRIBUTE_STANDARD_SIZE ","
628 G_FILE_ATTRIBUTE_TIME_MODIFIED ",",
629 0, NULL, &err);
630 if (err) {
631 if (err->code == G_IO_ERROR_PERMISSION_DENIED) {
632 /* TODO: PolicyKit integration */
634 goto out;
637 can_read = g_file_info_get_attribute_boolean (info,
638 G_FILE_ATTRIBUTE_ACCESS_CAN_READ);
639 if (!can_read) {
640 /* TODO: PolicyKit integration */
641 err = g_error_new_literal (LOGVIEW_ERROR_QUARK, LOGVIEW_ERROR_PERMISSION_DENIED,
642 _("You don't have enough permissions to read the file."));
643 g_object_unref (info);
645 goto out;
648 type = g_file_info_get_file_type (info);
649 content_type = g_file_info_get_content_type (info);
651 is_archive = g_content_type_equals (content_type, "application/x-gzip");
653 if (type != (G_FILE_TYPE_REGULAR || G_FILE_TYPE_SYMBOLIC_LINK) ||
654 (!g_content_type_is_a (content_type, "text/plain") && !is_archive))
656 err = g_error_new_literal (LOGVIEW_ERROR_QUARK, LOGVIEW_ERROR_NOT_A_LOG,
657 _("The file is not a regular file or is not a text file."));
658 g_object_unref (info);
660 goto out;
663 log->priv->file_size = g_file_info_get_size (info);
664 g_file_info_get_modification_time (info, &timeval);
665 log->priv->file_time = timeval.tv_sec;
666 log->priv->display_name = g_strdup (g_file_info_get_display_name (info));
668 g_object_unref (info);
670 /* initialize the stream */
671 is = G_INPUT_STREAM (g_file_read (f, NULL, &err));
673 if (err) {
674 if (err->code == G_IO_ERROR_PERMISSION_DENIED) {
675 /* TODO: PolicyKit integration */
678 goto out;
681 if (is_archive) {
682 #ifdef HAVE_ZLIB
683 GZHandle *gz;
684 gboolean res;
685 guchar * buffer;
686 gsize bytes_read;
687 GInputStream *real_is;
688 time_t mtime; /* seconds */
690 /* this also skips the header from |is| */
691 res = read_gzip_header (is, &mtime);
693 if (!res) {
694 g_object_unref (is);
696 err = create_zlib_error ();
697 goto out;
700 log->priv->file_time = mtime;
702 gz = gz_handle_new (f, is);
703 res = gz_handle_init (gz);
705 if (!res) {
706 g_object_unref (is);
707 gz_handle_free (gz);
709 err = create_zlib_error ();
710 goto out;
713 real_is = g_memory_input_stream_new ();
715 do {
716 buffer = g_malloc (1024);
717 res = gz_handle_read (gz, buffer, 1024, &bytes_read);
718 g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (real_is),
719 buffer, bytes_read, g_free);
720 } while (res == TRUE && bytes_read > 0);
722 if (!res) {
723 gz_handle_free (gz);
724 g_object_unref (real_is);
725 g_object_unref (is);
727 err = create_zlib_error ();
728 goto out;
731 g_object_unref (is);
732 is = real_is;
734 gz_handle_free (gz);
735 #else /* HAVE_ZLIB */
736 g_object_unref (is);
738 err = g_error_new_literal (LOGVIEW_ERROR_QUARK, LOGVIEW_ERROR_NOT_SUPPORTED,
739 _("This version of System Log does not support GZipped logs."));
740 goto out;
741 #endif /* HAVE_ZLIB */
744 log->priv->stream = g_data_input_stream_new (is);
746 /* sniff into the stream for a timestamped line */
747 g_buffered_input_stream_fill (G_BUFFERED_INPUT_STREAM (log->priv->stream),
748 (gssize) g_buffered_input_stream_get_buffer_size (G_BUFFERED_INPUT_STREAM (log->priv->stream)),
749 NULL, &err);
750 if (err == NULL) {
751 peeked_buffer = g_buffered_input_stream_peek_buffer
752 (G_BUFFERED_INPUT_STREAM (log->priv->stream), NULL);
753 parse_data[0] = peeked_buffer;
754 parse_data[1] = NULL;
756 if ((days = log_read_dates (parse_data, time (NULL))) != NULL) {
757 log->priv->has_days = TRUE;
758 g_slist_foreach (days, (GFunc) logview_utils_day_free, NULL);
759 g_slist_free (days);
760 } else {
761 log->priv->has_days = FALSE;
763 } else {
764 log->priv->has_days = FALSE;
765 g_clear_error (&err);
768 g_object_unref (is);
770 out:
771 if (err) {
772 job->err = err;
775 g_io_scheduler_job_send_to_mainloop_async (io_job,
776 log_load_done,
777 job, NULL);
778 return FALSE;
781 static void
782 log_setup_load (LogviewLog *log, LogviewCreateCallback callback,
783 gpointer user_data)
785 LoadJob *job;
787 job = g_slice_new0 (LoadJob);
788 job->callback = callback;
789 job->user_data = user_data;
790 job->log = log;
791 job->err = NULL;
793 /* push the loading job into another thread */
794 g_io_scheduler_push_job (log_load,
795 job,
796 NULL, 0, NULL);
799 /* public methods */
801 void
802 logview_log_read_new_lines (LogviewLog *log,
803 LogviewNewLinesCallback callback,
804 gpointer user_data)
806 NewLinesJob *job;
808 /* initialize the job struct with sensible values */
809 job = g_slice_new0 (NewLinesJob);
810 job->callback = callback;
811 job->user_data = user_data;
812 job->log = g_object_ref (log);
813 job->err = NULL;
814 job->lines = NULL;
815 job->new_days = NULL;
817 /* push the fetching job into another thread */
818 g_io_scheduler_push_job (do_read_new_lines,
819 job,
820 NULL, 0, NULL);
823 void
824 logview_log_create (const char *filename, LogviewCreateCallback callback,
825 gpointer user_data)
827 LogviewLog *log = g_object_new (LOGVIEW_TYPE_LOG, NULL);
829 log->priv->file = g_file_new_for_path (filename);
831 log_setup_load (log, callback, user_data);
834 void
835 logview_log_create_from_gfile (GFile *file, LogviewCreateCallback callback,
836 gpointer user_data)
838 LogviewLog *log = g_object_new (LOGVIEW_TYPE_LOG, NULL);
840 log->priv->file = g_object_ref (file);
842 log_setup_load (log, callback, user_data);
845 const char *
846 logview_log_get_display_name (LogviewLog *log)
848 g_assert (LOGVIEW_IS_LOG (log));
850 return log->priv->display_name;
853 time_t
854 logview_log_get_timestamp (LogviewLog *log)
856 g_assert (LOGVIEW_IS_LOG (log));
858 return log->priv->file_time;
861 goffset
862 logview_log_get_file_size (LogviewLog *log)
864 g_assert (LOGVIEW_IS_LOG (log));
866 return log->priv->file_size;
869 guint
870 logview_log_get_cached_lines_number (LogviewLog *log)
872 g_assert (LOGVIEW_IS_LOG (log));
874 return log->priv->lines_no;
877 const char **
878 logview_log_get_cached_lines (LogviewLog *log)
880 const char ** lines = NULL;
882 g_assert (LOGVIEW_IS_LOG (log));
884 if (log->priv->lines) {
885 lines = (const char **) log->priv->lines->pdata;
888 return lines;
891 GSList *
892 logview_log_get_days_for_cached_lines (LogviewLog *log)
894 g_assert (LOGVIEW_IS_LOG (log));
896 return log->priv->days;
899 gboolean
900 logview_log_has_new_lines (LogviewLog *log)
902 g_assert (LOGVIEW_IS_LOG (log));
904 return log->priv->has_new_lines;
907 char *
908 logview_log_get_uri (LogviewLog *log)
910 g_assert (LOGVIEW_IS_LOG (log));
912 return g_file_get_uri (log->priv->file);
915 GFile *
916 logview_log_get_gfile (LogviewLog *log)
918 g_assert (LOGVIEW_IS_LOG (log));
920 return g_object_ref (log->priv->file);
923 gboolean
924 logview_log_get_has_days (LogviewLog *log)
926 g_assert (LOGVIEW_IS_LOG (log));
928 return log->priv->has_days;