├── .github └── workflows │ └── main.yml ├── .gitignore ├── .project ├── .pydevproject ├── CHANGELOG.md ├── MANIFEST.in ├── Makefile ├── README.md ├── license.txt ├── setup.py ├── src ├── _readtags.c ├── _readtags.pyx ├── ctags │ └── __init__.py ├── examples │ ├── example.py │ └── tags ├── include │ └── readtags.h ├── readtags.c ├── readtags.pxi └── stdlib.pxi ├── tests ├── __init__.py ├── test_ctags.py └── test_import.py └── tox.ini /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: make 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ${{ matrix.platform }} 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | platform: [ubuntu-latest, macos-latest, windows-latest] 16 | python-version: 17 | - 2.7 18 | - 3.5 19 | - 3.6 20 | - 3.7 21 | - 3.8 22 | - 3.9 23 | - '3.10' 24 | - 3.11 25 | exclude: 26 | - {platform: windows-latest, python-version: 2.7} # Problem with MSVC version 27 | - {platform: ubuntu-latest, python-version: 3.5} # Missing in GHA 28 | - {platform: ubuntu-latest, python-version: 3.6} # Missing in GHA 29 | steps: 30 | - uses: actions/checkout@v3 31 | with: 32 | fetch-depth: 0 33 | - name: Set up Python ${{ matrix.python-version }} 34 | uses: actions/setup-python@v2 35 | with: 36 | python-version: ${{ matrix.python-version }} 37 | - name: Install dependencies 38 | run: | 39 | python -m pip install --upgrade pip 40 | pip install tox tox-gh-actions cython 41 | - name: Test with tox 42 | run: tox 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | *.pyc 3 | *.swp 4 | *.so 5 | *.pyd 6 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | python-ctags 4 | 5 | 6 | 7 | 8 | 9 | org.python.pydev.PyDevBuilder 10 | 11 | 12 | 13 | 14 | 15 | org.python.pydev.pythonNature 16 | 17 | 18 | -------------------------------------------------------------------------------- /.pydevproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Default 6 | python 2.6 7 | 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Version 1.6.0 4 | - Add wrappers for PseudoTags related APIs (Masatake YAMATO) 5 | 6 | ## Version 1.5.0 7 | - Support for str (rather than just bytes) file names 8 | 9 | ## Version 1.4.0 10 | - Python 3.9, 3.8 support (Louis Sautier) 11 | 12 | ## Version 1.3.0 13 | - Python 3.7 support (Louis Sautier) 14 | 15 | ## Version 1.2.4 16 | - Bug fixes (Masatake Yamato) 17 | 18 | ## Version 1.2.3 19 | - Include examples in distribution (Louis Sautier) 20 | 21 | ## Version 1.2.2 22 | - Include tests in distribution (Louis Sautier) 23 | 24 | ## Version 1.2.1 (May 10, 2016) 25 | - Fix packaging (Jonas Haag) 26 | 27 | ## Version 1.2 (May 10, 2016) 28 | - Internal clean up (Louis Sautier) 29 | 30 | ## Version 1.1 (May 9, 2016) 31 | - Initial version with Python 3 support (Louis Sautier, Jonas Haag) 32 | 33 | ## Version 1.0.6 34 | - Original version imported from Google Code (Aaron H. K. Diep) 35 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | include src/_readtags.c 3 | include src/readtags.c 4 | include src/include/readtags.h 5 | include src/examples/* 6 | recursive-include tests *.py 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | cython src/_readtags.pyx 3 | python setup.py test 4 | 5 | update-readtags: 6 | curl -Lv https://raw.githubusercontent.com/universal-ctags/ctags/master/libreadtags/readtags.c -o src/readtags.c 7 | curl -Lv https://raw.githubusercontent.com/universal-ctags/ctags/master/libreadtags/readtags.h -o src/include/readtags.h 8 | git commit src/readtags.c src/include/readtags.h -m "Update readtags from https://github.com/universal-ctags/ctags" 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/jonashaag/python-ctags3.svg?branch=py3)](https://travis-ci.org/jonashaag/python-ctags3) 2 | 3 | *NOTE*: This a fork from the original python-ctags that adds support for Python 3. It is currently maintained by Jonas Haag. 4 | 5 | Ctags supports indexing of many modern programming languages. Python is a powerful scriptable dynamic language. Using Python to access Ctags index file is a natural fit in extending an application's capability to examine source code. 6 | 7 | This project wrote a wrapper for read tags library. I have been using the package in a couple of projects and it has been shown that it could easily handle hundreds of source files. 8 | 9 | ## Requirements 10 | * C compiler (gcc/msvc) 11 | * Python version >= 2.7 12 | * Ctags implementation like [http://prdownloads.sourceforge.net/ctags/ctags-5.7.tar.gz Exuberant Ctags] or [https://github.com/universal-ctags/ctags Universal Ctags] (need it to generate tags file). 13 | 14 | ## Installation 15 | 16 | From Python Package Index, 17 | ```bash 18 | pip install python-ctags3 19 | ``` 20 | 21 | From https://github.com/hddmet/python-ctags/archive/master.zip, 22 | ```python 23 | python ./setup.py build 24 | python ./setup.py install 25 | ``` 26 | 27 | ## Use Cases 28 | ### Generating Tags 29 | 30 | In command line, run 31 | ```bash 32 | ctags --fields=afmikKlnsStz readtags.c readtags.h 33 | ``` 34 | 35 | **Opening Tags File** 36 | ```python 37 | import ctags 38 | from ctags import CTags, TagEntry 39 | import sys 40 | 41 | try: 42 | tagFile = CTags('tags') 43 | except: 44 | sys.exit(1) 45 | 46 | # Available file information keys: 47 | # opened - was the tag file successfully opened? 48 | # error_number - errno value when 'opened' is false 49 | # format - format of tag file (1 = original, 2 = extended) 50 | # sort - how is the tag file sorted? 51 | # author - name of author of generating program (may be empy string) 52 | # name - name of program (may be empy string) 53 | # url - URL of distribution (may be empy string) 54 | # version - program version (may be empty string) 55 | 56 | print tagFile['name'] 57 | print tagFile['author'] 58 | print tagFile['format'] 59 | 60 | # Available sort type: 61 | # TAG_UNSORTED, TAG_SORTED, TAG_FOLDSORTED 62 | 63 | # Note: use this only if you know how the tags file is sorted which is 64 | # specified when you generate the tag file 65 | status = tagFile.setSortType(ctags.TAG_SORTED) 66 | ``` 67 | 68 | **Obtaining First Tag Entry** 69 | ```python 70 | entry = TagEntry() 71 | status = tagFile.first(entry) 72 | 73 | if status: 74 | # Available TagEntry keys: 75 | # name - name of tag 76 | # file - path of source file containing definition of tag 77 | # pattern - pattern for locating source line (None if no pattern) 78 | # lineNumber - line number in source file of tag definition (may be zero if not known) 79 | # kind - kind of tag (none if not known) 80 | # fileScope - is tag of file-limited scope? 81 | 82 | # Note: other keys will be assumed as an extension key and will 83 | # return None if no such key is found 84 | 85 | print entry['name'] 86 | print entry['kind'] 87 | ``` 88 | 89 | **Finding a Tag Entry** 90 | ```python 91 | # Available options: 92 | # TAG_PARTIALMATCH - begin with 93 | # TAG_FULLMATCH - full length matching 94 | # TAG_IGNORECASE - disable binary search 95 | # TAG_OBSERVECASE - case sensitive and allowed binary search to perform 96 | 97 | if tagFile.find(entry, 'find', ctags.TAG_PARTIALMATCH | ctags.TAG_IGNORECASE): 98 | print 'found' 99 | print entry['lineNumber'] 100 | print entry['pattern'] 101 | print entry['kind'] 102 | 103 | # Find the next tag matching the name and options supplied to the 104 | # most recent call to tagFile.find(). (replace the entry if found) 105 | status = tagFile.findNext(entry) 106 | 107 | # Step to the next tag in the file (replace entry if found) 108 | status = tagFile.next(entry) 109 | ``` 110 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | """Ctags indexing python bindings 2 | 3 | Ctags supports indexing of many modern programming languages. Python 4 | is a powerful scriptable dynamic language. Using Python to access Ctags index 5 | file is a natural fit in extending an application's capability to examine source 6 | code. 7 | 8 | This project wrote a wrapper for readtags.c distributed from Universal-ctags project 9 | (https://ctags.io). I have been using the package in 10 | a couple of projects and it has been shown that it could easily handle hundreds 11 | source files. 12 | """ 13 | from setuptools import setup, Extension 14 | 15 | doclines = __doc__.split("\n") 16 | 17 | setup( 18 | name='python-ctags3', 19 | version='1.6.0' , 20 | description=doclines[0], 21 | long_description="\n".join(doclines[2:]), 22 | author='Aaron H. K. Diep', 23 | author_email='ahkdiep@gmail.com', 24 | license = 'LGPL', 25 | url='https://github.com/jonashaag/python-ctags', 26 | packages = ['ctags'], 27 | ext_package='ctags', 28 | ext_modules=[Extension('_readtags', ['src/readtags.c', 'src/_readtags.c'], 29 | include_dirs=['src/include']) 30 | ], 31 | package_dir = {'ctags' : 'src/ctags'}, 32 | test_suite='tests', 33 | classifiers = [ 34 | 'Development Status :: 5 - Production/Stable', 35 | 'Intended Audience :: Developers', 36 | 'Programming Language :: Python', 37 | 'Programming Language :: C', 38 | 'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)', 39 | 'Operating System :: MacOS :: MacOS X', 40 | 'Operating System :: Microsoft :: Windows', 41 | 'Operating System :: POSIX', 42 | 'Topic :: Software Development :: Libraries :: Python Modules', 43 | "Programming Language :: Python :: 2.7", 44 | "Programming Language :: Python :: 3.5", 45 | "Programming Language :: Python :: 3.6", 46 | "Programming Language :: Python :: 3.7", 47 | "Programming Language :: Python :: 3.8", 48 | "Programming Language :: Python :: 3.9", 49 | "Programming Language :: Python :: 3.10", 50 | "Programming Language :: Python :: 3.11", 51 | ], 52 | ) 53 | -------------------------------------------------------------------------------- /src/_readtags.pyx: -------------------------------------------------------------------------------- 1 | """ 2 | $Id$ 3 | 4 | This file is part of Python-Ctags. 5 | 6 | Python-Ctags is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Python-Ctags is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with Python-Ctags. If not, see . 18 | """ 19 | import sys 20 | 21 | include "stdlib.pxi" 22 | include "readtags.pxi" 23 | 24 | cdef class TagEntry: 25 | cdef tagEntry c_entry 26 | 27 | def __cinit__(self): 28 | self.c_entry.fields.count = 0 29 | self.c_entry.fields.list = NULL 30 | 31 | def __setitem__(self, key, item): 32 | if key == "name": 33 | self.c_entry.name = item 34 | elif key == "file": 35 | self.c_entry.file = item 36 | elif key == "pattern": 37 | self.c_entry.address.pattern = item 38 | elif key == "lineNumber": 39 | self.c_entry.address.lineNumber = item 40 | elif key == "kind": 41 | self.c_entry.kind = item 42 | elif key == "fileScope": 43 | self.c_entry.fileScope = item 44 | elif key == "fields": 45 | # fields.list is allocated by readtags.c 46 | if self.c_entry.fields.count != len(item): 47 | return 48 | 49 | fields = item 50 | if self.c_entry.fields.list != NULL: 51 | free(self.c_entry.fields.list) 52 | self.c_entry.fields.list = NULL 53 | 54 | for k, v in fields.iteritems(): 55 | self.c_entry.fields.list.key = k 56 | self.c_entry.fields.list.value = v 57 | 58 | def __getitem__(self, key): 59 | cdef char* result 60 | if key == "name": 61 | return self.c_entry.name 62 | elif key == "file": 63 | return self.c_entry.file 64 | elif key == "pattern": 65 | if self.c_entry.address.pattern == NULL: 66 | return None 67 | return self.c_entry.address.pattern 68 | elif key == "lineNumber": 69 | return self.c_entry.address.lineNumber 70 | elif key == "kind": 71 | if self.c_entry.kind == NULL: 72 | return None 73 | return self.c_entry.kind 74 | elif key == "fileScope": 75 | return self.c_entry.fileScope 76 | else: 77 | # It will crash if we mix NULL/0/None 78 | # don't mix comparison of type 79 | result = ctagsField(&self.c_entry, key) 80 | if result == NULL: 81 | return None 82 | 83 | return result 84 | 85 | 86 | cdef class CTags: 87 | cdef tagFile* file 88 | cdef tagFileInfo info 89 | 90 | def __cinit__(self, filepath): 91 | self.open(filepath) 92 | 93 | def __dealloc__(self): 94 | 95 | if self.file: 96 | ctagsClose(self.file) 97 | 98 | def __getitem__(self, key): 99 | if key == "opened": 100 | return self.info.status.opened 101 | if key == "error_number": 102 | return self.info.status.error_number 103 | if key == "format": 104 | return self.info.file.format 105 | if key == "sort": 106 | return self.info.file.sort 107 | if key == "author": 108 | if self.info.program.author == NULL: 109 | return "" 110 | return self.info.program.author 111 | if key == "name": 112 | if self.info.program.name == NULL: 113 | return "" 114 | return self.info.program.name 115 | if key == "url": 116 | if self.info.program.url == NULL: 117 | return "" 118 | return self.info.program.url 119 | if key == "version": 120 | if self.info.program.version == NULL: 121 | return "" 122 | return self.info.program.version 123 | 124 | def open(self, filepath): 125 | if isinstance(filepath, str): 126 | filepath = filepath.encode(sys.getfilesystemencoding()) 127 | 128 | self.file = ctagsOpen(filepath, &self.info) 129 | 130 | if not self.info.status.opened: 131 | raise Exception("Invalid tag file") 132 | 133 | def setSortType(self, tagSortType type): 134 | return ctagsSetSortType(self.file, type) 135 | 136 | def first(self, TagEntry entry): 137 | return ctagsFirst(self.file, &entry.c_entry) 138 | 139 | def find(self, TagEntry entry, char* name, int options): 140 | return ctagsFind(self.file, &entry.c_entry, name, options) 141 | 142 | def findNext(self, TagEntry entry): 143 | return ctagsFindNext(self.file, &entry.c_entry) 144 | 145 | def next(self, TagEntry entry): 146 | return ctagsNext(self.file, &entry.c_entry) 147 | 148 | def firstPseudoTag(self, TagEntry entry): 149 | return ctagsFirstPseudoTag(self.file, &entry.c_entry) 150 | 151 | def findPseudoTag(self, TagEntry entry, char* name, int options): 152 | return ctagsFindPseudoTag(self.file, &entry.c_entry, name, options) 153 | 154 | def nextPseudoTag(self, TagEntry entry): 155 | return ctagsNextPseudoTag(self.file, &entry.c_entry) 156 | -------------------------------------------------------------------------------- /src/ctags/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | $Id$ 3 | 4 | Copyright (C) 2008 Aaron Diep 5 | 6 | This file is part of Python-Ctags. 7 | 8 | Python-Ctags is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | Python-Ctags is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with Python-Ctags. If not, see . 20 | """ 21 | 22 | 23 | from ._readtags import TagEntry, CTags 24 | __all__ = ['TagEntry', 'CTags'] 25 | 26 | # sortType 27 | TAG_UNSORTED=0 28 | TAG_SORTED=1 29 | TAG_FOLDSORTED=2 30 | 31 | # Options for tagsFind() 32 | TAG_FULLMATCH=0x0 33 | TAG_PARTIALMATCH=0x1 34 | TAG_OBSERVECASE=0x0 35 | TAG_IGNORECASE=0x2 36 | 37 | # tagResult 38 | FAILURE = 0 39 | SUCCESS = 1 40 | -------------------------------------------------------------------------------- /src/examples/example.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | import sys 4 | 5 | import ctags 6 | from ctags import CTags, TagEntry 7 | 8 | try: 9 | tagFile = CTags(b"tags") 10 | except: 11 | sys.exit(1) 12 | 13 | 14 | entry = TagEntry() 15 | status = tagFile.setSortType(ctags.TAG_SORTED) 16 | status = tagFile.first(entry) 17 | 18 | print(tagFile["name"]) 19 | print(tagFile["author"]) 20 | print(tagFile["format"]) 21 | if status: 22 | print(entry["name"]) 23 | print(entry["kind"]) 24 | 25 | if tagFile.find(entry, b"find", ctags.TAG_PARTIALMATCH | ctags.TAG_IGNORECASE): 26 | print("found") 27 | print(entry["lineNumber"]) 28 | print(entry["pattern"]) 29 | print(entry["kind"]) 30 | 31 | status = tagFile.findNext(entry) 32 | if status: 33 | print(entry["lineNumber"]) 34 | print(entry["pattern"]) 35 | print(entry["kind"]) 36 | 37 | if tagFile.next(entry): 38 | print(entry["lineNumber"]) 39 | print(entry["pattern"]) 40 | print(entry["kind"]) 41 | -------------------------------------------------------------------------------- /src/examples/tags: -------------------------------------------------------------------------------- 1 | !_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ 2 | !_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ 3 | !_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/ 4 | !_TAG_PROGRAM_NAME Exuberant Ctags // 5 | !_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/ 6 | !_TAG_PROGRAM_VERSION 5.6b1 // 7 | DL_EXPORT ../_readtags.c 10;" kind:macro line:10 language:C file: 8 | EmptyString ../readtags.c /^const char *const EmptyString = "";$/;" kind:variable line:91 language:C 9 | INLINE ../_readtags.c 116;" kind:macro line:116 language:C file: 10 | INLINE ../_readtags.c 118;" kind:macro line:118 language:C file: 11 | INLINE ../_readtags.c 120;" kind:macro line:120 language:C file: 12 | JUMP_BACK ../readtags.c 561;" kind:macro line:561 language:C file: 13 | METH_COEXIST ../_readtags.c 13;" kind:macro line:13 language:C file: 14 | PY_LONG_LONG ../_readtags.c 7;" kind:macro line:7 language:C file: 15 | PY_SSIZE_T_CLEAN ../_readtags.c 3;" kind:macro line:3 language:C file: 16 | PY_SSIZE_T_MAX ../_readtags.c 17;" kind:macro line:17 language:C file: 17 | PY_SSIZE_T_MIN ../_readtags.c 18;" kind:macro line:18 language:C file: 18 | ProgramName ../readtags.c /^static const char *ProgramName;$/;" kind:variable line:790 language:C file: 19 | PseudoTagPrefix ../readtags.c /^const char *const PseudoTagPrefix = "!_";$/;" kind:variable line:92 language:C 20 | PyBUF_ANY_CONTIGUOUS ../_readtags.c 54;" kind:macro line:54 language:C file: 21 | PyBUF_C_CONTIGUOUS ../_readtags.c 52;" kind:macro line:52 language:C file: 22 | PyBUF_FORMAT ../_readtags.c 49;" kind:macro line:49 language:C file: 23 | PyBUF_F_CONTIGUOUS ../_readtags.c 53;" kind:macro line:53 language:C file: 24 | PyBUF_INDIRECT ../_readtags.c 55;" kind:macro line:55 language:C file: 25 | PyBUF_LOCK ../_readtags.c 48;" kind:macro line:48 language:C file: 26 | PyBUF_ND ../_readtags.c 50;" kind:macro line:50 language:C file: 27 | PyBUF_SIMPLE ../_readtags.c 46;" kind:macro line:46 language:C file: 28 | PyBUF_STRIDES ../_readtags.c 51;" kind:macro line:51 language:C file: 29 | PyBUF_WRITABLE ../_readtags.c 47;" kind:macro line:47 language:C file: 30 | PyBaseString_Type ../_readtags.c 71;" kind:macro line:71 language:C file: 31 | PyBytes_Type ../_readtags.c 89;" kind:macro line:89 language:C file: 32 | PyIndex_Check ../_readtags.c 22;" kind:macro line:22 language:C file: 33 | PyInt_AS_LONG ../_readtags.c 82;" kind:macro line:82 language:C file: 34 | PyInt_AsLong ../_readtags.c 81;" kind:macro line:81 language:C file: 35 | PyInt_AsSsize_t ../_readtags.c 20;" kind:macro line:20 language:C file: 36 | PyInt_AsSsize_t ../_readtags.c 83;" kind:macro line:83 language:C file: 37 | PyInt_AsUnsignedLongLongMask ../_readtags.c 85;" kind:macro line:85 language:C file: 38 | PyInt_AsUnsignedLongMask ../_readtags.c 84;" kind:macro line:84 language:C file: 39 | PyInt_Check ../_readtags.c 74;" kind:macro line:74 language:C file: 40 | PyInt_CheckExact ../_readtags.c 75;" kind:macro line:75 language:C file: 41 | PyInt_FromLong ../_readtags.c 78;" kind:macro line:78 language:C file: 42 | PyInt_FromSize_t ../_readtags.c 79;" kind:macro line:79 language:C file: 43 | PyInt_FromSsize_t ../_readtags.c 19;" kind:macro line:19 language:C file: 44 | PyInt_FromSsize_t ../_readtags.c 80;" kind:macro line:80 language:C file: 45 | PyInt_FromString ../_readtags.c 76;" kind:macro line:76 language:C file: 46 | PyInt_FromUnicode ../_readtags.c 77;" kind:macro line:77 language:C file: 47 | PyInt_Type ../_readtags.c 73;" kind:macro line:73 language:C file: 48 | PyMethod_New ../_readtags.c 92;" kind:macro line:92 language:C file: 49 | PyNumber_Index ../_readtags.c 21;" kind:macro line:21 language:C file: 50 | PyString_Type ../_readtags.c 72;" kind:macro line:72 language:C file: 51 | PyType_Modified ../_readtags.c 30;" kind:macro line:30 language:C file: 52 | PyVarObject_HEAD_INIT ../_readtags.c 28;" kind:macro line:28 language:C file: 53 | Py_REFCNT ../_readtags.c 25;" kind:macro line:25 language:C file: 54 | Py_SIZE ../_readtags.c 27;" kind:macro line:27 language:C file: 55 | Py_TPFLAGS_CHECKTYPES ../_readtags.c 64;" kind:macro line:64 language:C file: 56 | Py_TPFLAGS_HAVE_INDEX ../_readtags.c 65;" kind:macro line:65 language:C file: 57 | Py_TPFLAGS_HAVE_NEWBUFFER ../_readtags.c 68;" kind:macro line:68 language:C file: 58 | Py_TYPE ../_readtags.c 26;" kind:macro line:26 language:C file: 59 | Py_buffer ../_readtags.c /^ } Py_buffer;$/;" kind:typedef line:44 language:C typeref:struct:__anon5 file: 60 | Py_ssize_t ../_readtags.c /^ typedef int Py_ssize_t;$/;" kind:typedef line:16 language:C file: 61 | READTAGS_H ../include/readtags.h 22;" kind:macro line:22 language:C++ 62 | SortMethod ../readtags.c /^static sortType SortMethod;$/;" kind:variable line:793 language:C file: 63 | SortOverride ../readtags.c /^static int SortOverride;$/;" kind:variable line:792 language:C file: 64 | TAB ../readtags.c 26;" kind:macro line:26 language:C file: 65 | TAG_FOLDSORTED ../include/readtags.h /^ TAG_UNSORTED, TAG_SORTED, TAG_FOLDSORTED$/;" kind:enumerator line:34 language:C++ enum:__anon7 66 | TAG_FULLMATCH ../include/readtags.h 38;" kind:macro line:38 language:C++ 67 | TAG_IGNORECASE ../include/readtags.h 42;" kind:macro line:42 language:C++ 68 | TAG_OBSERVECASE ../include/readtags.h 41;" kind:macro line:41 language:C++ 69 | TAG_PARTIALMATCH ../include/readtags.h 39;" kind:macro line:39 language:C++ 70 | TAG_SORTED ../include/readtags.h /^ TAG_UNSORTED, TAG_SORTED, TAG_FOLDSORTED$/;" kind:enumerator line:34 language:C++ enum:__anon7 71 | TAG_UNSORTED ../include/readtags.h /^ TAG_UNSORTED, TAG_SORTED, TAG_FOLDSORTED$/;" kind:enumerator line:34 language:C++ enum:__anon7 72 | TagFailure ../include/readtags.h /^typedef enum { TagFailure = 0, TagSuccess = 1 } tagResult;$/;" kind:enumerator line:48 language:C++ enum:__anon8 73 | TagFileName ../readtags.c /^static const char *TagFileName = "tags";$/;" kind:variable line:789 language:C file: 74 | TagSuccess ../include/readtags.h /^typedef enum { TagFailure = 0, TagSuccess = 1 } tagResult;$/;" kind:enumerator line:48 language:C++ enum:__anon8 75 | Usage ../readtags.c /^const char *const Usage =$/;" kind:variable line:868 language:C 76 | _USE_MATH_DEFINES ../_readtags.c 102;" kind:macro line:102 language:C file: 77 | __PYX_EXTERN_C ../_readtags.c 105;" kind:macro line:105 language:C file: 78 | __PYX_EXTERN_C ../_readtags.c 107;" kind:macro line:107 language:C file: 79 | __PYX_HAVE_API___readtags ../_readtags.c 110;" kind:macro line:110 language:C file: 80 | __Pyx_AddTraceback ../_readtags.c /^static void __Pyx_AddTraceback(const char *funcname) {$/;" kind:function line:2558 language:C file: signature:(const char *funcname) 81 | __Pyx_ArgTypeTest ../_readtags.c /^static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed,$/;" kind:function line:2407 language:C file: signature:(PyObject *obj, PyTypeObject *type, int none_allowed, const char *name, int exact) 82 | __Pyx_BUILTIN_MODULE_NAME ../_readtags.c 59;" kind:macro line:59 language:C file: 83 | __Pyx_BUILTIN_MODULE_NAME ../_readtags.c 61;" kind:macro line:61 language:C file: 84 | __Pyx_CheckKeywordStrings ../_readtags.c /^static INLINE int __Pyx_CheckKeywordStrings($/;" kind:function line:2278 language:C file: signature:( PyObject *kwdict, const char* function_name, int kw_allowed) 85 | __Pyx_EndUnpack ../_readtags.c /^static int __Pyx_EndUnpack(PyObject *iter) {$/;" kind:function line:2442 language:C file: signature:(PyObject *iter) 86 | __Pyx_ErrFetch ../_readtags.c /^static INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb) {$/;" kind:function line:2542 language:C file: signature:(PyObject **type, PyObject **value, PyObject **tb) 87 | __Pyx_ErrRestore ../_readtags.c /^static INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb) {$/;" kind:function line:2527 language:C file: signature:(PyObject *type, PyObject *value, PyObject *tb) 88 | __Pyx_GetName ../_readtags.c /^static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) {$/;" kind:function line:2455 language:C file: signature:(PyObject *dict, PyObject *name) 89 | __Pyx_InitCachedBuiltins ../_readtags.c /^static int __Pyx_InitCachedBuiltins(void) {$/;" kind:function line:2163 language:C file: signature:(void) 90 | __Pyx_InitGlobals ../_readtags.c /^static int __Pyx_InitGlobals(void) {$/;" kind:function line:2170 language:C file: signature:(void) 91 | __Pyx_InitStrings ../_readtags.c /^static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) {$/;" kind:function line:2632 language:C file: signature:(__Pyx_StringTabEntry *t) 92 | __Pyx_ParseOptionalKeywords ../_readtags.c /^static int __Pyx_ParseOptionalKeywords($/;" kind:function line:2325 language:C file: signature:( PyObject *kwds, PyObject **argnames[], PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args, const char* function_name) 93 | __Pyx_PyBool_FromLong ../_readtags.c 140;" kind:macro line:140 language:C file: 94 | __Pyx_PyBytes_AsString ../_readtags.c 134;" kind:macro line:134 language:C file: 95 | __Pyx_PyBytes_AsString ../_readtags.c 137;" kind:macro line:137 language:C file: 96 | __Pyx_PyBytes_FromString ../_readtags.c 133;" kind:macro line:133 language:C file: 97 | __Pyx_PyBytes_FromString ../_readtags.c 136;" kind:macro line:136 language:C file: 98 | __Pyx_PyNumber_Divide ../_readtags.c 86;" kind:macro line:86 language:C file: 99 | __Pyx_PyNumber_Divide ../_readtags.c 88;" kind:macro line:88 language:C file: 100 | __Pyx_PyObject_IsTrue ../_readtags.c /^static INLINE int __Pyx_PyObject_IsTrue(PyObject* x) {$/;" kind:function line:2669 language:C file: signature:(PyObject* x) 101 | __Pyx_Raise ../_readtags.c /^static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) {$/;" kind:function line:2463 language:C file: signature:(PyObject *type, PyObject *value, PyObject *tb) 102 | __Pyx_RaiseArgtupleInvalid ../_readtags.c /^static void __Pyx_RaiseArgtupleInvalid($/;" kind:function line:2248 language:C file: signature:( const char* func_name, int exact, Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found) 103 | __Pyx_RaiseDoubleKeywordsError ../_readtags.c /^static void __Pyx_RaiseDoubleKeywordsError($/;" kind:function line:2312 language:C file: signature:( const char* func_name, PyObject* kw_name) 104 | __Pyx_StringTabEntry ../_readtags.c /^typedef struct {PyObject **p; char *s; long n; char is_unicode; char intern; char is_identifier;} __Pyx_StringTabEntry; \/*proto*\/$/;" kind:typedef line:123 language:C typeref:struct:__anon6 file: 105 | __Pyx_UnpackItem ../_readtags.c /^static PyObject *__Pyx_UnpackItem(PyObject *iter, Py_ssize_t index) {$/;" kind:function line:2427 language:C file: signature:(PyObject *iter, Py_ssize_t index) 106 | __cdecl ../_readtags.c 99;" kind:macro line:99 language:C file: 107 | __pyx_PyFloat_AsDouble ../_readtags.c 147;" kind:macro line:147 language:C file: 108 | __pyx_PyIndex_AsSsize_t ../_readtags.c /^static INLINE Py_ssize_t __pyx_PyIndex_AsSsize_t(PyObject* b) {$/;" kind:function line:2660 language:C file: signature:(PyObject* b) 109 | __pyx_PyInt_AsLong ../_readtags.c 146;" kind:macro line:146 language:C file: 110 | __pyx_PyInt_AsLongLong ../_readtags.c /^static INLINE PY_LONG_LONG __pyx_PyInt_AsLongLong(PyObject* x) {$/;" kind:function line:2675 language:C file: signature:(PyObject* x) 111 | __pyx_PyInt_AsUnsignedLongLong ../_readtags.c /^static INLINE unsigned PY_LONG_LONG __pyx_PyInt_AsUnsignedLongLong(PyObject* x) {$/;" kind:function line:2691 language:C file: signature:(PyObject* x) 112 | __pyx_PyInt_char ../_readtags.c /^static INLINE char __pyx_PyInt_char(PyObject* x) {$/;" kind:function line:2743 language:C file: signature:(PyObject* x) 113 | __pyx_PyInt_int ../_readtags.c /^static INLINE int __pyx_PyInt_int(PyObject* x) {$/;" kind:function line:2773 language:C file: signature:(PyObject* x) 114 | __pyx_PyInt_long ../_readtags.c /^static INLINE long __pyx_PyInt_long(PyObject* x) {$/;" kind:function line:2788 language:C file: signature:(PyObject* x) 115 | __pyx_PyInt_long_double ../_readtags.c /^static INLINE long double __pyx_PyInt_long_double(PyObject* x) {$/;" kind:function line:2863 language:C file: signature:(PyObject* x) 116 | __pyx_PyInt_short ../_readtags.c /^static INLINE short __pyx_PyInt_short(PyObject* x) {$/;" kind:function line:2758 language:C file: signature:(PyObject* x) 117 | __pyx_PyInt_signed_char ../_readtags.c /^static INLINE signed char __pyx_PyInt_signed_char(PyObject* x) {$/;" kind:function line:2803 language:C file: signature:(PyObject* x) 118 | __pyx_PyInt_signed_int ../_readtags.c /^static INLINE signed int __pyx_PyInt_signed_int(PyObject* x) {$/;" kind:function line:2833 language:C file: signature:(PyObject* x) 119 | __pyx_PyInt_signed_long ../_readtags.c /^static INLINE signed long __pyx_PyInt_signed_long(PyObject* x) {$/;" kind:function line:2848 language:C file: signature:(PyObject* x) 120 | __pyx_PyInt_signed_short ../_readtags.c /^static INLINE signed short __pyx_PyInt_signed_short(PyObject* x) {$/;" kind:function line:2818 language:C file: signature:(PyObject* x) 121 | __pyx_PyInt_unsigned_char ../_readtags.c /^static INLINE unsigned char __pyx_PyInt_unsigned_char(PyObject* x) {$/;" kind:function line:2713 language:C file: signature:(PyObject* x) 122 | __pyx_PyInt_unsigned_short ../_readtags.c /^static INLINE unsigned short __pyx_PyInt_unsigned_short(PyObject* x) {$/;" kind:function line:2728 language:C file: signature:(PyObject* x) 123 | __pyx_b ../_readtags.c /^static PyObject *__pyx_b;$/;" kind:variable line:175 language:C file: 124 | __pyx_builtin_Exception ../_readtags.c /^static PyObject *__pyx_builtin_Exception;$/;" kind:variable line:330 language:C file: 125 | __pyx_cfilenm ../_readtags.c /^static const char * __pyx_cfilenm= __FILE__;$/;" kind:variable line:179 language:C file: 126 | __pyx_clineno ../_readtags.c /^static int __pyx_clineno = 0;$/;" kind:variable line:178 language:C file: 127 | __pyx_empty_tuple ../_readtags.c /^static PyObject *__pyx_empty_tuple;$/;" kind:variable line:176 language:C file: 128 | __pyx_f ../_readtags.c /^static const char **__pyx_f;$/;" kind:variable line:181 language:C file: 129 | __pyx_filename ../_readtags.c /^static const char *__pyx_filename;$/;" kind:variable line:180 language:C file: 130 | __pyx_filenames ../_readtags.c /^static const char *__pyx_filenames[] = {$/;" kind:variable line:2238 language:C file: 131 | __pyx_init_filenames ../_readtags.c /^static void __pyx_init_filenames(void) {$/;" kind:function line:2244 language:C file: signature:(void) 132 | __pyx_k_1 ../_readtags.c /^static char __pyx_k_1[] = "name";$/;" kind:variable line:284 language:C file: 133 | __pyx_k_10 ../_readtags.c /^static char __pyx_k_10[] = "pattern";$/;" kind:variable line:304 language:C file: 134 | __pyx_k_11 ../_readtags.c /^static char __pyx_k_11[] = "lineNumber";$/;" kind:variable line:306 language:C file: 135 | __pyx_k_12 ../_readtags.c /^static char __pyx_k_12[] = "kind";$/;" kind:variable line:308 language:C file: 136 | __pyx_k_13 ../_readtags.c /^static char __pyx_k_13[] = "fileScope";$/;" kind:variable line:310 language:C file: 137 | __pyx_k_14 ../_readtags.c /^static char __pyx_k_14[] = "opened";$/;" kind:variable line:312 language:C file: 138 | __pyx_k_15 ../_readtags.c /^static char __pyx_k_15[] = "error_number";$/;" kind:variable line:314 language:C file: 139 | __pyx_k_16 ../_readtags.c /^static char __pyx_k_16[] = "format";$/;" kind:variable line:316 language:C file: 140 | __pyx_k_17 ../_readtags.c /^static char __pyx_k_17[] = "sort";$/;" kind:variable line:318 language:C file: 141 | __pyx_k_18 ../_readtags.c /^static char __pyx_k_18[] = "author";$/;" kind:variable line:320 language:C file: 142 | __pyx_k_19 ../_readtags.c /^static char __pyx_k_19[] = "";$/;" kind:variable line:335 language:C file: 143 | __pyx_k_2 ../_readtags.c /^static char __pyx_k_2[] = "file";$/;" kind:variable line:286 language:C file: 144 | __pyx_k_20 ../_readtags.c /^static char __pyx_k_20[] = "name";$/;" kind:variable line:322 language:C file: 145 | __pyx_k_21 ../_readtags.c /^static char __pyx_k_21[] = "";$/;" kind:variable line:336 language:C file: 146 | __pyx_k_22 ../_readtags.c /^static char __pyx_k_22[] = "url";$/;" kind:variable line:324 language:C file: 147 | __pyx_k_23 ../_readtags.c /^static char __pyx_k_23[] = "";$/;" kind:variable line:337 language:C file: 148 | __pyx_k_24 ../_readtags.c /^static char __pyx_k_24[] = "version";$/;" kind:variable line:326 language:C file: 149 | __pyx_k_25 ../_readtags.c /^static char __pyx_k_25[] = "";$/;" kind:variable line:338 language:C file: 150 | __pyx_k_26 ../_readtags.c /^static char __pyx_k_26[] = "Invalid tag file";$/;" kind:variable line:340 language:C file: 151 | __pyx_k_3 ../_readtags.c /^static char __pyx_k_3[] = "pattern";$/;" kind:variable line:288 language:C file: 152 | __pyx_k_4 ../_readtags.c /^static char __pyx_k_4[] = "lineNumber";$/;" kind:variable line:290 language:C file: 153 | __pyx_k_5 ../_readtags.c /^static char __pyx_k_5[] = "kind";$/;" kind:variable line:292 language:C file: 154 | __pyx_k_6 ../_readtags.c /^static char __pyx_k_6[] = "fileScope";$/;" kind:variable line:294 language:C file: 155 | __pyx_k_7 ../_readtags.c /^static char __pyx_k_7[] = "fields";$/;" kind:variable line:296 language:C file: 156 | __pyx_k_8 ../_readtags.c /^static char __pyx_k_8[] = "name";$/;" kind:variable line:300 language:C file: 157 | __pyx_k_9 ../_readtags.c /^static char __pyx_k_9[] = "file";$/;" kind:variable line:302 language:C file: 158 | __pyx_k_Exception ../_readtags.c /^static char __pyx_k_Exception[] = "Exception";$/;" kind:variable line:328 language:C file: 159 | __pyx_k___cinit__ ../_readtags.c /^static char __pyx_k___cinit__[] = "__cinit__";$/;" kind:variable line:250 language:C file: 160 | __pyx_k___dealloc__ ../_readtags.c /^static char __pyx_k___dealloc__[] = "__dealloc__";$/;" kind:variable line:256 language:C file: 161 | __pyx_k___getitem__ ../_readtags.c /^static char __pyx_k___getitem__[] = "__getitem__";$/;" kind:variable line:254 language:C file: 162 | __pyx_k___setitem__ ../_readtags.c /^static char __pyx_k___setitem__[] = "__setitem__";$/;" kind:variable line:252 language:C file: 163 | __pyx_k_entry ../_readtags.c /^static char __pyx_k_entry[] = "entry";$/;" kind:variable line:278 language:C file: 164 | __pyx_k_filepath ../_readtags.c /^static char __pyx_k_filepath[] = "filepath";$/;" kind:variable line:274 language:C file: 165 | __pyx_k_find ../_readtags.c /^static char __pyx_k_find[] = "find";$/;" kind:variable line:264 language:C file: 166 | __pyx_k_findNext ../_readtags.c /^static char __pyx_k_findNext[] = "findNext";$/;" kind:variable line:266 language:C file: 167 | __pyx_k_first ../_readtags.c /^static char __pyx_k_first[] = "first";$/;" kind:variable line:262 language:C file: 168 | __pyx_k_item ../_readtags.c /^static char __pyx_k_item[] = "item";$/;" kind:variable line:272 language:C file: 169 | __pyx_k_iteritems ../_readtags.c /^static char __pyx_k_iteritems[] = "iteritems";$/;" kind:variable line:298 language:C file: 170 | __pyx_k_key ../_readtags.c /^static char __pyx_k_key[] = "key";$/;" kind:variable line:270 language:C file: 171 | __pyx_k_name ../_readtags.c /^static char __pyx_k_name[] = "name";$/;" kind:variable line:280 language:C file: 172 | __pyx_k_next ../_readtags.c /^static char __pyx_k_next[] = "next";$/;" kind:variable line:268 language:C file: 173 | __pyx_k_open ../_readtags.c /^static char __pyx_k_open[] = "open";$/;" kind:variable line:258 language:C file: 174 | __pyx_k_options ../_readtags.c /^static char __pyx_k_options[] = "options";$/;" kind:variable line:282 language:C file: 175 | __pyx_k_setSortType ../_readtags.c /^static char __pyx_k_setSortType[] = "setSortType";$/;" kind:variable line:260 language:C file: 176 | __pyx_k_type ../_readtags.c /^static char __pyx_k_type[] = "type";$/;" kind:variable line:276 language:C file: 177 | __pyx_kp_1 ../_readtags.c /^static PyObject *__pyx_kp_1;$/;" kind:variable line:285 language:C file: 178 | __pyx_kp_10 ../_readtags.c /^static PyObject *__pyx_kp_10;$/;" kind:variable line:305 language:C file: 179 | __pyx_kp_11 ../_readtags.c /^static PyObject *__pyx_kp_11;$/;" kind:variable line:307 language:C file: 180 | __pyx_kp_12 ../_readtags.c /^static PyObject *__pyx_kp_12;$/;" kind:variable line:309 language:C file: 181 | __pyx_kp_13 ../_readtags.c /^static PyObject *__pyx_kp_13;$/;" kind:variable line:311 language:C file: 182 | __pyx_kp_14 ../_readtags.c /^static PyObject *__pyx_kp_14;$/;" kind:variable line:313 language:C file: 183 | __pyx_kp_15 ../_readtags.c /^static PyObject *__pyx_kp_15;$/;" kind:variable line:315 language:C file: 184 | __pyx_kp_16 ../_readtags.c /^static PyObject *__pyx_kp_16;$/;" kind:variable line:317 language:C file: 185 | __pyx_kp_17 ../_readtags.c /^static PyObject *__pyx_kp_17;$/;" kind:variable line:319 language:C file: 186 | __pyx_kp_18 ../_readtags.c /^static PyObject *__pyx_kp_18;$/;" kind:variable line:321 language:C file: 187 | __pyx_kp_19 ../_readtags.c /^static PyObject *__pyx_kp_19;$/;" kind:variable line:331 language:C file: 188 | __pyx_kp_2 ../_readtags.c /^static PyObject *__pyx_kp_2;$/;" kind:variable line:287 language:C file: 189 | __pyx_kp_20 ../_readtags.c /^static PyObject *__pyx_kp_20;$/;" kind:variable line:323 language:C file: 190 | __pyx_kp_21 ../_readtags.c /^static PyObject *__pyx_kp_21;$/;" kind:variable line:332 language:C file: 191 | __pyx_kp_22 ../_readtags.c /^static PyObject *__pyx_kp_22;$/;" kind:variable line:325 language:C file: 192 | __pyx_kp_23 ../_readtags.c /^static PyObject *__pyx_kp_23;$/;" kind:variable line:333 language:C file: 193 | __pyx_kp_24 ../_readtags.c /^static PyObject *__pyx_kp_24;$/;" kind:variable line:327 language:C file: 194 | __pyx_kp_25 ../_readtags.c /^static PyObject *__pyx_kp_25;$/;" kind:variable line:334 language:C file: 195 | __pyx_kp_26 ../_readtags.c /^static PyObject *__pyx_kp_26;$/;" kind:variable line:339 language:C file: 196 | __pyx_kp_3 ../_readtags.c /^static PyObject *__pyx_kp_3;$/;" kind:variable line:289 language:C file: 197 | __pyx_kp_4 ../_readtags.c /^static PyObject *__pyx_kp_4;$/;" kind:variable line:291 language:C file: 198 | __pyx_kp_5 ../_readtags.c /^static PyObject *__pyx_kp_5;$/;" kind:variable line:293 language:C file: 199 | __pyx_kp_6 ../_readtags.c /^static PyObject *__pyx_kp_6;$/;" kind:variable line:295 language:C file: 200 | __pyx_kp_7 ../_readtags.c /^static PyObject *__pyx_kp_7;$/;" kind:variable line:297 language:C file: 201 | __pyx_kp_8 ../_readtags.c /^static PyObject *__pyx_kp_8;$/;" kind:variable line:301 language:C file: 202 | __pyx_kp_9 ../_readtags.c /^static PyObject *__pyx_kp_9;$/;" kind:variable line:303 language:C file: 203 | __pyx_kp_Exception ../_readtags.c /^static PyObject *__pyx_kp_Exception;$/;" kind:variable line:329 language:C file: 204 | __pyx_kp___cinit__ ../_readtags.c /^static PyObject *__pyx_kp___cinit__;$/;" kind:variable line:251 language:C file: 205 | __pyx_kp___dealloc__ ../_readtags.c /^static PyObject *__pyx_kp___dealloc__;$/;" kind:variable line:257 language:C file: 206 | __pyx_kp___getitem__ ../_readtags.c /^static PyObject *__pyx_kp___getitem__;$/;" kind:variable line:255 language:C file: 207 | __pyx_kp___setitem__ ../_readtags.c /^static PyObject *__pyx_kp___setitem__;$/;" kind:variable line:253 language:C file: 208 | __pyx_kp_entry ../_readtags.c /^static PyObject *__pyx_kp_entry;$/;" kind:variable line:279 language:C file: 209 | __pyx_kp_filepath ../_readtags.c /^static PyObject *__pyx_kp_filepath;$/;" kind:variable line:275 language:C file: 210 | __pyx_kp_find ../_readtags.c /^static PyObject *__pyx_kp_find;$/;" kind:variable line:265 language:C file: 211 | __pyx_kp_findNext ../_readtags.c /^static PyObject *__pyx_kp_findNext;$/;" kind:variable line:267 language:C file: 212 | __pyx_kp_first ../_readtags.c /^static PyObject *__pyx_kp_first;$/;" kind:variable line:263 language:C file: 213 | __pyx_kp_item ../_readtags.c /^static PyObject *__pyx_kp_item;$/;" kind:variable line:273 language:C file: 214 | __pyx_kp_iteritems ../_readtags.c /^static PyObject *__pyx_kp_iteritems;$/;" kind:variable line:299 language:C file: 215 | __pyx_kp_key ../_readtags.c /^static PyObject *__pyx_kp_key;$/;" kind:variable line:271 language:C file: 216 | __pyx_kp_name ../_readtags.c /^static PyObject *__pyx_kp_name;$/;" kind:variable line:281 language:C file: 217 | __pyx_kp_next ../_readtags.c /^static PyObject *__pyx_kp_next;$/;" kind:variable line:269 language:C file: 218 | __pyx_kp_open ../_readtags.c /^static PyObject *__pyx_kp_open;$/;" kind:variable line:259 language:C file: 219 | __pyx_kp_options ../_readtags.c /^static PyObject *__pyx_kp_options;$/;" kind:variable line:283 language:C file: 220 | __pyx_kp_setSortType ../_readtags.c /^static PyObject *__pyx_kp_setSortType;$/;" kind:variable line:261 language:C file: 221 | __pyx_kp_type ../_readtags.c /^static PyObject *__pyx_kp_type;$/;" kind:variable line:277 language:C file: 222 | __pyx_lineno ../_readtags.c /^static int __pyx_lineno;$/;" kind:variable line:177 language:C file: 223 | __pyx_m ../_readtags.c /^static PyObject *__pyx_m;$/;" kind:variable line:174 language:C file: 224 | __pyx_mdoc ../_readtags.c /^static char __pyx_mdoc[] = "\\nCopyright (C) 2008 Aaron Diep \\n\\nThis file is part of Python-Ctags.\\n\\nPython-Ctags is free software: you can redistribute it and\/or modify\\nit under the terms of the GNU General Public License as published by\\nthe Free Software Foundation, either version 3 of the License, or\\n(at your option) any later version.\\n\\nPython-Ctags is distributed in the hope that it will be useful,\\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\\nGNU General Public License for more details.\\n\\nYou should have received a copy of the GNU General Public License\\nalong with Python-Ctags. If not, see .\\n";$/;" kind:variable line:183 language:C file: 225 | __pyx_methods ../_readtags.c /^static struct PyMethodDef __pyx_methods[] = {$/;" kind:variable line:2095 language:C typeref:struct:PyMethodDef file: 226 | __pyx_methods_9_readtags_CTags ../_readtags.c /^static struct PyMethodDef __pyx_methods_9_readtags_CTags[] = {$/;" kind:variable line:1942 language:C typeref:struct:PyMethodDef file: 227 | __pyx_methods_9_readtags_TagEntry ../_readtags.c /^static struct PyMethodDef __pyx_methods_9_readtags_TagEntry[] = {$/;" kind:variable line:1766 language:C typeref:struct:PyMethodDef file: 228 | __pyx_moduledef ../_readtags.c /^static struct PyModuleDef __pyx_moduledef = {$/;" kind:variable line:2102 language:C typeref:struct:PyModuleDef file: 229 | __pyx_mp_ass_subscript_9_readtags_TagEntry ../_readtags.c /^static int __pyx_mp_ass_subscript_9_readtags_TagEntry(PyObject *o, PyObject *i, PyObject *v) {$/;" kind:function line:1755 language:C file: signature:(PyObject *o, PyObject *i, PyObject *v) 230 | __pyx_obj_9_readtags_CTags ../_readtags.c /^struct __pyx_obj_9_readtags_CTags {$/;" kind:struct line:225 language:C file: 231 | __pyx_obj_9_readtags_TagEntry ../_readtags.c /^struct __pyx_obj_9_readtags_TagEntry {$/;" kind:struct line:239 language:C file: 232 | __pyx_pf_9_readtags_5CTags___cinit__ ../_readtags.c /^static int __pyx_pf_9_readtags_5CTags___cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {$/;" kind:function line:992 language:C file: signature:(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) 233 | __pyx_pf_9_readtags_5CTags___dealloc__ ../_readtags.c /^static void __pyx_pf_9_readtags_5CTags___dealloc__(PyObject *__pyx_v_self) {$/;" kind:function line:1067 language:C file: signature:(PyObject *__pyx_v_self) 234 | __pyx_pf_9_readtags_5CTags___getitem__ ../_readtags.c /^static PyObject *__pyx_pf_9_readtags_5CTags___getitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_key) {$/;" kind:function line:1103 language:C file: signature:(PyObject *__pyx_v_self, PyObject *__pyx_v_key) 235 | __pyx_pf_9_readtags_5CTags_find ../_readtags.c /^static PyObject *__pyx_pf_9_readtags_5CTags_find(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {$/;" kind:function line:1585 language:C file: signature:(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) 236 | __pyx_pf_9_readtags_5CTags_findNext ../_readtags.c /^static PyObject *__pyx_pf_9_readtags_5CTags_findNext(PyObject *__pyx_v_self, PyObject *__pyx_v_entry) {$/;" kind:function line:1673 language:C file: signature:(PyObject *__pyx_v_self, PyObject *__pyx_v_entry) 237 | __pyx_pf_9_readtags_5CTags_first ../_readtags.c /^static PyObject *__pyx_pf_9_readtags_5CTags_first(PyObject *__pyx_v_self, PyObject *__pyx_v_entry) {$/;" kind:function line:1549 language:C file: signature:(PyObject *__pyx_v_self, PyObject *__pyx_v_entry) 238 | __pyx_pf_9_readtags_5CTags_next ../_readtags.c /^static PyObject *__pyx_pf_9_readtags_5CTags_next(PyObject *__pyx_v_self, PyObject *__pyx_v_entry) {$/;" kind:function line:1709 language:C file: signature:(PyObject *__pyx_v_self, PyObject *__pyx_v_entry) 239 | __pyx_pf_9_readtags_5CTags_open ../_readtags.c /^static PyObject *__pyx_pf_9_readtags_5CTags_open(PyObject *__pyx_v_self, PyObject *__pyx_v_filepath) {$/;" kind:function line:1439 language:C file: signature:(PyObject *__pyx_v_self, PyObject *__pyx_v_filepath) 240 | __pyx_pf_9_readtags_5CTags_setSortType ../_readtags.c /^static PyObject *__pyx_pf_9_readtags_5CTags_setSortType(PyObject *__pyx_v_self, PyObject *__pyx_arg_type) {$/;" kind:function line:1505 language:C file: signature:(PyObject *__pyx_v_self, PyObject *__pyx_arg_type) 241 | __pyx_pf_9_readtags_8TagEntry___cinit__ ../_readtags.c /^static int __pyx_pf_9_readtags_8TagEntry___cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {$/;" kind:function line:351 language:C file: signature:(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) 242 | __pyx_pf_9_readtags_8TagEntry___getitem__ ../_readtags.c /^static PyObject *__pyx_pf_9_readtags_8TagEntry___getitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_key) {$/;" kind:function line:737 language:C file: signature:(PyObject *__pyx_v_self, PyObject *__pyx_v_key) 243 | __pyx_pf_9_readtags_8TagEntry___setitem__ ../_readtags.c /^static int __pyx_pf_9_readtags_8TagEntry___setitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_key, PyObject *__pyx_v_item) {$/;" kind:function line:388 language:C file: signature:(PyObject *__pyx_v_self, PyObject *__pyx_v_key, PyObject *__pyx_v_item) 244 | __pyx_ptype_9_readtags_CTags ../_readtags.c /^static PyTypeObject *__pyx_ptype_9_readtags_CTags = 0;$/;" kind:variable line:246 language:C file: 245 | __pyx_ptype_9_readtags_TagEntry ../_readtags.c /^static PyTypeObject *__pyx_ptype_9_readtags_TagEntry = 0;$/;" kind:variable line:245 language:C file: 246 | __pyx_skip_dispatch ../_readtags.c /^static int __pyx_skip_dispatch = 0;$/;" kind:variable line:127 language:C file: 247 | __pyx_sq_item_9_readtags_CTags ../_readtags.c /^static PyObject *__pyx_sq_item_9_readtags_CTags(PyObject *o, Py_ssize_t i) {$/;" kind:function line:1934 language:C file: signature:(PyObject *o, Py_ssize_t i) 248 | __pyx_sq_item_9_readtags_TagEntry ../_readtags.c /^static PyObject *__pyx_sq_item_9_readtags_TagEntry(PyObject *o, Py_ssize_t i) {$/;" kind:function line:1747 language:C file: signature:(PyObject *o, Py_ssize_t i) 249 | __pyx_string_tab ../_readtags.c /^static __Pyx_StringTabEntry __pyx_string_tab[] = {$/;" kind:variable line:2115 language:C file: 250 | __pyx_t_9_readtags_signal_handler ../_readtags.c /^typedef void (*__pyx_t_9_readtags_signal_handler)(int);$/;" kind:typedef line:215 language:C file: 251 | __pyx_tp_as_buffer_CTags ../_readtags.c /^static PyBufferProcs __pyx_tp_as_buffer_CTags = {$/;" kind:variable line:2026 language:C file: 252 | __pyx_tp_as_buffer_TagEntry ../_readtags.c /^static PyBufferProcs __pyx_tp_as_buffer_TagEntry = {$/;" kind:variable line:1844 language:C file: 253 | __pyx_tp_as_mapping_CTags ../_readtags.c /^static PyMappingMethods __pyx_tp_as_mapping_CTags = {$/;" kind:variable line:2020 language:C file: 254 | __pyx_tp_as_mapping_TagEntry ../_readtags.c /^static PyMappingMethods __pyx_tp_as_mapping_TagEntry = {$/;" kind:variable line:1838 language:C file: 255 | __pyx_tp_as_number_CTags ../_readtags.c /^static PyNumberMethods __pyx_tp_as_number_CTags = {$/;" kind:variable line:1953 language:C file: 256 | __pyx_tp_as_number_TagEntry ../_readtags.c /^static PyNumberMethods __pyx_tp_as_number_TagEntry = {$/;" kind:variable line:1771 language:C file: 257 | __pyx_tp_as_sequence_CTags ../_readtags.c /^static PySequenceMethods __pyx_tp_as_sequence_CTags = {$/;" kind:variable line:2007 language:C file: 258 | __pyx_tp_as_sequence_TagEntry ../_readtags.c /^static PySequenceMethods __pyx_tp_as_sequence_TagEntry = {$/;" kind:variable line:1825 language:C file: 259 | __pyx_tp_dealloc_9_readtags_CTags ../_readtags.c /^static void __pyx_tp_dealloc_9_readtags_CTags(PyObject *o) {$/;" kind:function line:1922 language:C file: signature:(PyObject *o) 260 | __pyx_tp_dealloc_9_readtags_TagEntry ../_readtags.c /^static void __pyx_tp_dealloc_9_readtags_TagEntry(PyObject *o) {$/;" kind:function line:1744 language:C file: signature:(PyObject *o) 261 | __pyx_tp_new_9_readtags_CTags ../_readtags.c /^static PyObject *__pyx_tp_new_9_readtags_CTags(PyTypeObject *t, PyObject *a, PyObject *k) {$/;" kind:function line:1913 language:C file: signature:(PyTypeObject *t, PyObject *a, PyObject *k) 262 | __pyx_tp_new_9_readtags_TagEntry ../_readtags.c /^static PyObject *__pyx_tp_new_9_readtags_TagEntry(PyTypeObject *t, PyObject *a, PyObject *k) {$/;" kind:function line:1735 language:C file: signature:(PyTypeObject *t, PyObject *a, PyObject *k) 263 | __pyx_type_9_readtags_CTags ../_readtags.c /^PyTypeObject __pyx_type_9_readtags_CTags = {$/;" kind:variable line:2047 language:C 264 | __pyx_type_9_readtags_TagEntry ../_readtags.c /^PyTypeObject __pyx_type_9_readtags_TagEntry = {$/;" kind:variable line:1865 language:C 265 | __stdcall ../_readtags.c 96;" kind:macro line:96 language:C file: 266 | address ../include/readtags.h /^ } address;$/;" kind:member line:123 language:C++ struct:__anon14 typeref:struct:__anon14::__anon15 access:public 267 | author ../include/readtags.h /^ const char *author;$/;" kind:member line:78 language:C++ struct:__anon9::__anon12 access:public 268 | author ../readtags.c /^ char *author;$/;" kind:member line:78 language:C struct:sTagFile::__anon4 file: access:public 269 | buf ../_readtags.c /^ void *buf;$/;" kind:member line:33 language:C struct:__anon5 file: access:public 270 | buffer ../readtags.c /^ char *buffer;$/;" kind:member line:34 language:C struct:__anon1 file: access:public 271 | c_entry ../_readtags.c /^ tagEntry c_entry;$/;" kind:member line:241 language:C struct:__pyx_obj_9_readtags_TagEntry file: access:public 272 | copyName ../readtags.c /^static void copyName (tagFile *const file)$/;" kind:function line:153 language:C file: signature:(tagFile *const file) 273 | count ../include/readtags.h /^ unsigned short count;$/;" kind:member line:134 language:C++ struct:__anon14::__anon16 access:public 274 | duplicate ../readtags.c /^static char *duplicate (const char *str)$/;" kind:function line:359 language:C file: signature:(const char *str) 275 | error_number ../include/readtags.h /^ int error_number;$/;" kind:member line:62 language:C++ struct:__anon9::__anon10 access:public 276 | extensionFields ../readtags.c /^static int extensionFields;$/;" kind:variable line:791 language:C file: 277 | fields ../include/readtags.h /^ } fields;$/;" kind:member line:138 language:C++ struct:__anon14 typeref:struct:__anon14::__anon16 access:public 278 | fields ../readtags.c /^ } fields;$/;" kind:member line:74 language:C struct:sTagFile typeref:struct:sTagFile::__anon3 file: access:public 279 | file ../_readtags.c /^ tagFile *file;$/;" kind:member line:227 language:C struct:__pyx_obj_9_readtags_CTags file: access:public 280 | file ../include/readtags.h /^ const char *file;$/;" kind:member line:112 language:C++ struct:__anon14 access:public 281 | file ../include/readtags.h /^ } file;$/;" kind:member line:72 language:C++ struct:__anon9 typeref:struct:__anon9::__anon11 access:public 282 | fileScope ../include/readtags.h /^ short fileScope;$/;" kind:member line:129 language:C++ struct:__anon14 access:public 283 | find ../readtags.c /^static tagResult find (tagFile *const file, tagEntry *const entry,$/;" kind:function line:649 language:C file: signature:(tagFile *const file, tagEntry *const entry, const char *const name, const int options) 284 | findBinary ../readtags.c /^static tagResult findBinary (tagFile *const file)$/;" kind:function line:592 language:C file: signature:(tagFile *const file) 285 | findFirstMatchBefore ../readtags.c /^static tagResult findFirstMatchBefore (tagFile *const file)$/;" kind:function line:577 language:C file: signature:(tagFile *const file) 286 | findFirstNonMatchBefore ../readtags.c /^static void findFirstNonMatchBefore (tagFile *const file)$/;" kind:function line:559 language:C file: signature:(tagFile *const file) 287 | findNext ../readtags.c /^static tagResult findNext (tagFile *const file, tagEntry *const entry)$/;" kind:function line:689 language:C file: signature:(tagFile *const file, tagEntry *const entry) 288 | findSequential ../readtags.c /^static tagResult findSequential (tagFile *const file)$/;" kind:function line:635 language:C file: signature:(tagFile *const file) 289 | findTag ../readtags.c /^static void findTag (const char *const name, const int options)$/;" kind:function line:823 language:C file: signature:(const char *const name, const int options) 290 | format ../_readtags.c /^ char *format;$/;" kind:member line:39 language:C struct:__anon5 file: access:public 291 | format ../include/readtags.h /^ short format;$/;" kind:member line:68 language:C++ struct:__anon9::__anon11 access:public 292 | format ../readtags.c /^ short format;$/;" kind:member line:42 language:C struct:sTagFile file: access:public 293 | fp ../readtags.c /^ FILE* fp;$/;" kind:member line:46 language:C struct:sTagFile file: access:public 294 | gotoFirstLogicalTag ../readtags.c /^static void gotoFirstLogicalTag (tagFile *const file)$/;" kind:function line:424 language:C file: signature:(tagFile *const file) 295 | growFields ../readtags.c /^static tagResult growFields (tagFile *const file)$/;" kind:function line:233 language:C file: signature:(tagFile *const file) 296 | growString ../readtags.c /^static int growString (vstring *s)$/;" kind:function line:125 language:C file: signature:(vstring *s) 297 | ignorecase ../readtags.c /^ short ignorecase;$/;" kind:member line:66 language:C struct:sTagFile::__anon2 file: access:public 298 | info ../_readtags.c /^ tagFileInfo info;$/;" kind:member line:228 language:C struct:__pyx_obj_9_readtags_CTags file: access:public 299 | init_readtags ../_readtags.c /^PyMODINIT_FUNC init_readtags(void)$/;" kind:function line:2179 language:C signature:(void) 300 | initialize ../readtags.c /^static tagFile *initialize (const char *const filePath, tagFileInfo *const info)$/;" kind:function line:440 language:C file: signature:(const char *const filePath, tagFileInfo *const info) 301 | initialized ../readtags.c /^ short initialized;$/;" kind:member line:40 language:C struct:sTagFile file: access:public 302 | intern ../_readtags.c /^typedef struct {PyObject **p; char *s; long n; char is_unicode; char intern; char is_identifier;} __Pyx_StringTabEntry; \/*proto*\/$/;" kind:member line:123 language:C struct:__anon6 file: access:public 303 | internal ../_readtags.c /^ void *internal;$/;" kind:member line:43 language:C struct:__anon5 file: access:public 304 | is_identifier ../_readtags.c /^typedef struct {PyObject **p; char *s; long n; char is_unicode; char intern; char is_identifier;} __Pyx_StringTabEntry; \/*proto*\/$/;" kind:member line:123 language:C struct:__anon6 file: access:public 305 | is_unicode ../_readtags.c /^typedef struct {PyObject **p; char *s; long n; char is_unicode; char intern; char is_identifier;} __Pyx_StringTabEntry; \/*proto*\/$/;" kind:member line:123 language:C struct:__anon6 file: access:public 306 | itemsize ../_readtags.c /^ Py_ssize_t itemsize;$/;" kind:member line:36 language:C struct:__anon5 file: access:public 307 | key ../include/readtags.h /^ const char *key;$/;" kind:member line:98 language:C++ struct:__anon13 access:public 308 | kind ../include/readtags.h /^ const char *kind;$/;" kind:member line:126 language:C++ struct:__anon14 access:public 309 | len ../_readtags.c /^ Py_ssize_t len;$/;" kind:member line:35 language:C struct:__anon5 file: access:public 310 | likely ../_readtags.c 163;" kind:macro line:163 language:C file: 311 | likely ../_readtags.c 166;" kind:macro line:166 language:C file: 312 | likely ../_readtags.c 170;" kind:macro line:170 language:C file: 313 | line ../readtags.c /^ vstring line;$/;" kind:member line:52 language:C struct:sTagFile file: access:public 314 | lineNumber ../include/readtags.h /^ unsigned long lineNumber;$/;" kind:member line:122 language:C++ struct:__anon14::__anon15 access:public 315 | list ../include/readtags.h /^ tagExtensionField *list;$/;" kind:member line:137 language:C++ struct:__anon14::__anon16 access:public 316 | list ../readtags.c /^ tagExtensionField *list;$/;" kind:member line:73 language:C struct:sTagFile::__anon3 file: access:public 317 | listTags ../readtags.c /^static void listTags (void)$/;" kind:function line:849 language:C file: signature:(void) 318 | main ../readtags.c /^extern int main (int argc, char **argv)$/;" kind:function line:880 language:C signature:(int argc, char **argv) 319 | max ../readtags.c /^ unsigned short max;$/;" kind:member line:71 language:C struct:sTagFile::__anon3 file: access:public 320 | n ../_readtags.c /^typedef struct {PyObject **p; char *s; long n; char is_unicode; char intern; char is_identifier;} __Pyx_StringTabEntry; \/*proto*\/$/;" kind:member line:123 language:C struct:__anon6 file: access:public 321 | name ../include/readtags.h /^ const char *name;$/;" kind:member line:81 language:C++ struct:__anon9::__anon12 access:public 322 | name ../include/readtags.h /^ const char *name;$/;" kind:member line:109 language:C++ struct:__anon14 access:public 323 | name ../readtags.c /^ char *name;$/;" kind:member line:60 language:C struct:sTagFile::__anon2 file: access:public 324 | name ../readtags.c /^ char *name;$/;" kind:member line:80 language:C struct:sTagFile::__anon4 file: access:public 325 | name ../readtags.c /^ vstring name;$/;" kind:member line:54 language:C struct:sTagFile file: access:public 326 | nameComparison ../readtags.c /^static int nameComparison (tagFile *const file)$/;" kind:function line:537 language:C file: signature:(tagFile *const file) 327 | nameLength ../readtags.c /^ size_t nameLength;$/;" kind:member line:62 language:C struct:sTagFile::__anon2 file: access:public 328 | ndim ../_readtags.c /^ int ndim;$/;" kind:member line:38 language:C struct:__anon5 file: access:public 329 | obj ../_readtags.c /^ PyObject *obj;$/;" kind:member line:34 language:C struct:__anon5 file: access:public 330 | opened ../include/readtags.h /^ int opened;$/;" kind:member line:59 language:C++ struct:__anon9::__anon10 access:public 331 | p ../_readtags.c /^typedef struct {PyObject **p; char *s; long n; char is_unicode; char intern; char is_identifier;} __Pyx_StringTabEntry; \/*proto*\/$/;" kind:member line:123 language:C struct:__anon6 file: access:public 332 | parseExtensionFields ../readtags.c /^static void parseExtensionFields (tagFile *const file, tagEntry *const entry,$/;" kind:function line:250 language:C file: signature:(tagFile *const file, tagEntry *const entry, char *const string) 333 | parseTagLine ../readtags.c /^static void parseTagLine (tagFile *file, tagEntry *const entry)$/;" kind:function line:292 language:C file: signature:(tagFile *file, tagEntry *const entry) 334 | partial ../readtags.c /^ short partial;$/;" kind:member line:64 language:C struct:sTagFile::__anon2 file: access:public 335 | pattern ../include/readtags.h /^ const char *pattern;$/;" kind:member line:118 language:C++ struct:__anon14::__anon15 access:public 336 | pos ../readtags.c /^ off_t pos; $/;" kind:member line:58 language:C struct:sTagFile::__anon2 file: access:public 337 | pos ../readtags.c /^ off_t pos;$/;" kind:member line:48 language:C struct:sTagFile file: access:public 338 | printTag ../readtags.c /^static void printTag (const tagEntry *entry)$/;" kind:function line:795 language:C file: signature:(const tagEntry *entry) 339 | program ../include/readtags.h /^ } program;$/;" kind:member line:88 language:C++ struct:__anon9 typeref:struct:__anon9::__anon12 access:public 340 | program ../readtags.c /^ } program;$/;" kind:member line:85 language:C struct:sTagFile typeref:struct:sTagFile::__anon4 file: access:public 341 | readFieldValue ../readtags.c /^static const char *readFieldValue ($/;" kind:function line:510 language:C file: signature:( const tagEntry *const entry, const char *const key) 342 | readNext ../readtags.c /^static tagResult readNext (tagFile *const file, tagEntry *const entry)$/;" kind:function line:494 language:C file: signature:(tagFile *const file, tagEntry *const entry) 343 | readPseudoTags ../readtags.c /^static void readPseudoTags (tagFile *const file, tagFileInfo *const info)$/;" kind:function line:371 language:C file: signature:(tagFile *const file, tagFileInfo *const info) 344 | readTagLine ../readtags.c /^static int readTagLine (tagFile *const file)$/;" kind:function line:223 language:C file: signature:(tagFile *const file) 345 | readTagLineRaw ../readtags.c /^static int readTagLineRaw (tagFile *const file)$/;" kind:function line:173 language:C file: signature:(tagFile *const file) 346 | readTagLineSeek ../readtags.c /^static int readTagLineSeek (tagFile *const file, const off_t pos)$/;" kind:function line:525 language:C file: signature:(tagFile *const file, const off_t pos) 347 | readonly ../_readtags.c /^ int readonly;$/;" kind:member line:37 language:C struct:__anon5 file: access:public 348 | s ../_readtags.c /^typedef struct {PyObject **p; char *s; long n; char is_unicode; char intern; char is_identifier;} __Pyx_StringTabEntry; \/*proto*\/$/;" kind:member line:123 language:C struct:__anon6 file: access:public 349 | sTagFile ../readtags.c /^struct sTagFile {$/;" kind:struct line:38 language:C file: 350 | search ../readtags.c /^ } search;$/;" kind:member line:67 language:C struct:sTagFile typeref:struct:sTagFile::__anon2 file: access:public 351 | sep ../readtags.c 802;" kind:macro line:802 language:C file: 352 | sep ../readtags.c 820;" kind:macro line:820 language:C file: 353 | shape ../_readtags.c /^ Py_ssize_t *shape;$/;" kind:member line:40 language:C struct:__anon5 file: access:public 354 | size ../readtags.c /^ off_t size;$/;" kind:member line:50 language:C struct:sTagFile file: access:public 355 | size ../readtags.c /^ size_t size;$/;" kind:member line:33 language:C struct:__anon1 file: access:public 356 | sort ../include/readtags.h /^ sortType sort;$/;" kind:member line:71 language:C++ struct:__anon9::__anon11 access:public 357 | sortMethod ../readtags.c /^ sortType sortMethod;$/;" kind:member line:44 language:C struct:sTagFile file: access:public 358 | sortType ../include/readtags.h /^} sortType ;$/;" kind:typedef line:35 language:C++ typeref:enum:__anon7 359 | status ../include/readtags.h /^ } status;$/;" kind:member line:63 language:C++ struct:__anon9 typeref:struct:__anon9::__anon10 access:public 360 | strides ../_readtags.c /^ Py_ssize_t *strides;$/;" kind:member line:41 language:C struct:__anon5 file: access:public 361 | strnuppercmp ../readtags.c /^static int strnuppercmp (const char *s1, const char *s2, size_t n)$/;" kind:function line:115 language:C file: signature:(const char *s1, const char *s2, size_t n) 362 | struppercmp ../readtags.c /^static int struppercmp (const char *s1, const char *s2)$/;" kind:function line:105 language:C file: signature:(const char *s1, const char *s2) 363 | suboffsets ../_readtags.c /^ Py_ssize_t *suboffsets;$/;" kind:member line:42 language:C struct:__anon5 file: access:public 364 | tagEntry ../include/readtags.h /^} tagEntry;$/;" kind:typedef line:140 language:C++ typeref:struct:__anon14 365 | tagExtensionField ../include/readtags.h /^} tagExtensionField;$/;" kind:typedef line:103 language:C++ typeref:struct:__anon13 366 | tagFile ../include/readtags.h /^typedef struct sTagFile tagFile;$/;" kind:typedef line:52 language:C++ typeref:struct:sTagFile 367 | tagFileInfo ../include/readtags.h /^} tagFileInfo;$/;" kind:typedef line:90 language:C++ typeref:struct:__anon9 368 | tagResult ../include/readtags.h /^typedef enum { TagFailure = 0, TagSuccess = 1 } tagResult;$/;" kind:typedef line:48 language:C++ typeref:enum:__anon8 369 | tagsClose ../readtags.c /^extern tagResult tagsClose (tagFile *const file)$/;" kind:function line:772 language:C signature:(tagFile *const file) 370 | tagsField ../readtags.c /^extern const char *tagsField (const tagEntry *const entry, const char *const key)$/;" kind:function line:747 language:C signature:(const tagEntry *const entry, const char *const key) 371 | tagsFind ../readtags.c /^extern tagResult tagsFind (tagFile *const file, tagEntry *const entry,$/;" kind:function line:755 language:C signature:(tagFile *const file, tagEntry *const entry, const char *const name, const int options) 372 | tagsFindNext ../readtags.c /^extern tagResult tagsFindNext (tagFile *const file, tagEntry *const entry)$/;" kind:function line:764 language:C signature:(tagFile *const file, tagEntry *const entry) 373 | tagsFirst ../readtags.c /^extern tagResult tagsFirst (tagFile *const file, tagEntry *const entry)$/;" kind:function line:728 language:C signature:(tagFile *const file, tagEntry *const entry) 374 | tagsNext ../readtags.c /^extern tagResult tagsNext (tagFile *const file, tagEntry *const entry)$/;" kind:function line:739 language:C signature:(tagFile *const file, tagEntry *const entry) 375 | tagsOpen ../readtags.c /^extern tagFile *tagsOpen (const char *const filePath, tagFileInfo *const info)$/;" kind:function line:712 language:C signature:(const char *const filePath, tagFileInfo *const info) 376 | tagsSetSortType ../readtags.c /^extern tagResult tagsSetSortType (tagFile *const file, const sortType type)$/;" kind:function line:717 language:C signature:(tagFile *const file, const sortType type) 377 | terminate ../readtags.c /^static void terminate (tagFile *const file)$/;" kind:function line:470 language:C file: signature:(tagFile *const file) 378 | unlikely ../_readtags.c 164;" kind:macro line:164 language:C file: 379 | unlikely ../_readtags.c 167;" kind:macro line:167 language:C file: 380 | unlikely ../_readtags.c 171;" kind:macro line:171 language:C file: 381 | url ../include/readtags.h /^ const char *url;$/;" kind:member line:84 language:C++ struct:__anon9::__anon12 access:public 382 | url ../readtags.c /^ char *url;$/;" kind:member line:82 language:C struct:sTagFile::__anon4 file: access:public 383 | value ../include/readtags.h /^ const char *value;$/;" kind:member line:101 language:C++ struct:__anon13 access:public 384 | version ../include/readtags.h /^ const char *version;$/;" kind:member line:87 language:C++ struct:__anon9::__anon12 access:public 385 | version ../readtags.c /^ char *version;$/;" kind:member line:84 language:C struct:sTagFile::__anon4 file: access:public 386 | vstring ../readtags.c /^} vstring;$/;" kind:typedef line:35 language:C typeref:struct:__anon1 file: 387 | -------------------------------------------------------------------------------- /src/include/readtags.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1996-2003, Darren Hiebert 3 | * 4 | * This source code is released for the public domain. 5 | * 6 | * This file defines the public interface for looking up tag entries in tag 7 | * files. 8 | * 9 | * The functions defined in this interface are intended to provide tag file 10 | * support to a software tool. The tag lookups provided are sufficiently fast 11 | * enough to permit opening a sorted tag file, searching for a matching tag, 12 | * then closing the tag file each time a tag is looked up (search times are 13 | * on the order of hundredths of a second, even for huge tag files). This is 14 | * the recommended use of this library for most tool applications. Adhering 15 | * to this approach permits a user to regenerate a tag file at will without 16 | * the tool needing to detect and resynchronize with changes to the tag file. 17 | * Even for an unsorted 24MB tag file, tag searches take about one second. 18 | */ 19 | #ifndef READTAGS_H 20 | #define READTAGS_H 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | /* 27 | * MACROS 28 | */ 29 | 30 | /* Options for tagsSetSortType() */ 31 | typedef enum { 32 | TAG_UNSORTED, TAG_SORTED, TAG_FOLDSORTED 33 | } tagSortType ; 34 | 35 | /* For source code level compatibility, sortType is defined here. 36 | * Define TAG_NO_COMPAT_SORT_TYPE if you want to avoid namespace pollution. 37 | */ 38 | #ifndef TAG_NO_COMPAT_SORT_TYPE 39 | #define sortType tagSortType 40 | #endif 41 | 42 | /* Options for tagsFind() and tagsFindPseudoTag() */ 43 | #define TAG_FULLMATCH 0x0 44 | #define TAG_PARTIALMATCH 0x1 45 | 46 | #define TAG_OBSERVECASE 0x0 47 | #define TAG_IGNORECASE 0x2 48 | 49 | /* 50 | * DATA DECLARATIONS 51 | */ 52 | 53 | typedef enum { TagFailure = 0, TagSuccess = 1 } tagResult; 54 | 55 | typedef enum { 56 | TagErrnoUnexpectedSortedMethod = -1, /* Unexpected sorted method */ 57 | TagErrnoUnexpectedFormat = -2, /* Unexpected format number */ 58 | TagErrnoUnexpectedLineno = -3, /* Unexpected value for line: field 59 | * (Zero or a positive integer is expected.) */ 60 | TagErrnoInvalidArgument = -4, /* Unexpected argument passed to the API 61 | * function */ 62 | TagErrnoFileMaybeTooBig = -5, /* Maybe the tags file is too big */ 63 | } tagErrno; 64 | 65 | struct sTagFile; 66 | 67 | typedef struct sTagFile tagFile; 68 | 69 | /* This structure contains information about the tag file. */ 70 | typedef struct { 71 | 72 | struct { 73 | /* was the tag file successfully opened? */ 74 | int opened; 75 | 76 | /* errno value or tagErrno typed value 77 | when 'opened' is false */ 78 | int error_number; 79 | } status; 80 | 81 | /* information about the structure of the tag file */ 82 | struct { 83 | /* format of tag file (1 = original, 2 = extended) */ 84 | short format; 85 | 86 | /* how is the tag file sorted? */ 87 | tagSortType sort; 88 | } file; 89 | 90 | 91 | /* information about the program which created this tag file */ 92 | struct { 93 | /* name of author of generating program (may be null) */ 94 | const char *author; 95 | 96 | /* name of program (may be null) */ 97 | const char *name; 98 | 99 | /* URL of distribution (may be null) */ 100 | const char *url; 101 | 102 | /* program version (may be null) */ 103 | const char *version; 104 | } program; 105 | 106 | } tagFileInfo; 107 | 108 | /* This structure contains information about an extension field for a tag. 109 | * These exist at the end of the tag in the form "key:value"). 110 | */ 111 | typedef struct { 112 | 113 | /* the key of the extension field */ 114 | const char *key; 115 | 116 | /* the value of the extension field (may be an empty string) */ 117 | const char *value; 118 | 119 | } tagExtensionField; 120 | 121 | /* This structure contains information about a specific tag. */ 122 | typedef struct { 123 | 124 | /* name of tag */ 125 | const char *name; 126 | 127 | /* path of source file containing definition of tag. 128 | For a broken tags file, this can be NULL. */ 129 | const char *file; 130 | 131 | /* address for locating tag in source file */ 132 | struct { 133 | /* pattern for locating source line 134 | * (may be NULL if not present) */ 135 | const char *pattern; 136 | 137 | /* line number in source file of tag definition 138 | * (may be zero if not known) */ 139 | unsigned long lineNumber; 140 | } address; 141 | 142 | /* kind of tag (may by name, character, or NULL if not known) */ 143 | const char *kind; 144 | 145 | /* is tag of file-limited scope? */ 146 | short fileScope; 147 | 148 | /* miscellaneous extension fields */ 149 | struct { 150 | /* number of entries in `list' */ 151 | unsigned short count; 152 | 153 | /* list of key value pairs */ 154 | tagExtensionField *list; 155 | } fields; 156 | 157 | } tagEntry; 158 | 159 | 160 | /* 161 | * FUNCTION PROTOTYPES 162 | */ 163 | 164 | /* 165 | * This function must be called before calling other functions in this 166 | * library. It is passed the path to the tag file to read and a (possibly 167 | * null) pointer to a structure which, if not null, will be populated with 168 | * information about the tag file. If successful, the function will return a 169 | * handle which must be supplied to other calls to read information from the 170 | * tag file, and info.status.opened will be set to true. 171 | * If unsuccessful, the function will return NULL, and 172 | * info.status.opened will be set to false and 173 | * info.status.error_number will be set to either the errno value 174 | * representing the system error preventing the tag file from being 175 | * successfully opened, or the tagErrno typed value representing the 176 | * library level error. The error_number will be ENOMEM if the memory 177 | * allocation for the handle is failed. 178 | */ 179 | extern tagFile *tagsOpen (const char *const filePath, tagFileInfo *const info); 180 | 181 | /* 182 | * This function allows the client to override the normal automatic detection 183 | * of how a tag file is sorted. Permissible values for `type' are 184 | * TAG_UNSORTED, TAG_SORTED, TAG_FOLDSORTED. Tag files in the new extended 185 | * format contain a key indicating whether or not they are sorted. However, 186 | * tag files in the original format do not contain such a key even when 187 | * sorted, preventing this library from taking advantage of fast binary 188 | * lookups. If the client knows that such an unmarked tag file is indeed 189 | * sorted (or not), it can override the automatic detection. Note that 190 | * incorrect lookup results will result if a tag file is marked as sorted when 191 | * it actually is not. The function will return TagSuccess if called on an 192 | * open tag file or TagFailure if not. 193 | */ 194 | extern tagResult tagsSetSortType (tagFile *const file, const tagSortType type); 195 | 196 | /* 197 | * Reads the first tag in the file, if any. It is passed the handle to an 198 | * opened tag file and a (possibly null) pointer to a structure which, if not 199 | * null, will be populated with information about the first tag file entry. 200 | * The function will return TagSuccess another tag entry is found, or 201 | * TagFailure if not (i.e. it reached end of file). 202 | */ 203 | extern tagResult tagsFirst (tagFile *const file, tagEntry *const entry); 204 | 205 | /* 206 | * Step to the next tag in the file, if any. It is passed the handle to an 207 | * opened tag file and a (possibly null) pointer to a structure which, if not 208 | * null, will be populated with information about the next tag file entry. The 209 | * function will return TagSuccess another tag entry is found, or TagFailure 210 | * if not (i.e. it reached end of file). It will always read the first tag in 211 | * the file immediately after calling tagsOpen(). 212 | */ 213 | extern tagResult tagsNext (tagFile *const file, tagEntry *const entry); 214 | 215 | /* 216 | * Retrieve the value associated with the extension field for a specified key. 217 | * It is passed a pointer to a structure already populated with values by a 218 | * previous call to tagsNext(), tagsFind(), or tagsFindNext(), and a string 219 | * containing the key of the desired extension field. If no such field of the 220 | * specified key exists, the function will return null. 221 | */ 222 | extern const char *tagsField (const tagEntry *const entry, const char *const key); 223 | 224 | /* 225 | * Find the first tag matching `name'. The structure pointed to by `entry' 226 | * will be populated with information about the tag file entry. If a tag file 227 | * is sorted using the C locale, a binary search algorithm is used to search 228 | * the tag file, resulting in very fast tag lookups, even in huge tag files. 229 | * Various options controlling the matches can be combined by bit-wise or-ing 230 | * certain values together. The available values are: 231 | * 232 | * TAG_PARTIALMATCH 233 | * Tags whose leading characters match `name' will qualify. 234 | * 235 | * TAG_FULLMATCH 236 | * Only tags whose full lengths match `name' will qualify. 237 | * 238 | * TAG_IGNORECASE 239 | * Matching will be performed in a case-insensitive manner. Note that 240 | * this disables binary searches of the tag file. 241 | * 242 | * TAG_OBSERVECASE 243 | * Matching will be performed in a case-sensitive manner. Note that 244 | * this enables binary searches of the tag file. 245 | * 246 | * The function will return TagSuccess if a tag matching the name is found, or 247 | * TagFailure if not. 248 | */ 249 | extern tagResult tagsFind (tagFile *const file, tagEntry *const entry, const char *const name, const int options); 250 | 251 | /* 252 | * Find the next tag matching the name and options supplied to the most recent 253 | * call to tagsFind() for the same tag file. The structure pointed to by 254 | * `entry' will be populated with information about the tag file entry. The 255 | * function will return TagSuccess if another tag matching the name is found, 256 | * or TagFailure if not. 257 | */ 258 | extern tagResult tagsFindNext (tagFile *const file, tagEntry *const entry); 259 | 260 | /* 261 | * Does the same as tagsFirst(), but is specialized to pseudo tags. 262 | * If tagFileInfo doesn't contain pseudo tags you are interested in, read 263 | * them sequentially with this function and tagsNextPseudoTag(). 264 | */ 265 | extern tagResult tagsFirstPseudoTag (tagFile *const file, tagEntry *const entry); 266 | 267 | /* 268 | * Does the same as tagsNext(), but is specialized to pseudo tags. Use with 269 | * tagsFirstPseudoTag(). 270 | */ 271 | extern tagResult tagsNextPseudoTag (tagFile *const file, tagEntry *const entry); 272 | 273 | /* 274 | * Does the same as tagsFind(), but is specialized to pseudo tags. 275 | * The available values for `match' are: 276 | * 277 | * TAG_PARTIALMATCH 278 | * Tags whose leading characters match `name' will qualify. 279 | * 280 | * TAG_FULLMATCH 281 | * Only tags whose full lengths match `name' will qualify. 282 | * 283 | * NOTE: unlike tagsFind(), this function uses liner-searching even if 284 | * the tags file is sorted. 285 | */ 286 | extern tagResult tagsFindPseudoTag (tagFile *const file, tagEntry *const entry, const char *const name, const int match); 287 | 288 | /* 289 | * Call tagsClose() at completion of reading the tag file, which will 290 | * close the file and free any internal memory allocated. The function will 291 | * return TagFailure if no file is currently open, TagSuccess otherwise. 292 | */ 293 | extern tagResult tagsClose (tagFile *const file); 294 | 295 | /* 296 | * Get the error status set in the last API call. 297 | * Much of the API functions return TagFailure because (1) no tag is 298 | * found, or (2) an error occurs. tagsGetErrno() is for distinguishing 299 | * (1) or (2). This function will return 0 for (1). The errno value 300 | * representing the system error or tagErrno value for (2). 301 | * 302 | * This function does not deal with the results of tagsOpen(), 303 | * tagsClose(), and tagsField(). 304 | */ 305 | extern int tagsGetErrno (tagFile *const file); 306 | 307 | #ifdef __cplusplus 308 | }; 309 | #endif 310 | 311 | #endif 312 | -------------------------------------------------------------------------------- /src/readtags.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1996-2003, Darren Hiebert 3 | * 4 | * This source code is released into the public domain. 5 | * 6 | * This module contains functions for reading tag files. 7 | */ 8 | 9 | /* 10 | * INCLUDE FILES 11 | */ 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include /* to declare off_t */ 18 | 19 | #include "readtags.h" 20 | 21 | /* 22 | * MACROS 23 | */ 24 | #define TAB '\t' 25 | 26 | 27 | /* 28 | * DATA DECLARATIONS 29 | */ 30 | typedef struct { 31 | size_t size; 32 | char *buffer; 33 | } vstring; 34 | 35 | /* Define readtags' own off_t. */ 36 | #ifdef _WIN32 37 | typedef long long rt_off_t; 38 | #else 39 | typedef off_t rt_off_t; 40 | #endif 41 | 42 | /* Information about current tag file */ 43 | struct sTagFile { 44 | /* has the file been opened and this structure initialized? */ 45 | unsigned char initialized; 46 | /* format of tag file */ 47 | unsigned char format; 48 | /* 1 "u-ctags" is set to !_TAG_OUTPUT_MODE pseudo tag 49 | * and "slash" is set to !_TAG_OUTPUT_FILESEP 50 | * pseudo tag in the tags file. */ 51 | unsigned char inputUCtagsMode; 52 | /* how is the tag file sorted? */ 53 | tagSortType sortMethod; 54 | /* pointer to file structure */ 55 | FILE* fp; 56 | /* file position of first character of `line' */ 57 | rt_off_t pos; 58 | /* size of tag file in seekable positions */ 59 | rt_off_t size; 60 | /* last line read */ 61 | vstring line; 62 | /* name of tag in last line read */ 63 | vstring name; 64 | /* defines tag search state */ 65 | struct { 66 | /* file position of last match for tag */ 67 | rt_off_t pos; 68 | /* name of tag last searched for */ 69 | char *name; 70 | /* length of name for partial matches */ 71 | size_t nameLength; 72 | /* performing partial match */ 73 | short partial; 74 | /* ignoring case */ 75 | short ignorecase; 76 | } search; 77 | /* miscellaneous extension fields */ 78 | struct { 79 | /* number of entries in `list' */ 80 | unsigned short max; 81 | /* list of key value pairs */ 82 | tagExtensionField *list; 83 | } fields; 84 | /* buffers to be freed at close */ 85 | struct { 86 | /* name of program author */ 87 | char *author; 88 | /* name of program */ 89 | char *name; 90 | /* URL of distribution */ 91 | char *url; 92 | /* program version */ 93 | char *version; 94 | } program; 95 | /* 0 (initial state set by calloc), errno value, 96 | * or tagErrno typed value */ 97 | int err; 98 | }; 99 | 100 | /* 101 | * DATA DEFINITIONS 102 | */ 103 | static const char *const EmptyString = ""; 104 | static const char *const PseudoTagPrefix = "!_"; 105 | static const size_t PseudoTagPrefixLength = 2; 106 | 107 | /* 108 | * FUNCTION DEFINITIONS 109 | */ 110 | 111 | static rt_off_t readtags_ftell(FILE *fp) 112 | { 113 | rt_off_t pos; 114 | 115 | #ifdef _WIN32 116 | pos = _ftelli64(fp); 117 | #else 118 | pos = ftell(fp); 119 | #endif 120 | 121 | return pos; 122 | } 123 | 124 | static int readtags_fseek(FILE *fp, rt_off_t pos, int whence) 125 | { 126 | int ret; 127 | 128 | #ifdef _WIN32 129 | ret = _fseeki64(fp, pos, whence); 130 | #else 131 | ret = fseek(fp, pos, whence); 132 | #endif 133 | 134 | return ret; 135 | } 136 | 137 | /* Converts a hexadecimal digit to its value */ 138 | static int xdigitValue (unsigned char digit) 139 | { 140 | if (digit >= '0' && digit <= '9') 141 | return digit - '0'; 142 | else if (digit >= 'a' && digit <= 'f') 143 | return 10 + digit - 'a'; 144 | else if (digit >= 'A' && digit <= 'F') 145 | return 10 + digit - 'A'; 146 | else 147 | return 0; 148 | } 149 | 150 | /* 151 | * Reads the first character from the string, possibly un-escaping it, and 152 | * advances *s to the start of the next character. 153 | */ 154 | static int readTagCharacter (const char **const s) 155 | { 156 | const unsigned char *p = (const unsigned char *) *s; 157 | int c = *p; 158 | 159 | p++; 160 | 161 | if (c == '\\') 162 | { 163 | switch (*p) 164 | { 165 | case 't': c = '\t'; p++; break; 166 | case 'r': c = '\r'; p++; break; 167 | case 'n': c = '\n'; p++; break; 168 | case '\\': c = '\\'; p++; break; 169 | /* Universal-CTags extensions */ 170 | case 'a': c = '\a'; p++; break; 171 | case 'b': c = '\b'; p++; break; 172 | case 'v': c = '\v'; p++; break; 173 | case 'f': c = '\f'; p++; break; 174 | case 'x': 175 | if (isxdigit (p[1]) && isxdigit (p[2])) 176 | { 177 | int val = (xdigitValue (p[1]) << 4) | xdigitValue (p[2]); 178 | if (val < 0x80) 179 | { 180 | p += 3; 181 | c = val; 182 | } 183 | } 184 | break; 185 | } 186 | } 187 | 188 | *s = (const char *) p; 189 | 190 | return c; 191 | } 192 | 193 | /* 194 | * Compare two strings, ignoring case. 195 | * Return 0 for match, < 0 for smaller, > 0 for bigger 196 | * Make sure case is folded to uppercase in comparison (like for 'sort -f') 197 | * This makes a difference when one of the chars lies between upper and lower 198 | * ie. one of the chars [ \ ] ^ _ ` for ascii. (The '_' in particular !) 199 | */ 200 | static int taguppercmp (const char *s1, const char *s2) 201 | { 202 | int result; 203 | int c1, c2; 204 | do 205 | { 206 | c1 = (unsigned char)*s1++; 207 | c2 = readTagCharacter (&s2); 208 | 209 | result = toupper (c1) - toupper (c2); 210 | } while (result == 0 && c1 != '\0' && c2 != '\0'); 211 | return result; 212 | } 213 | 214 | static int tagnuppercmp (const char *s1, const char *s2, size_t n) 215 | { 216 | int result; 217 | int c1, c2; 218 | do 219 | { 220 | c1 = (unsigned char)*s1++; 221 | c2 = readTagCharacter (&s2); 222 | 223 | result = toupper (c1) - toupper (c2); 224 | } while (result == 0 && --n > 0 && c1 != '\0' && c2 != '\0'); 225 | return result; 226 | } 227 | 228 | static int tagcmp (const char *s1, const char *s2) 229 | { 230 | int result; 231 | int c1, c2; 232 | do 233 | { 234 | c1 = (unsigned char)*s1++; 235 | c2 = readTagCharacter (&s2); 236 | 237 | result = c1 - c2; 238 | } while (result == 0 && c1 != '\0' && c2 != '\0'); 239 | return result; 240 | } 241 | 242 | static int tagncmp (const char *s1, const char *s2, size_t n) 243 | { 244 | int result; 245 | int c1, c2; 246 | do 247 | { 248 | c1 = *s1++; 249 | c2 = readTagCharacter (&s2); 250 | 251 | result = c1 - c2; 252 | } while (result == 0 && --n > 0 && c1 != '\0' && c2 != '\0'); 253 | return result; 254 | } 255 | 256 | static tagResult growString (vstring *s) 257 | { 258 | tagResult result = TagFailure; 259 | size_t newLength; 260 | char *newLine; 261 | if (s->size == 0) 262 | { 263 | newLength = 128; 264 | newLine = (char*) malloc (newLength); 265 | if (newLine) 266 | *newLine = '\0'; 267 | } 268 | else 269 | { 270 | newLength = 2 * s->size; 271 | newLine = (char*) realloc (s->buffer, newLength); 272 | } 273 | if (newLine == NULL) 274 | perror ("string too large"); 275 | else 276 | { 277 | s->buffer = newLine; 278 | s->size = newLength; 279 | result = TagSuccess; 280 | } 281 | return result; 282 | } 283 | 284 | /* Copy name of tag out of tag line */ 285 | static tagResult copyName (tagFile *const file) 286 | { 287 | size_t length; 288 | const char *end = strchr (file->line.buffer, '\t'); 289 | if (end == NULL) 290 | { 291 | end = strchr (file->line.buffer, '\n'); 292 | if (end == NULL) 293 | end = strchr (file->line.buffer, '\r'); 294 | } 295 | if (end != NULL) 296 | length = end - file->line.buffer; 297 | else 298 | length = strlen (file->line.buffer); 299 | while (length >= file->name.size) 300 | { 301 | if (growString (&file->name) != TagSuccess) 302 | return TagFailure; 303 | } 304 | strncpy (file->name.buffer, file->line.buffer, length); 305 | file->name.buffer [length] = '\0'; 306 | return TagSuccess; 307 | } 308 | 309 | /* Return 1 on success. 310 | * Return 0 on failure or EOF. 311 | * errno is set to *err unless EOF. 312 | */ 313 | static int readTagLineRaw (tagFile *const file, int *err) 314 | { 315 | int result = 1; 316 | int reReadLine; 317 | 318 | /* If reading the line places any character other than a null or a 319 | * newline at the last character position in the buffer (one less than 320 | * the buffer size), then we must resize the buffer and reattempt to read 321 | * the line. 322 | */ 323 | do 324 | { 325 | char *const pLastChar = file->line.buffer + file->line.size - 2; 326 | char *line; 327 | 328 | file->pos = readtags_ftell (file->fp); 329 | if (file->pos < 0) 330 | { 331 | *err = errno; 332 | result = 0; 333 | break; 334 | } 335 | reReadLine = 0; 336 | *pLastChar = '\0'; 337 | line = fgets (file->line.buffer, (int) file->line.size, file->fp); 338 | if (line == NULL) 339 | { 340 | /* read error */ 341 | *err = 0; 342 | if (! feof (file->fp)) 343 | *err = errno; 344 | result = 0; 345 | } 346 | else if (*pLastChar != '\0' && 347 | *pLastChar != '\n' && *pLastChar != '\r') 348 | { 349 | /* buffer overflow */ 350 | if (growString (&file->line) != TagSuccess) 351 | { 352 | *err = ENOMEM; 353 | result = 0; 354 | } 355 | 356 | if (readtags_fseek (file->fp, file->pos, SEEK_SET) < 0) 357 | { 358 | *err = errno; 359 | result = 0; 360 | } 361 | reReadLine = 1; 362 | } 363 | else 364 | { 365 | size_t i = strlen (file->line.buffer); 366 | while (i > 0 && 367 | (file->line.buffer [i - 1] == '\n' || file->line.buffer [i - 1] == '\r')) 368 | { 369 | file->line.buffer [i - 1] = '\0'; 370 | --i; 371 | } 372 | } 373 | } while (reReadLine && result); 374 | if (result) 375 | { 376 | if (copyName (file) != TagSuccess) 377 | { 378 | *err = ENOMEM; 379 | result = 0; 380 | } 381 | } 382 | return result; 383 | } 384 | 385 | /* Return 1 on success. 386 | * Return 0 on failure or EOF. 387 | * errno is set to *err unless EOF. 388 | */ 389 | static int readTagLine (tagFile *const file, int *err) 390 | { 391 | int result; 392 | do 393 | { 394 | result = readTagLineRaw (file, err); 395 | } while (result && *file->name.buffer == '\0'); 396 | return result; 397 | } 398 | 399 | static tagResult growFields (tagFile *const file) 400 | { 401 | tagResult result = TagFailure; 402 | unsigned short newCount = (unsigned short) 2 * file->fields.max; 403 | tagExtensionField *newFields = (tagExtensionField*) 404 | realloc (file->fields.list, newCount * sizeof (tagExtensionField)); 405 | if (newFields == NULL) 406 | perror ("too many extension fields"); 407 | else 408 | { 409 | file->fields.list = newFields; 410 | file->fields.max = newCount; 411 | result = TagSuccess; 412 | } 413 | return result; 414 | } 415 | 416 | static tagResult parseExtensionFields (tagFile *const file, tagEntry *const entry, 417 | char *const string, int *err) 418 | { 419 | char *p = string; 420 | char *tail = string + (string? strlen(string):0); 421 | size_t q_len; 422 | 423 | while (p != NULL && *p != '\0') 424 | { 425 | while (*p == TAB) 426 | *p++ = '\0'; 427 | if (*p != '\0') 428 | { 429 | char *colon; 430 | char *field = p; 431 | p = strchr (p, TAB); 432 | if (p != NULL) 433 | *p++ = '\0'; 434 | colon = strchr (field, ':'); 435 | if (colon == NULL) 436 | entry->kind = field; 437 | else 438 | { 439 | const char *key = field; 440 | char *q = colon + 1; 441 | const char *value = q; 442 | const int key_len = colon - key; 443 | *colon = '\0'; 444 | 445 | q_len = tail - q; 446 | 447 | /* Unescaping */ 448 | while (*q != '\0') 449 | { 450 | const char *next = q; 451 | int ch = readTagCharacter (&next); 452 | size_t skip = next - q; 453 | 454 | *q = (char) ch; 455 | q++; 456 | q_len -= skip; 457 | if (skip > 1) 458 | { 459 | /* + 1 is for moving the area including the last '\0'. */ 460 | memmove (q, next, q_len + 1); 461 | if (p) 462 | p -= skip - 1; 463 | if (tail != string) 464 | tail -= skip - 1; 465 | } 466 | } 467 | 468 | if (key_len == 4) 469 | { 470 | if (memcmp (key, "kind", 4) == 0) 471 | entry->kind = value; 472 | else if (memcmp (key, "file", 4) == 0) 473 | entry->fileScope = 1; 474 | else if (memcmp (key, "line", 4) == 0) 475 | { 476 | char *endptr = NULL; 477 | long m = strtol (value, &endptr, 10); 478 | if (*endptr != '\0' || m < 0) 479 | { 480 | *err = TagErrnoUnexpectedLineno; 481 | return TagFailure; 482 | } 483 | entry->address.lineNumber = m; 484 | } 485 | else 486 | goto normalField; 487 | } 488 | else 489 | { 490 | normalField: 491 | if (entry->fields.count == file->fields.max) 492 | { 493 | if (growFields (file) != TagSuccess) 494 | { 495 | *err = ENOMEM; 496 | return TagFailure; 497 | } 498 | } 499 | file->fields.list [entry->fields.count].key = key; 500 | file->fields.list [entry->fields.count].value = value; 501 | ++entry->fields.count; 502 | } 503 | } 504 | } 505 | } 506 | return TagSuccess; 507 | } 508 | 509 | static int isOdd (unsigned int i) 510 | { 511 | return (i % 2); 512 | } 513 | 514 | static unsigned int countContinuousBackslashesBackward(const char *from, 515 | const char *till) 516 | { 517 | unsigned int counter = 0; 518 | 519 | for (; from > till; from--) 520 | { 521 | if (*from == '\\') 522 | counter++; 523 | else 524 | break; 525 | } 526 | return counter; 527 | } 528 | 529 | /* When unescaping, the input string becomes shorter. 530 | * e.g. \t occupies two bytes on the tag file. 531 | * It is converted to 0x9 and occupies one byte. 532 | * memmove called here for shortening the line 533 | * buffer. */ 534 | static char *unescapeInPlace (char *q, char **tab, size_t *p_len) 535 | { 536 | char *p = q; 537 | 538 | while (*p != '\0') 539 | { 540 | const char *next = p; 541 | int ch = readTagCharacter (&next); 542 | size_t skip = next - p; 543 | 544 | *p = (char) ch; 545 | p++; 546 | *p_len -= skip; 547 | if (skip > 1) 548 | { 549 | /* + 1 is for moving the area including the last '\0'. */ 550 | memmove (p, next, *p_len + 1); 551 | if (*tab) 552 | *tab -= skip - 1; 553 | } 554 | } 555 | 556 | return p; 557 | } 558 | 559 | static tagResult parseTagLine (tagFile *file, tagEntry *const entry, int *err) 560 | { 561 | int i; 562 | char *p = file->line.buffer; 563 | size_t p_len = strlen (p); 564 | char *tab = strchr (p, TAB); 565 | 566 | memset(entry, 0, sizeof(*entry)); 567 | 568 | entry->name = p; 569 | if (tab != NULL) 570 | { 571 | *tab = '\0'; 572 | } 573 | 574 | p = unescapeInPlace (p, &tab, &p_len); 575 | 576 | if (tab != NULL) 577 | { 578 | p = tab + 1; 579 | entry->file = p; 580 | tab = strchr (p, TAB); 581 | if (file->inputUCtagsMode) 582 | { 583 | if (tab != NULL) 584 | { 585 | *tab = '\0'; 586 | } 587 | p = unescapeInPlace (p, &tab, &p_len); 588 | } 589 | 590 | if (tab != NULL) 591 | { 592 | int fieldsPresent; 593 | int combinedPattern; 594 | *tab = '\0'; 595 | p = tab + 1; 596 | if (*p == '/' || *p == '?') 597 | { 598 | /* parse pattern */ 599 | int delimiter = *(unsigned char*) p; 600 | entry->address.lineNumber = 0; 601 | entry->address.pattern = p; 602 | do 603 | { 604 | p = strchr (p + 1, delimiter); 605 | } while (p != NULL 606 | && isOdd (countContinuousBackslashesBackward (p - 1, 607 | entry->address.pattern))); 608 | 609 | if (p == NULL) 610 | { 611 | /* TODO: invalid pattern */ 612 | } 613 | else 614 | ++p; 615 | } 616 | else if (isdigit (*(unsigned char*) p)) 617 | { 618 | /* parse line number */ 619 | entry->address.pattern = p; 620 | entry->address.lineNumber = atol (p); 621 | while (isdigit (*(unsigned char*) p)) 622 | ++p; 623 | if (p) 624 | { 625 | combinedPattern = (strncmp (p, ";/", 2) == 0) || 626 | (strncmp (p, ";?", 2) == 0); 627 | if (combinedPattern) 628 | { 629 | ++p; 630 | /* parse pattern */ 631 | int delimiter = *(unsigned char*) p; 632 | do 633 | { 634 | p = strchr (p + 1, delimiter); 635 | } while (p != NULL 636 | && isOdd (countContinuousBackslashesBackward (p - 1, 637 | entry->address.pattern))); 638 | 639 | if (p == NULL) 640 | { 641 | /* TODO: invalid pattern */ 642 | } 643 | else 644 | ++p; 645 | } 646 | } 647 | } 648 | else 649 | { 650 | /* TODO: invalid pattern */ 651 | } 652 | 653 | if (p) 654 | { 655 | fieldsPresent = (strncmp (p, ";\"", 2) == 0); 656 | *p = '\0'; 657 | if (fieldsPresent) 658 | { 659 | if (parseExtensionFields (file, entry, p + 2, err) != TagSuccess) 660 | return TagFailure; 661 | } 662 | } 663 | } 664 | } 665 | if (entry->fields.count > 0) 666 | entry->fields.list = file->fields.list; 667 | for (i = entry->fields.count ; i < file->fields.max ; ++i) 668 | { 669 | file->fields.list [i].key = NULL; 670 | file->fields.list [i].value = NULL; 671 | } 672 | return TagSuccess; 673 | } 674 | 675 | static char *duplicate (const char *str) 676 | { 677 | char *result = NULL; 678 | if (str != NULL) 679 | { 680 | result = strdup (str); 681 | if (result == NULL) 682 | perror (NULL); 683 | } 684 | return result; 685 | } 686 | 687 | static int isPseudoTagLine (const char *buffer) 688 | { 689 | return (strncmp (buffer, PseudoTagPrefix, PseudoTagPrefixLength) == 0); 690 | } 691 | 692 | static tagResult readPseudoTags (tagFile *const file, tagFileInfo *const info) 693 | { 694 | fpos_t startOfLine; 695 | int err = 0; 696 | tagResult result = TagSuccess; 697 | const size_t prefixLength = strlen (PseudoTagPrefix); 698 | int tag_output_mode_u_ctags = 0; 699 | int tag_output_filesep_slash = 0; 700 | 701 | info->file.format = 1; 702 | info->file.sort = TAG_UNSORTED; 703 | info->program.author = NULL; 704 | info->program.name = NULL; 705 | info->program.url = NULL; 706 | info->program.version = NULL; 707 | 708 | while (1) 709 | { 710 | if (fgetpos (file->fp, &startOfLine) < 0) 711 | { 712 | err = errno; 713 | break; 714 | } 715 | if (! readTagLine (file, &err)) 716 | break; 717 | if (!isPseudoTagLine (file->line.buffer)) 718 | break; 719 | else 720 | { 721 | tagEntry entry; 722 | const char *key, *value; 723 | if (parseTagLine (file, &entry, &err) != TagSuccess) 724 | break; 725 | key = entry.name + prefixLength; 726 | value = entry.file; 727 | if (strcmp (key, "TAG_FILE_SORTED") == 0) 728 | { 729 | char *endptr = NULL; 730 | long m = strtol (value, &endptr, 10); 731 | if (*endptr != '\0' || m < 0 || m > 2) 732 | { 733 | err = TagErrnoUnexpectedSortedMethod; 734 | break; 735 | } 736 | file->sortMethod = (tagSortType) m; 737 | } 738 | else if (strcmp (key, "TAG_FILE_FORMAT") == 0) 739 | { 740 | char *endptr = NULL; 741 | long m = strtol (value, &endptr, 10); 742 | if (*endptr != '\0' || m < 1 || m > 2) 743 | { 744 | err = TagErrnoUnexpectedFormat; 745 | break; 746 | } 747 | file->format = (unsigned char) m; 748 | } 749 | else if (strcmp (key, "TAG_PROGRAM_AUTHOR") == 0) 750 | { 751 | file->program.author = duplicate (value); 752 | if (value && file->program.author == NULL) 753 | { 754 | err = ENOMEM; 755 | break; 756 | } 757 | } 758 | else if (strcmp (key, "TAG_PROGRAM_NAME") == 0) 759 | { 760 | file->program.name = duplicate (value); 761 | if (value && file->program.name == NULL) 762 | { 763 | err = ENOMEM; 764 | break; 765 | } 766 | } 767 | else if (strcmp (key, "TAG_PROGRAM_URL") == 0) 768 | { 769 | file->program.url = duplicate (value); 770 | if (value && file->program.url == NULL) 771 | { 772 | err = ENOMEM; 773 | break; 774 | } 775 | } 776 | else if (strcmp (key, "TAG_PROGRAM_VERSION") == 0) 777 | { 778 | file->program.version = duplicate (value); 779 | if (value && file->program.version == NULL) 780 | { 781 | err = ENOMEM; 782 | break; 783 | } 784 | } 785 | else if (strcmp (key, "TAG_OUTPUT_MODE") == 0) 786 | { 787 | if (strcmp (value, "u-ctags") == 0) 788 | tag_output_mode_u_ctags = 1; 789 | } 790 | else if (strcmp (key, "TAG_OUTPUT_FILESEP") == 0) 791 | { 792 | if (strcmp (value, "slash") == 0) 793 | tag_output_filesep_slash = 1; 794 | } 795 | 796 | info->file.format = file->format; 797 | info->file.sort = file->sortMethod; 798 | info->program.author = file->program.author; 799 | info->program.name = file->program.name; 800 | info->program.url = file->program.url; 801 | info->program.version = file->program.version; 802 | } 803 | } 804 | 805 | if (tag_output_mode_u_ctags && tag_output_filesep_slash) 806 | file->inputUCtagsMode = 1; 807 | 808 | if (fsetpos (file->fp, &startOfLine) < 0) 809 | err = errno; 810 | 811 | info->status.error_number = err; 812 | if (err) 813 | result = TagFailure; 814 | return result; 815 | } 816 | 817 | static int doesFilePointPseudoTag (tagFile *const file, void *unused) 818 | { 819 | return isPseudoTagLine (file->name.buffer); 820 | } 821 | 822 | static tagResult gotoFirstLogicalTag (tagFile *const file) 823 | { 824 | fpos_t startOfLine; 825 | 826 | if (readtags_fseek(file->fp, 0, SEEK_SET) == -1) 827 | { 828 | file->err = errno; 829 | return TagFailure; 830 | } 831 | 832 | while (1) 833 | { 834 | if (fgetpos (file->fp, &startOfLine) < 0) 835 | { 836 | file->err = errno; 837 | return TagFailure; 838 | } 839 | if (! readTagLine (file, &file->err)) 840 | { 841 | if (file->err) 842 | return TagFailure; 843 | break; 844 | } 845 | if (!isPseudoTagLine (file->line.buffer)) 846 | break; 847 | } 848 | if (fsetpos (file->fp, &startOfLine) < 0) 849 | { 850 | file->err = errno; 851 | return TagFailure; 852 | } 853 | return TagSuccess; 854 | } 855 | 856 | static tagFile *initialize (const char *const filePath, tagFileInfo *const info) 857 | { 858 | tagFile *result = (tagFile*) calloc ((size_t) 1, sizeof (tagFile)); 859 | 860 | if (result == NULL) 861 | { 862 | info->status.opened = 0; 863 | info->status.error_number = ENOMEM; 864 | return NULL; 865 | } 866 | 867 | if (growString (&result->line) != TagSuccess) 868 | goto mem_error; 869 | if (growString (&result->name) != TagSuccess) 870 | goto mem_error; 871 | result->fields.max = 20; 872 | result->fields.list = (tagExtensionField*) calloc ( 873 | result->fields.max, sizeof (tagExtensionField)); 874 | if (result->fields.list == NULL) 875 | goto mem_error; 876 | 877 | #if defined(__GLIBC__) && (__GLIBC__ >= 2) \ 878 | && defined(__GLIBC_MINOR__) && (__GLIBC_MINOR__ >= 3) 879 | result->fp = fopen (filePath, "rbm"); 880 | #endif 881 | if (result->fp == NULL) 882 | { 883 | errno = 0; 884 | result->fp = fopen (filePath, "rb"); 885 | } 886 | if (result->fp == NULL) 887 | { 888 | info->status.error_number = errno; 889 | goto file_error; 890 | } 891 | 892 | /* Record the size of the tags file to `size` field of result. */ 893 | if (readtags_fseek (result->fp, 0, SEEK_END) == -1) 894 | { 895 | info->status.error_number = errno; 896 | goto file_error; 897 | } 898 | result->size = readtags_ftell (result->fp); 899 | if (result->size == -1) 900 | { 901 | /* fseek() retruns an int value. 902 | * We observed following behavior on Windows; 903 | * if sizeof(int) of the platform is too small for 904 | * representing the size of the tags file, fseek() 905 | * returns -1 and it doesn't set errno. 906 | */ 907 | info->status.error_number = errno; 908 | if (info->status.error_number == 0) 909 | info->status.error_number = TagErrnoFileMaybeTooBig; 910 | 911 | goto file_error; 912 | } 913 | if (readtags_fseek(result->fp, 0, SEEK_SET) == -1) 914 | { 915 | info->status.error_number = errno; 916 | goto file_error; 917 | } 918 | 919 | if (readPseudoTags (result, info) == TagFailure) 920 | goto file_error; 921 | 922 | info->status.opened = 1; 923 | result->initialized = 1; 924 | 925 | return result; 926 | mem_error: 927 | info->status.error_number = ENOMEM; 928 | file_error: 929 | free (result->line.buffer); 930 | free (result->name.buffer); 931 | free (result->fields.list); 932 | if (result->fp) 933 | fclose (result->fp); 934 | free (result); 935 | info->status.opened = 0; 936 | return NULL; 937 | } 938 | 939 | static void terminate (tagFile *const file) 940 | { 941 | fclose (file->fp); 942 | 943 | free (file->line.buffer); 944 | free (file->name.buffer); 945 | free (file->fields.list); 946 | 947 | if (file->program.author != NULL) 948 | free (file->program.author); 949 | if (file->program.name != NULL) 950 | free (file->program.name); 951 | if (file->program.url != NULL) 952 | free (file->program.url); 953 | if (file->program.version != NULL) 954 | free (file->program.version); 955 | if (file->search.name != NULL) 956 | free (file->search.name); 957 | 958 | memset (file, 0, sizeof (tagFile)); 959 | 960 | free (file); 961 | } 962 | 963 | static tagResult readNext (tagFile *const file, tagEntry *const entry) 964 | { 965 | tagResult result; 966 | 967 | if (file == NULL) 968 | return TagFailure; 969 | 970 | if (! file->initialized) 971 | { 972 | file->err = TagErrnoInvalidArgument; 973 | return TagFailure; 974 | } 975 | 976 | if (! readTagLine (file, &file->err)) 977 | return TagFailure; 978 | 979 | result = (entry != NULL) 980 | ? parseTagLine (file, entry, &file->err) 981 | : TagSuccess; 982 | 983 | return result; 984 | } 985 | 986 | static const char *readFieldValue ( 987 | const tagEntry *const entry, const char *const key) 988 | { 989 | const char *result = NULL; 990 | int i; 991 | if (strcmp (key, "kind") == 0) 992 | result = entry->kind; 993 | else if (strcmp (key, "file") == 0) 994 | result = EmptyString; 995 | else for (i = 0 ; i < entry->fields.count && result == NULL ; ++i) 996 | if (strcmp (entry->fields.list [i].key, key) == 0) 997 | result = entry->fields.list [i].value; 998 | return result; 999 | } 1000 | 1001 | static int readTagLineSeek (tagFile *const file, const rt_off_t pos) 1002 | { 1003 | if (readtags_fseek (file->fp, pos, SEEK_SET) < 0) 1004 | { 1005 | file->err = errno; 1006 | return 0; 1007 | } 1008 | 1009 | /* read probable partial line */ 1010 | if (!readTagLine (file, &file->err)) 1011 | return 0; 1012 | 1013 | /* read complete line */ 1014 | if (pos > 0) 1015 | return readTagLine (file, &file->err); 1016 | 1017 | return 1; 1018 | } 1019 | 1020 | static int nameComparison (tagFile *const file) 1021 | { 1022 | int result; 1023 | if (file->search.ignorecase) 1024 | { 1025 | if (file->search.partial) 1026 | result = tagnuppercmp (file->search.name, file->name.buffer, 1027 | file->search.nameLength); 1028 | else 1029 | result = taguppercmp (file->search.name, file->name.buffer); 1030 | } 1031 | else 1032 | { 1033 | if (file->search.partial) 1034 | result = tagncmp (file->search.name, file->name.buffer, 1035 | file->search.nameLength); 1036 | else 1037 | result = tagcmp (file->search.name, file->name.buffer); 1038 | } 1039 | return result; 1040 | } 1041 | 1042 | static tagResult findFirstNonMatchBefore (tagFile *const file) 1043 | { 1044 | #define JUMP_BACK 512 1045 | int more_lines; 1046 | int comp; 1047 | rt_off_t start = file->pos; 1048 | rt_off_t pos = start; 1049 | do 1050 | { 1051 | if (pos < (rt_off_t) JUMP_BACK) 1052 | pos = 0; 1053 | else 1054 | pos = pos - JUMP_BACK; 1055 | more_lines = readTagLineSeek (file, pos); 1056 | if (more_lines == 0 && file->err) 1057 | return TagFailure; 1058 | comp = nameComparison (file); 1059 | } while (more_lines && comp == 0 && pos > 0 && pos < start); 1060 | return TagSuccess; 1061 | } 1062 | 1063 | static tagResult findFirstMatchBefore (tagFile *const file) 1064 | { 1065 | tagResult result = TagFailure; 1066 | int more_lines; 1067 | rt_off_t start = file->pos; 1068 | if (findFirstNonMatchBefore (file) != TagSuccess) 1069 | return TagFailure; 1070 | do 1071 | { 1072 | more_lines = readTagLine (file, &file->err); 1073 | if (more_lines == 0 && file->err) 1074 | return TagFailure; 1075 | if (nameComparison (file) == 0) 1076 | result = TagSuccess; 1077 | } while (more_lines && result != TagSuccess && file->pos < start); 1078 | return result; 1079 | } 1080 | 1081 | static tagResult findBinary (tagFile *const file) 1082 | { 1083 | tagResult result = TagFailure; 1084 | rt_off_t lower_limit = 0; 1085 | rt_off_t upper_limit = file->size; 1086 | rt_off_t last_pos = 0; 1087 | rt_off_t pos = upper_limit / 2; 1088 | while (result != TagSuccess) 1089 | { 1090 | if (! readTagLineSeek (file, pos)) 1091 | { 1092 | if (file->err) 1093 | break; 1094 | /* in case we fell off end of file */ 1095 | result = findFirstMatchBefore (file); 1096 | break; 1097 | } 1098 | else if (pos == last_pos) 1099 | { 1100 | /* prevent infinite loop if we backed up to beginning of file */ 1101 | break; 1102 | } 1103 | else 1104 | { 1105 | const int comp = nameComparison (file); 1106 | last_pos = pos; 1107 | if (comp < 0) 1108 | { 1109 | upper_limit = pos; 1110 | pos = lower_limit + ((upper_limit - lower_limit) / 2); 1111 | } 1112 | else if (comp > 0) 1113 | { 1114 | lower_limit = pos; 1115 | pos = lower_limit + ((upper_limit - lower_limit) / 2); 1116 | } 1117 | else if (pos == 0) 1118 | result = TagSuccess; 1119 | else 1120 | { 1121 | result = findFirstMatchBefore (file); 1122 | if (result != TagSuccess && file->err) 1123 | break; 1124 | } 1125 | } 1126 | } 1127 | return result; 1128 | } 1129 | 1130 | static tagResult findSequentialFull (tagFile *const file, 1131 | int (* isAcceptable) (tagFile *const, void *), 1132 | void *data) 1133 | { 1134 | if (file == NULL) 1135 | return TagFailure; 1136 | 1137 | if (!file->initialized || file->err) 1138 | { 1139 | file->err = TagErrnoInvalidArgument; 1140 | return TagFailure; 1141 | } 1142 | 1143 | tagResult result = TagFailure; 1144 | while (result == TagFailure) 1145 | { 1146 | if (! readTagLine (file, &file->err)) 1147 | break; 1148 | if (isAcceptable (file, data)) 1149 | result = TagSuccess; 1150 | } 1151 | return result; 1152 | } 1153 | 1154 | static int nameAcceptable (tagFile *const file, void *unused) 1155 | { 1156 | return (nameComparison (file) == 0); 1157 | } 1158 | 1159 | static tagResult findSequential (tagFile *const file) 1160 | { 1161 | return findSequentialFull (file, nameAcceptable, NULL); 1162 | } 1163 | 1164 | static tagResult find (tagFile *const file, tagEntry *const entry, 1165 | const char *const name, const int options) 1166 | { 1167 | tagResult result; 1168 | if (file->search.name != NULL) 1169 | free (file->search.name); 1170 | file->search.name = duplicate (name); 1171 | if (file->search.name == NULL) 1172 | { 1173 | file->err = ENOMEM; 1174 | return TagFailure; 1175 | } 1176 | file->search.nameLength = strlen (name); 1177 | file->search.partial = (options & TAG_PARTIALMATCH) != 0; 1178 | file->search.ignorecase = (options & TAG_IGNORECASE) != 0; 1179 | if (readtags_fseek (file->fp, 0, SEEK_END) < 0) 1180 | { 1181 | file->err = errno; 1182 | return TagFailure; 1183 | } 1184 | file->size = readtags_ftell (file->fp); 1185 | if (file->size == -1) 1186 | { 1187 | file->err = errno; 1188 | return TagFailure; 1189 | } 1190 | if (readtags_fseek(file->fp, 0, SEEK_SET) == -1) 1191 | { 1192 | file->err = errno; 1193 | return TagFailure; 1194 | } 1195 | if ((file->sortMethod == TAG_SORTED && !file->search.ignorecase) || 1196 | (file->sortMethod == TAG_FOLDSORTED && file->search.ignorecase)) 1197 | { 1198 | result = findBinary (file); 1199 | if (result == TagFailure && file->err) 1200 | return TagFailure; 1201 | } 1202 | else 1203 | { 1204 | result = findSequential (file); 1205 | if (result == TagFailure && file->err) 1206 | return TagFailure; 1207 | } 1208 | 1209 | if (result != TagSuccess) 1210 | file->search.pos = file->size; 1211 | else 1212 | { 1213 | file->search.pos = file->pos; 1214 | result = (entry != NULL) 1215 | ? parseTagLine (file, entry, &file->err) 1216 | : TagSuccess; 1217 | } 1218 | return result; 1219 | } 1220 | 1221 | static tagResult findNextFull (tagFile *const file, tagEntry *const entry, 1222 | int sorted, 1223 | int (* isAcceptable) (tagFile *const, void *), 1224 | void *data) 1225 | { 1226 | tagResult result; 1227 | if (sorted) 1228 | { 1229 | result = tagsNext (file, entry); 1230 | if (result == TagSuccess && !isAcceptable (file, data)) 1231 | result = TagFailure; 1232 | } 1233 | else 1234 | { 1235 | result = findSequentialFull (file, isAcceptable, data); 1236 | if (result == TagSuccess && entry != NULL) 1237 | result = parseTagLine (file, entry, &file->err); 1238 | } 1239 | return result; 1240 | } 1241 | 1242 | static tagResult findNext (tagFile *const file, tagEntry *const entry) 1243 | { 1244 | return findNextFull (file, entry, 1245 | (file->sortMethod == TAG_SORTED && !file->search.ignorecase) || 1246 | (file->sortMethod == TAG_FOLDSORTED && file->search.ignorecase), 1247 | nameAcceptable, NULL); 1248 | } 1249 | 1250 | static tagResult findPseudoTag (tagFile *const file, int rewindBeforeFinding, tagEntry *const entry) 1251 | { 1252 | if (file == NULL) 1253 | return TagFailure; 1254 | 1255 | if (!file->initialized || file->err) 1256 | { 1257 | file->err = TagErrnoInvalidArgument; 1258 | return TagFailure; 1259 | } 1260 | 1261 | if (rewindBeforeFinding) 1262 | { 1263 | if (readtags_fseek(file->fp, 0, SEEK_SET) == -1) 1264 | { 1265 | file->err = errno; 1266 | return TagFailure; 1267 | } 1268 | } 1269 | return findNextFull (file, entry, 1270 | (file->sortMethod == TAG_SORTED || file->sortMethod == TAG_FOLDSORTED), 1271 | doesFilePointPseudoTag, 1272 | NULL); 1273 | } 1274 | 1275 | 1276 | /* 1277 | * EXTERNAL INTERFACE 1278 | */ 1279 | 1280 | extern tagFile *tagsOpen (const char *const filePath, tagFileInfo *const info) 1281 | { 1282 | tagFileInfo infoDummy; 1283 | return initialize (filePath, info? info: &infoDummy); 1284 | } 1285 | 1286 | extern tagResult tagsSetSortType (tagFile *const file, const tagSortType type) 1287 | { 1288 | if (file == NULL) 1289 | return TagFailure; 1290 | 1291 | if (!file->initialized || file->err) 1292 | { 1293 | file->err = TagErrnoInvalidArgument; 1294 | return TagFailure; 1295 | } 1296 | 1297 | switch (type) 1298 | { 1299 | case TAG_UNSORTED: 1300 | case TAG_SORTED: 1301 | case TAG_FOLDSORTED: 1302 | file->sortMethod = type; 1303 | return TagSuccess; 1304 | default: 1305 | file->err = TagErrnoUnexpectedSortedMethod; 1306 | return TagFailure; 1307 | } 1308 | } 1309 | 1310 | extern tagResult tagsFirst (tagFile *const file, tagEntry *const entry) 1311 | { 1312 | if (file == NULL) 1313 | return TagFailure; 1314 | 1315 | if (!file->initialized || file->err) 1316 | { 1317 | file->err = TagErrnoInvalidArgument; 1318 | return TagFailure; 1319 | } 1320 | 1321 | if (gotoFirstLogicalTag (file) != TagSuccess) 1322 | return TagFailure; 1323 | return readNext (file, entry); 1324 | } 1325 | 1326 | extern tagResult tagsNext (tagFile *const file, tagEntry *const entry) 1327 | { 1328 | if (file == NULL) 1329 | return TagFailure; 1330 | 1331 | if (!file->initialized || file->err) 1332 | { 1333 | file->err = TagErrnoInvalidArgument; 1334 | return TagFailure; 1335 | } 1336 | 1337 | return readNext (file, entry); 1338 | } 1339 | 1340 | extern const char *tagsField (const tagEntry *const entry, const char *const key) 1341 | { 1342 | const char *result = NULL; 1343 | if (entry != NULL) 1344 | result = readFieldValue (entry, key); 1345 | return result; 1346 | } 1347 | 1348 | extern tagResult tagsFind (tagFile *const file, tagEntry *const entry, 1349 | const char *const name, const int options) 1350 | { 1351 | if (file == NULL) 1352 | return TagFailure; 1353 | 1354 | if (!file->initialized || file->err) 1355 | { 1356 | file->err = TagErrnoInvalidArgument; 1357 | return TagFailure; 1358 | } 1359 | 1360 | return find (file, entry, name, options); 1361 | } 1362 | 1363 | extern tagResult tagsFindNext (tagFile *const file, tagEntry *const entry) 1364 | { 1365 | if (file == NULL) 1366 | return TagFailure; 1367 | 1368 | if (!file->initialized || file->err) 1369 | { 1370 | file->err = TagErrnoInvalidArgument; 1371 | return TagFailure; 1372 | } 1373 | 1374 | return findNext (file, entry); 1375 | } 1376 | 1377 | extern tagResult tagsFirstPseudoTag (tagFile *const file, tagEntry *const entry) 1378 | { 1379 | return findPseudoTag (file, 1, entry); 1380 | } 1381 | 1382 | extern tagResult tagsNextPseudoTag (tagFile *const file, tagEntry *const entry) 1383 | { 1384 | return findPseudoTag (file, 0, entry); 1385 | } 1386 | 1387 | extern tagResult tagsFindPseudoTag (tagFile *const file, tagEntry *const entry, 1388 | const char *const name, const int match) 1389 | { 1390 | size_t len; 1391 | tagEntry entry0; 1392 | tagEntry *entryp = entry? entry: &entry0; 1393 | 1394 | tagResult r = tagsFirstPseudoTag (file, entryp); 1395 | if (r != TagSuccess) 1396 | return r; 1397 | 1398 | if (match & TAG_PARTIALMATCH) 1399 | len = strlen (name); 1400 | 1401 | do 1402 | { 1403 | if (match & TAG_PARTIALMATCH) 1404 | { 1405 | if (strncmp (entryp->name, name, len) == 0) 1406 | return TagSuccess; 1407 | } 1408 | else 1409 | { 1410 | if (strcmp (entryp->name, name) == 0) 1411 | return TagSuccess; 1412 | } 1413 | r = tagsNextPseudoTag (file, entryp); 1414 | } 1415 | while (r == TagSuccess); 1416 | 1417 | return r; 1418 | } 1419 | 1420 | extern tagResult tagsClose (tagFile *const file) 1421 | { 1422 | tagResult result = TagFailure; 1423 | if (file != NULL && file->initialized) 1424 | { 1425 | terminate (file); 1426 | result = TagSuccess; 1427 | } 1428 | return result; 1429 | } 1430 | 1431 | extern int tagsGetErrno (tagFile *const file) 1432 | { 1433 | if (file == NULL) 1434 | return TagErrnoInvalidArgument; 1435 | return file->err; 1436 | } 1437 | -------------------------------------------------------------------------------- /src/readtags.pxi: -------------------------------------------------------------------------------- 1 | """ 2 | $Id$ 3 | 4 | Copyright (C) 2008 Aaron Diep 5 | 6 | This file is part of Python-Ctags. 7 | 8 | Python-Ctags is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | Python-Ctags is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with Python-Ctags. If not, see . 20 | """ 21 | 22 | cdef extern from "readtags.h": 23 | ctypedef struct tagFile 24 | 25 | ctypedef enum tagSortType "sortType": 26 | TAG_UNSORTED 27 | TAG_SORTED 28 | TAG_FOLDSORTED 29 | 30 | ctypedef struct fileType "file": 31 | short format 32 | tagSortType sort 33 | 34 | ctypedef struct statusType "status": 35 | int opened 36 | int error_number 37 | 38 | ctypedef struct programType "program": 39 | char *author 40 | char *name 41 | char *url 42 | char *version 43 | 44 | ctypedef struct tagFileInfo: 45 | statusType status 46 | fileType file 47 | programType program 48 | 49 | 50 | ctypedef struct tagExtensionField: 51 | char* key 52 | char* value 53 | 54 | ctypedef struct addressType "address": 55 | char* pattern 56 | unsigned long lineNumber 57 | 58 | ctypedef struct fieldsType: 59 | unsigned short count 60 | tagExtensionField *list 61 | 62 | ctypedef struct tagEntry: 63 | char* name 64 | char* file 65 | 66 | addressType address 67 | 68 | char* kind 69 | short fileScope 70 | 71 | fieldsType fields 72 | 73 | ctypedef enum tagResult: 74 | TagFailure 75 | TagSuccess 76 | 77 | 78 | tagFile* ctagsOpen "tagsOpen" (char *filePath, tagFileInfo *info) 79 | tagResult ctagsSetSortType "tagsSetSortType" (tagFile* file, tagSortType type) 80 | tagResult ctagsFirst "tagsFirst" (tagFile *file, tagEntry *entry) 81 | #C++: char *ctagsField "tagsField" (tagEntry *entry, char *key) except +MemoryError 82 | char *ctagsField "tagsField" (tagEntry *entry, char *key) 83 | tagResult ctagsFind "tagsFind" (tagFile *file, tagEntry *entry, char *name, int options) 84 | tagResult ctagsNext "tagsNext" (tagFile *file, tagEntry *entry) 85 | tagResult ctagsFindNext "tagsFindNext" (tagFile *file, tagEntry *entry) 86 | tagResult ctagsFirstPseudoTag "tagsFirstPseudoTag" (tagFile *file, tagEntry *entry) 87 | tagResult ctagsNextPseudoTag "tagsNextPseudoTag" (tagFile *file, tagEntry *entry) 88 | tagResult ctagsFindPseudoTag "tagsFindPseudoTag" (tagFile *file, tagEntry *entry, char *name, int options) 89 | tagResult ctagsClose "tagsClose" (tagFile *file) 90 | -------------------------------------------------------------------------------- /src/stdlib.pxi: -------------------------------------------------------------------------------- 1 | """ 2 | $Id$ 3 | 4 | Copyright (C) 2008 Aaron Diep 5 | 6 | This file is part of Python-Ctags. 7 | 8 | Python-Ctags is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | Python-Ctags is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with Python-Ctags. If not, see . 20 | """ 21 | 22 | cdef extern from "stdlib.h": 23 | ctypedef unsigned long size_t 24 | void free(void *ptr) 25 | void *malloc(size_t size) 26 | void *realloc(void *ptr, size_t size) 27 | size_t strlen(char *s) 28 | char *strcpy(char *dest, char *src) 29 | 30 | ctypedef void (*signal_handler)(int) 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/universal-ctags/python-ctags3/d797d37880dae3a12a40fd7904f7c64567a2ed06/tests/__init__.py -------------------------------------------------------------------------------- /tests/test_ctags.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | src_dir = os.path.join( 5 | os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "src" 6 | ) 7 | sys.path.insert(0, src_dir) 8 | from unittest import TestCase 9 | 10 | import ctags 11 | 12 | 13 | class TestCTagsParse(TestCase): 14 | def setUp(self): 15 | file_path = os.path.join(src_dir, "examples", "tags") 16 | self.ctags = ctags.CTags(file_path) 17 | 18 | def test_tag_entry(self): 19 | entry = ctags.TagEntry() 20 | self.ctags.setSortType(ctags.TAG_SORTED) 21 | self.ctags.first(entry) 22 | entry_info = [ 23 | entry[_] for _ in ("file", "name", "pattern", "kind", b"language") 24 | ] 25 | self.assertEqual( 26 | entry_info, [b"../_readtags.c", b"DL_EXPORT", b"10", b"macro", b"C"] 27 | ) 28 | 29 | def test_tag_find(self): 30 | entry = ctags.TagEntry() 31 | self.ctags.setSortType(ctags.TAG_SORTED) 32 | self.ctags.find(entry, b"find", ctags.TAG_PARTIALMATCH | ctags.TAG_IGNORECASE) 33 | entry_info = [ 34 | entry[_] for _ in ("file", "name", "pattern", "kind", b"language") 35 | ] 36 | self.assertEqual( 37 | entry_info, 38 | [ 39 | b"../readtags.c", 40 | b"find", 41 | b"/^static tagResult find (tagFile " 42 | b"*const file, tagEntry *const entry,$/", 43 | b"function", 44 | b"C", 45 | ], 46 | ) 47 | 48 | def test_ptag_find(self): 49 | entry = ctags.TagEntry() 50 | self.ctags.findPseudoTag(entry, b"!_TAG_PROGRAM_URL", ctags.TAG_FULLMATCH) 51 | entry_info = [ 52 | entry[_] for _ in ("file", "name", "pattern") 53 | ] 54 | self.assertEqual( 55 | entry_info, 56 | [ 57 | b"http://ctags.sourceforge.net", 58 | b"!_TAG_PROGRAM_URL", 59 | b"/official site/", 60 | ], 61 | ) 62 | 63 | self.ctags.nextPseudoTag(entry) 64 | entry_info = [ 65 | entry[_] for _ in ("file", "name", "pattern") 66 | ] 67 | self.assertEqual( 68 | entry_info, 69 | [ 70 | b"5.6b1", 71 | b"!_TAG_PROGRAM_VERSION", 72 | b"//", 73 | ], 74 | ) 75 | 76 | self.ctags.firstPseudoTag(entry) 77 | entry_info = [ 78 | entry[_] for _ in ("file", "name", "pattern") 79 | ] 80 | self.assertEqual( 81 | entry_info, 82 | [ 83 | b"2", 84 | b"!_TAG_FILE_FORMAT", 85 | b"/extended format; --format=1 will not append ;\" to lines/", 86 | ], 87 | ) 88 | 89 | class TestCTagsParseBytes(TestCTagsParse): 90 | def setUp(self): 91 | file_path = os.path.join(src_dir, "examples", "tags") 92 | self.ctags = ctags.CTags(file_path.encode(sys.getfilesystemencoding())) 93 | -------------------------------------------------------------------------------- /tests/test_import.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | 4 | class ImportTests(TestCase): 5 | def test_import(self): 6 | import ctags 7 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py{27,34,35,36,37,38,39,310,311} 3 | skip_missing_interpreters = true 4 | 5 | [gh-actions] 6 | python = 7 | 2.7: py27 8 | 3.4: py34 9 | 3.5: py35 10 | 3.6: py36 11 | 3.7: py37 12 | 3.8: py38 13 | 3.9: py39 14 | 3.10: py310 15 | 3.11: py311 16 | 17 | [testenv] 18 | deps = cython 19 | commands = 20 | make 21 | setenv = 22 | PYTHONPATH = {toxinidir}/src 23 | allowlist_externals = 24 | make 25 | --------------------------------------------------------------------------------