update-copyright.py 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797
  1. #!/usr/bin/env python3
  2. #
  3. # Copyright (C) 2013-2022 Free Software Foundation, Inc.
  4. #
  5. # This script is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation; either version 3, or (at your option)
  8. # any later version.
  9. # This script adjusts the copyright notices at the top of source files
  10. # so that they have the form:
  11. #
  12. # Copyright XXXX-YYYY Free Software Foundation, Inc.
  13. #
  14. # It doesn't change code that is known to be maintained elsewhere or
  15. # that carries a non-FSF copyright.
  16. #
  17. # The script also doesn't change testsuite files, except those in
  18. # libstdc++-v3. This is because libstdc++-v3 has a conformance testsuite,
  19. # while most tests in other directories are just things that failed at some
  20. # point in the past.
  21. #
  22. # Pass --this-year to the script if you want it to add the current year
  23. # to all applicable notices. Pass --quilt if you are using quilt and
  24. # want files to be added to the quilt before being changed.
  25. #
  26. # By default the script will update all directories for which the
  27. # output has been vetted. You can instead pass the names of individual
  28. # directories, including those that haven't been approved. So:
  29. #
  30. # update-copyright.py --this-year
  31. #
  32. # is the command that would be used at the beginning of a year to update
  33. # all copyright notices (and possibly at other times to check whether
  34. # new files have been added with old years). On the other hand:
  35. #
  36. # update-copyright.py --this-year libitm
  37. #
  38. # would run the script on just libitm/.
  39. #
  40. # Note that things like --version output strings must be updated before
  41. # this script is run. There's already a separate procedure for that.
  42. import os
  43. import re
  44. import sys
  45. import time
  46. import subprocess
  47. class Errors:
  48. def __init__ (self):
  49. self.num_errors = 0
  50. def report (self, filename, string):
  51. if filename:
  52. string = filename + ': ' + string
  53. sys.stderr.write (string + '\n')
  54. self.num_errors += 1
  55. def ok (self):
  56. return self.num_errors == 0
  57. class GenericFilter:
  58. def __init__ (self):
  59. self.skip_files = set()
  60. self.skip_dirs = set()
  61. self.skip_extensions = set([
  62. '.png',
  63. '.pyc',
  64. ])
  65. self.fossilised_files = set()
  66. self.own_files = set()
  67. self.skip_files |= set ([
  68. # Skip licence files.
  69. 'COPYING',
  70. 'COPYING.LIB',
  71. 'COPYING3',
  72. 'COPYING3.LIB',
  73. 'LICENSE',
  74. 'LICENSE.txt',
  75. 'fdl.texi',
  76. 'gpl_v3.texi',
  77. 'fdl-1.3.xml',
  78. 'gpl-3.0.xml',
  79. # Skip auto- and libtool-related files
  80. 'aclocal.m4',
  81. 'compile',
  82. 'config.guess',
  83. 'config.sub',
  84. 'depcomp',
  85. 'install-sh',
  86. 'libtool.m4',
  87. 'ltmain.sh',
  88. 'ltoptions.m4',
  89. 'ltsugar.m4',
  90. 'ltversion.m4',
  91. 'lt~obsolete.m4',
  92. 'missing',
  93. 'mkdep',
  94. 'mkinstalldirs',
  95. 'move-if-change',
  96. 'shlibpath.m4',
  97. 'symlink-tree',
  98. 'ylwrap',
  99. # Skip FSF mission statement, etc.
  100. 'gnu.texi',
  101. 'funding.texi',
  102. 'appendix_free.xml',
  103. # Skip imported texinfo files.
  104. 'texinfo.tex',
  105. ])
  106. def get_line_filter (self, dir, filename):
  107. if filename.startswith ('ChangeLog'):
  108. # Ignore references to copyright in changelog entries.
  109. return re.compile ('\t')
  110. return None
  111. def skip_file (self, dir, filename):
  112. if filename in self.skip_files:
  113. return True
  114. (base, extension) = os.path.splitext (os.path.join (dir, filename))
  115. if extension in self.skip_extensions:
  116. return True
  117. if extension == '.in':
  118. # Skip .in files produced by automake.
  119. if os.path.exists (base + '.am'):
  120. return True
  121. # Skip files produced by autogen
  122. if (os.path.exists (base + '.def')
  123. and os.path.exists (base + '.tpl')):
  124. return True
  125. # Skip configure files produced by autoconf
  126. if filename == 'configure':
  127. if os.path.exists (base + '.ac'):
  128. return True
  129. if os.path.exists (base + '.in'):
  130. return True
  131. return False
  132. def skip_dir (self, dir, subdir):
  133. return subdir in self.skip_dirs
  134. def is_fossilised_file (self, dir, filename):
  135. if filename in self.fossilised_files:
  136. return True
  137. # Only touch current current ChangeLogs.
  138. if filename != 'ChangeLog' and filename.find ('ChangeLog') >= 0:
  139. return True
  140. return False
  141. def by_package_author (self, dir, filename):
  142. return filename in self.own_files
  143. class Copyright:
  144. def __init__ (self, errors):
  145. self.errors = errors
  146. # Characters in a range of years. Include '.' for typos.
  147. ranges = '[0-9](?:[-0-9.,\s]|\s+and\s+)*[0-9]'
  148. # Non-whitespace characters in a copyright holder's name.
  149. name = '[\w.,-]'
  150. # Matches one year.
  151. self.year_re = re.compile ('[0-9]+')
  152. # Matches part of a year or copyright holder.
  153. self.continuation_re = re.compile (ranges + '|' + name)
  154. # Matches a full copyright notice:
  155. self.copyright_re = re.compile (
  156. # 1: 'Copyright (C)', etc.
  157. '([Cc]opyright'
  158. '|[Cc]opyright\s+\([Cc]\)'
  159. '|[Cc]opyright\s+%s'
  160. '|[Cc]opyright\s+©'
  161. '|[Cc]opyright\s+@copyright{}'
  162. '|copyright = u\''
  163. '|@set\s+copyright[\w-]+)'
  164. # 2: the years. Include the whitespace in the year, so that
  165. # we can remove any excess.
  166. '(\s*(?:' + ranges + ',?'
  167. '|@value\{[^{}]*\})\s*)'
  168. # 3: 'by ', if used
  169. '(by\s+)?'
  170. # 4: the copyright holder. Don't allow multiple consecutive
  171. # spaces, so that right-margin gloss doesn't get caught
  172. # (e.g. gnat_ugn.texi).
  173. '(' + name + '(?:\s?' + name + ')*)?')
  174. # A regexp for notices that might have slipped by. Just matching
  175. # 'copyright' is too noisy, and 'copyright.*[0-9]' falls foul of
  176. # HTML header markers, so check for 'copyright' and two digits.
  177. self.other_copyright_re = re.compile ('copyright.*[0-9][0-9]',
  178. re.IGNORECASE)
  179. self.comment_re = re.compile('#+|[*]+|;+|%+|//+|@c |dnl ')
  180. self.holders = { '@copying': '@copying' }
  181. self.holder_prefixes = set()
  182. # True to 'quilt add' files before changing them.
  183. self.use_quilt = False
  184. # If set, force all notices to include this year.
  185. self.max_year = None
  186. # Goes after the year(s). Could be ', '.
  187. self.separator = ' '
  188. def add_package_author (self, holder, canon_form = None):
  189. if not canon_form:
  190. canon_form = holder
  191. self.holders[holder] = canon_form
  192. index = holder.find (' ')
  193. while index >= 0:
  194. self.holder_prefixes.add (holder[:index])
  195. index = holder.find (' ', index + 1)
  196. def add_external_author (self, holder):
  197. self.holders[holder] = None
  198. class BadYear (Exception):
  199. def __init__ (self, year):
  200. self.year = year
  201. def __str__ (self):
  202. return 'unrecognised year: ' + self.year
  203. def parse_year (self, string):
  204. year = int (string)
  205. if len (string) == 2:
  206. if year > 70:
  207. return year + 1900
  208. elif len (string) == 4:
  209. return year
  210. raise self.BadYear (string)
  211. def year_range (self, years):
  212. year_list = [self.parse_year (year)
  213. for year in self.year_re.findall (years)]
  214. assert len (year_list) > 0
  215. return (min (year_list), max (year_list))
  216. def set_use_quilt (self, use_quilt):
  217. self.use_quilt = use_quilt
  218. def include_year (self, year):
  219. assert not self.max_year
  220. self.max_year = year
  221. def canonicalise_years (self, dir, filename, filter, years):
  222. # Leave texinfo variables alone.
  223. if years.startswith ('@value'):
  224. return years
  225. (min_year, max_year) = self.year_range (years)
  226. # Update the upper bound, if enabled.
  227. if self.max_year and not filter.is_fossilised_file (dir, filename):
  228. max_year = max (max_year, self.max_year)
  229. # Use a range.
  230. if min_year == max_year:
  231. return '%d' % min_year
  232. else:
  233. return '%d-%d' % (min_year, max_year)
  234. def strip_continuation (self, line):
  235. line = line.lstrip()
  236. match = self.comment_re.match (line)
  237. if match:
  238. line = line[match.end():].lstrip()
  239. return line
  240. def is_complete (self, match):
  241. holder = match.group (4)
  242. return (holder
  243. and (holder not in self.holder_prefixes
  244. or holder in self.holders))
  245. def update_copyright (self, dir, filename, filter, file, line, match):
  246. orig_line = line
  247. next_line = None
  248. pathname = os.path.join (dir, filename)
  249. intro = match.group (1)
  250. if intro.startswith ('@set'):
  251. # Texinfo year variables should always be on one line
  252. after_years = line[match.end (2):].strip()
  253. if after_years != '':
  254. self.errors.report (pathname,
  255. 'trailing characters in @set: '
  256. + after_years)
  257. return (False, orig_line, next_line)
  258. else:
  259. # If it looks like the copyright is incomplete, add the next line.
  260. while not self.is_complete (match):
  261. try:
  262. next_line = file.readline()
  263. except StopIteration:
  264. break
  265. # If the next line doesn't look like a proper continuation,
  266. # assume that what we've got is complete.
  267. continuation = self.strip_continuation (next_line)
  268. if not self.continuation_re.match (continuation):
  269. break
  270. # Merge the lines for matching purposes.
  271. orig_line += next_line
  272. line = line.rstrip() + ' ' + continuation
  273. next_line = None
  274. # Rematch with the longer line, at the original position.
  275. match = self.copyright_re.match (line, match.start())
  276. assert match
  277. holder = match.group (4)
  278. # Use the filter to test cases where markup is getting in the way.
  279. if filter.by_package_author (dir, filename):
  280. assert holder not in self.holders
  281. elif not holder:
  282. self.errors.report (pathname, 'missing copyright holder')
  283. return (False, orig_line, next_line)
  284. elif holder not in self.holders:
  285. self.errors.report (pathname,
  286. 'unrecognised copyright holder: ' + holder)
  287. return (False, orig_line, next_line)
  288. else:
  289. # See whether the copyright is associated with the package
  290. # author.
  291. canon_form = self.holders[holder]
  292. if not canon_form:
  293. return (False, orig_line, next_line)
  294. # Make sure the author is given in a consistent way.
  295. line = (line[:match.start (4)]
  296. + canon_form
  297. + line[match.end (4):])
  298. # Remove any 'by'
  299. line = line[:match.start (3)] + line[match.end (3):]
  300. # Update the copyright years.
  301. years = match.group (2).strip()
  302. try:
  303. canon_form = self.canonicalise_years (dir, filename, filter, years)
  304. except self.BadYear as e:
  305. self.errors.report (pathname, str (e))
  306. return (False, orig_line, next_line)
  307. line = (line[:match.start (2)]
  308. + ('' if intro.startswith ('copyright = ') else ' ')
  309. + canon_form + self.separator
  310. + line[match.end (2):])
  311. # Use the standard (C) form.
  312. if intro.endswith ('right'):
  313. intro += ' (C)'
  314. elif intro.endswith ('(c)'):
  315. intro = intro[:-3] + '(C)'
  316. line = line[:match.start (1)] + intro + line[match.end (1):]
  317. # Strip trailing whitespace
  318. line = line.rstrip() + '\n'
  319. return (line != orig_line, line, next_line)
  320. def guess_encoding (self, pathname):
  321. for encoding in ('utf8', 'iso8859'):
  322. try:
  323. open(pathname, 'r', encoding=encoding).read()
  324. return encoding
  325. except UnicodeDecodeError:
  326. pass
  327. return None
  328. def process_file (self, dir, filename, filter):
  329. pathname = os.path.join (dir, filename)
  330. if filename.endswith ('.tmp'):
  331. # Looks like something we tried to create before.
  332. try:
  333. os.remove (pathname)
  334. except OSError:
  335. pass
  336. return
  337. lines = []
  338. changed = False
  339. line_filter = filter.get_line_filter (dir, filename)
  340. mode = None
  341. encoding = self.guess_encoding(pathname)
  342. with open (pathname, 'r', encoding=encoding) as file:
  343. prev = None
  344. mode = os.fstat (file.fileno()).st_mode
  345. for line in file:
  346. while line:
  347. next_line = None
  348. # Leave filtered-out lines alone.
  349. if not (line_filter and line_filter.match (line)):
  350. match = self.copyright_re.search (line)
  351. if match:
  352. res = self.update_copyright (dir, filename, filter,
  353. file, line, match)
  354. (this_changed, line, next_line) = res
  355. changed = changed or this_changed
  356. # Check for copyright lines that might have slipped by.
  357. elif self.other_copyright_re.search (line):
  358. self.errors.report (pathname,
  359. 'unrecognised copyright: %s'
  360. % line.strip())
  361. lines.append (line)
  362. line = next_line
  363. # If something changed, write the new file out.
  364. if changed and self.errors.ok():
  365. tmp_pathname = pathname + '.tmp'
  366. with open (tmp_pathname, 'w', encoding=encoding) as file:
  367. for line in lines:
  368. file.write (line)
  369. os.fchmod (file.fileno(), mode)
  370. if self.use_quilt:
  371. subprocess.call (['quilt', 'add', pathname])
  372. os.rename (tmp_pathname, pathname)
  373. def process_tree (self, tree, filter):
  374. for (dir, subdirs, filenames) in os.walk (tree):
  375. # Don't recurse through directories that should be skipped.
  376. for i in range (len (subdirs) - 1, -1, -1):
  377. if filter.skip_dir (dir, subdirs[i]):
  378. del subdirs[i]
  379. # Handle the files in this directory.
  380. for filename in filenames:
  381. if filter.skip_file (dir, filename):
  382. sys.stdout.write ('Skipping %s\n'
  383. % os.path.join (dir, filename))
  384. else:
  385. self.process_file (dir, filename, filter)
  386. class CmdLine:
  387. def __init__ (self, copyright = Copyright):
  388. self.errors = Errors()
  389. self.copyright = copyright (self.errors)
  390. self.dirs = []
  391. self.default_dirs = []
  392. self.chosen_dirs = []
  393. self.option_handlers = dict()
  394. self.option_help = []
  395. self.add_option ('--help', 'Print this help', self.o_help)
  396. self.add_option ('--quilt', '"quilt add" files before changing them',
  397. self.o_quilt)
  398. self.add_option ('--this-year', 'Add the current year to every notice',
  399. self.o_this_year)
  400. def add_option (self, name, help, handler):
  401. self.option_help.append ((name, help))
  402. self.option_handlers[name] = handler
  403. def add_dir (self, dir, filter = GenericFilter()):
  404. self.dirs.append ((dir, filter))
  405. def o_help (self, option = None):
  406. sys.stdout.write ('Usage: %s [options] dir1 dir2...\n\n'
  407. 'Options:\n' % sys.argv[0])
  408. format = '%-15s %s\n'
  409. for (what, help) in self.option_help:
  410. sys.stdout.write (format % (what, help))
  411. sys.stdout.write ('\nDirectories:\n')
  412. format = '%-25s'
  413. i = 0
  414. for (dir, filter) in self.dirs:
  415. i += 1
  416. if i % 3 == 0 or i == len (self.dirs):
  417. sys.stdout.write (dir + '\n')
  418. else:
  419. sys.stdout.write (format % dir)
  420. sys.exit (0)
  421. def o_quilt (self, option):
  422. self.copyright.set_use_quilt (True)
  423. def o_this_year (self, option):
  424. self.copyright.include_year (time.localtime().tm_year)
  425. def main (self):
  426. for arg in sys.argv[1:]:
  427. if arg[:1] != '-':
  428. self.chosen_dirs.append (arg)
  429. elif arg in self.option_handlers:
  430. self.option_handlers[arg] (arg)
  431. else:
  432. self.errors.report (None, 'unrecognised option: ' + arg)
  433. if self.errors.ok():
  434. if len (self.chosen_dirs) == 0:
  435. self.chosen_dirs = self.default_dirs
  436. if len (self.chosen_dirs) == 0:
  437. self.o_help()
  438. else:
  439. for chosen_dir in self.chosen_dirs:
  440. canon_dir = os.path.join (chosen_dir, '')
  441. count = 0
  442. for (dir, filter) in self.dirs:
  443. if (dir + os.sep).startswith (canon_dir):
  444. count += 1
  445. self.copyright.process_tree (dir, filter)
  446. if count == 0:
  447. self.errors.report (None, 'unrecognised directory: '
  448. + chosen_dir)
  449. sys.exit (0 if self.errors.ok() else 1)
  450. #----------------------------------------------------------------------------
  451. class TopLevelFilter (GenericFilter):
  452. def skip_dir (self, dir, subdir):
  453. return True
  454. class ConfigFilter (GenericFilter):
  455. def __init__ (self):
  456. GenericFilter.__init__ (self)
  457. def skip_file (self, dir, filename):
  458. if filename.endswith ('.m4'):
  459. pathname = os.path.join (dir, filename)
  460. with open (pathname) as file:
  461. # Skip files imported from gettext.
  462. if file.readline().find ('gettext-') >= 0:
  463. return True
  464. return GenericFilter.skip_file (self, dir, filename)
  465. class GCCFilter (GenericFilter):
  466. def __init__ (self):
  467. GenericFilter.__init__ (self)
  468. self.skip_files |= set ([
  469. # Not part of GCC
  470. 'math-68881.h',
  471. ])
  472. self.skip_dirs |= set ([
  473. # Better not create a merge nightmare for the GNAT folks.
  474. 'ada',
  475. # Handled separately.
  476. 'testsuite',
  477. ])
  478. self.skip_extensions |= set ([
  479. # Maintained by the translation project.
  480. '.po',
  481. # Automatically-generated.
  482. '.pot',
  483. ])
  484. self.fossilised_files |= set ([
  485. # Old news won't be updated.
  486. 'ONEWS',
  487. ])
  488. class TestsuiteFilter (GenericFilter):
  489. def __init__ (self):
  490. GenericFilter.__init__ (self)
  491. self.skip_extensions |= set ([
  492. # Don't change the tests, which could be woend by anyone.
  493. '.c',
  494. '.C',
  495. '.cc',
  496. '.d',
  497. '.h',
  498. '.hs',
  499. '.f',
  500. '.f90',
  501. '.go',
  502. '.inc',
  503. '.java',
  504. ])
  505. def skip_file (self, dir, filename):
  506. # g++.niklas/README contains historical copyright information
  507. # and isn't updated.
  508. if filename == 'README' and os.path.basename (dir) == 'g++.niklas':
  509. return True
  510. # Similarly params/README.
  511. if filename == 'README' and os.path.basename (dir) == 'params':
  512. return True
  513. if filename == 'pdt_5.f03' and os.path.basename (dir) == 'gfortran.dg':
  514. return True
  515. return GenericFilter.skip_file (self, dir, filename)
  516. class LibCppFilter (GenericFilter):
  517. def __init__ (self):
  518. GenericFilter.__init__ (self)
  519. self.skip_extensions |= set ([
  520. # Maintained by the translation project.
  521. '.po',
  522. # Automatically-generated.
  523. '.pot',
  524. ])
  525. class LibGCCFilter (GenericFilter):
  526. def __init__ (self):
  527. GenericFilter.__init__ (self)
  528. self.skip_dirs |= set ([
  529. # Imported from GLIBC.
  530. 'soft-fp',
  531. ])
  532. class LibPhobosFilter (GenericFilter):
  533. def __init__ (self):
  534. GenericFilter.__init__ (self)
  535. self.skip_files |= set ([
  536. # Source module imported from upstream.
  537. 'object.d',
  538. ])
  539. self.skip_dirs |= set ([
  540. # Contains sources imported from upstream.
  541. 'core',
  542. 'etc',
  543. 'gc',
  544. 'gcstub',
  545. 'rt',
  546. 'std',
  547. ])
  548. class LibStdCxxFilter (GenericFilter):
  549. def __init__ (self):
  550. GenericFilter.__init__ (self)
  551. self.skip_files |= set ([
  552. # Contains no copyright of its own, but quotes the GPL.
  553. 'intro.xml',
  554. ])
  555. self.skip_dirs |= set ([
  556. # Contains automatically-generated sources.
  557. 'html',
  558. # The testsuite data files shouldn't be changed.
  559. 'data',
  560. # Contains imported images
  561. 'images',
  562. ])
  563. self.own_files |= set ([
  564. # Contains markup around the copyright owner.
  565. 'spine.xml',
  566. ])
  567. def get_line_filter (self, dir, filename):
  568. if filename == 'boost_concept_check.h':
  569. return re.compile ('// \(C\) Copyright Jeremy Siek')
  570. return GenericFilter.get_line_filter (self, dir, filename)
  571. class GCCCopyright (Copyright):
  572. def __init__ (self, errors):
  573. Copyright.__init__ (self, errors)
  574. canon_fsf = 'Free Software Foundation, Inc.'
  575. self.add_package_author ('Free Software Foundation', canon_fsf)
  576. self.add_package_author ('Free Software Foundation.', canon_fsf)
  577. self.add_package_author ('Free Software Foundation Inc.', canon_fsf)
  578. self.add_package_author ('Free Software Foundation, Inc', canon_fsf)
  579. self.add_package_author ('Free Software Foundation, Inc.', canon_fsf)
  580. self.add_package_author ('The Free Software Foundation', canon_fsf)
  581. self.add_package_author ('The Free Software Foundation, Inc.', canon_fsf)
  582. self.add_package_author ('Software Foundation, Inc.', canon_fsf)
  583. self.add_external_author ('ARM')
  584. self.add_external_author ('AdaCore')
  585. self.add_external_author ('Advanced Micro Devices Inc.')
  586. self.add_external_author ('Ami Tavory and Vladimir Dreizin, IBM-HRL.')
  587. self.add_external_author ('Cavium Networks.')
  588. self.add_external_author ('Faraday Technology Corp.')
  589. self.add_external_author ('Florida State University')
  590. self.add_external_author ('Gerard Jungman')
  591. self.add_external_author ('Greg Colvin and Beman Dawes.')
  592. self.add_external_author ('Hewlett-Packard Company')
  593. self.add_external_author ('Intel Corporation')
  594. self.add_external_author ('Information Technology Industry Council.')
  595. self.add_external_author ('James Theiler, Brian Gough')
  596. self.add_external_author ('Makoto Matsumoto and Takuji Nishimura,')
  597. self.add_external_author ('Mentor Graphics Corporation')
  598. self.add_external_author ('National Research Council of Canada.')
  599. self.add_external_author ('NVIDIA Corporation')
  600. self.add_external_author ('Peter Dimov and Multi Media Ltd.')
  601. self.add_external_author ('Peter Dimov')
  602. self.add_external_author ('Pipeline Associates, Inc.')
  603. self.add_external_author ('Regents of the University of California.')
  604. self.add_external_author ('Silicon Graphics Computer Systems, Inc.')
  605. self.add_external_author ('Silicon Graphics')
  606. self.add_external_author ('Stephen L. Moshier')
  607. self.add_external_author ('Sun Microsystems, Inc. All rights reserved.')
  608. self.add_external_author ('The D Language Foundation, All Rights Reserved')
  609. self.add_external_author ('The Go Authors. All rights reserved.')
  610. self.add_external_author ('The Go Authors. All rights reserved.')
  611. self.add_external_author ('The Go Authors.')
  612. self.add_external_author ('The Regents of the University of California.')
  613. self.add_external_author ('Ulf Adams')
  614. self.add_external_author ('Unicode, Inc.')
  615. self.add_external_author ('University of Illinois at Urbana-Champaign.')
  616. self.add_external_author ('University of Toronto.')
  617. self.add_external_author ('Yoshinori Sato')
  618. class GCCCmdLine (CmdLine):
  619. def __init__ (self):
  620. CmdLine.__init__ (self, GCCCopyright)
  621. self.add_dir ('.', TopLevelFilter())
  622. # boehm-gc is imported from upstream.
  623. self.add_dir ('c++tools')
  624. self.add_dir ('config', ConfigFilter())
  625. # contrib isn't really part of GCC.
  626. self.add_dir ('fixincludes')
  627. self.add_dir ('gcc', GCCFilter())
  628. self.add_dir (os.path.join ('gcc', 'testsuite'), TestsuiteFilter())
  629. self.add_dir ('gnattools')
  630. self.add_dir ('gotools')
  631. self.add_dir ('include')
  632. # intl is imported from upstream.
  633. self.add_dir ('libada')
  634. self.add_dir ('libatomic')
  635. self.add_dir ('libbacktrace')
  636. self.add_dir ('libcc1')
  637. self.add_dir ('libcpp', LibCppFilter())
  638. self.add_dir ('libdecnumber')
  639. # libffi is imported from upstream.
  640. self.add_dir ('libgcc', LibGCCFilter())
  641. self.add_dir ('libgfortran')
  642. # libgo is imported from upstream.
  643. self.add_dir ('libgomp')
  644. self.add_dir ('libiberty')
  645. self.add_dir ('libitm')
  646. self.add_dir ('libobjc')
  647. # liboffloadmic is imported from upstream.
  648. self.add_dir ('libphobos', LibPhobosFilter())
  649. self.add_dir ('libquadmath')
  650. # libsanitizer is imported from upstream.
  651. self.add_dir ('libssp')
  652. self.add_dir ('libstdc++-v3', LibStdCxxFilter())
  653. self.add_dir ('libvtv')
  654. self.add_dir ('lto-plugin')
  655. # maintainer-scripts maintainer-scripts
  656. # zlib is imported from upstream.
  657. self.default_dirs = [
  658. 'c++tools',
  659. 'gcc',
  660. 'include',
  661. 'libada',
  662. 'libatomic',
  663. 'libbacktrace',
  664. 'libcc1',
  665. 'libcpp',
  666. 'libdecnumber',
  667. 'libgcc',
  668. 'libgfortran',
  669. 'libgomp',
  670. 'libiberty',
  671. 'libitm',
  672. 'libobjc',
  673. 'libphobos',
  674. 'libssp',
  675. 'libstdc++-v3',
  676. 'libvtv',
  677. 'lto-plugin',
  678. ]
  679. GCCCmdLine().main()