Updated Spanish translation
[gnome-utils.git] / logview / logview-utils.c
blob82070b18b7d0c0d6ef91975fb3be70468bc35d38
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,
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
26 #define _XOPEN_SOURCE
27 #include <time.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <math.h>
32 #include <glib.h>
34 #include "logview-utils.h"
36 void
37 logview_utils_day_free (Day *day)
39 if (!day) {
40 return;
43 g_date_free (day->date);
44 g_slice_free (Day, day);
47 Day *
48 logview_utils_day_copy (Day *day)
50 Day *retval;
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;
58 return retval;
61 GSList *
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);
73 gint
74 days_compare (gconstpointer a, gconstpointer b)
76 const Day *day1 = a, *day2 = b;
78 return g_date_compare (day1->date, day2->date);
81 static GDate *
82 string_get_date (const char *line, char **time_string, int *timestamp_len)
84 GDate *date = NULL;
85 struct tm tp;
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') {
94 return NULL;
97 /* this parses the "MonthName DayNo" format */
98 cp = strptime (line, "%b %d", &tp);
99 if (cp) {
100 goto out;
103 /* this parses the YYYY-MM-DD format */
104 cp = strptime (line, "%F", &tp);
105 if (cp) {
106 goto out;
109 out:
110 if (cp) {
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);
116 if (timestamp) {
117 *timestamp_len = timestamp - line;
121 return date;
125 * log_read_dates:
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
133 * reach the end.
135 * Returns: a #GSList of #Day structures.
138 GSList *
139 log_read_dates (const char **buffer_lines, time_t current)
141 int current_year, offsetyear, i, n, rangemin, rangemax, timestamp_len = 0;
142 GSList *days = NULL;
143 GDate *date = NULL;
144 GDate *newdate;
145 struct tm *tmptm;
146 char *date_string;
147 Day *day;
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 (&current);
155 current_year = tmptm->tm_year + 1900;
156 offsetyear = 0;
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, &timestamp_len)) != NULL)
161 break;
164 if (!date) {
165 /* no valid dates in the array, return NULL */
166 return NULL;
169 if (!g_date_valid (date)) {
170 g_date_free (date);
171 g_free (date_string);
172 return NULL;
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 */
181 day->date = date;
182 day->first_line = i;
183 day->last_line = -1;
184 day->timestamp_len = timestamp_len;
186 /* now scan the logfile to get the last line of the day */
187 rangemin = i;
188 rangemax = n - 1;
190 while (!done) {
191 /* find out the last line of the day we're currently building */
193 i = n - 1;
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 */
198 if (i == n - 1) {
199 done = TRUE;
200 day->last_line = i;
201 break;
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)) {
210 day->last_line = i;
211 break;
212 } else {
213 rangemin = i;
214 i = floor (((float) i + (float) rangemax) / 2.);
216 } else {
217 /* we can't find the same date here; go back to a safer range. */
218 rangemax = i;
219 i = floor (((float) rangemin + (float) i) / 2.);
223 g_free (date_string);
224 date_string = NULL;
226 if (!done) {
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.
230 newdate = NULL;
232 for (i = day->last_line + 1; buffer_lines[i]; i++) {
233 if ((newdate = string_get_date (buffer_lines[i], &date_string, &timestamp_len)) != NULL)
234 break;
237 if (date_string == NULL && i == n - 1) {
238 done = TRUE;
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;
247 if (newdate) {
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);
257 offsetyear++;
260 date = newdate;
261 day = g_slice_new0 (Day);
262 days = g_slist_prepend (days, day);
264 day->date = date;
265 day->first_line = i;
266 day->last_line = -1;
267 day->timestamp_len = timestamp_len;
268 rangemin = i;
269 rangemax = n - 1;
274 if (date_string) {
275 g_free (date_string);
278 /* sort the days in chronological order */
279 days = g_slist_sort (days, days_compare);
281 return days;