1 """Script to generate reports on translator classes from Doxygen sources. 3 The main purpose of the script is to extract the information from sources 4 related to internationalization (the translator classes). It uses the 5 information to generate documentation (language.doc, 6 translator_report.txt) from templates (language.tpl, maintainers.txt). 8 Simply run the script without parameters to get the reports and 9 documentation for all supported languages. If you want to generate the 10 translator report only for some languages, pass their codes as arguments 11 to the script. In that case, the language.doc will not be generated. 14 python translator.py en nl cz 16 Originally, the script was written in Perl and was known as translator.pl. 17 The last Perl version was dated 2002/05/21 (plus some later corrections) 19 Petr Prikryl (prikryl at atlas dot cz) 23 2002/05/21 - This was the last Perl version. 24 2003/05/16 - List of language marks can be passed as arguments. 25 2004/01/24 - Total reimplementation started: classes TrManager, and Transl. 26 2004/02/05 - First version that produces translator report. No language.doc yet. 27 2004/02/10 - First fully functional version that generates both the translator 28 report and the documentation. It is a bit slower than the 29 Perl version, but is much less tricky and much more flexible. 30 It also solves some problems that were not solved by the Perl 31 version. The translator report content should be more useful 33 2004/02/11 - Some tuning-up to provide more useful information. 34 2004/04/16 - Added new tokens to the tokenizer (to remove some warnings). 35 2004/05/25 - Added from __future__ import generators not to force Python 2.3. 36 2004/06/03 - Removed dependency on textwrap module. 37 2004/07/07 - Fixed the bug in the fill() function. 38 2004/07/21 - Better e-mail mangling for HTML part of language.doc. 39 - Plural not used for reporting a single missing method. 40 - Removal of not used translator adapters is suggested only 41 when the report is not restricted to selected languages 42 explicitly via script arguments. 43 2004/07/26 - Better reporting of not-needed adapters. 44 2004/10/04 - Reporting of not called translator methods added. 45 2004/10/05 - Modified to check only doxygen/src sources for the previous report. 46 2005/02/28 - Slight modification to generate "mailto.txt" auxiliary file. 47 2005/08/15 - Doxygen's root directory determined primarily from DOXYGEN 48 environment variable. When not found, then relatively to the script. 49 2007/03/20 - The "translate me!" searched in comments and reported if found. 50 2008/06/09 - Warning when the MAX_DOT_GRAPH_HEIGHT is still part of trLegendDocs(). 51 2009/05/09 - Changed HTML output to fit it with XHTML DTD 52 2009/09/02 - Added percentage info to the report (implemented / to be implemented). 53 2010/02/09 - Added checking/suggestion 'Reimplementation using UTF-8 suggested. 54 2010/03/03 - Added [unreachable] prefix used in maintainers.txt. 55 2010/05/28 - BOM skipped; minor code cleaning. 56 2010/05/31 - e-mail mangled already in maintainers.txt 57 2010/08/20 - maintainers.txt to UTF-8, related processin of unicode strings 58 - [any mark] introduced instead of [unreachable] only 59 - marks hihglighted in HTML 60 2010/08/30 - Highlighting in what will be the table in langhowto.html modified. 61 2010/09/27 - The underscore in \latexonly part of the generated language.doc 62 was prefixed by backslash (was LaTeX related error). 63 2013/02/19 - Better diagnostics when translator_xx.h is too crippled. 64 2013/06/25 - TranslatorDecoder checks removed after removing the class. 65 2013/09/04 - Coloured status in langhowto. *ALMOST up-to-date* category 66 of translators introduced. 67 2014/06/16 - unified for Python 2.6+ and 3.0+ 70 from __future__
import print_function
79 def xopen(fname, mode='r', encoding='utf-8-sig'):
80 '''Unified file opening for Python 2 an Python 3. 82 Python 2 does not have the encoding argument. Python 3 has one, and 83 the default 'utf-8-sig' is used (skips the BOM automatically). 86 major, minor, patch = (
int(e)
for e
in platform.python_version_tuple())
88 return open(fname, mode=mode)
90 return open(fname, mode=mode, encoding=encoding)
94 """Returns string formated to the wrapped paragraph multiline string. 96 Replaces whitespaces by one space and then uses he textwrap.fill().""" 101 rexWS = re.compile(
r'\s+')
102 lst = rexWS.sub(
' ', s).strip().
split()
110 if len(line) + len(word) < 70:
116 return '\n'.join(lines)
120 """One instance is build for each translator. 122 The abbreviation of the source file--part after 'translator_'--is used as 123 the identification of the object. The empty string is used for the 124 abstract Translator class from translator.h. The other information is 125 extracted from inside the source file.""" 128 """Bind to the manager and initialize.""" 136 if not os.path.isfile(fname):
137 sys.stderr.write(
"\a\nFile '%s' not found!\n" % fname)
158 """Generator that reads the file and yields tokens as 4-tuples. 160 The tokens have the form (tokenId, tokenString, lineNo). The 161 last returned token has the form ('eof', None, None). When trying 162 to access next token afer that, the exception would be raised.""" 167 tokenDic = {
'class':
'class',
170 'protected':
'protected',
171 'private':
'private',
173 'virtual':
'virtual',
201 rexId = re.compile(
r'^[a-zA-Z]\w*$')
241 if tokenId ==
'unknown':
242 if tokenStr
in tokenDic:
243 tokenId = tokenDic[tokenStr]
244 elif tokenStr.isdigit():
246 elif rexId.match(tokenStr):
249 msg =
'\aWarning: unknown token "' + tokenStr +
'"' 250 msg +=
'\tfound on line %d' % tokenLineNo
251 msg +=
' in "' + self.
fname +
'".\n' 252 sys.stderr.write(msg)
254 yield (tokenId, tokenStr, tokenLineNo)
296 tokenId = tokenDic[c]
398 assert(status == 777)
400 yield (tokenId, tokenStr, tokenLineNo)
408 yield (
'eof',
None,
None)
412 """Collect the information about the class and base class. 414 The tokens including the opening left curly brace of the class are 423 tokenId, tokenStr, tokenLineNo = next(tokenIterator)
427 if tokenId ==
'class':
438 if tokenId ==
'lcurly':
440 elif tokenId ==
'colon':
446 if tokenId ==
'public':
459 if tokenId ==
'lcurly':
461 elif tokenId ==
'comment':
470 lst = self.baseClassId.split(
'_')
471 if lst[0] ==
'Translator':
474 elif lst[0] ==
'TranslatorAdapter':
475 self.
status = lst[1] +
'.' + lst[2]
478 self.
status +=
'.' + (
'%02d' %
int(lst[3]))
482 elif lst[0] ==
'TranslatorEnglish':
499 if self.
lang ==
'Brazilian':
501 elif self.
lang ==
'Chinesetraditional':
508 """Reports unexpected token and quits with exit code 1.""" 511 calledFrom = inspect.stack()[1][3]
512 msg =
"\a\nUnexpected token '%s' on the line %d in '%s'.\n" 513 msg = msg % (tokenId, tokenLineNo, self.
fname)
514 msg +=
'status = %d in %s()\n' % (status, calledFrom)
515 sys.stderr.write(msg)
520 """Returns dictionary 'unified prototype' -> 'full prototype'. 522 The method is expected to be called only for the translator.h. It 523 extracts only the pure virtual method and build the dictionary where 524 key is the unified prototype without argument identifiers.""" 534 assert(self.
classId ==
'Translator')
554 tokenId, tokenStr, tokenLineNo = next(tokenIterator)
557 if tokenId ==
'public':
561 if tokenId ==
'colon':
567 if tokenId ==
'virtual':
570 elif tokenId ==
'comment':
572 elif tokenId ==
'rcurly':
579 prototype +=
' ' + tokenStr
580 uniPrototype = tokenStr
582 elif tokenId ==
'tilde':
589 prototype +=
' ' + tokenStr
590 uniPrototype +=
' ' + tokenStr
596 if tokenId ==
'lpar':
597 prototype += tokenStr
598 uniPrototype += tokenStr
604 if tokenId ==
'rpar':
605 prototype += tokenStr
606 uniPrototype += tokenStr
608 elif tokenId ==
'const':
609 prototype += tokenStr
610 uniPrototype += tokenStr
612 elif tokenId ==
'id':
613 prototype += tokenStr
614 uniPrototype += tokenStr
620 if tokenId ==
'assign':
622 elif tokenId ==
'lcurly':
629 if tokenId ==
'num' and tokenStr ==
'0':
635 if tokenId ==
'semic':
636 assert(uniPrototype
not in resultDic)
637 resultDic[uniPrototype] = prototype
643 if tokenId ==
'rcurly':
647 elif tokenId ==
'lcurly':
651 if tokenId ==
'semic':
658 prototype +=
' ' + tokenStr
659 uniPrototype +=
' ' + tokenStr
665 if tokenId ==
'colon':
666 prototype += tokenStr
667 uniPrototype += tokenStr
669 elif tokenId ==
'star' or tokenId ==
'amp':
670 prototype +=
' ' + tokenStr
671 uniPrototype +=
' ' + tokenStr
673 elif tokenId ==
'id':
674 prototype +=
' ' + tokenStr
681 if tokenId ==
'colon':
682 prototype += tokenStr
683 uniPrototype += tokenStr
690 prototype += tokenStr
691 uniPrototype += tokenStr
698 prototype +=
' ' + tokenStr
705 if tokenId ==
'comma':
709 elif tokenId ==
'rpar':
710 prototype += tokenStr
711 uniPrototype += tokenStr
717 while tokenId !=
'eof':
718 tokenId, tokenStr, tokenLineNo = next(tokenIterator)
725 """Collects prototypes of public methods and fills self.prototypeDic. 727 The dictionary is filled by items: uniPrototype -> prototype. 728 The method is expected to be called only for TranslatorXxxx classes, 729 i.e. for the classes that implement translation to some language. 730 It assumes that the openning curly brace of the class was already 731 consumed. The source is consumed until the end of the class. 732 The caller should consume the source until the eof to cause closing 735 assert(self.
classId !=
'Translator')
766 tokenId, tokenStr, tokenLineNo = next(tokenIterator)
769 if tokenId ==
'public':
771 elif tokenId ==
'eof':
775 if tokenId ==
'colon':
781 if tokenId ==
'virtual':
784 elif tokenId ==
'id':
786 uniPrototype = tokenStr
788 elif tokenId ==
'comment':
790 elif tokenId ==
'protected' or tokenId ==
'private':
792 elif tokenId ==
'rcurly':
799 prototype +=
' ' + tokenStr
800 uniPrototype = tokenStr
807 prototype +=
' ' + tokenStr
808 uniPrototype +=
' ' + tokenStr
815 if tokenId ==
'lpar':
816 prototype += tokenStr
817 uniPrototype += tokenStr
823 if tokenId ==
'rpar':
824 prototype += tokenStr
825 uniPrototype += tokenStr
827 elif tokenId ==
'const':
828 prototype += tokenStr
829 uniPrototype += tokenStr
831 elif tokenId ==
'id':
832 prototype += tokenStr
833 uniPrototype += tokenStr
839 if tokenId ==
'lcurly':
842 elif tokenId ==
'comment':
844 elif tokenId ==
'assign':
845 assert(self.
classId ==
'TranslatorAdapterBase')
851 assert(self.
classId ==
'TranslatorAdapterBase')
852 if tokenId ==
'num' and tokenStr ==
'0':
858 assert(self.
classId ==
'TranslatorAdapterBase')
859 if tokenId ==
'semic':
865 if tokenId ==
'rcurly':
872 msg =
"'%s' prototype found again (duplicity)\n" 873 msg +=
"in '%s'.\n" % self.
fname 874 msg = msg % uniPrototype
875 sys.stderr.write(msg)
883 elif tokenId ==
'lcurly':
887 elif methodId ==
'trLegendDocs' and tokenId ==
'string' \
888 and tokenStr.find(
'MAX_DOT_GRAPH_HEIGHT') >= 0:
893 if tokenId ==
'semic':
900 prototype +=
' ' + tokenStr
901 uniPrototype +=
' ' + tokenStr
907 if tokenId ==
'colon':
908 prototype += tokenStr
909 uniPrototype += tokenStr
911 elif tokenId ==
'star' or tokenId ==
'amp':
912 prototype +=
' ' + tokenStr
913 uniPrototype +=
' ' + tokenStr
915 elif tokenId ==
'id':
916 prototype +=
' ' + tokenStr
919 elif tokenId ==
'comment':
920 prototype += tokenStr
921 elif tokenId ==
'rpar':
922 prototype += tokenStr
923 uniPrototype += tokenStr
925 elif tokenId ==
'comma':
933 if tokenId ==
'colon':
934 prototype += tokenStr
935 uniPrototype += tokenStr
942 prototype += tokenStr
943 uniPrototype += tokenStr
950 prototype +=
' ' + tokenStr
953 elif tokenId ==
'rpar':
954 prototype += tokenStr
955 uniPrototype += tokenStr
957 elif tokenId ==
'comment':
958 prototype += tokenStr
963 if tokenId ==
'comma':
967 elif tokenId ==
'rpar':
968 prototype += tokenStr
969 uniPrototype += tokenStr
977 """Returns the dictionary of prototypes implemented by adapters. 979 It is created to process the translator_adapter.h. The returned 980 dictionary has the form: unifiedPrototype -> (version, classId) 981 thus by looking for the prototype, we get the information what is 982 the newest (least adapting) adapter that is sufficient for 983 implementing the method.""" 986 assert(os.path.split(self.
fname)[1] ==
'translator_adapter.h')
990 reqDic = self.manager.requiredMethodsDic
1007 lst = self.classId.split(
'_')
1009 if lst[0] ==
'TranslatorAdapter':
1010 version = lst[1] +
'.' + lst[2]
1012 version +=
'.' + (
'%02d' %
int(lst[3]))
1022 if protoUni
in reqDic:
1027 assert(protoUni
not in adaptDic)
1028 adaptDic[protoUni] = (version, self.
classId)
1032 self.prototypeDic.clear()
1036 except StopIteration:
1044 """Processing of the source file -- only for TranslatorXxxx classes.""" 1051 assert(self.
classId !=
'Translator')
1052 assert(self.
classId[:17] !=
'TranslatorAdapter')
1060 t = next(tokenIterator)
1061 except StopIteration:
1065 reqDic = self.manager.requiredMethodsDic
1066 adaptDic = self.manager.adaptMethodsDic
1073 self.obsoleteMethods.append(p)
1074 self.obsoleteMethods.sort()
1082 self.implementedMethods.append(p)
1084 self.missingMethods.append(p)
1085 self.missingMethods.sort()
1086 self.implementedMethods.sort()
1092 self.
note =
'Change the base class to Translator.' 1099 adaptMinVersion =
'9.9.99' 1100 adaptMinClass =
'TranslatorAdapter_9_9_99' 1102 if uniProto
in adaptDic:
1103 version, cls = adaptDic[uniProto]
1104 if version < adaptMinVersion:
1105 adaptMinVersion = version
1116 if adaptMinVersion > status:
1117 self.
note =
'Change the base class to %s.' % adaptMinClass
1118 self.
status = adaptMinVersion
1130 self.
note +=
'\n\t\t' 1132 self.
note +=
'The MAX_DOT_GRAPH_HEIGHT found in trLegendDocs()' 1138 self.
note =
'Remove the obsolete methods (never used).' 1147 """Returns the report part for the source as a multiline string. 1149 No output for up-to-date translators without problem.""" 1156 fout.write(
'\n\n\n')
1158 percentImplemented = 100
1159 allNum = len(self.manager.requiredMethodsDic)
1162 percentImplemented = 100 * (allNum - num) / allNum
1163 fout.write(
' %d' % num)
1164 fout.write(
' method')
1167 fout.write(
' to implement (%d %%)' % (100 * num / allNum))
1168 fout.write(
'\n' +
'-' * len(self.
classId))
1172 fout.write(
' of the required methods (%d %%).' % percentImplemented)
1177 fout.write(
'\n\n Missing methods (should be implemented):\n')
1178 reqDic = self.manager.requiredMethodsDic
1180 fout.write(
'\n ' + reqDic[p])
1184 fout.write(
'\n\n Obsolete methods (should be removed, never used):\n')
1187 fout.write(
'\n ' + myDic[p])
1191 fout.write(
'\n\n This English-based translator implements ')
1192 fout.write(
'the following methods:\n')
1193 reqDic = self.manager.requiredMethodsDic
1195 fout.write(
'\n ' + reqDic[p])
1199 """Returns the last modification time of the source file.""" 1200 assert(os.path.isfile(self.
fname))
1201 return os.path.getmtime(self.
fname)
1205 """Collects basic info and builds subordinate Transl objects.""" 1208 """Determines paths, creates and initializes structures. 1210 The arguments of the script may explicitly say what languages should 1211 be processed. Write the two letter identifications that are used 1212 for composing the source filenames, so... 1214 python translator.py cz 1216 this will process only translator_cz.h source. 1227 doxy_default = os.path.join(self.
script_path,
'..')
1228 self.
doxy_path = os.path.abspath(os.getenv(
'DOXYGEN', doxy_default))
1281 """Find the translator files and build the objects for translators.""" 1294 tr =
Transl(os.path.join(self.
src_path,
'translator_adapter.h'), self)
1304 lst = [
'translator_' + x +
'.h' for x
in self.
script_argLst]
1306 if not os.path.isfile(os.path.join(self.
src_path, fname)):
1307 sys.stderr.write(
"\a\nFile '%s' not found!\n" % fname)
1311 lst = [x
for x
in lst
if x[:11] ==
'translator_' 1313 and x !=
'translator_adapter.h']
1319 fullname = os.path.join(self.
src_path, fname)
1320 tr =
Transl(fullname, self)
1322 assert(tr.classId !=
'Translator')
1330 """Build lists and strings of the processed info.""" 1335 for obj
in list(self.__translDic.values()):
1336 assert(obj.classId !=
'Translator')
1337 s = obj.status +
'|' + obj.langReadable +
'|' + obj.classId
1348 self.
adaptIdLst = [x.split(
'|')[2]
for x
in statLst
if x[0].isdigit()]
1353 for obj
in list(self.__translDic.values()):
1354 self.langLst.append((obj.langReadable, obj))
1356 self.langLst.sort(key=
lambda x: x[0])
1362 langReadableLst = []
1363 for name, obj
in self.
langLst:
1364 if obj.status ==
'En':
continue 1369 classIdEn = obj.classId +
'En' 1374 langReadableLst.append(name)
1378 if len(langReadableLst) == 1:
1379 s = langReadableLst[0]
1380 elif len(langReadableLst) == 2:
1381 s =
' and '.join(langReadableLst)
1383 s =
', '.join(langReadableLst[:-1]) +
', and ' 1384 s += langReadableLst[-1]
1391 for name, obj
in self.
langLst:
1392 if obj.status ==
'En':
1393 classId = obj.classId[:-2]
1403 for tr
in list(self.__translDic.values()):
1410 """Returns the list of sources to be checked. 1412 All .cpp files and also .h files that do not declare or define 1413 the translator methods are included in the list. The file names 1414 are searched in doxygen/src directory. 1417 for item
in os.listdir(self.
src_path):
1419 name, ext = os.path.splitext(item)
1424 if ext ==
'.cpp' or (ext ==
'.h' and name.find(
'translator') == -1):
1425 fname = os.path.join(self.
src_path, item)
1426 assert os.path.isfile(fname)
1432 """Removes items for method identifiers that are found in fname. 1434 The method reads the content of the file as one string and searches 1435 for all identifiers from dic. The identifiers that were found in 1436 the file are removed from the dictionary. 1438 Note: If more files is to be checked, the files where most items are 1439 probably used should be checked first and the resulting reduced 1440 dictionary should be used for checking the next files (speed up). 1442 lst_in = list(dic.keys())
1445 assert os.path.isfile(fname)
1452 item = lst_in.pop(0)
1453 if cont.find(item) != -1:
1458 """Returns the dictionary of not used translator methods. 1460 The method can be called only after self.requiredMethodsDic has been 1461 built. The stripped prototypes are the values, the method identifiers 1467 for prototype
in list(self.requiredMethodsDic.keys()):
1468 ri = prototype.split(
'(')[0]
1469 identifier = ri.split()[1].strip()
1470 trdic[identifier] = prototype
1485 """Returns the list of maintainer emails. 1487 The method returns the list of e-mail adresses for the translator 1488 class, but only the addresses that were not marked as [xxx].""" 1491 if not m[1].startswith(
'['):
1493 email = email.replace(
' at ',
'@')
1494 email = email.replace(
' dot ',
'.')
1500 if readableStatus ==
'up-to-date':
1502 elif readableStatus.startswith(
'almost'):
1504 elif readableStatus.startswith(
'English'):
1506 elif readableStatus.startswith(
'1.8'):
1508 elif readableStatus.startswith(
'1.7'):
1510 elif readableStatus.startswith(
'1.6'):
1518 """Generates the translator report.""" 1523 f =
xopen(output,
'w')
1532 f.write(
'The report was generated for the following, explicitly')
1533 f.write(
' identified languages:\n\n')
1536 f.write(
'Doxygen supports the following ')
1538 f.write(
' languages (sorted alphabetically):\n\n')
1543 s =
'Of them, %d translators are up-to-date, ' % len(self.
upToDateIdLst)
1544 s +=
'%d translators are based on some adapter class, ' % len(self.
adaptIdLst)
1545 s +=
'and %d are English based.' % len(self.
EnBasedIdLst)
1546 f.write(
fill(s) +
'\n\n')
1551 fmail =
xopen(
'mailto.txt',
'w')
1555 s =
'''The following translator classes are up-to-date (sorted 1556 alphabetically). This means that they derive from the 1557 Translator class, they implement all %d of the required 1558 methods, and even minor problems were not spotted by the script:''' 1560 f.write(
'-' * 70 +
'\n')
1561 f.write(
fill(s) +
'\n\n')
1566 if obj.note
is None:
1567 f.write(
' ' + obj.classId +
'\n')
1568 mailtoLst.extend(self.
__emails(obj.classId))
1570 fmail.write(
'up-to-date\n')
1571 fmail.write(
'; '.join(mailtoLst))
1575 s =
'''The following translator classes are ALMOST up-to-date (sorted 1576 alphabetically). This means that they derive from the 1577 Translator class, but there still may be some minor problems 1579 f.write(
'\n' + (
'-' * 70) +
'\n')
1580 f.write(
fill(s) +
'\n\n')
1584 if obj.note
is not None:
1585 f.write(
' ' + obj.classId +
'\t-- ' + obj.note +
'\n')
1586 mailtoLst.extend(self.
__emails(obj.classId))
1588 fmail.write(
'\n\nalmost up-to-date\n')
1589 fmail.write(
'; '.join(mailtoLst))
1594 s =
'''The following translator classes need maintenance 1595 (the most obsolete at the end). The other info shows the 1596 estimation of Doxygen version when the class was last 1597 updated and number of methods that must be implemented to 1598 become up-to-date:''' 1599 f.write(
'\n' +
'-' * 70 +
'\n')
1600 f.write(
fill(s) +
'\n\n')
1603 adaptMinVersion =
'9.9.99' 1609 f.write(
' %-30s' % obj.classId)
1610 f.write(
' %-6s' % obj.readableStatus)
1611 numimpl = len(obj.missingMethods)
1613 if numimpl > 1: pluralS =
's' 1614 percent = 100 * numimpl / numRequired
1615 f.write(
'\t%2d method%s to implement (%d %%)' % (
1616 numimpl, pluralS, percent))
1618 f.write(
'\n\tNote: ' + obj.note +
'\n')
1620 mailtoLst.extend(self.
__emails(obj.classId))
1623 if obj.status !=
'0.0.00' and obj.status < adaptMinVersion:
1624 adaptMinVersion = obj.status
1626 fmail.write(
'\n\ntranslator based\n')
1627 fmail.write(
'; '.join(mailtoLst))
1635 for version, adaptClassId
in list(self.adaptMethodsDic.values()):
1636 if version < adaptMinVersion:
1637 to_remove[adaptClassId] =
True 1640 lst = list(to_remove.keys())
1642 plural = len(lst) > 1
1643 note =
'Note: The adapter class' 1644 if plural: note +=
'es' 1645 note +=
' ' +
', '.join(lst)
1650 note +=
' not used and can be removed.' 1651 f.write(
'\n' +
fill(note) +
'\n')
1655 s =
'''The following translator classes derive directly from the 1656 TranslatorEnglish. The class identifier has the suffix 'En' 1657 that says that this is intentional. Usually, there is also 1658 a non-English based version of the translator for 1660 f.write(
'\n' +
'-' * 70 +
'\n')
1661 f.write(
fill(s) +
'\n\n')
1665 f.write(
' ' + obj.classId)
1666 f.write(
'\timplements %d methods' % len(obj.implementedMethods))
1668 f.write(
' -- ' + obj.note)
1677 s =
'''WARNING: The following translator methods are declared 1678 in the Translator class but their identifiers do not appear 1679 in source files. The situation should be checked. The .cpp 1680 files and .h files excluding the '*translator*' files 1681 in doxygen/src directory were simply searched for occurrence 1682 of the method identifiers:''' 1683 f.write(
'\n' +
'=' * 70 +
'\n')
1684 f.write(
fill(s) +
'\n\n')
1686 keys = list(dic.keys())
1689 f.write(
' ' + dic[key] +
'\n')
1693 f.write(
'\n' +
'=' * 70)
1694 f.write(
'\nDetails for translators (classes sorted alphabetically):\n')
1696 cls = list(self.__translDic.keys())
1701 assert(obj.classId !=
'Translator')
1710 """Load and process the file with the maintainers. 1712 Fills the dictionary classId -> [(name, e-mail), ...].""" 1718 tim = os.path.getmtime(fname)
1727 maintainersLst =
None 1731 lineReady = line !=
'' 1734 if line !=
'' and line[0] ==
'%':
1755 lst = line.split(
':', 1)
1756 assert(len(lst) == 2)
1757 t = (lst[0].strip(), lst[1].strip())
1763 """Checks the modtime of files and generates language.doc.""" 1770 tim = os.path.getmtime(fTplName)
1778 if os.path.isfile(fDocName):
1791 pos = doctpl.find(
'/***')
1793 doctpl = doctpl[pos:]
1799 s = (
'Do not edit this file. It was generated by the %s script.\n' +\
1800 ' * Edit the %s and %s files instead.') % (
1802 tplDic[
'editnote'] = s
1810 ahref +=
'</code></a>' 1811 tplDic[
'translatorReportLink'] = ahref
1818 <table align="center" cellspacing="0" cellpadding="0" border="0"> 1819 <tr bgcolor="#000000"> 1821 <table cellspacing="1" cellpadding="2" border="0"> 1822 <tr bgcolor="#4040c0"> 1823 <td ><b><font size="+1" color="#ffffff"> Language </font></b></td> 1824 <td ><b><font size="+1" color="#ffffff"> Maintainer </font></b></td> 1825 <td ><b><font size="+1" color="#ffffff"> Contact address </font> 1826 <font size="-2" color="#ffffff">(replace the at and dot)</font></b></td> 1827 <td ><b><font size="+1" color="#ffffff"> Status </font></b></td> 1829 <!-- table content begin --> 1831 <!-- table content end --> 1839 htmlTableTpl = textwrap.dedent(htmlTableTpl)
1840 htmlTrTpl =
'\n <tr bgcolor="#ffffff">%s\n </tr>' 1841 htmlTdTpl =
'\n <td>%s</td>' 1842 htmlTdStatusColorTpl =
'\n <td bgcolor="%s">%s</td>' 1847 for name, obj
in self.
langLst:
1852 if obj.readableStatus.startswith(
'1.4'):
1857 lst = [ htmlTdStatusColorTpl % (bkcolor, obj.langReadable) ]
1865 if obj.status ==
'En':
1867 classId = obj.classId[:-2]
1870 mm =
'see the %s language' % lang
1878 name = maintainer[0]
1879 if name.startswith(
'--'):
1880 name =
'<span style="color: red; background-color: yellow">'\
1883 mm =
'<br/>'.join(lm)
1888 rexMark = re.compile(
'(?P<mark>\\[.*?\\])')
1891 address = maintainer[1]
1892 m = rexMark.search(address)
1894 address =
'<span style="color: brown">'\
1895 + m.group(
'mark') +
'</span>' 1897 ee =
'<br/>'.join(le)
1900 lst.append(htmlTdTpl % mm)
1901 lst.append(htmlTdTpl % ee)
1905 lst.append(htmlTdStatusColorTpl % (bgcolor, obj.readableStatus))
1908 trlst.append(htmlTrTpl % (
''.join(lst)))
1911 htmlTable = htmlTableTpl % (
''.join(trlst))
1914 latexTableTpl =
r''' 1917 \begin{longtable}{|l|l|l|l|} 1919 {\bf Language} & {\bf Maintainer} & {\bf Contact address} & {\bf Status} \\ 1927 latexTableTpl = textwrap.dedent(latexTableTpl)
1928 latexLineTpl =
'\n' +
r' %s & %s & {\tt\tiny %s} & %s \\' 1933 for name, obj
in self.
langLst:
1942 lang = obj.langReadable
1945 if obj.status ==
'En':
1947 classId = obj.classId[:-2]
1950 maintainer =
'see the %s language' % langNE
1955 maintainer = maintainers[0][0]
1956 email = maintainers[0][1]
1958 status = obj.readableStatus
1963 trlst.append(
'\n \\hline')
1964 s = latexLineTpl % (lang, maintainer, email, status)
1965 s = s.replace(
'_',
'\\_')
1972 for m
in maintainers[1:]:
1975 s = latexLineTpl % (lang, maintainer, email, status)
1976 s = s.replace(
'_',
'\\_')
1980 latexTable = latexTableTpl % (
''.join(trlst))
1983 tplDic[
'informationTable'] = htmlTable +
'\n' + latexTable
1986 f =
xopen(fDocName,
'w')
1987 f.write(doctpl % tplDic)
1990 if __name__ ==
'__main__':
1993 major, minor, patch = (
int(e)
for e
in platform.python_version_tuple())
1994 if (major == 2
and minor < 6)
or (major == 3
and minor < 0):
1995 print(
'Python 2.6+ or Python 3.0+ are required for the script')
2003 trMan.generateLanguageDoc()
2004 trMan.generateTranslatorReport()
def generateLanguageDoc(self)
def xopen(fname, mode='r', encoding='utf-8-sig')
def __getNoTrSourceFilesLst(self)
def __tokenGenerator(self)
int open(const char *, int)
Opens a file descriptor.
def __checkForNotUsedTrMethods(self)
def __emails(self, classId)
def collectAdapterPrototypes(self)
def __unexpectedToken(self, status, tokenId, tokenLineNo)
def generateTranslatorReport(self)
def __collectPublicMethodPrototypes(self, tokenIterator)
def __loadMaintainers(self)
def __extractProcessedInfo(self)
def __removeUsedInFiles(self, fname, dic)
txtMAX_DOT_GRAPH_HEIGHT_flag
def collectPureVirtualPrototypes(self)
def __collectClassInfo(self, tokenIterator)
void split(std::string const &s, char c, OutIter dest)
def getBgcolorByReadableStatus(self, readableStatus)
def __init__(self, fname, manager)