1#!/usr/local/bin/python3.8
2
3# file listerrors
4# This file is part of LyX, the document processor.
5# Licence details can be found in the file COPYING.
6
7# author Kayvan A. Sylvan
8
9# Full author contact details are available in file CREDITS.
10
11"""reformat noweb and compiler errors for LyX.
12
13Expects to read from stdin and output to stdout.
14"""
15
16__author__ = "Kayvan A. Sylvan <kayvan@sylvan.com>"
17__date__ = "$Date: 2003/10/13 09:50:10 $"
18__version__ = "$Revision: 1.4 $"
19__credits__ = """Edmar Wienskoski Jr. <edmar-w-jr@technologist.com>
20    original Literate support for LyX.
21Bernard Michael Hurley <berhardh@westherts.ac.uk>
22    modifications to original listerrors."""
23__copyright__ = "Copyright 2002 - Kayvan A. Sylvan."
24
25from __future__ import print_function
26import sys, string
27
28def write_error(msg, tool = "noweb", line_number = 1):
29  """Write out the given message in TeX error style.
30
31  called like: write_error(msg, tool, line_number)."""
32  print ("! Build Error: ==> %s ==>" % tool)
33  print (" ...\n\nl.%d ..." % line_number)
34  if type(msg) == type("str"): # simple string
35    print (msg)
36  else: # some kind of list (sequence or tuple)
37    for m in msg:
38        if m != "": print (m, end=" ")
39    print ()
40
41__lines = [] # lines pushed back
42
43def getline(file = sys.stdin):
44  """read a line from internal stack or from file.
45
46  optional file argument defaults to sys.stdin."""
47  global __lines
48  lines = __lines
49  if lines:
50    line = lines.pop()
51  else:
52    line = file.readline()
53  return line
54
55def pushline(line):
56  "push a line onto the pushback stack."
57  global __lines
58  lines = __lines
59  lines.append(line)
60
61def main():
62  """Entry point for listerrors. Takes no options.
63
64  Reads stdin and writes to stdout. Filter errors"""
65
66  while True:
67    line = getline()
68    if line == "": break
69    try_patterns_dispatch = [ noweb_try, gcc_try, xlc_try ]
70    for predicate in try_patterns_dispatch:
71      if predicate(line): break
72
73def noweb_try(line):
74  """see if line is a noweb error.
75
76  Returns 1 on success, 0 otherwise. Outputs on stdout."""
77  retval = 0
78  if string.find(line, ": unescaped << in documentation chunk") != -1:
79    line_parts = string.split(line, ':')
80    num_str = line_parts[1]
81    num_len = len(num_str)
82    i = 0
83    while i < num_len and (num_str[i] in string.digits): i = i + 1
84    if i == num_len:
85      write_error(":" + line_parts[2], "noweb", int(num_str))
86      retval = 1
87  if (not retval):
88    left = string.find(line, "<<")
89    if (left != -1) and ((left + 2) < len(line)) and \
90       (string.find(line[left+2:], ">>") != -1):
91      write_error(line, "noweb");
92      retval = 1;
93  if (not retval):
94    msgs_to_try = ("couldn't open file",
95      "couldn't open temporary file",
96      "error writing temporary file",
97      "ill-formed option",
98      "unknown option",
99      "Bad format sequence",
100      "Can't open output file",
101      "Can't open temporary file",
102      "Capacity exceeded:",
103      "Ignoring unknown option -",
104      "This can't happen:",
105      "non-numeric line number in")
106    for msg in msgs_to_try:
107      if string.find(line, msg) != -1:
108        write_error(line, "noweb")
109        retval = 1
110        break
111  return retval
112
113def gcc_try(line):
114  """See if line is a gcc error. Read ahead to handle all the lines.
115
116  Returns 1 on success, 0 otherwise. Outputs on stdout."""
117  retval = 0
118  first_space = string.find(line, ' ')
119  if first_space > 1: # The smallest would be "X: "
120    if line[first_space - 1] == ':':
121      header_to_see = line[:first_space - 1]
122      next_line = getline()
123      if next_line and next_line[:first_space - 1] == header_to_see:
124        num_end = first_space
125        while next_line[num_end] in string.digits: num_end = num_end + 1
126        if num_end > first_space: # good!
127          num_str = next_line[first_space:num_end]
128          msgs = [line[first_space:]]
129          msgs.append(next_line[num_end + 1:])
130          header_to_see = next_line[:num_end]
131          next_line = getline()
132          while next_line and next_line[:num_end] == header_to_see:
133            msgs.append(next_line[num_end + 1:])
134            next_line = getline()
135          if next_line: pushline(next_line)
136          write_error(msgs, "gcc", int(num_str))
137          retval = 1
138        else: # oops! Not a gcc error.
139          pushline(next_line)
140      elif next_line:
141        pushline(next_line) # return this line to input stream
142  return retval
143
144def xlc_try(line):
145  """see if line is an xlc error.
146
147  Returns 1 on success, 0 otherwise. Outputs on stdout."""
148  retval = 0
149  if line[0] == '"': # This is the first character of all xlc errors
150    next_quote = string.find(line, '"', 1)
151    first_space = string.find(line, ' ')
152    if (next_quote != -1) and (first_space > next_quote): # no space inisde quotes
153      if line[first_space - 1:first_space + 6] == ", line ":
154        num_start = num_end = first_space + 6
155        while line[num_end] in string.digits: num_end = num_end + 1
156        if num_end > num_start:
157          write_error(line, "xlc", int(line[num_start : num_end]))
158          retval = 1
159  return retval
160
161
162if __name__ == "__main__":
163  main()
164