gpscap.py.in 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. """
  2. gpscap - GPS/AIS capability dictionary class.
  3. This file is Copyright 2010 by the GPSD project
  4. SPDX-License-Identifier: BSD-2-clause
  5. """
  6. # This code runs compatibly under Python 2 and 3.x for x >= 2.
  7. # Preserve this property!
  8. from __future__ import absolute_import, print_function, division
  9. try:
  10. import configparser
  11. except ImportError:
  12. import ConfigParser as configparser
  13. class GPSDictionary(configparser.RawConfigParser):
  14. """Class GPSDictionary."""
  15. def __init__(self, *files):
  16. """Initialize the capability dictionary."""
  17. configparser.RawConfigParser.__init__(self)
  18. if not files:
  19. files = ["gpscap.ini", "@SHAREPATH@/gpscap.ini"]
  20. try:
  21. self.read(files, encoding='utf-8')
  22. except TypeError:
  23. self.read(files) # For Python 2.6
  24. # Resolve uses= members
  25. while True:
  26. keepgoing = False
  27. for section in self.sections():
  28. if self.has_option(section, "uses"):
  29. parent = self.get(section, "uses")
  30. if self.has_option(parent, "uses"):
  31. continue
  32. # Found a parent section without a uses = part.
  33. for heritable in self.options(parent):
  34. if not self.has_option(section, heritable):
  35. self.set(section,
  36. heritable,
  37. self.get(parent, heritable))
  38. keepgoing = True
  39. self.remove_option(section, "uses")
  40. if not keepgoing:
  41. break
  42. # Sanity check: All items must have a type field.
  43. for section in self.sections():
  44. if not self.has_option(section, "type"):
  45. raise configparser.Error("%s has no type" % section)
  46. if ((self.get(section, "type")
  47. not in ("engine", "vendor", "device"))):
  48. raise configparser.Error("%s has invalid type" % section)
  49. # Sanity check: All devices must point at a vendor object.
  50. # Side effect: build the lists of vendors and devices.
  51. self.vendors = []
  52. self.devices = []
  53. for section in self.sections():
  54. if self.get(section, "type") == "vendor":
  55. self.vendors.append(section)
  56. if self.get(section, "type") == "device":
  57. self.devices.append(section)
  58. self.vendors.sort()
  59. for section in self.sections():
  60. if self.get(section, "type") == "device":
  61. if not self.has_option(section, "vendor"):
  62. raise configparser.Error("%s has no vendor" % section)
  63. if self.get(section, "vendor") not in self.vendors:
  64. raise configparser.Error("%s has invalid vendor" % section)
  65. def HTMLDump(self, ofp):
  66. """HTMLDUmper."""
  67. thead = """
  68. <table style='border:1px solid gray;font-size:small;background-color:#CCCCCC'>
  69. <caption>Listing %s devices from %s vendors</caption>
  70. <tr>
  71. <th>Name</th>
  72. <th>Packaging</th>
  73. <th>Engine</th>
  74. <th>Interface</th>
  75. <th>Tested with</th>
  76. <th>NMEA version</th>
  77. <th>PPS</th>
  78. <th style='width:50%%'>Notes</th>
  79. </tr>
  80. """
  81. vhead1 = "<tr><td style='text-align:center;' colspan='8'>" \
  82. "<a href='%s'>%s</a></td></tr>\n"
  83. vhead2 = "<tr><td style='text-align:center;' colspan='8'>" \
  84. "<a href='%s'>%s</a><br><p>%s</p></td></tr>\n"
  85. hotpluggables = ("pl2303", "CP2101")
  86. ofp.write(thead % (len(self.devices), len(self.vendors)))
  87. for vendor in self.vendors:
  88. if self.has_option(vendor, "notes"):
  89. ofp.write(vhead2 % (self.get(vendor, "vendor_site"), vendor,
  90. self.get(vendor, "notes")))
  91. else:
  92. ofp.write(vhead1 % (self.get(vendor, "vendor_site"), vendor))
  93. relevant = []
  94. for dev in self.devices:
  95. if self.get(dev, "vendor") == vendor:
  96. relevant.append(dev)
  97. relevant.sort()
  98. for dev in relevant:
  99. rowcolor = "white"
  100. if self.get(dev, "packaging") == "OEM module":
  101. rowcolor = "#32CD32"
  102. elif self.get(dev, "packaging") == "chipset":
  103. rowcolor = "#FFFFE0"
  104. elif self.get(dev, "packaging") == "handset":
  105. rowcolor = "#00FFFF"
  106. elif self.get(dev, "packaging") == "hansdfree":
  107. rowcolor = "#008B8B"
  108. ofp.write("<tr itemscope itemtype='http://schema.org/Product'"
  109. " style='background-color:%s'>\n" % rowcolor)
  110. namefield = dev
  111. if self.has_option(dev, "techdoc"):
  112. namefield = "<a href='%s'>%s</a>" \
  113. % (self.get(dev, "techdoc"), dev)
  114. if ((self.has_option(dev, "discontinued") and
  115. self.getboolean(dev, "discontinued"))):
  116. namefield = namefield + "&nbsp;<img title='Device " \
  117. "discontinued' src='discontinued.png' " \
  118. "alt='Discontinued icon'>"
  119. ofp.write("<td itemprop='name'>%s</td>\n" % namefield)
  120. ofp.write("<td>%s</td>\n" % self.get(dev, "packaging"))
  121. engine = self.get(dev, "engine")
  122. if self.has_option(engine, "techdoc"):
  123. engine = "<a href='%s'>%s</a>" \
  124. % (self.get(engine, "techdoc"), engine)
  125. if self.has_option(dev, "subtype"):
  126. engine += " (" + self.get(dev, "subtype") + ")"
  127. ofp.write("<td>%s</td>\n" % engine)
  128. interfaces = self.get(dev, "interfaces")
  129. if self.has_option(dev, "pps"):
  130. interfaces += ",PPS"
  131. ofp.write("<td>%s</td>\n" % interfaces)
  132. testfield = ""
  133. if self.has_option(dev, "tested"):
  134. tested = self.get(dev, "tested")
  135. if tested == "regression":
  136. testfield += "<img title='Have regression test' " \
  137. "src='regression.png' " \
  138. "alt='Regression-test icon'>"
  139. else:
  140. testfield += tested
  141. if ((self.has_option(dev, "configurable") and
  142. self.get(dev, "configurable") == 'insane')):
  143. testfield += "<img title='Requires -b option' " \
  144. "src='noconfigure.png' " \
  145. "alt='No-configure icon'>"
  146. if self.get(dev, "rating") == "excellent":
  147. testfield += "<img src='star.png' alt='Star icon'>" \
  148. "<img src='star.png' alt='Star icon'>" \
  149. "<img src='star.png' alt='Star icon'>" \
  150. "<img src='star.png' alt='Star icon'>"
  151. elif self.get(dev, "rating") == "good":
  152. testfield += "<img src='star.png' alt='Star icon'>" \
  153. "<img src='star.png' alt='Star icon'>" \
  154. "<img src='star.png' alt='Star icon'>"
  155. elif self.get(dev, "rating") == "fair":
  156. testfield += "<img src='star.png' alt='Star icon'>" \
  157. "<img src='star.png' alt='Star icon'>"
  158. elif self.get(dev, "rating") == "poor":
  159. testfield += "<img src='star.png' alt='Star icon'>"
  160. elif self.get(dev, "rating") == "broken":
  161. testfield += "<img title='Device is broken' " \
  162. "src='bomb.png' alt='Bomb icon'>"
  163. if ((self.has_option(dev, "usbchip") and
  164. self.get(dev, "usbchip") in hotpluggables)):
  165. testfield += "<img title='udev hotplug' " \
  166. "src='hotplug.png' alt='Hotplug icon'>"
  167. ofp.write("<td>%s</td>\n" % testfield)
  168. nmea = "&nbsp;"
  169. if self.has_option(dev, "nmea"):
  170. nmea = self.get(dev, "nmea")
  171. ofp.write("<td>%s</td>\n" % nmea)
  172. if ((self.has_option(dev, "pps") and
  173. self.get(dev, "pps") == "True")):
  174. pps_accuracy = time_offset = ""
  175. if self.has_option(dev, "pps_accuracy"):
  176. pps_accuracy = self.get(dev, "pps_accuracy")
  177. if self.has_option(dev, "time_offset"):
  178. time_offset = self.get(dev, "time_offset")
  179. if pps_accuracy and time_offset:
  180. ofp.write("<td>%s<br>%s</td>\n"
  181. % (pps_accuracy, time_offset))
  182. else:
  183. ofp.write("<td>?<br>\n")
  184. else:
  185. ofp.write("<td>No</td>\n")
  186. if self.has_option(dev, "notes"):
  187. notes = self.get(dev, "notes")
  188. else:
  189. notes = ""
  190. if self.has_option(dev, "submitter"):
  191. notes += " Reported by %s." % self.get(
  192. dev, "submitter").replace("@", "&#x40;").replace(
  193. "<", "&lt;").replace(">", "&gt;")
  194. ofp.write("<td itemscope itemtype='http://schema.org/"
  195. "description'>%s</td>\n" % notes)
  196. ofp.write("</tr>\n")
  197. ofp.write("</table>\n")
  198. if __name__ == "__main__":
  199. import sys
  200. try:
  201. d = GPSDictionary()
  202. d.HTMLDump(sys.stdout)
  203. except configparser.Error as e:
  204. sys.stderr.write(sys.argv[0] + ":%s\n" % e)
  205. raise SystemExit(1)
  206. # vim: set expandtab shiftwidth=4