├── .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 | [](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 |
--------------------------------------------------------------------------------