2
* This file is part of LaTeXila.
4
* Copyright Ā© 2010 SĆ©bastien Wilmet
6
* LaTeXila is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
11
* LaTeXila is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with LaTeXila. If not, see <http://www.gnu.org/licenses/>.
22
#include <ctype.h> // for isspace()
27
#include "latex_output_filter.h"
30
static gboolean detect_badbox (const gchar *line);
31
static gboolean detect_badbox_line (const gchar *badbox,
32
gboolean current_line_is_empty);
34
static gboolean detect_warning (const gchar *line);
35
static gboolean detect_warning_line (const gchar *warning,
36
gboolean current_line_is_empty);
38
static gboolean detect_error (const gchar *line);
39
static gboolean detect_other (const gchar *line);
41
static void update_stack_file (const gchar *line);
42
static void update_stack_file_heuristic (const gchar *line);
44
static gboolean file_exists (const gchar *filename);
45
static gchar * get_path_if_file_exists (const gchar *filename);
46
static gchar * get_current_filename (void);
47
static void push_file_on_stack (gchar *filename, gboolean reliable);
48
static void pop_file_from_stack (void);
49
static gboolean top_file_on_stack_reliable (void);
50
static void print_msg (void);
52
// the current message
55
// if a message is splitted, we enter in a different status, so we fetch the end
57
static enum filter_status status = START;
59
// if a message is splitted, the lines are concatenated in this buffer
60
static gchar line_buf[BUFFER_SIZE] = "";
61
static gint nb_lines = 0;
63
// the stack containing the files that TeX is processing
64
static GSList *stack_file = NULL;
66
// the directory where the document is compiled
67
static const gchar *path = NULL;
69
// some regex, initialised in latex_output_filter_init() and freed by
70
// latex_output_filter_free()
71
static GRegex *reg_badbox = NULL;
72
static GRegex *reg_badbox_lines = NULL;
73
static GRegex *reg_badbox_line = NULL;
74
static GRegex *reg_badbox_output = NULL;
76
static GRegex *reg_warning = NULL;
77
static GRegex *reg_warning_no_file = NULL;
78
static GRegex *reg_warning_line = NULL;
79
static GRegex *reg_warning_international_line = NULL;
81
static GRegex *reg_latex_error = NULL;
82
static GRegex *reg_pdflatex_error = NULL;
83
static GRegex *reg_tex_error = NULL;
84
static GRegex *reg_error_line = NULL;
86
static GRegex *reg_file_pop = NULL;
87
static GRegex *reg_other_bytes = NULL;
90
static gint nb_badboxes = 0;
91
static gint nb_warnings = 0;
92
static gint nb_errors = 0;
95
latex_output_filter (const gchar *line)
103
if (strlen (line) == 0)
106
if (! (detect_badbox (line) || detect_warning (line)
107
|| detect_error (line) || detect_other (line)))
108
update_stack_file (line);
112
detect_badbox (line);
116
detect_warning (line);
120
case ERROR_SEARCH_LINE:
125
case FILENAME_HEURISTIC:
126
update_stack_file (line);
135
latex_output_filter_init (void)
137
reg_badbox = g_regex_new ("^(Over|Under)full \\\\[hv]box", 0, 0, NULL);
138
reg_badbox_lines = g_regex_new ("(.*) at lines ([0-9]+)--([0-9]+)", 0, 0, NULL);
139
reg_badbox_line = g_regex_new ("(.*) at line ([0-9]+)", 0, 0, NULL);
140
reg_badbox_output = g_regex_new ("(.*)has occurred while \\output is active", 0, 0, NULL);
142
reg_warning = g_regex_new ("^(((! )?(La|pdf)TeX)|Package|Class) .*Warning.*:(.*)",
143
G_REGEX_CASELESS, 0, NULL);
144
reg_warning_no_file = g_regex_new ("(No file .*)", 0, 0, NULL);
145
reg_warning_line = g_regex_new ("(.*) on input line ([0-9]+)\\.$", 0, 0, NULL);
146
reg_warning_international_line = g_regex_new ("(.*)([0-9]+)\\.$", 0, 0, NULL);
148
reg_latex_error = g_regex_new ("^! LaTeX Error: (.*)$", 0, 0, NULL);
149
reg_pdflatex_error = g_regex_new ("^Error: pdflatex (.*)$", 0, 0, NULL);
150
reg_tex_error = g_regex_new ("^! (.*)\\.$", 0, 0, NULL);
151
reg_error_line = g_regex_new ("^l\\.([0-9]+)(.*)", 0, 0, NULL);
153
reg_file_pop = g_regex_new ("(\\) )?:<-$", 0, 0, NULL);
154
reg_other_bytes = g_regex_new ("([0-9]+) bytes", 0, 0, NULL);
160
latex_output_filter_free (void)
162
g_regex_unref (reg_badbox);
163
g_regex_unref (reg_badbox_lines);
164
g_regex_unref (reg_badbox_line);
165
g_regex_unref (reg_badbox_output);
166
g_regex_unref (reg_warning);
167
g_regex_unref (reg_warning_no_file);
168
g_regex_unref (reg_warning_line);
169
g_regex_unref (reg_warning_international_line);
170
g_regex_unref (reg_latex_error);
171
g_regex_unref (reg_pdflatex_error);
172
g_regex_unref (reg_tex_error);
173
g_regex_unref (reg_error_line);
174
g_regex_unref (reg_file_pop);
175
g_regex_unref (reg_other_bytes);
176
g_free ((gpointer) path);
180
latex_output_filter_set_path (const gchar *dir)
182
path = g_strdup (dir);
186
latex_output_filter_print_stats (void)
188
print_output_stats (nb_errors, nb_warnings, nb_badboxes);
190
// it's finish, we reset the counters
195
// empty the stack file
196
gint nb_files_in_stack = g_slist_length (stack_file);
197
if (nb_files_in_stack > 0)
198
print_warning ("the file stack was not empty!");
199
for (int i = 0 ; i < nb_files_in_stack ; i++)
201
print_info ("%s", get_current_filename ());
202
pop_file_from_stack ();
207
detect_badbox (const gchar *line)
209
gboolean current_line_is_empty;
214
if (g_regex_match (reg_badbox, line, 0, NULL))
216
msg.message_type = MESSAGE_TYPE_BADBOX;
219
if (detect_badbox_line (line, FALSE))
223
g_strlcpy (line_buf, line, BUFFER_SIZE);
233
g_strlcat (line_buf, line, BUFFER_SIZE);
235
current_line_is_empty = strlen (line) == 0;
236
if (detect_badbox_line (line_buf, current_line_is_empty))
242
// the return value is not important here
254
detect_badbox_line (const gchar *badbox, gboolean current_line_is_empty)
256
if (g_regex_match (reg_badbox_lines, badbox, 0, NULL))
259
gchar **strings = g_regex_split (reg_badbox_lines, badbox, 0);
260
msg.message = g_strdup (strings[1]);
261
long n1 = strtol (strings[2], NULL, 10);
262
long n2 = strtol (strings[3], NULL, 10);
263
msg.line = n1 < n2 ? n1 : n2;
264
g_strfreev (strings);
268
else if (g_regex_match (reg_badbox_line, badbox, 0, NULL))
271
gchar **strings = g_regex_split (reg_badbox_line, badbox, 0);
272
msg.message = g_strdup (strings[1]);
273
msg.line = strtol (strings[2], NULL, 10);
274
g_strfreev (strings);
278
else if (g_regex_match (reg_badbox_output, badbox, 0, NULL))
281
gchar **strings = g_regex_split (reg_badbox_output, badbox, 0);
282
msg.message = g_strdup (strings[1]);
284
g_strfreev (strings);
288
else if (nb_lines > 4 || current_line_is_empty)
291
msg.message = g_strdup (badbox);
301
detect_warning (const gchar *line)
303
gboolean current_line_is_empty;
309
if (g_regex_match (reg_warning, line, 0, NULL))
312
msg.message_type = MESSAGE_TYPE_WARNING;
314
strings = g_regex_split (reg_warning, line, 0);
316
if (detect_warning_line (strings[5], FALSE))
320
g_strlcpy (line_buf, strings[5], BUFFER_SIZE);
324
g_strfreev (strings);
328
else if (g_regex_match (reg_warning_no_file, line, 0, NULL))
331
msg.message_type = MESSAGE_TYPE_WARNING;
332
strings = g_regex_split (reg_warning_no_file, line, 0);
333
msg.message = g_strdup (strings[1]);
334
g_strfreev (strings);
344
g_strlcat (line_buf, line, BUFFER_SIZE);
346
current_line_is_empty = strlen (line) == 0;
347
if (detect_warning_line (line_buf, current_line_is_empty))
353
// the return value is not important here
365
detect_warning_line (const gchar *warning, gboolean current_line_is_empty)
367
if (g_regex_match (reg_warning_line, warning, 0, NULL))
370
gchar **strings = g_regex_split (reg_warning_line, warning, 0);
371
msg.message = g_strdup (strings[1]);
372
msg.line = strtol (strings[2], NULL, 10);
373
g_strfreev (strings);
377
else if (g_regex_match (reg_warning_international_line, warning, 0, NULL))
380
gchar **strings = g_regex_split (reg_warning_international_line, warning, 0);
381
msg.message = g_strdup (strings[1]);
382
msg.line = strtol (strings[2], NULL, 10);
383
g_strfreev (strings);
387
else if (warning[strlen (warning) - 1] == '.')
390
msg.message = g_strdup (warning);
395
else if (nb_lines > 5 || current_line_is_empty)
398
msg.message = g_strdup (warning);
408
detect_error (const gchar *line)
410
gboolean found = FALSE;
417
if (g_regex_match (reg_latex_error, line, 0, NULL))
420
strings = g_regex_split (reg_latex_error, line, 0);
421
tmp = g_strdup (strings[1]);
422
g_strfreev (strings);
425
else if (g_regex_match (reg_pdflatex_error, line, 0, NULL))
428
strings = g_regex_split (reg_pdflatex_error, line, 0);
429
tmp = g_strdup (strings[1]);
430
g_strfreev (strings);
433
else if (g_regex_match (reg_tex_error, line, 0, NULL))
436
strings = g_regex_split (reg_tex_error, line, 0);
437
tmp = g_strdup (strings[1]);
438
g_strfreev (strings);
445
msg.message_type = MESSAGE_TYPE_ERROR;
447
// the message is complete
448
if (line[strlen (line) - 1] == '.')
451
status = ERROR_SEARCH_LINE;
453
// the message is splitted
456
g_strlcpy (line_buf, tmp, BUFFER_SIZE);
467
g_strlcat (line_buf, line, BUFFER_SIZE);
470
if (line[strlen (line) - 1] == '.')
472
msg.message = g_strdup (line_buf);
473
status = ERROR_SEARCH_LINE;
475
else if (nb_lines > 4)
477
msg.message = g_strdup (line_buf);
484
// the return value is not important here
488
case ERROR_SEARCH_LINE:
490
if (g_regex_match (reg_error_line, line, 0, NULL))
492
strings = g_regex_split (reg_error_line, line, 0);
493
msg.line = strtol (strings[1], NULL, 10);
494
g_strfreev (strings);
500
else if (nb_lines > 11)
518
detect_other (const gchar *line)
520
if (strstr (line, "Output written on"))
522
/* try to show the file size in a human readable format */
523
if (g_regex_match (reg_other_bytes, line, 0, NULL))
525
gchar **strings = g_regex_split (reg_other_bytes, line, 0);
526
gint nb_bytes = strtol (strings[1], NULL, 10);
527
g_strfreev (strings);
529
gboolean replace = FALSE;
530
gchar *human_size = NULL;
534
msg.message = g_strdup (line);
536
// size in KB (less than 1 MB)
537
else if (nb_bytes < 1024 * 1024)
539
gint nb_kb = nb_bytes / 1024;
540
human_size = g_strdup_printf ("%d KB", nb_kb);
544
// size in MB (with one decimal)
547
gdouble nb_mb = (gdouble) nb_bytes / (1024.0 * 1024.0);
548
human_size = g_strdup_printf ("%.1f MB", nb_mb);
554
GError *error = NULL;
555
gchar *new_line = g_regex_replace_literal (reg_other_bytes,
556
line, -1, 0, human_size, 0, &error);
562
g_error_free (error);
564
msg.message = g_strdup (line);
567
msg.message = new_line;
573
msg.message = g_strdup (line);
576
msg.message_type = MESSAGE_TYPE_OTHER;
584
// There are basically two ways to detect the current file TeX is processing:
585
// 1) Use \Input (srctex or srcltx package) and \include exclusively. This will
586
// cause (La)TeX to print the line ":<+ filename" in the log file when opening a file,
587
// ":<-" when closing a file. Filenames pushed on the stack in this mode are marked
590
// 2) Since people will probably also use the \input command, we also have to be
591
// to detect the old-fashioned way. TeX prints '(filename' when opening a file and a ')'
592
// when closing one. It is impossible to detect this with 100% certainty (TeX prints many messages
593
// and even text (a context) from the TeX source file, there could be unbalanced parentheses),
594
// so we use a heuristic algorithm. In heuristic mode a ')' will only be considered as a signal that
595
// TeX is closing a file if the top of the stack is not marked as "reliable".
597
// The method used here is almost the same as in Kile.
599
update_stack_file (const gchar *line)
601
static gchar filename[BUFFER_SIZE] = "";
607
case FILENAME_HEURISTIC:
608
// TeX is opening a file
609
if (g_str_has_prefix (line, ":<+ "))
611
g_strlcpy (filename, line + 4, BUFFER_SIZE);
612
g_strstrip (filename);
616
else if (g_regex_match (reg_file_pop, line, 0, NULL)
617
|| g_str_has_prefix (line, ":<-"))
618
pop_file_from_stack ();
619
// fallback to the heuristic detection of filenames
621
update_stack_file_heuristic (line);
625
// The partial filename was followed by '(', this means that TeX is
626
// signalling it is opening the file. We are sure the filename is
627
// complete now. Don't call update_stack_file_heuristic()
628
// since we don't want the filename on the stack twice.
629
if (line[0] == '(' || g_str_has_prefix (line, "\\openout"))
631
push_file_on_stack (filename, TRUE);
635
// The partial filename was followed by a TeX error, meaning the
636
// file doesn't exist. Don't push it on the stack, instead try to
638
else if (line[0] == '!')
643
else if (g_str_has_prefix (line, "No file"))
646
detect_warning (line);
649
// the filename is not complete
652
tmp = g_strdup (line);
654
g_strlcat (filename, tmp, BUFFER_SIZE);
665
update_stack_file_heuristic (const gchar *line)
667
static gchar filename[BUFFER_SIZE] = "";
668
gboolean expect_filename = status == FILENAME_HEURISTIC;
670
int length = strlen (line);
672
// handle special case
673
if (expect_filename && length > 0 && line[0] == ')')
675
push_file_on_stack (filename, FALSE);
676
expect_filename = FALSE;
680
// scan for parentheses and grab filenames
681
for (int i = 0 ; i < length ; i++)
684
We're expecting a filename. If a filename really ends at this position,
685
one of the following must be true:
686
1) Next character is a space, indicating the end of a filename
687
(yes, there can't spaces in the path, this is a TeX limitation).
688
2) We're at the end of the line, the filename is probably
689
continued on the next line.
690
3) The file was closed already, signalled by the ')'.
693
gboolean is_last_char = i + 1 == length;
694
gboolean next_is_terminator =
695
is_last_char ? FALSE : (isspace (line[i+1]) || line[i+1] == ')');
697
if (expect_filename && (is_last_char || next_is_terminator))
699
g_strlcat (filename, line + index, strlen (filename) + i - index + 2);
701
if (strlen (filename) == 0)
704
// by default, an output line is 79 characters max
705
if ((is_last_char && i < 78) || next_is_terminator || file_exists (filename))
707
push_file_on_stack (filename, FALSE);
708
expect_filename = FALSE;
712
// Guess the filename is continued on the next line, only if the
713
// current filename does not exist
714
else if (is_last_char)
716
if (file_exists (filename))
718
push_file_on_stack (filename, FALSE);
719
expect_filename = FALSE;
723
status = FILENAME_HEURISTIC;
726
// filename not detected
731
expect_filename = FALSE;
735
// TeX is opening a file
736
else if (line[i] == '(')
740
// we need to extract the filename
741
expect_filename = TRUE;
742
// this is where the filename is supposed to start
746
// TeX is closing a file
747
// If this filename was pushed on the stack by the reliable ":<+-"
748
// method, don't pop, a ":<-" will follow. This helps in preventing
749
// unbalanced ')' from popping filenames from the stack too soon.
750
else if (line[i] == ')' && g_slist_length (stack_file) > 0
751
&& ! top_file_on_stack_reliable ())
752
pop_file_from_stack ();
757
file_exists (const gchar *filename)
759
gchar *full_path = get_path_if_file_exists (filename);
760
if (full_path != NULL)
768
// return NULL if the filename does not exist
769
// return the path of the filename if it exists (must be freed)
771
get_path_if_file_exists (const gchar *filename)
773
if (g_path_is_absolute (filename))
775
if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
776
return g_strdup (filename);
782
if (g_str_has_prefix (filename, "./"))
783
full_path = g_build_filename (path, filename + 2, NULL);
785
full_path = g_build_filename (path, filename, NULL);
787
if (g_file_test (full_path, G_FILE_TEST_IS_REGULAR))
790
// try to add various extensions on the filename to see if the file exists
791
gchar *extensions[] = {".tex", ".ltx", ".latex", ".dtx", ".ins"};
792
guint nb_ext = G_N_ELEMENTS (extensions);
793
for (guint i = 0 ; i < nb_ext ; i++)
795
gchar *tmp = g_strdup_printf ("%s%s", full_path, extensions[i]);
796
if (g_file_test (tmp, G_FILE_TEST_IS_REGULAR))
809
get_current_filename (void)
811
if (stack_file != NULL)
813
file_in_stack_t *file = stack_file->data;
814
return file->filename;
821
push_file_on_stack (gchar *filename, gboolean reliable)
823
//print_info ("***\tpush\t\"%s\" (%s)", filename, reliable ? "reliable" : "not reliable");
824
file_in_stack_t *file = g_malloc (sizeof (file_in_stack_t));
826
gchar *path = get_path_if_file_exists (filename);
828
file->filename = path;
830
file->filename = g_strdup (filename);
832
file->reliable = reliable;
833
stack_file = g_slist_prepend (stack_file, file);
837
pop_file_from_stack (void)
839
if (stack_file == NULL)
842
file_in_stack_t *file = stack_file->data;
843
//print_info ("***\tpop\t\"%s\" (%s)", file->filename, file->reliable ? "reliable" : "not reliable");
844
stack_file = g_slist_remove (stack_file, file);
845
g_free (file->filename);
850
top_file_on_stack_reliable (void)
852
// stack_file must contain at least one file
853
g_assert (stack_file != NULL);
855
file_in_stack_t *file = stack_file->data;
856
return file->reliable;
862
gchar *filename = get_current_filename ();
863
print_output_message (filename, msg.line, msg.message, msg.message_type);
866
msg.message_type = MESSAGE_TYPE_OTHER;
867
g_free (msg.message);