parser_standard_options.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. """
  2. Created on Fri Jun 26 19:10:58 2015
  3. @author: pietro
  4. """
  5. from __future__ import print_function
  6. import argparse
  7. import sys
  8. try:
  9. from urllib.request import urlopen
  10. except ImportError:
  11. from urllib2 import urlopen
  12. from build_html import *
  13. def parse_options(lines, startswith="Opt"):
  14. def split_in_groups(lines):
  15. def count_par_diff(line):
  16. open_par = line.count("(")
  17. close_par = line.count(")")
  18. return open_par - close_par
  19. res = None
  20. diff = 0
  21. for line in lines:
  22. if line.startswith("case"):
  23. optname = line.split()[1][:-1]
  24. res = []
  25. # if optname == 'G_OPT_R_BASENAME_INPUT':
  26. # import ipdb; ipdb.set_trace()
  27. elif line == "break;":
  28. diff = 0
  29. yield optname, res
  30. elif line.startswith("G_"):
  31. diff = count_par_diff(line)
  32. elif diff > 0:
  33. diff -= count_par_diff(line)
  34. else:
  35. res.append(line) if res is not None else None
  36. def split_opt_line(line):
  37. index = line.index("=")
  38. key = line[:index].strip()
  39. default = line[index + 1 :].strip()
  40. if default.startswith("_("):
  41. default = default[2:]
  42. return key, default
  43. def parse_glines(glines):
  44. res = {}
  45. key = None
  46. dynamic_answer = False
  47. for line in glines:
  48. if line.strip() == "/* start dynamic answer */":
  49. dynamic_answer = True
  50. if line.strip() == "/* end dynamic answer */":
  51. dynamic_answer = False
  52. if dynamic_answer or line.startswith("/*"):
  53. continue
  54. if line.startswith("/*"):
  55. continue
  56. if line.startswith(startswith) and line.endswith(";"):
  57. key, default = [w.strip() for w in split_opt_line(line[5:])]
  58. res[key] = default
  59. elif line.startswith(startswith):
  60. key, default = split_opt_line(line[5:])
  61. res[key] = [
  62. default,
  63. ]
  64. else:
  65. if key is not None:
  66. if key not in res:
  67. res[key] = []
  68. start, end = 0, -1
  69. if line.startswith("_("):
  70. start = 2
  71. if line.endswith(");"):
  72. end = -3
  73. elif line.endswith(";"):
  74. end = -2
  75. res[key].append(line[start:end])
  76. # pprint(glines)
  77. # pprint(res)
  78. return res
  79. def clean_value(val):
  80. if isinstance(val, list):
  81. val = " ".join(val)
  82. return (
  83. (val.replace('"', "").replace("'", "'").strip().strip(";"))
  84. .strip()
  85. .strip("_(")
  86. .strip()
  87. .strip(")")
  88. .strip()
  89. )
  90. # with open(optionfile, mode='r') as optfile:
  91. lines = [line.strip() for line in lines]
  92. result = []
  93. for optname, glines in split_in_groups(lines):
  94. if glines:
  95. res = parse_glines(glines)
  96. if res:
  97. for key, val in res.items():
  98. res[key] = clean_value(val)
  99. result.append((optname, res))
  100. return result
  101. class OptTable(object):
  102. def __init__(self, list_of_dict):
  103. self.options = list_of_dict
  104. self.columns = sorted(set([key for _, d in self.options for key in d.keys()]))
  105. def csv(self, delimiter=";", endline="\n"):
  106. """Return a CSV string with the options"""
  107. csv = []
  108. csv.append(delimiter.join(self.columns))
  109. for optname, options in self.options:
  110. opts = [options.get(col, "") for col in self.columns]
  111. csv.append(
  112. delimiter.join(
  113. [
  114. optname,
  115. ]
  116. + opts
  117. )
  118. )
  119. return endline.join(csv)
  120. def html(self, endline="\n", indent=" ", toptions="border=1"):
  121. """Return a HTML table with the options"""
  122. html = ["<table{0}>".format(" " + toptions if toptions else "")]
  123. # write headers
  124. html.append(indent + "<thead>")
  125. html.append(indent + "<tr>")
  126. html.append(indent * 2 + "<th>{0}</th>".format("option"))
  127. for col in self.columns:
  128. html.append(indent * 2 + "<th>{0}</th>".format(col))
  129. html.append(indent + "</tr>")
  130. html.append(indent + "</thead>")
  131. html.append(indent + "<tbody>")
  132. for optname, options in self.options:
  133. html.append(indent + "<tr>")
  134. html.append(indent * 2 + "<td>{0}</td>".format(optname))
  135. for col in self.columns:
  136. html.append(indent * 2 + "<td>{0}</td>".format(options.get(col, "")))
  137. html.append(indent + "</tr>")
  138. html.append(indent + "</tbody>")
  139. html.append("</table>")
  140. return endline.join(html)
  141. def _repr_html_(self):
  142. """Method used by IPython notebook"""
  143. return self.html()
  144. if __name__ == "__main__":
  145. URL = (
  146. "https://trac.osgeo.org/grass/browser/grass/"
  147. "trunk/lib/gis/parser_standard_options.c?format=txt"
  148. )
  149. parser = argparse.ArgumentParser(
  150. description="Extract GRASS default " "options from link."
  151. )
  152. parser.add_argument(
  153. "-f",
  154. "--format",
  155. default="html",
  156. dest="format",
  157. choices=["html", "csv", "grass"],
  158. help="Define the output format",
  159. )
  160. parser.add_argument(
  161. "-l",
  162. "--link",
  163. default=URL,
  164. dest="url",
  165. type=str,
  166. help="Provide the url with the file to parse",
  167. )
  168. parser.add_argument(
  169. "-t",
  170. "--text",
  171. dest="text",
  172. type=argparse.FileType("r"),
  173. help="Provide the file to parse",
  174. )
  175. parser.add_argument(
  176. "-o",
  177. "--output",
  178. default=sys.stdout,
  179. dest="output",
  180. type=argparse.FileType("w"),
  181. help="Provide the url with the file to parse",
  182. )
  183. parser.add_argument(
  184. "-s",
  185. "--starts-with",
  186. default="Opt",
  187. dest="startswith",
  188. type=str,
  189. help="Extract only the options that starts with this",
  190. )
  191. parser.add_argument(
  192. "-p",
  193. "--html_params",
  194. default="border=1",
  195. type=str,
  196. dest="htmlparmas",
  197. help="Options for the HTML table",
  198. )
  199. args = parser.parse_args()
  200. cfile = args.text if args.text else urlopen(args.url, proxies=None)
  201. options = OptTable(parse_options(cfile.readlines(), startswith=args.startswith))
  202. outform = args.format
  203. if outform in ["csv", "html"]:
  204. print(getattr(options, outform)(), file=args.output)
  205. args.output.close()
  206. else:
  207. year = os.getenv("VERSION_DATE")
  208. name = args.output.name
  209. args.output.close()
  210. topicsfile = open(name, "w")
  211. topicsfile.write(
  212. header1_tmpl.substitute(
  213. title="GRASS GIS "
  214. "%s Reference Manual: Parser standard options index" % grass_version
  215. )
  216. )
  217. topicsfile.write(headerpso_tmpl)
  218. topicsfile.write(options.html(toptions=args.htmlparmas))
  219. write_html_footer(topicsfile, "index.html", year)
  220. topicsfile.close()