1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
2 /* logview-utils.c - misc logview utilities
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,
34 #include "logview-utils.h"
37 logview_utils_day_free (Day
*day
)
43 g_date_free (day
->date
);
44 g_slice_free (Day
, day
);
48 logview_utils_day_copy (Day
*day
)
52 retval
= g_slice_new0 (Day
);
53 retval
->date
= g_date_new_julian (g_date_get_julian (day
->date
));
54 retval
->first_line
= day
->first_line
;
55 retval
->last_line
= day
->last_line
;
56 retval
->timestamp_len
= day
->timestamp_len
;
62 logview_utils_day_list_copy (GSList
*days
)
64 GSList
*l
, *retval
= NULL
;
66 for (l
= days
; l
; l
= l
->next
) {
67 retval
= g_slist_prepend (retval
, logview_utils_day_copy (l
->data
));
70 return g_slist_reverse (retval
);
74 days_compare (gconstpointer a
, gconstpointer b
)
76 const Day
*day1
= a
, *day2
= b
;
78 return g_date_compare (day1
->date
, day2
->date
);
82 string_get_date (const char *line
, char **time_string
, int *timestamp_len
)
86 char *cp
= NULL
, *timestamp
= NULL
;
88 /* it's safe to assume that if strptime returns NULL, it's
89 * because of an error (format unmatched). being a log file, it's very
90 * unlikely that there aren't any more characters after the date.
93 if (line
== NULL
|| line
[0] == '\0') {
97 /* this parses the "MonthName DayNo" format */
98 cp
= strptime (line
, "%b %d", &tp
);
103 /* this parses the YYYY-MM-DD format */
104 cp
= strptime (line
, "%F", &tp
);
111 /* the year doesn't matter to us now */
112 date
= g_date_new_dmy (tp
.tm_mday
, tp
.tm_mon
+ 1, 1);
113 *time_string
= g_strndup (line
, cp
- line
);
115 timestamp
= strptime (cp
, "%X", &tp
);
117 *timestamp_len
= timestamp
- line
;
127 * @buffer_lines: an array of text lines.
128 * @current: the mtime of the file being parsed.
130 * Reads all the dates inside the text buffer.
131 * All dates are given with respect to the 1/1/1970
132 * and are then corrected to the correct year once we
135 * Returns: a #GSList of #Day structures.
139 log_read_dates (const char **buffer_lines
, time_t current
)
141 int current_year
, offsetyear
, i
, n
, rangemin
, rangemax
, timestamp_len
= 0;
148 gboolean done
= FALSE
;
150 g_return_val_if_fail (buffer_lines
!= NULL
, NULL
);
152 n
= g_strv_length ((char **) buffer_lines
);
154 tmptm
= localtime (¤t
);
155 current_year
= tmptm
->tm_year
+ 1900;
158 /* find the first line with a date we're able to parse */
159 for (i
= 0; buffer_lines
[i
]; i
++) {
160 if ((date
= string_get_date (buffer_lines
[i
], &date_string
, ×tamp_len
)) != NULL
)
165 /* no valid dates in the array, return NULL */
169 if (!g_date_valid (date
)) {
171 g_free (date_string
);
175 g_date_set_year (date
, current_year
);
177 day
= g_slice_new0 (Day
);
178 days
= g_slist_append (days
, day
);
180 /* $i now contains the line number for the first good date */
184 day
->timestamp_len
= timestamp_len
;
186 /* now scan the logfile to get the last line of the day */
191 /* find out the last line of the day we're currently building */
195 while (day
->last_line
< 0) {
196 if (strstr (buffer_lines
[i
], date_string
)) {
197 /* if we find the same string on the last line of the log, we're done */
204 /* we're still in a section of lines with the same date;
205 * - if the next one changes, then we're on the last.
206 * - else we keep searching in the following.
209 if (!strstr (buffer_lines
[i
+ 1], date_string
)) {
214 i
= floor (((float) i
+ (float) rangemax
) / 2.);
217 /* we can't find the same date here; go back to a safer range. */
219 i
= floor (((float) rangemin
+ (float) i
) / 2.);
223 g_free (date_string
);
227 /* this means we finished the current day but we're not at the end
228 * of the buffer: reset the parameters for the next day.
232 for (i
= day
->last_line
+ 1; buffer_lines
[i
]; i
++) {
233 if ((newdate
= string_get_date (buffer_lines
[i
], &date_string
, ×tamp_len
)) != NULL
)
237 if (date_string
== NULL
&& i
== n
- 1) {
241 /* this will set the last line of the "old" log to either:
242 * - "n - 1" if we can't find another date
243 * - the line before the new date else.
245 day
->last_line
= i
- 1;
248 /* append a new day to the list */
250 g_date_set_year (newdate
, current_year
+ offsetyear
);
252 if (g_date_compare (newdate
, date
) < 1) {
253 /* this isn't possible, as we're reading the log forward.
254 * so it means that newdate is the next year.
256 g_date_add_years (newdate
, 1);
261 day
= g_slice_new0 (Day
);
262 days
= g_slist_prepend (days
, day
);
267 day
->timestamp_len
= timestamp_len
;
275 g_free (date_string
);
278 /* sort the days in chronological order */
279 days
= g_slist_sort (days
, days_compare
);