Coverage for /builds/ahmed.baizid.0/gtk-doc/gtkdoc/scan.py: 71%

595 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2024-11-05 19:25 +0000

1# -*- python -*- 

2# 

3# gtk-doc - GTK DocBook documentation generator. 

4# Copyright (C) 1998 Damon Chaplin 

5# 2007-2016 Stefan Sauer 

6# 

7# This program is free software; you can redistribute it and/or modify 

8# it under the terms of the GNU General Public License as published by 

9# the Free Software Foundation; either version 2 of the License, or 

10# (at your option) any later version. 

11# 

12# This program is distributed in the hope that it will be useful, 

13# but WITHOUT ANY WARRANTY; without even the implied warranty of 

14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

15# GNU General Public License for more details. 

16# 

17# You should have received a copy of the GNU General Public License 

18# along with this program; if not, write to the Free Software 

19# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 

20# 

21 

22""" 

23Extracts declarations of functions, macros, enums, structs and unions from 

24header files. 

25 

26It is called with a module name, an optional source directory, an optional 

27output directory, and the header files to scan. 

28 

29It outputs all declarations found to a file named '$MODULE-decl.txt', and the 

30list of decarations to another file '$MODULE-decl-list.txt'. 

31 

32This second list file is typically copied to '$MODULE-sections.txt' and 

33organized into sections ready to output the XML pages. 

34""" 

35 

36import argparse 

37import logging 

38import os 

39import re 

40import shutil 

41 

42from . import common, config 

43 

44TYPE_MODIFIERS = ['const', 'signed', 'unsigned', 'long', 'short', 'struct', 'union', 'enum'] 

45VAR_TYPE_MODIFIER = '(?:' + '|'.join([t + '\s+' for t in TYPE_MODIFIERS]) + ')*' 

46RET_TYPE_MODIFIER = '(?:' + '|'.join([t + '\s+' for t in TYPE_MODIFIERS + ['G_CONST_RETURN']]) + ')*' 

47 

48# Matchers for current line 

49CLINE_MATCHER = [ 

50 # 0: MACROS 

51 re.compile( 

52 r"""^\s*\#\s*define\s+ 

53 (\w+) # 1: name 

54 """, re.VERBOSE), 

55 # 1-4: TYPEDEF'D FUNCTIONS 

56 re.compile( 

57 r"""^\s*typedef\s+ 

58 (%s\w+) # 1: return type 

59 (\s+const)?\s* # 2: 2nd const 

60 (\**)\s* # 3: ptr 

61 \(\*\s* 

62 (\w+) # 4: name 

63 \)\s*\(""" % RET_TYPE_MODIFIER, re.VERBOSE), 

64 re.compile( 

65 r"""^\s* 

66 (%s?\w+) # 1: return type 

67 (\s+const)?\s* # 2: 2nd const 

68 (\**)\s* # 3: ptr 

69 \(\*\s* 

70 (\w+) # 4: name 

71 \)\s*\(""" % RET_TYPE_MODIFIER, re.VERBOSE), 

72 re.compile( 

73 r"""^\s* 

74 (\**)\s* # 1: ptr 

75 \(\*\s* 

76 (\w+) # 2: name 

77 \)\s*\(""", re.VERBOSE), 

78 # 4: FUNCTION POINTER VARIABLES 

79 None, # in InitScanner() 

80 # 5-7: ENUMS 

81 re.compile( 

82 r"""^\s*enum\s+ 

83 _?(\w+) # 1: name 

84 \s+\{""", re.VERBOSE), 

85 None, # in InitScanner() 

86 re.compile(r'^\s*typedef\s+enum'), 

87 # 8-11: STRUCTS AND UNIONS 

88 None, # in InitScanner() 

89 re.compile(r'^\s*(?:struct|union)\s+_(\w+)\s*;'), 

90 re.compile( 

91 r"""^\s* 

92 (struct|union)\s+ # 1: struct/union 

93 (\w+) # 2: name 

94 \s*;""", re.VERBOSE), 

95 re.compile( 

96 r"""^\s*typedef\s+ 

97 (struct|union)\s* 

98 \w*\s*{""", re.VERBOSE), 

99 # 12-14: OTHER TYPEDEFS 

100 None, # in InitScanner() 

101 None, # in InitScanner() 

102 re.compile(r'^\s*typedef\s+'), 

103 # 15: VARIABLES (extern'ed variables) 

104 None, # in InitScanner() 

105 # 16: VARIABLES 

106 re.compile( 

107 r"""^\s* 

108 (?:%s\w+) 

109 (?:\s+\*+|\*+|\s)\s* 

110 (?:const\s+)* 

111 ([A-Za-z]\w*) # 1: name 

112 \s*\=""" % VAR_TYPE_MODIFIER, re.VERBOSE), 

113 # 17: G_DECLARE_* 

114 re.compile( 

115 r""".*(G_DECLARE_|GDK_DECLARE_) 

116 (FINAL_TYPE|DERIVABLE_TYPE|INTERNAL_TYPE|INTERFACE) # 1: variant 

117 \s*\(""", re.VERBOSE), 

118 # 18-21: FUNCTIONS 

119 None, # in InitScanner() 

120 None, # in InitScanner() 

121 re.compile(r'^\s*\(?([A-Za-z]\w*)\)?\s*\('), 

122 re.compile(r'^\s*\('), 

123 # 22-23: STRUCTS 

124 re.compile(r'^\s*struct\s+_?(\w+)\s*\*'), 

125 re.compile(r'^\s*struct\s+_?(\w+)'), 

126 # 24-25: UNIONS 

127 re.compile(r'^\s*union\s+_(\w+)\s*\*'), 

128 re.compile(r'^\s*union\s+_?(\w+)'), 

129] 

130 

131# Matchers for previous line 

132PLINE_MATCHER = [ 

133 # 0-1: TYPEDEF'D FUNCTIONS 

134 re.compile( 

135 r"""^\s*typedef\s* 

136 (%s\w+) # 1: return type 

137 (\s+const)?\s* # 2: 2nd const 

138 (\**)\s* # 3: ptr 

139 """ % RET_TYPE_MODIFIER, re.VERBOSE), 

140 re.compile(r'^\s*typedef\s*'), 

141 # 2-4 :FUNCTIONS 

142 None, # in InitScanner() 

143 None, # in InitScanner() 

144 None, # in InitScanner() 

145] 

146 

147# Matchers for 2nd previous line 

148PPLINE_MATCHER = None 

149 

150# Matchers for sub expressions 

151SUB_MATCHER = [ 

152 # 0: STRUCTS AND UNIONS 

153 re.compile(r'^(\S+)(Class|Iface|Interface)\b'), 

154] 

155 

156 

157def Run(options): 

158 logging.info('options: %s', str(options.__dict__)) 

159 

160 InitScanner(options) 

161 

162 if not os.path.isdir(options.output_dir): 

163 os.mkdir(options.output_dir) 

164 

165 base_filename = os.path.join(options.output_dir, options.module) 

166 old_decl_list = base_filename + '-decl-list.txt' 

167 new_decl_list = base_filename + '-decl-list.new' 

168 old_decl = base_filename + '-decl.txt' 

169 new_decl = base_filename + '-decl.new' 

170 old_types = base_filename + '.types' 

171 new_types = base_filename + '.types.new' 

172 sections_file = base_filename + '-sections.txt' 

173 

174 # If this is the very first run then we create the .types file automatically. 

175 if not os.path.exists(sections_file) and not os.path.exists(old_types): 

176 options.rebuild_types = True 

177 

178 section_list = {} 

179 decl_list = [] 

180 get_types = [] 

181 

182 # do not read files twice; checking it here permits to give both srcdir and 

183 # builddir as --source-dir without fear of duplicities 

184 seen_headers = {} 

185 

186 for file in options.headers: 

187 ScanHeader(file, section_list, decl_list, get_types, seen_headers, options) 

188 

189 for dir in options.source_dir: 

190 ScanHeaders(dir, section_list, decl_list, get_types, seen_headers, options) 

191 

192 with open(new_decl_list, 'w', encoding='utf-8') as f: 

193 for section in sorted(section_list.keys()): 

194 f.write(section_list[section]) 

195 common.UpdateFileIfChanged(old_decl_list, new_decl_list, True) 

196 

197 with open(new_decl, 'w', encoding='utf-8') as f: 

198 for decl in decl_list: 

199 f.write(decl) 

200 common.UpdateFileIfChanged(old_decl, new_decl, True) 

201 

202 if options.rebuild_types: 

203 with open(new_types, 'w', encoding='utf-8') as f: 

204 for func in sorted(get_types): 

205 f.write(func + '\n') 

206 

207 # remove the file if empty 

208 if len(get_types) == 0: 

209 os.unlink(new_types) 

210 if os.path.exists(old_types): 

211 os.rename(old_types, old_types + '.bak') 

212 else: 

213 common.UpdateFileIfChanged(old_types, new_types, True) 

214 

215 # If there is no MODULE-sections.txt file yet or we are asked to rebuild it, 

216 # we copy the MODULE-decl-list.txt file into its place. The user can tweak it 

217 # later if they want. 

218 if options.rebuild_sections or not os.path.exists(sections_file): 

219 new_sections_file = base_filename + '-sections.new' 

220 shutil.copyfile(old_decl_list, new_sections_file) 

221 common.UpdateFileIfChanged(sections_file, new_sections_file, False) 

222 

223 # If there is no MODULE-overrides.txt file we create an empty one 

224 # because EXTRA_DIST in gtk-doc.make requires it. 

225 overrides_file = base_filename + '-overrides.txt' 

226 if not os.path.exists(overrides_file): 

227 open(overrides_file, 'w', encoding='utf-8').close() 

228 

229 

230def InitScanner(options): 

231 """Apply options to regexps. 

232 """ 

233 

234 # avoid generating regex with |'' (matching no string) 

235 # TODO(ensonic): keep in sync with ScanHeaderContent() 

236 ignore_decorators = '' 

237 optional_decorators_regex = '' 

238 if options.ignore_decorators: 

239 ignore_decorators = '|' + options.ignore_decorators.replace('()', '\(\w*\)') 

240 optional_decorators_regex = '(?:\s+(?:%s))?' % ignore_decorators[1:] 

241 

242 # FUNCTION POINTER VARIABLES 

243 CLINE_MATCHER[4] = re.compile( 

244 r"""^\s*(?:\b(?:extern|static|inline|G_INLINE_FUNC%s)\s*)* 

245 ((?:const\s+|G_CONST_RETURN\s+)?\w+) # 1: 1st const 

246 (\s+const)?\s* # 2: 2nd const 

247 (\**)\s* # 3: ptr 

248 \(\*\s* 

249 (\w+) # 4: name 

250 \)\s*\(""" % ignore_decorators, re.VERBOSE) 

251 

252 CLINE_MATCHER[6] = re.compile(r'^\s*typedef\s+enum\s+_?(\w+)\s+\1%s\s*;' % optional_decorators_regex) 

253 CLINE_MATCHER[8] = re.compile( 

254 r"""^\s*typedef\s+ 

255 (struct|union)\s+ # 1: struct/union 

256 _(\w+)\s+\2 # 2: name 

257 %s # 3: optional decorator 

258 \s*;""" % optional_decorators_regex, re.VERBOSE) 

259 # OTHER TYPEDEFS 

260 CLINE_MATCHER[12] = re.compile( 

261 r"""^\s*typedef\s+ 

262 (?:struct|union)\s+\w+[\s\*]+ 

263 (\w+) # 1: name 

264 %s # 2: optional decorator 

265 \s*;""" % optional_decorators_regex, re.VERBOSE) 

266 CLINE_MATCHER[13] = re.compile( 

267 r"""^\s* 

268 (?:G_GNUC_EXTENSION\s+)? 

269 typedef\s+ 

270 (.+?[\s\*]) # 1: e.g. 'unsigned int' 

271 (\w+) # 2: name 

272 (?:\s*\[[^\]]+\])* 

273 %s # 3: optional decorator 

274 \s*;""" % optional_decorators_regex, re.VERBOSE) 

275 CLINE_MATCHER[15] = re.compile( 

276 r"""^\s* 

277 (?:extern|[A-Za-z_]+VAR%s)\s+ 

278 (?:%s\w+) 

279 (?:\s+\*+|\*+|\s)\s* 

280 (?:const\s+)* 

281 ([A-Za-z]\w*) # 1: name 

282 \s*;""" % (ignore_decorators, RET_TYPE_MODIFIER), re.VERBOSE) 

283 # FUNCTIONS 

284 CLINE_MATCHER[18] = re.compile( 

285 r"""^\s* 

286 (?:\b(?:extern|static|inline|G_INLINE_FUNC%s)\s*)* 

287 (%s\w+) # 1: return type 

288 ([\s*]+(?:\s*(?:\*+|\bconst\b|\bG_CONST_RETURN\b))*)\s* # 2: .. cont' 

289 (_[A-Za-z]\w*) # 3: name 

290 \s*\(""" % (ignore_decorators, RET_TYPE_MODIFIER), re.VERBOSE) 

291 CLINE_MATCHER[19] = re.compile( 

292 r"""^\s* 

293 (?:\b(?:extern|static|inline|G_INLINE_FUNC%s)\s*)* 

294 (%s\w+) # 1: return type 

295 ([\s*]+(?:\s*(?:\*+|\bconst\b|\bG_CONST_RETURN\b))*)\s* # 2: .. cont' 

296 \(?([A-Za-z]\w*)\)? # 3: name 

297 \s*\(""" % (ignore_decorators, RET_TYPE_MODIFIER), re.VERBOSE) 

298 

299 PLINE_MATCHER[2] = re.compile( 

300 r"""^\s* 

301 (?:\b(?:extern%s)\s*)* 

302 (%s\w+) # 1: retun type 

303 ((?:\s*(?:\*+|\bconst\b|\bG_CONST_RETURN\b))*) # 2: .. cont' 

304 \s*$""" % (ignore_decorators, RET_TYPE_MODIFIER), re.VERBOSE) 

305 

306 PLINE_MATCHER[3] = re.compile( 

307 r"""^\s*(?:\b(?:extern|static|inline|G_INLINE_FUNC%s)\s*)* 

308 (%s\w+) # 1: return type 

309 ((?:\s*(?:\*+|\bconst\b|\bG_CONST_RETURN\b))*) # 2: .. cont' 

310 \s*$""" % (ignore_decorators, RET_TYPE_MODIFIER), re.VERBOSE) 

311 

312 PLINE_MATCHER[4] = re.compile( 

313 r"""^\s*(?:\b(?:extern|static|inline|G_INLINE_FUNC%s)\s*)* 

314 (%s\w+) # 1: return type 

315 (\s+\*+|\*+|\s)\s* # 2: ptr? 

316 ([A-Za-z]\w*) # 3: symbols 

317 \s*$""" % (ignore_decorators, RET_TYPE_MODIFIER), re.VERBOSE) 

318 

319 # Matchers for 2nd previous line 

320 global PPLINE_MATCHER 

321 PPLINE_MATCHER = [ 

322 # 0: FUNCTIONS 

323 re.compile( 

324 r"""^\s*(?:\b(?:extern|static|inline|G_INLINE_FUNC%s)\s*)* 

325 ( 

326 (?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|struct\s+|union\s+|enum\s+)* 

327 \w+ 

328 (?:\**\s+\**(?:const|G_CONST_RETURN))? 

329 (?:\s+|\s*\*+) 

330 )\s*$""" % ignore_decorators, re.VERBOSE) 

331 ] 

332 

333 

334def ScanHeaders(source_dir, section_list, decl_list, get_types, seen_headers, options): 

335 """Scans a directory tree looking for header files. 

336 

337 Args: 

338 source_dir (str): the directory to scan. 

339 section_list (dict): map of section to filenames. 

340 seen_headers (set): set to avoid scanning headers twice 

341 """ 

342 

343 logging.info('Scanning source directory: %s', source_dir) 

344 

345 # This array holds any subdirectories found. 

346 subdirs = [] 

347 

348 for file in sorted(os.listdir(source_dir)): 

349 if file.startswith('.'): 

350 continue 

351 fullname = os.path.join(source_dir, file) 

352 if os.path.isdir(fullname): 

353 subdirs.append(file) 

354 elif file.endswith('.h'): 

355 ScanHeader(fullname, section_list, decl_list, get_types, 

356 seen_headers, options) 

357 

358 # Now recursively scan the subdirectories. 

359 for dir in subdirs: 

360 matchstr = r'(\s|^)' + re.escape(dir) + r'(\s|$)' 

361 if re.search(matchstr, options.ignore_headers): 

362 continue 

363 ScanHeaders(os.path.join(source_dir, dir), section_list, decl_list, 

364 get_types, seen_headers, options) 

365 

366 

367def ScanHeader(input_file, section_list, decl_list, get_types, seen_headers, options): 

368 """Scan a header file for doc commants. 

369 

370 Look for doc comments and extract them. Parse each doc comments and the 

371 symbol declaration. 

372 

373 Args: 

374 input_file (str): the header file to scan. 

375 section_list (dict): a map of section per filename 

376 decl_list (list): a list of declarations 

377 seen_headers (set): set to avoid scanning headers twice 

378 """ 

379 

380 # Don't scan headers twice 

381 canonical_input_file = os.path.realpath(input_file) 

382 if canonical_input_file in seen_headers: 

383 logging.info('File already scanned: %s', input_file) 

384 return 

385 

386 seen_headers[canonical_input_file] = 1 

387 

388 file_basename = os.path.split(input_file)[1][:-2] # filename ends in .h 

389 

390 # Check if the basename is in the list of headers to ignore. 

391 matchstr = r'(\s|^)' + re.escape(file_basename) + r'\.h(\s|$)' 

392 if re.search(matchstr, options.ignore_headers): 

393 logging.info('File ignored: %s', input_file) 

394 return 

395 

396 # Check if the full name is in the list of headers to ignore. 

397 matchstr = r'(\s|^)' + re.escape(input_file) + r'(\s|$)' 

398 if re.search(matchstr, options.ignore_headers): 

399 logging.info('File ignored: %s', input_file) 

400 return 

401 

402 if not os.path.exists(input_file): 

403 logging.warning('File does not exist: %s', input_file) 

404 return 

405 

406 logging.info('Scanning %s', input_file) 

407 

408 with open(input_file, 'r', encoding='utf-8') as hdr: 

409 input_lines = hdr.readlines() 

410 

411 try: 

412 slist, doc_comments = ScanHeaderContent(input_lines, decl_list, get_types, options) 

413 logging.info("Scanning %s done", input_file) 

414 

415 liststr = SeparateSubSections(slist, doc_comments) 

416 if liststr != '': 

417 if file_basename not in section_list: 

418 section_list[file_basename] = '' 

419 section_list[file_basename] += "<SECTION>\n<FILE>%s</FILE>\n%s</SECTION>\n\n" % (file_basename, liststr) 

420 

421 except RuntimeError as e: 

422 common.LogWarning(input_file, 0, str(e)) 

423 

424 

425def ScanHeaderContent(input_lines, decl_list, get_types, options): 

426 """Scan the the given content lines. 

427 

428 Args: 

429 input_lines (list): 

430 decl_list (list): symbols declarations 

431 get_types (list): lst of symbols that have a get_type function 

432 options: commandline options 

433 

434 Returns: 

435 list: a list of symbols found and a set of symbols for which we have a 

436 doc-comment 

437 """ 

438 

439 # Holds the resulting list of declarations. 

440 slist = [] 

441 # Holds the title of the section 

442 title = None 

443 # True if we are in a comment. 

444 in_comment = 0 

445 # The type of declaration we are in, e.g. 'function' or 'macro'. 

446 in_declaration = '' 

447 # True if we should skip a block. 

448 skip_block = False 

449 # The current symbol being declared. 

450 symbol = None 

451 # Holds the declaration of the current symbol. 

452 decl = '' 

453 # For functions and function typedefs this holds the function's return type. 

454 ret_type = None 

455 # The pre-previous line read in - some Gnome functions have the return type 

456 # on one line, the function name on the next, and the rest of the 

457 # declaration after. 

458 pre_previous_line = '' 

459 # The previous line read in - some Gnome functions have the return type on 

460 # one line and the rest of the declaration after. 

461 previous_line = '' 

462 # Used to try to skip the standard #ifdef XXX #define XXX at the start of 

463 # headers. 

464 first_macro = 1 

465 # Used to handle structs/unions which contain nested structs or unions. 

466 level = None 

467 # Set to 1 for internal symbols, we need to fully parse, but don't add them 

468 # to docs 

469 internal = 0 

470 # Dict of forward declarations, we skip them if we find the real declaration 

471 # later. 

472 forward_decls = {} 

473 # Dict of doc-comments we found. The key is lowercase symbol name, val=1. 

474 doc_comments = {} 

475 

476 deprecated_conditional_nest = 0 

477 ignore_conditional_nest = 0 

478 

479 deprecated = '' 

480 doc_comment = '' 

481 

482 # avoid generating regex with |'' (matching no string) 

483 # TODO(ensonic): keep in sync with InitScanner() 

484 # TODO(ensonic): extract the remaining regexps 

485 ignore_decorators = '' # 1 uses 

486 optional_decorators_regex = '' # 4 uses 

487 if options.ignore_decorators: 

488 ignore_decorators = '|' + options.ignore_decorators.replace('()', '\(\w*\)') 

489 optional_decorators_regex = '(?:\s+(?:%s))?' % ignore_decorators[1:] 

490 

491 for line in input_lines: 

492 # If this is a private header, skip it. 

493 # TODO: consider scanning this first, so that we don't modify: decl_list 

494 # and get_types 

495 if re.search(r'^\s*/\*\s*<\s*private_header\s*>\s*\*/', line): 

496 return [], {} 

497 

498 # Skip to the end of the current comment. 

499 if in_comment: 

500 logging.info('Comment: %s', line.strip()) 

501 doc_comment += line 

502 if re.search(r'\*/', line): 

503 m = re.search(r'\* ([a-zA-Z][a-zA-Z0-9_]+):', doc_comment) 

504 if m: 

505 doc_comments[m.group(1).lower()] = 1 

506 in_comment = 0 

507 doc_comment = '' 

508 continue 

509 

510 # Keep a count of #if, #ifdef, #ifndef nesting, 

511 # and if we enter a deprecation-symbol-bracketed 

512 # zone, take note. 

513 m = re.search(r'^\s*#\s*if(?:n?def\b|\s+!?\s*defined\s*\()\s*(\w+)', line) 

514 if m: 

515 define_name = m.group(1) 

516 if deprecated_conditional_nest < 1 and re.search(options.deprecated_guards, define_name): 

517 deprecated_conditional_nest = 1 

518 elif deprecated_conditional_nest >= 1: 

519 deprecated_conditional_nest += 1 

520 if ignore_conditional_nest == 0 and '__GTK_DOC_IGNORE__' in define_name: 

521 ignore_conditional_nest = 1 

522 elif ignore_conditional_nest > 0: 

523 ignore_conditional_nest = 1 

524 

525 elif re.search(r'^\s*#\sif', line): 

526 if deprecated_conditional_nest >= 1: 

527 deprecated_conditional_nest += 1 

528 if ignore_conditional_nest > 0: 

529 ignore_conditional_nest += 1 

530 elif re.search(r'^\s*#endif', line): 

531 if deprecated_conditional_nest >= 1: 

532 deprecated_conditional_nest -= 1 

533 if ignore_conditional_nest > 0: 

534 ignore_conditional_nest -= 1 

535 

536 # If we find a line containing _DEPRECATED, we hope that this is 

537 # attribute based deprecation and also treat this as a deprecation 

538 # guard, unless it's a macro definition or the end of a deprecation 

539 # section (#endif /* XXX_DEPRECATED */ 

540 if deprecated_conditional_nest == 0 and '_DEPRECATED' in line: 

541 m = re.search(r'^\s*#\s*(if*|define|endif)', line) 

542 if not (m or in_declaration == 'enum' or in_declaration == 'struct'): 

543 logging.info('Found deprecation annotation (decl: "%s"): "%s"', 

544 in_declaration, line.strip()) 

545 deprecated_conditional_nest += 0.1 

546 

547 # set flag that is used later when we do AddSymbolToList 

548 if deprecated_conditional_nest > 0: 

549 deprecated = '<DEPRECATED/>\n' 

550 else: 

551 deprecated = '' 

552 

553 if ignore_conditional_nest: 

554 continue 

555 

556 if not in_declaration: 

557 # Skip top-level comments. 

558 m = re.search(r'^\s*/\*', line) 

559 if m: 

560 re.sub(r'^\s*/\*', '', line) 

561 if re.search(r'\*/', line): 

562 logging.info('Found one-line comment: %s', line.strip()) 

563 else: 

564 in_comment = 1 

565 doc_comment = line 

566 logging.info('Found start of comment: %s', line.strip()) 

567 continue 

568 

569 # Skip begin/end deprecation macros. 

570 m = re.search(r'^\s*G_GNUC_(BEGIN|END)_IGNORE_DEPRECATIONS', line) 

571 if m: 

572 continue 

573 

574 logging.info('no decl: %s', line.strip()) 

575 

576 cm = [m.match(line) for m in CLINE_MATCHER] 

577 pm = [m.match(previous_line) for m in PLINE_MATCHER] 

578 ppm = [m.match(pre_previous_line) for m in PPLINE_MATCHER] 

579 

580 # MACROS 

581 

582 if cm[0]: 

583 symbol = cm[0].group(1) 

584 decl = line 

585 # We assume all macros which start with '_' are private, but 

586 # we accept '_' itself which is the standard gettext macro. 

587 # We also try to skip the first macro if it looks like the 

588 # standard #ifndef HEADER_FILE #define HEADER_FILE etc. 

589 # And we only want TRUE & FALSE defined in GLib. 

590 if not symbol.startswith('_') \ 

591 and (not re.search(r'#ifndef\s+' + symbol, previous_line) 

592 or first_macro == 0) \ 

593 and ((symbol != 'TRUE' and symbol != 'FALSE') 

594 or options.module == 'glib') \ 

595 or symbol == '_': 

596 in_declaration = 'macro' 

597 logging.info('Macro: "%s"', symbol) 

598 else: 

599 logging.info('skipping Macro: "%s"', symbol) 

600 in_declaration = 'macro' 

601 internal = 1 

602 first_macro = 0 

603 

604 # TYPEDEF'D FUNCTIONS (i.e. user functions) 

605 elif cm[1]: 

606 ret_type = format_ret_type(cm[1].group(1), cm[1].group(2), cm[1].group(3)) 

607 symbol = cm[1].group(4) 

608 decl = line[cm[1].end():] 

609 in_declaration = 'user_function' 

610 logging.info('user function (1): "%s", Returns: "%s"', symbol, ret_type) 

611 

612 elif pm[1] and cm[2]: 

613 ret_type = format_ret_type(cm[2].group(1), cm[2].group(2), cm[2].group(3)) 

614 symbol = cm[2].group(4) 

615 decl = line[cm[2].end():] 

616 in_declaration = 'user_function' 

617 logging.info('user function (2): "%s", Returns: "%s"', symbol, ret_type) 

618 

619 elif pm[1] and cm[3]: 

620 ret_type = cm[3].group(1) 

621 symbol = cm[3].group(2) 

622 decl = line[cm[3].end():] 

623 if pm[0]: 

624 ret_type = format_ret_type(pm[0].group(1), pm[0].group(2), pm[0].group(3)) + ret_type 

625 in_declaration = 'user_function' 

626 logging.info('user function (3): "%s", Returns: "%s"', symbol, ret_type) 

627 

628 # FUNCTION POINTER VARIABLES 

629 elif cm[4]: 

630 ret_type = format_ret_type(cm[4].group(1), cm[4].group(2), cm[4].group(3)) 

631 symbol = cm[4].group(4) 

632 decl = line[cm[4].end():] 

633 in_declaration = 'user_function' 

634 logging.info('function pointer variable: "%s", Returns: "%s"', symbol, ret_type) 

635 

636 # ENUMS 

637 

638 elif cm[5]: 

639 re.sub(r'^\s*enum\s+_?(\w+)\s+\{', r'enum \1 {', line) 

640 # We assume that 'enum _<enum_name> {' is really the 

641 # declaration of enum <enum_name>. 

642 symbol = cm[5].group(1) 

643 decl = line 

644 in_declaration = 'enum' 

645 logging.info('plain enum: "%s"', symbol) 

646 

647 elif cm[6]: 

648 # We skip 'typedef enum <enum_name> _<enum_name>;' as the enum will 

649 # be declared elsewhere. 

650 logging.info('skipping enum typedef: "%s"', line) 

651 

652 elif cm[7]: 

653 symbol = '' 

654 decl = line 

655 in_declaration = 'enum' 

656 logging.info('typedef enum: -') 

657 

658 # STRUCTS AND UNIONS 

659 

660 elif cm[8]: 

661 # We've found a 'typedef struct _<name> <name>;' 

662 # This could be an opaque data structure, so we output an 

663 # empty declaration. If the structure is actually found that 

664 # will override this (technically if will just be another entry 

665 # in the output file and will be joined when reading the file). 

666 structsym = cm[8].group(1).upper() 

667 logging.info('%s typedef: "%s"', structsym, cm[8].group(2)) 

668 forward_decls[cm[8].group(2)] = '<%s>\n<NAME>%s</NAME>\n%s</%s>\n' % ( 

669 structsym, cm[8].group(2), deprecated, structsym) 

670 

671 m = SUB_MATCHER[0].match(cm[8].group(2)) 

672 if m: 

673 objectname = m.group(1) 

674 logging.info('Found object: "%s"', objectname) 

675 title = '<TITLE>%s</TITLE>' % objectname 

676 

677 elif cm[9]: 

678 # Skip private structs/unions. 

679 logging.info('private struct/union') 

680 

681 elif cm[10]: 

682 # Do a similar thing for normal structs as for typedefs above. 

683 # But we output the declaration as well in this case, so we 

684 # can differentiate it from a typedef. 

685 structsym = cm[10].group(1).upper() 

686 logging.info('%s:%s', structsym, cm[10].group(2)) 

687 forward_decls[cm[10].group(2)] = '<%s>\n<NAME>%s</NAME>\n%s%s</%s>\n' % ( 

688 structsym, cm[10].group(2), line, deprecated, structsym) 

689 

690 elif cm[11]: 

691 symbol = '' 

692 decl = line 

693 level = 0 

694 in_declaration = cm[11].group(1) 

695 logging.info('typedef struct/union "%s"', in_declaration) 

696 

697 # OTHER TYPEDEFS 

698 

699 elif cm[12]: 

700 logging.info('Found struct/union(*) typedef "%s": "%s"', cm[12].group(1), line) 

701 if AddSymbolToList(slist, cm[12].group(1)): 

702 decl_list.append('<TYPEDEF>\n<NAME>%s</NAME>\n%s%s</TYPEDEF>\n' % 

703 (cm[12].group(1), deprecated, line)) 

704 

705 elif cm[13]: 

706 if cm[13].group(1).split()[0] not in ('struct', 'union'): 

707 logging.info('Found typedef: "%s"', line) 

708 if AddSymbolToList(slist, cm[13].group(2)): 

709 decl_list.append( 

710 '<TYPEDEF>\n<NAME>%s</NAME>\n%s%s</TYPEDEF>\n' % (cm[13].group(2), deprecated, line)) 

711 elif cm[14]: 

712 logging.info('Skipping typedef: "%s"', line) 

713 

714 # VARIABLES (extern'ed variables) 

715 

716 elif cm[15]: 

717 symbol = cm[15].group(1) 

718 line = re.sub(r'^\s*([A-Za-z_]+VAR)\b', r'extern', line) 

719 decl = line 

720 logging.info('Possible extern var "%s": "%s"', symbol, decl) 

721 if AddSymbolToList(slist, symbol): 

722 decl_list.append('<VARIABLE>\n<NAME>%s</NAME>\n%s%s</VARIABLE>\n' % (symbol, deprecated, decl)) 

723 

724 # VARIABLES 

725 

726 elif cm[16]: 

727 symbol = cm[16].group(1) 

728 decl = line 

729 logging.info('Possible global var" %s": "%s"', symbol, decl) 

730 if AddSymbolToList(slist, symbol): 

731 decl_list.append('<VARIABLE>\n<NAME>%s</NAME>\n%s%s</VARIABLE>\n' % (symbol, deprecated, decl)) 

732 

733 # G_DECLARE_* 

734 

735 elif cm[17]: 

736 in_declaration = 'g-declare' 

737 symbol = cm[17].group(1) + cm[17].group(2) 

738 decl = line[cm[17].end():] 

739 

740 # FUNCTIONS 

741 

742 elif cm[18]: 

743 # We assume that functions starting with '_' are private and skip them. 

744 ret_type = format_ret_type(cm[18].group(1), None, cm[18].group(2)) 

745 symbol = cm[18].group(3) 

746 decl = line[cm[18].end():] 

747 logging.info('internal Function: "%s", Returns: "%s""%s"', symbol, cm[18].group(1), cm[18].group(2)) 

748 in_declaration = 'function' 

749 internal = 1 

750 skip_block |= is_inline_func(line) 

751 

752 elif cm[19]: 

753 ret_type = format_ret_type(cm[19].group(1), None, cm[19].group(2)) 

754 symbol = cm[19].group(3) 

755 decl = line[cm[19].end():] 

756 logging.info('Function (1): "%s", Returns: "%s""%s"', symbol, cm[19].group(1), cm[19].group(2)) 

757 in_declaration = 'function' 

758 skip_block |= is_inline_func(line) 

759 

760 # Try to catch function declarations which have the return type on 

761 # the previous line. But we don't want to catch complete functions 

762 # which have been declared G_INLINE_FUNC, e.g. g_bit_nth_lsf in 

763 # glib, or 'static inline' functions. 

764 elif cm[20]: 

765 symbol = cm[20].group(1) 

766 decl = line[cm[20].end():] 

767 

768 if is_inline_func(previous_line): 

769 skip_block = True 

770 if pm[3]: 

771 ret_type = format_ret_type(pm[3].group(1), None, pm[3].group(2)) 

772 logging.info('Function (3): "%s", Returns: "%s"', symbol, ret_type) 

773 in_declaration = 'function' 

774 else: 

775 if pm[2]: 

776 ret_type = format_ret_type(pm[2].group(1), None, pm[2].group(2)) 

777 logging.info('Function (2): "%s", Returns: "%s"', symbol, ret_type) 

778 in_declaration = 'function' 

779 

780 # Try to catch function declarations with the return type and name 

781 # on the previous line(s), and the start of the parameters on this. 

782 elif cm[21]: 

783 decl = line[cm[21].end():] 

784 if pm[4]: 

785 ret_type = pm[4].group(1) + ' ' + pm[4].group(2).strip() 

786 symbol = pm[4].group(3) 

787 in_declaration = 'function' 

788 logging.info('Function (5): "%s", Returns: "%s"', symbol, ret_type) 

789 

790 elif re.search(r'^\s*\w+\s*$', previous_line) and ppm[0]: 

791 ret_type = ppm[0].group(1) 

792 ret_type = re.sub(r'\s*\n', '', ret_type, flags=re.MULTILINE) 

793 in_declaration = 'function' 

794 

795 symbol = previous_line 

796 symbol = re.sub(r'^\s+', '', symbol) 

797 symbol = re.sub(r'\s*\n', '', symbol, flags=re.MULTILINE) 

798 logging.info('Function (6): "%s", Returns: "%s"', symbol, ret_type) 

799 

800 # } elsif (m/^extern\s+/) { 

801 # print "DEBUG: Skipping extern: $_" 

802 

803 # STRUCTS 

804 elif cm[22]: 

805 # Skip 'struct _<struct_name> *', since it could be a 

806 # return type on its own line. 

807 pass 

808 elif cm[23]: 

809 # We assume that 'struct _<struct_name>' is really the 

810 # declaration of struct <struct_name>. 

811 symbol = cm[23].group(1) 

812 decl = line 

813 # we will find the correct level as below we do $level += tr/{// 

814 level = 0 

815 in_declaration = 'struct' 

816 logging.info('Struct(_): "%s"', symbol) 

817 

818 # UNIONS 

819 elif cm[24]: 

820 # Skip 'union _<union_name> *' (see above) 

821 pass 

822 elif cm[25]: 

823 symbol = cm[25].group(1) 

824 decl = line 

825 level = 0 

826 in_declaration = 'union' 

827 logging.info('Union(_): "%s"', symbol) 

828 else: 

829 logging.info('in decl %s: skip=%s %s', in_declaration, skip_block, line.strip()) 

830 decl += line 

831 

832 if skip_block and '{' in decl: 

833 (skip_block, decl) = remove_braced_content(decl) 

834 logging.info('in decl: skip=%s decl=[%s]', skip_block, decl) 

835 

836 pre_previous_line = previous_line 

837 previous_line = line 

838 

839 if skip_block: 

840 logging.info('skipping, in decl %s, decl=[%s]', in_declaration, decl) 

841 continue 

842 

843 if in_declaration == "g-declare": 

844 dm = re.search(r'\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*\).*$', decl) 

845 # FIXME the original code does s// stuff here and we don't. Is it necessary? 

846 if dm: 

847 ModuleObjName = dm.group(1) 

848 module_obj_name = dm.group(2) 

849 if options.rebuild_types: 

850 get_types.append(module_obj_name + '_get_type') 

851 forward_decls[ModuleObjName] = '<STRUCT>\n<NAME>%s</NAME>\n%s</STRUCT>\n' % (ModuleObjName, deprecated) 

852 if symbol.startswith('G_DECLARE_DERIVABLE'): 

853 forward_decls[ModuleObjName + 'Class'] = '<STRUCT>\n<NAME>%sClass</NAME>\n%s</STRUCT>\n' % ( 

854 ModuleObjName, deprecated) 

855 if symbol.startswith('G_DECLARE_INTERFACE'): 

856 forward_decls[ModuleObjName + 'Interface'] = '<STRUCT>\n<NAME>%sInterface</NAME>\n%s</STRUCT>\n' % ( 

857 ModuleObjName, deprecated) 

858 in_declaration = '' 

859 

860 if in_declaration == 'function': 

861 # Note that sometimes functions end in ') G_GNUC_PRINTF (2, 3);' or 

862 # ') __attribute__ (...);'. 

863 regex = r'\)\s*(G_GNUC_.*|.*DEPRECATED.*%s\s*|__attribute__\s*\(.*\)\s*)*;.*$' % ignore_decorators 

864 pm = re.search(regex, decl, flags=re.MULTILINE) 

865 if pm: 

866 logging.info('scrubbing:[%s]', decl.strip()) 

867 decl = re.sub(regex, '', decl, flags=re.MULTILINE) 

868 logging.info('scrubbed:[%s]', decl.strip()) 

869 if internal == 0: 

870 decl = re.sub(r'/\*.*?\*/', '', decl, flags=re.MULTILINE) # remove comments. 

871 decl = re.sub(r'\s*\n\s*(?!$)', ' ', decl, flags=re.MULTILINE) # remove newlines 

872 # consolidate whitespace at start/end of lines. 

873 decl = decl.strip() 

874 ret_type = re.sub(r'/\*.*?\*/', '', ret_type).strip() # remove comments in ret type. 

875 if AddSymbolToList(slist, symbol): 

876 decl_list.append('<FUNCTION>\n<NAME>%s</NAME>\n%s<RETURNS>%s</RETURNS>\n%s\n</FUNCTION>\n' % 

877 (symbol, deprecated, ret_type, decl)) 

878 if options.rebuild_types: 

879 # check if this looks like a get_type function and if so remember 

880 if symbol.endswith('_get_type') and 'GType' in ret_type and re.search(r'^(void|)$', decl): 

881 logging.info( 

882 "Adding get-type: [%s] [%s] [%s]", ret_type, symbol, decl) 

883 get_types.append(symbol) 

884 else: 

885 internal = 0 

886 deprecated_conditional_nest = int(deprecated_conditional_nest) 

887 in_declaration = '' 

888 skip_block = False 

889 

890 if in_declaration == 'user_function': 

891 if re.search(r'\).*$', decl): 

892 decl = re.sub(r'\).*$', '', decl) 

893 # TODO: same as above 

894 decl = re.sub(r'/\*.*?\*/', '', decl, flags=re.MULTILINE) # remove comments. 

895 decl = re.sub(r'\s*\n\s*(?!$)', ' ', decl, flags=re.MULTILINE) # remove newlines 

896 # TODO: don't stip here (it works above, but fails some test 

897 # consolidate whitespace at start/end of lines. 

898 # decl = decl.strip() 

899 if AddSymbolToList(slist, symbol): 

900 decl_list.append('<USER_FUNCTION>\n<NAME>%s</NAME>\n%s<RETURNS>%s</RETURNS>\n%s</USER_FUNCTION>\n' % 

901 (symbol, deprecated, ret_type, decl)) 

902 deprecated_conditional_nest = int(deprecated_conditional_nest) 

903 in_declaration = '' 

904 

905 if in_declaration == 'macro': 

906 if not re.search(r'\\\s*$', decl): 

907 if internal == 0: 

908 if AddSymbolToList(slist, symbol): 

909 decl_list.append('<MACRO>\n<NAME>%s</NAME>\n%s%s</MACRO>\n' % (symbol, deprecated, decl)) 

910 else: 

911 logging.info('skip internal macro: [%s]', symbol) 

912 internal = 0 

913 deprecated_conditional_nest = int(deprecated_conditional_nest) 

914 in_declaration = '' 

915 else: 

916 logging.info('skip empty macro: [%s]', symbol) 

917 

918 if in_declaration == 'enum': 

919 # Examples: 

920 # "};" 

921 # "} MyEnum;" 

922 # "} MyEnum DEPRECATED_FOR(NewEnum);" 

923 # "} DEPRECATED_FOR(NewEnum);" 

924 em = re.search(r'\n\s*\}\s*(?:(\w+)?%s)?;\s*$' % optional_decorators_regex, decl) 

925 if em: 

926 if symbol == '': 

927 symbol = em.group(1) 

928 # Enums could contain deprecated values and that doesn't mean 

929 # the whole enum is deprecated, so they are ignored when setting 

930 # deprecated_conditional_nest above. Here we can check if the 

931 # _DEPRECATED is between '}' and ';' which would mean the enum 

932 # as a whole is deprecated. 

933 if re.search(r'\n\s*\}.*_DEPRECATED.*;\s*$', decl): 

934 deprecated = '<DEPRECATED/>\n' 

935 if AddSymbolToList(slist, symbol): 

936 stripped_decl = re.sub(optional_decorators_regex, '', decl) 

937 decl_list.append('<ENUM>\n<NAME>%s</NAME>\n%s%s</ENUM>\n' % (symbol, deprecated, stripped_decl)) 

938 deprecated_conditional_nest = int(deprecated_conditional_nest) 

939 in_declaration = '' 

940 

941 # We try to handle nested structs/unions, but unmatched brackets in 

942 # comments will cause problems. 

943 if in_declaration == 'struct' or in_declaration == 'union': 

944 # Same regex as for enum 

945 sm = re.search(r'\n\}\s*(?:(\w+)?%s)?;\s*$' % optional_decorators_regex, decl) 

946 if level <= 1 and sm: 

947 if symbol == '': 

948 symbol = sm.group(1) 

949 

950 bm = re.search(r'^(\S+)(Class|Iface|Interface)\b', symbol) 

951 if bm: 

952 objectname = bm.group(1) 

953 logging.info('Found object: "%s"', objectname) 

954 title = '<TITLE>%s</TITLE>' % objectname 

955 

956 logging.info('Store struct: "%s"', symbol) 

957 # Structs could contain deprecated members and that doesn't 

958 # mean the whole struct is deprecated, so they are ignored when 

959 # setting deprecated_conditional_nest above. Here we can check 

960 # if the _DEPRECATED is between '}' and ';' which would mean 

961 # the struct as a whole is deprecated. 

962 if re.search(r'\n\s*\}.*_DEPRECATED.*;\s*$', decl): 

963 deprecated = '<DEPRECATED/>\n' 

964 if AddSymbolToList(slist, symbol): 

965 structsym = in_declaration.upper() 

966 regex = r'(?:\s+(?:G_GNUC_\w+(?:\(\w*\))?%s))' % ignore_decorators 

967 stripped_decl = re.sub(regex, '', decl) 

968 decl_list.append('<%s>\n<NAME>%s</NAME>\n%s%s</%s>\n' % 

969 (structsym, symbol, deprecated, stripped_decl, structsym)) 

970 if symbol in forward_decls: 

971 del forward_decls[symbol] 

972 deprecated_conditional_nest = int(deprecated_conditional_nest) 

973 in_declaration = '' 

974 else: 

975 # We use tr to count the brackets in the line, and adjust 

976 # $level accordingly. 

977 level += line.count('{') 

978 level -= line.count('}') 

979 logging.info('struct/union level : %d', level) 

980 

981 # here we want in_declaration=='', otherwise we have a partial declaration 

982 # Code commented out because it breaks some projects. More work is needed. 

983 #if in_declaration != '': 

984 # raise RuntimeError('partial declaration (%s) : %s ' % (in_declaration, decl)) 

985 

986 # print remaining forward declarations 

987 for symbol in sorted(forward_decls.keys()): 

988 if forward_decls[symbol]: 

989 AddSymbolToList(slist, symbol) 

990 decl_list.append(forward_decls[symbol]) 

991 

992 # add title 

993 if title: 

994 slist = [title] + slist 

995 return slist, doc_comments 

996 

997 

998def remove_braced_content(decl): 

999 """Remove all nested pairs of curly braces. 

1000 

1001 Args: 

1002 decl (str): the decl 

1003 

1004 Returns: 

1005 str: a declaration stripped of braced content 

1006 """ 

1007 

1008 skip_block = True 

1009 # Remove all nested pairs of curly braces. 

1010 brace_remover = r'{[^{]*?}' 

1011 bm = re.search(brace_remover, decl) 

1012 while bm: 

1013 decl = re.sub(brace_remover, '', decl) 

1014 logging.info('decl=[%s]' % decl) 

1015 bm = re.search(brace_remover, decl) 

1016 

1017 # If all '{' have been matched and removed, we're done 

1018 bm = re.search(r'(.*?){', decl) 

1019 if not bm: 

1020 # this is a hack to detect the end of declaration 

1021 decl = decl.rstrip() + ';' 

1022 skip_block = False 

1023 logging.info('skip_block done') 

1024 

1025 return skip_block, decl 

1026 

1027 

1028def is_inline_func(line): 

1029 line = line.strip() 

1030 if line.startswith('G_INLINE_FUNC'): 

1031 logging.info('skip block after G_INLINE_FUNC function') 

1032 return True 

1033 if re.search(r'static\s+inline', line): 

1034 logging.info('skip block after static inline function') 

1035 return True 

1036 return False 

1037 

1038 

1039def format_ret_type(base_type, const, ptr): 

1040 ret_type = base_type 

1041 if const: 

1042 ret_type += const 

1043 if ptr: 

1044 ret_type += ' ' + ptr.strip() 

1045 return ret_type 

1046 

1047 

1048def SeparateSubSections(slist, doc_comments): 

1049 """Separate the standard macros and functions. 

1050 

1051 Place them at the end of the current section, in a subsection named 

1052 'Standard'. Do this in a loop to catch objects, enums and flags. 

1053 

1054 Args: 

1055 slist (list): list of symbols 

1056 doc_comments (dict): comments for each symbol 

1057 

1058 Returns: 

1059 str: the section doc xml fomatted as string 

1060 """ 

1061 

1062 klass = lclass = prefix = lprefix = None 

1063 standard_decl = [] 

1064 liststr = '\n'.join(s for s in slist if s) + '\n' 

1065 while True: 

1066 m = re.search(r'^(\S+)_IS_(\S*)_CLASS\n', liststr, flags=re.MULTILINE) 

1067 m2 = re.search(r'^(\S+)_IS_(\S*)\n', liststr, flags=re.MULTILINE) 

1068 m3 = re.search(r'^(\S+?)_(\S*)_get_type\n', liststr, flags=re.MULTILINE) 

1069 if m: 

1070 prefix = m.group(1) 

1071 lprefix = prefix.lower() 

1072 klass = m.group(2) 

1073 lclass = klass.lower() 

1074 logging.info("Found gobject type '%s_%s' from is_class macro", prefix, klass) 

1075 elif m2: 

1076 prefix = m2.group(1) 

1077 lprefix = prefix.lower() 

1078 klass = m2.group(2) 

1079 lclass = klass.lower() 

1080 logging.info("Found gobject type '%s_%s' from is_ macro", prefix, klass) 

1081 elif m3: 

1082 lprefix = m3.group(1) 

1083 prefix = lprefix.upper() 

1084 lclass = m3.group(2) 

1085 klass = lclass.upper() 

1086 logging.info("Found gobject type '%s_%s' from get_type function", prefix, klass) 

1087 else: 

1088 break 

1089 

1090 cclass = lclass 

1091 cclass = cclass.replace('_', '') 

1092 mtype = lprefix + cclass 

1093 

1094 liststr, standard_decl = replace_once(liststr, standard_decl, r'^%sPrivate\n' % mtype) 

1095 

1096 # We only leave XxYy* in the normal section if they have docs 

1097 if mtype not in doc_comments: 

1098 logging.info(" Hide instance docs for %s", mtype) 

1099 liststr, standard_decl = replace_once(liststr, standard_decl, r'^%s\n' % mtype) 

1100 

1101 if mtype + 'class' not in doc_comments: 

1102 logging.info(" Hide class docs for %s", mtype) 

1103 liststr, standard_decl = replace_once(liststr, standard_decl, r'^%sClass\n' % mtype) 

1104 

1105 if mtype + 'interface' not in doc_comments: 

1106 logging.info(" Hide iface docs for %s", mtype) 

1107 liststr, standard_decl = replace_once(liststr, standard_decl, r'%sInterface\n' % mtype) 

1108 

1109 if mtype + 'iface' not in doc_comments: 

1110 logging.info(" Hide iface docs for " + mtype) 

1111 liststr, standard_decl = replace_once(liststr, standard_decl, r'%sIface\n' % mtype) 

1112 

1113 liststr, standard_decl = replace_all(liststr, standard_decl, r'^\S+_IS_%s\n' % klass) 

1114 liststr, standard_decl = replace_all(liststr, standard_decl, r'^\S+_TYPE_%s\n' % klass) 

1115 liststr, standard_decl = replace_all(liststr, standard_decl, r'^\S+_%s_get_type\n' % lclass) 

1116 liststr, standard_decl = replace_all(liststr, standard_decl, r'^\S+_IS_%s_CLASS\n' % klass) 

1117 liststr, standard_decl = replace_all(liststr, standard_decl, r'^\S+_%s_CLASS\n' % klass) 

1118 liststr, standard_decl = replace_all(liststr, standard_decl, r'^\S+_%s_GET_CLASS\n' % klass) 

1119 liststr, standard_decl = replace_all(liststr, standard_decl, r'^\S+_%s_GET_IFACE\n' % klass) 

1120 liststr, standard_decl = replace_all(liststr, standard_decl, r'^\S+_%s_GET_INTERFACE\n' % klass) 

1121 # We do this one last, otherwise it tends to be caught by the IS_$class macro 

1122 liststr, standard_decl = replace_all(liststr, standard_decl, r'^\S+_%s\n' % klass) 

1123 

1124 logging.info('Decl:%s---', liststr) 

1125 logging.info('Std :%s---', ''.join(sorted(standard_decl))) 

1126 if len(standard_decl): 

1127 # sort the symbols 

1128 liststr += '<SUBSECTION Standard>\n' + ''.join(sorted(standard_decl)) 

1129 return liststr 

1130 

1131 

1132def replace_once(liststr, standard_decl, regex): 

1133 mre = re.search(regex, liststr, flags=re.IGNORECASE | re.MULTILINE) 

1134 if mre: 

1135 standard_decl.append(mre.group(0)) 

1136 liststr = re.sub(regex, '', liststr, flags=re.IGNORECASE | re.MULTILINE) 

1137 return liststr, standard_decl 

1138 

1139 

1140def replace_all(liststr, standard_decl, regex): 

1141 mre = re.search(regex, liststr, flags=re.MULTILINE) 

1142 while mre: 

1143 standard_decl.append(mre.group(0)) 

1144 liststr = re.sub(regex, '', liststr, flags=re.MULTILINE) 

1145 mre = re.search(regex, liststr, flags=re.MULTILINE) 

1146 return liststr, standard_decl 

1147 

1148 

1149def AddSymbolToList(slist, symbol): 

1150 """ Adds symbol to list of declaration if not already present. 

1151 

1152 Args: 

1153 slist: The list of symbols. 

1154 symbol: The symbol to add to the list. 

1155 """ 

1156 if symbol in slist: 

1157 # logging.info('Symbol %s already in list. skipping', symbol) 

1158 # we return False to skip outputting another entry to -decl.txt 

1159 # this is to avoid redeclarations (e.g. in conditional sections). 

1160 return False 

1161 slist.append(symbol) 

1162 return True 

1163 

1164 

1165def new_args_parser(): 

1166 parser = argparse.ArgumentParser( 

1167 description=f"gtkdoc-scan version {config.version} - scan header files for public symbols" 

1168 ) 

1169 parser.add_argument("--version", action="version", version=config.version) 

1170 parser.add_argument( 

1171 "--module", required=True, help="Name of the doc module being processed." 

1172 ) 

1173 parser.add_argument( 

1174 "--source-dir", 

1175 action="append", 

1176 default=[], 

1177 help="Directories containing the source files to scan", 

1178 ) 

1179 parser.add_argument( 

1180 "--ignore-headers", 

1181 default="", 

1182 help="A space-separated list of header files/dirs not to scan", 

1183 ) 

1184 parser.add_argument( 

1185 "--output-dir", default=".", help="The directory where the results are stored" 

1186 ) 

1187 parser.add_argument( 

1188 "--deprecated-guards", 

1189 default="does_not_match_any_cpp_symbols_at_all_nope", 

1190 help="A |-separated list of symbols used as deprecation guards", 

1191 ) 

1192 parser.add_argument( 

1193 "--ignore-decorators", 

1194 default="(?=no)match", 

1195 help="A |-separated list of additional decorators in" 

1196 "declarations that should be ignored", 

1197 ) 

1198 parser.add_argument( 

1199 "--rebuild-sections", 

1200 action="store_true", 

1201 default=False, 

1202 help="Rebuild (overwrite) the MODULE-sections.txt file", 

1203 ) 

1204 parser.add_argument( 

1205 "--rebuild-types", 

1206 action="store_true", 

1207 default=False, 

1208 help="Automatically recreate the MODULE.types file using" 

1209 "all the *_get_type() functions found", 

1210 ) 

1211 parser.add_argument("headers", nargs="*") 

1212 return parser