maskaudit.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. #!/usr/bin/env python3
  2. #
  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. # Codacy D203 and D211 conflict, I choose D203
  9. # Codacy D212 and D213 conflict, I choose D212
  10. """Program to generate code for gpsd masks.
  11. With -p, dump a Python status mask list translated from the C one.
  12. With -c, generate C code to dump masks for debugging purposes.
  13. With -t, tabulate usage of defines to find unused ones. Requires -c or -d.
  14. """
  15. from __future__ import absolute_import, print_function, division
  16. import argparse
  17. import glob
  18. import sys
  19. try:
  20. from subprocess import getstatusoutput
  21. except ImportError:
  22. from commands import getstatusoutput
  23. class SourceExtractor(object):
  24. """SourceExtractor Class."""
  25. def __init__(self, sourcefile, clientside):
  26. """Init for SourceExtractor."""
  27. self.sourcefile = sourcefile
  28. self.clientside = clientside
  29. self.daemonfiles = [
  30. "gpsd.c",
  31. "libgpsd_core.c",
  32. "pseudonmea.c",
  33. "drivers.c",
  34. "gpsmon/gpsmon.c",
  35. "subframe.c"
  36. ] + glob.glob("driver_*.c") + glob.glob("gpsmon/monitor_*.c")
  37. self.masks = []
  38. self.primitive_masks = []
  39. for line in open(self.sourcefile):
  40. if (((line.startswith("#define") and
  41. ("_SET" in line or "_IS" in line)))):
  42. fields = line.split()
  43. self.masks.append((fields[1], fields[2]))
  44. if ((fields[2].startswith("(1llu<<") or
  45. fields[2].startswith("INTERNAL_SET"))):
  46. self.primitive_masks.append((fields[1], fields[2]))
  47. def in_library(self, flg):
  48. """Grep in library."""
  49. (status, _output) = getstatusoutput(
  50. "grep '%s' libgps/libgps_core.c libgps/libgps_json.c gpsctl.c" %
  51. flg)
  52. return status == 0
  53. def in_daemon(self, flg):
  54. """Grep in daemon."""
  55. (status, _output) = getstatusoutput(
  56. "grep '%s' %s" % (flg, " ".join(self.daemonfiles)))
  57. return status == 0
  58. def relevant(self, flg):
  59. """Relevant??"""
  60. if self.clientside:
  61. return self.in_library(flg)
  62. return self.in_daemon(flg)
  63. if __name__ == '__main__':
  64. description = 'Tool for reporting gpsd status masks.'
  65. usage = '%(prog)s [OPTIONS] [host[:port[:device]]]'
  66. epilog = ('BSD terms apply: see the file COPYING in the distribution root'
  67. ' for details.')
  68. parser = argparse.ArgumentParser(
  69. description=description,
  70. epilog=epilog,
  71. formatter_class=argparse.RawDescriptionHelpFormatter,
  72. usage=usage)
  73. parser.add_argument(
  74. '-?',
  75. action="help",
  76. help='show this help message and exit'
  77. )
  78. parser.add_argument(
  79. '-d',
  80. '--daemongen',
  81. action="store_true",
  82. default=False,
  83. dest='daemongen',
  84. help=('Generate C code to dump masks for debugging'
  85. ' [Default %(default)s]'),
  86. )
  87. parser.add_argument(
  88. '-c',
  89. '--clientgen',
  90. action="store_true",
  91. default=False,
  92. dest='clientgen',
  93. help=('Generate C code to dump masks for debugging'
  94. ' [Default %(default)s]'),
  95. )
  96. parser.add_argument(
  97. '-p',
  98. '--pythonize',
  99. action="store_true",
  100. default=False,
  101. dest='pythonize',
  102. help=('Dump a Python status mask list. [Default %(default)s]'),
  103. )
  104. parser.add_argument(
  105. '-t',
  106. '--tabulate',
  107. action="store_true",
  108. default=False,
  109. dest='tabulate',
  110. help=('Tabulate usage of defines to find unused ones. '
  111. ' Requires -c or -d. [Default %(default)s]'),
  112. )
  113. # parser.add_argument(
  114. # '-V', '--version',
  115. # action='version',
  116. # help='Output version to stderr, then exit',
  117. # version="%(prog)s: Version " + gps_version + "\n",
  118. # )
  119. parser.add_argument(
  120. 'arguments',
  121. help='Source Directory',
  122. nargs='?',
  123. )
  124. options = parser.parse_args()
  125. if not options.arguments:
  126. srcdir = '.'
  127. else:
  128. srcdir = options.arguments
  129. clientside = SourceExtractor(srcdir + "/include/gps.h",
  130. clientside=True)
  131. daemonside = SourceExtractor(srcdir + "/include/gpsd.h",
  132. clientside=False)
  133. if options.clientgen:
  134. source = clientside
  135. banner = "Library"
  136. elif options.daemongen:
  137. source = daemonside
  138. banner = "Daemon"
  139. else:
  140. sys.stderr.write("maskaudit: need -c or -d option\n")
  141. sys.exit(1)
  142. try:
  143. if options.tabulate:
  144. print("%-14s %8s" % (" ", banner))
  145. for (flag, value) in source.masks:
  146. print("%-14s %8s" % (flag, source.relevant(flag)))
  147. if options.pythonize:
  148. for (d, v) in source.masks:
  149. if v[-1] == 'u':
  150. v = v[:-1]
  151. print("%-15s\t= %s" % (d, v))
  152. if not options.pythonize and not options.tabulate:
  153. maxout = 0
  154. for (d, v) in source.primitive_masks:
  155. if source.relevant(d):
  156. stem = d
  157. if stem.endswith("_SET"):
  158. stem = stem[:-4]
  159. if stem.endswith("_IS"):
  160. stem = stem[:-3]
  161. maxout += len(stem) + 1
  162. print("""
  163. // This code is generated by maskaudit.py. Do not hand-hack it!
  164. /*
  165. * Also, beware that it is something of a CPU hog when called on every packet.
  166. * Try to write guards so it is only called at higher log levels.
  167. */
  168. #include \"../include/gpsd_config.h\" /* must be before all includes */
  169. #include <stdio.h>
  170. #include <string.h>
  171. #include \"../include/gpsd.h\"
  172. const char *gps_maskdump(gps_mask_t set)
  173. {
  174. static char buf[%d];
  175. const struct {
  176. gps_mask_t mask;
  177. const char *name;
  178. } *sp, names[] = {""" % (maxout + 3,))
  179. masks = clientside.primitive_masks + daemonside.primitive_masks
  180. for (flag, value) in masks:
  181. stem = flag
  182. if stem.endswith("_SET"):
  183. stem = stem[:-4]
  184. if stem.endswith("_IS"):
  185. stem = stem[:-3]
  186. print(" {%s,\t\"%s\"}," % (flag, stem))
  187. print('''\
  188. };
  189. memset(buf, '\\0', sizeof(buf));
  190. buf[0] = '{';
  191. for (sp = names; sp < names + sizeof(names)/sizeof(names[0]); sp++)
  192. if ((set & sp->mask)!=0) {
  193. (void)strlcat(buf, sp->name, sizeof(buf));
  194. (void)strlcat(buf, "|", sizeof(buf));
  195. }
  196. if (buf[1] != \'\\0\')
  197. buf[strlen(buf)-1] = \'\\0\';
  198. (void)strlcat(buf, "}", sizeof(buf));
  199. return buf;
  200. }
  201. ''')
  202. except KeyboardInterrupt:
  203. pass
  204. # The following sets edit modes for GNU EMACS
  205. # Local Variables:
  206. # mode:python
  207. # End:
  208. # vim: set expandtab shiftwidth=4