Integration patch from kaliber as of bug #1127, with a minor fix. Thanks!


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20438 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval
2007-03-27 18:49:40 +00:00
parent 073ddff0ad
commit 7bd0beb35e
110 changed files with 38291 additions and 1 deletions
+1 -1
View File
@@ -21,7 +21,7 @@ if $(INCLUDE_GPL_ADDONS) = 1 {
}
BEOS_BIN = "[" addattr alert arp basename bc beep cat catattr chgrp chmod chop chown cksum clear
clockconfig cmp comm cp copyattr csplit cut date dc dd desklink df diff dircolors dirname driveinfo
clockconfig cmp comm cp copyattr csplit ctags cut date dc dd desklink df diff dircolors dirname driveinfo
dstcheck du echo eject env error expand expr factor false fdinfo ffm find finddir fortune ftp funzip gawk
$(X86_ONLY)gdb grep groups gzip head hey id ideinfo idestatus ifconfig iroster isvolume
join keymap kill less lessecho lesskey link listarea listattr listdev listimage
+1
View File
@@ -151,6 +151,7 @@ SubInclude HAIKU_TOP src bin bison ;
SubInclude HAIKU_TOP src bin chkbfs ;
SubInclude HAIKU_TOP src bin compress ;
SubInclude HAIKU_TOP src bin coreutils ;
SubInclude HAIKU_TOP src bin ctags ;
SubInclude HAIKU_TOP src bin desklink ;
SubInclude HAIKU_TOP src bin diffutils ;
SubInclude HAIKU_TOP src bin findutils ;
+28
View File
@@ -0,0 +1,28 @@
--blank-before-sizeof
--blank-lines-after-procedures
--brace-indent0
--braces-after-if-line
--braces-on-struct-decl-line
--break-after-boolean-operator
--case-brace-indentation0
--case-indentation0
--comment-indentation0
--continuation-indentation4
--declaration-comment-column0
--declaration-indentation0
--dont-break-function-decl-args
--dont-break-procedure-type
--dont-line-up-parentheses
--honour-newlines
--indent-level4
--line-length80
--no-blank-lines-after-commas
--space-after-cast
--space-after-for
--space-after-if
--space-after-procedure-calls
--space-after-while
--space-special-semicolon
--start-left-side-of-comments
--struct-brace-indentation4
--tab-size8
+340
View File
@@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
+386
View File
@@ -0,0 +1,386 @@
<!-- $Id: EXTENDING.html,v 1.9 2002/09/04 01:17:32 darren Exp $ -->
<html>
<head>
<title>Exuberant Ctags: Adding support for a new language</title>
</head>
<body>
<h1>How to Add Support for a New Language to Exuberant Ctags</h1>
<p>
<b>Exuberant Ctags</b> has been designed to make it very easy to add your own
custom language parser. As an exercise, let us assume that I want to add
support for my new language, <em>Swine</em>, the successor to Perl (i.e. Perl
before Swine &lt;wince&gt;). This language consists of simple definitions of
labels in the form "<code>def my_label</code>". Let us now examine the various
ways to do this.
</p>
<h2>Operational background</h2>
<p>
As ctags considers each file name, it tries to determine the language of the
file by applying the following three tests in order: if the file extension has
been mapped to a language, if the file name matches a shell pattern mapped to
a language, and finally if the file is executable and its first line specifies
an interpreter using the Unix-style "#!" specification (if supported on the
platform). If a language was identified, the file is opened and then the
appropriate language parser is called to operate on the currently open file.
The parser parses through the file and whenever it finds some interesting
token, calls a function to define a tag entry.
</p>
<h2>Creating a user-defined language</h2>
<p>
The quickest and easiest way to do this is by defining a new language using
the program options. In order to have Swine support available every time I
start ctags, I will place the following lines into the file
<code>$HOME/.ctags</code>, which is read in every time ctags starts:
<code>
<pre>
--langdef=swine
--langmap=swine:.swn
--regex-swine=/^def[ \t]*([a-zA-Z0-9_]+)/\1/d,definition/
</pre>
</code>
The first line defines the new language, the second maps a file extension to
it, and the third defines a regular expression to identify a language
definition and generate a tag file entry for it.
</p>
<h2>Integrating a new language parser</h2>
<p>
Now suppose that I want to truly integrate compiled-in support for Swine into
ctags. First, I create a new module, <code>swine.c</code>, and add one
externally visible function to it, <code>extern parserDefinition
*SwineParser(void)</code>, and add its name to the table in
<code>parsers.h</code>. The job of this parser definition function is to
create an instance of the <code>parserDefinition</code> structure (using
<code>parserNew()</code>) and populate it with information defining how files
of this language are recognized, what kinds of tags it can locate, and the
function used to invoke the parser on the currently open file.
</p>
<p>
The structure <code>parserDefinition</code> allows assignment of the following
fields:
<code>
<pre>
const char *name; /* name of language */
kindOption *kinds; /* tag kinds handled by parser */
unsigned int kindCount; /* size of `kinds' list */
const char *const *extensions; /* list of default extensions */
const char *const *patterns; /* list of default file name patterns */
parserInitialize initialize; /* initialization routine, if needed */
simpleParser parser; /* simple parser (common case) */
rescanParser parser2; /* rescanning parser (unusual case) */
boolean regex; /* is this a regex parser? */
</pre>
</code>
</p>
<p>
The <code>name</code> field must be set to a non-empty string. Also, unless
<code>regex</code> is set true (see below), either <code>parser</code> or
<code>parser2</code> must set to point to a parsing routine which will
generate the tag entries. All other fields are optional.
<p>
Now all that is left is to implement the parser. In order to do its job, the
parser should read the file stream using using one of the two I/O interfaces:
either the character-oriented <code>fileGetc()</code>, or the line-oriented
<code>fileReadLine()</code>. When using <code>fileGetc()</code>, the parser
can put back a character using <code>fileUngetc()</code>. How our Swine parser
actually parses the contents of the file is entirely up to the writer of the
parser--it can be as crude or elegant as desired. You will note a variety of
examples from the most complex (c.c) to the simplest (make.c).
</p>
<p>
When the Swine parser identifies an interesting token for which it wants to
add a tag to the tag file, it should create a <code>tagEntryInfo</code>
structure and initialize it by calling <code>initTagEntry()</code>, which
initializes defaults and fills information about the current line number and
the file position of the beginning of the line. After filling in information
defining the current entry (and possibly overriding the file position or other
defaults), the parser passes this structure to <code>makeTagEntry()</code>.
</p>
<p>
Instead of writing a character-oriented parser, it may be possible to specify
regular expressions which define the tags. In this case, instead of defining a
parsing function, <code>SwineParser()</code>, sets <code>regex</code> to true,
and points <code>initialize</code> to a function which calls
<code>addTagRegex()</code> to install the regular expressions which define its
tags. The regular expressions thus installed are compared against each line
of the input file and generate a specified tag when matched. It is usually
much easier to write a regex-based parser, although they can be slower (one
parser example was 4 times slower). Whether the speed difference matters to
you depends upon how much code you have to parse. It is probably a good
strategy to implement a regex-based parser first, and if it is too slow for
you, then invest the time and effort to write a character-based parser.
</p>
<p>
A regex-based parser is inherently line-oriented (i.e. the entire tag must be
recognizable from looking at a single line) and context-insensitive (i.e the
generation of the tag is entirely based upon when the regular expression
matches a single line). However, a regex-based callback mechanism is also
available, installed via the function <code>addCallbackRegex()</code>. This
allows a specified function to be invoked whenever a specific regular
expression is matched. This allows a character-oriented parser to operate
based upon context of what happened on a previous line (e.g. the start or end
of a multi-line comment). Note that regex callbacks are called just before the
first character of that line can is read via either <code>fileGetc()</code> or
using <code>fileGetc()</code>. The effect of this is that before either of
these routines return, a callback routine may be invoked because the line
matched a regex callback. A callback function to be installed is defined by
these types:
<code>
<pre>
typedef void (*regexCallback) (const char *line, const regexMatch *matches, unsigned int count);
typedef struct {
size_t start; /* character index in line where match starts */
size_t length; /* length of match */
} regexMatch;
</pre>
</code>
</p>
<p>
The callback function is passed the line matching the regular expression and
an array of <code>count</code> structures defining the subexpression matches
of the regular expression, starting from \0 (the entire line).
</p>
<p>
Lastly, be sure to add your the name of the file containing your parser (e.g.
swine.c) to the macro <code>SOURCES</code> in the file <code>source.mak</code>
and an entry for the object file to the macro <code>OBJECTS</code> in the same
file, so that your new module will be compiled into the program.
</p>
<p>
This is all there is to it. All other details are specific to the parser and
how it wants to do its job. There are some support functions which can take
care of some commonly needed parsing tasks, such as keyword table lookups (see
keyword.c), which you can make use of if desired (examples of its use can be
found in c.c, eiffel.c, and fortran.c). Almost everything is already taken care
of automatically for you by the infrastructure. Writing the actual parsing
algorithm is the hardest part, but is not constrained by any need to conform
to anything in ctags other than that mentioned above.
</p>
<p>
There are several different approaches used in the parsers inside <b>Exuberant
Ctags</b> and you can browse through these as examples of how to go about
creating your own.
</p>
<h2>Examples</h2>
<p>
Below you will find several example parsers demonstrating most of the
facilities available. These include three alternative implementations
of a Swine parser, which generate tags for lines beginning with
"<CODE>def</CODE>" followed by some name.
</p>
<code>
<pre>
/***************************************************************************
* swine.c
* Character-based parser for Swine definitions
**************************************************************************/
/* INCLUDE FILES */
#include "general.h" /* always include first */
#include &lt;string.h&gt; /* to declare strxxx() functions */
#include &lt;ctype.h&gt; /* to define isxxx() macros */
#include "parse.h" /* always include */
#include "read.h" /* to define file fileReadLine() */
/* DATA DEFINITIONS */
typedef enum eSwineKinds {
K_DEFINE
} swineKind;
static kindOption SwineKinds [] = {
{ TRUE, 'd', "definition", "pig definition" }
};
/* FUNCTION DEFINITIONS */
static void findSwineTags (void)
{
vString *name = vStringNew ();
const unsigned char *line;
while ((line = fileReadLine ()) != NULL)
{
/* Look for a line beginning with "def" followed by name */
if (strncmp ((const char*) line, "def", (size_t) 3) == 0 &amp;&amp;
isspace ((int) line [3]))
{
const unsigned char *cp = line + 4;
while (isspace ((int) *cp))
++cp;
while (isalnum ((int) *cp) || *cp == '_')
{
vStringPut (name, (int) *cp);
++cp;
}
vStringTerminate (name);
makeSimpleTag (name, SwineKinds, K_DEFINE);
vStringClear (name);
}
}
vStringDelete (name);
}
/* Create parser definition stucture */
extern parserDefinition* SwineParser (void)
{
static const char *const extensions [] = { "swn", NULL };
parserDefinition* def = parserNew ("Swine");
def-&gt;kinds = SwineKinds;
def-&gt;kindCount = KIND_COUNT (SwineKinds);
def-&gt;extensions = extensions;
def-&gt;parser = findSwineTags;
return def;
}
</pre>
</code>
<p>
<pre>
<code>
/***************************************************************************
* swine.c
* Regex-based parser for Swine
**************************************************************************/
/* INCLUDE FILES */
#include "general.h" /* always include first */
#include "parse.h" /* always include */
/* FUNCTION DEFINITIONS */
static void installSwineRegex (const langType language)
{
addTagRegex (language, "^def[ \t]*([a-zA-Z0-9_]+)", "\\1", "d,definition", NULL);
}
/* Create parser definition stucture */
extern parserDefinition* SwineParser (void)
{
static const char *const extensions [] = { "swn", NULL };
parserDefinition* def = parserNew ("Swine");
parserDefinition* const def = parserNew ("Makefile");
def-&gt;patterns = patterns;
def-&gt;extensions = extensions;
def-&gt;initialize = installMakefileRegex;
def-&gt;regex = TRUE;
return def;
}
</code>
</pre>
<p>
<pre>
/***************************************************************************
* swine.c
* Regex callback-based parser for Swine definitions
**************************************************************************/
/* INCLUDE FILES */
#include "general.h" /* always include first */
#include "parse.h" /* always include */
#include "read.h" /* to define file fileReadLine() */
/* DATA DEFINITIONS */
typedef enum eSwineKinds {
K_DEFINE
} swineKind;
static kindOption SwineKinds [] = {
{ TRUE, 'd', "definition", "pig definition" }
};
/* FUNCTION DEFINITIONS */
static void definition (const char *const line, const regexMatch *const matches,
const unsigned int count)
{
if (count &gt; 1) /* should always be true per regex */
{
vString *const name = vStringNew ();
vStringNCopyS (name, line + matches [1].start, matches [1].length);
makeSimpleTag (name, SwineKinds, K_DEFINE);
}
}
static void findSwineTags (void)
{
while (fileReadLine () != NULL)
; /* don't need to do anything here since callback is sufficient */
}
static void installSwine (const langType language)
{
addCallbackRegex (language, "^def[ \t]+([a-zA-Z0-9_]+)", NULL, definition);
}
/* Create parser definition stucture */
extern parserDefinition* SwineParser (void)
{
static const char *const extensions [] = { "swn", NULL };
parserDefinition* def = parserNew ("Swine");
def-&gt;kinds = SwineKinds;
def-&gt;kindCount = KIND_COUNT (SwineKinds);
def-&gt;extensions = extensions;
def-&gt;parser = findSwineTags;
def-&gt;initialize = installSwine;
return def;
}
</pre>
<p>
<pre>
/***************************************************************************
* make.c
* Regex-based parser for makefile macros
**************************************************************************/
/* INCLUDE FILES */
#include "general.h" /* always include first */
#include "parse.h" /* always include */
/* FUNCTION DEFINITIONS */
static void installMakefileRegex (const langType language)
{
addTagRegex (language, "(^|[ \t])([A-Z0-9_]+)[ \t]*:?=", "\\2", "m,macro", "i");
}
/* Create parser definition stucture */
extern parserDefinition* MakefileParser (void)
{
static const char *const patterns [] = { "[Mm]akefile", NULL };
static const char *const extensions [] = { "mak", NULL };
parserDefinition* const def = parserNew ("Makefile");
def-&gt;patterns = patterns;
def-&gt;extensions = extensions;
def-&gt;initialize = installMakefileRegex;
def-&gt;regex = TRUE;
return def;
}
</pre>
</body>
</html>
+371
View File
@@ -0,0 +1,371 @@
Frequently Asked Questions
==========================
* 1. Why do you call it "Exuberant Ctags"?
* 2. Why doesn't my editor work with these tag files?
* 3. What are these strange bits of text beginning with ;"?
* 4. Why doesn't XEmacs' Speedbar module work with Exuberant Ctags?
* 5. Why doesn't Xemacs correctly locate the tag in the source file?
* 6. Why doesn't NEdit correctly locate the tag in the source file?
* 7. Why can't I jump to "class::member"?
* 8. How can I avoid having to specify my favorite option every time?
* 9. Why do I end up on the wrong line when I jump to a tag?
* 10. How do I jump to the tag I want instead of the wrong one by the
same name?
* 11. What is "Vim"?
* 12. How can I locate all references to a specific function or variable?
* 13. Why does appending tags to a tag file tag so long?
* 14. How do I get regex support for Win32?
* 15. How should I set up tag files for a multi-level directory hierarchy?
----------------------------------------------------------------------
1. Why do you call it "Exuberant Ctags"?
Because one of the meanings of the word "exuberant" is:
exuberant : produced in extreme abundance : PLENTIFUL syn see PROFUSE
Compare the tag file produced by Exuberant Ctags with that produced by any
other ctags and you will see how appropriate the name is.
----------------------------------------------------------------------
2. Why doesn't my editor work with these tag files?
3. What are these strange bits of text beginning with ;" which follow
many of the lines in the tag file?
These are "extension flags". They are added in order to provide extra
information about the tag that may be utilized by the editor in order to
more intelligently handle tags. They are appended to the EX command part of
the tag line in a manner that provides backwards compatibility with existing
implementations of the Vi editor. The semicolon is an EX command separator
and the double quote begins an EX comment. Thus, the extension flags appear
as an EX comment and should be ignored by the editor when it processes the
EX command.
Some non-vi editors, however, implement only the bare minimum of EX commands
in order to process the search command or line number in the third field of
the tag file. If you encounter this problem, use the option "--format=1" to
generate a tag file without these extensions (remember that you can set the
CTAGS environment variable to any default arguments you wish to supply). Then
ask the supplier of your editor to implement handling of this feature of EX
commands.
----------------------------------------------------------------------
4. Why doesn't XEmacs' Speedbar module work with Exuberant Ctags?
The default command line switches used by XEmacs for "etags" are not
compatible with Exuberant Ctags options. By default, Exuberant Ctags installs
a symbolic link, "etags", pointing to the ctags executable. When Exuberant
Ctags is started with the name "etags", it produces Emacs-style tag files by
default.
To fix this, add the following lines to your .emacs file, replacing the path
to "etags" with the path where the symbolic link was installed.
(autoload 'speedbar "speedbar")
(setq speedbar-fetch-etags-command "/usr/local/bin/etags"
speedbar-fetch-etags-arguments '("-f" "-"))
----------------------------------------------------------------------
5. Why doesn't Xemacs correctly locate the tag in the source file?
This has been observed with version 20.3. It seems that when Xemacs searches
for a tag, it searches using the tag name instead of the search string located
in the TAGS file. This is a bug in Xemacs and does not occur in the GNU
version of Emacs.
----------------------------------------------------------------------
6. Why doesn't NEdit correctly locate the tag in the source file?
Versions of NEdit prior to 5.1 did not support the extended tag file format
generated by Exuberant Ctags by default. Either upgrade to version 5.1 or
specify the option "--format=1" when running ctags to output the old tag file
format.
----------------------------------------------------------------------
7. Why can't I jump to "class::member"?
Because, by default, ctags only generates tags for the separate identifiers
found in the source files. If you specify the --extra=+q option, then
ctags will also generate a second, class-qualified tag for each class member
(data and function/method) in the form class::member for C++, and in the form
class.method for Eiffel and Java.
----------------------------------------------------------------------
8. How can I avoid having to specify my favorite option every time?
Either by setting the environment variable CTAGS to your custom
options, or putting them into a .ctags file in your home directory.
----------------------------------------------------------------------
9. Why do I end up on the wrong line when I jump to a tag?
By default, ctags encodes the line number in the file where macro (#define)
tags are found. This was done to remain compatible with the original UNIX
version of ctags. If you change the file containing the tag without
rebuilding the tag file, the location of tag in the tag file may no longer
match the current location.
In order to avoid this problem, you can specify the option "--excmd=p",
which causes ctags to use a search pattern to locate macro tags. I have
never uncovered the reason why the original UNIX ctags used line numbers
exclusively for macro tags, but have so far resisted changing the default
behaviour of Exuberant Ctags to behave differently.
----------------------------------------------------------------------
10. How do I jump to the tag I want instead of the wrong one by the
same name?
A tag file is simple a list of tag names and where to find them. If there
are duplicate entries, you often end up going to the wrong one because the
tag file is sorted and your editor locates the first one in the tag file.
Standard Vi provides no facilities to alter this behavior. However, Vim
has some nice features to minimize this problem, primarly by examining all
matches and choosing the best one under the circumstances. Vim also provides
commands which allow for selection of the desired matching tag.
----------------------------------------------------------------------
11. What is "Vim"?
Vim is a vi-compatible editor available as source and compilable for any
platform. Yeah, I know the first reaction is to shy away from this. But you
will never regret getting it, and you will become greatly attached to its
features, which you can learn gradually. I would be willing to say that it
is the best vi-clone available within 4 light-years of Alpha Centauri. It
works (nearly) exactly like standard vi, but provides some incredibly useful
extensions (some of which I have participated in designing with the author).
Most Linux distributions have adopted Vim as its standard vi.
----------------------------------------------------------------------
12. How can I locate all references to a specific function or variable?
There are several packages already available which provide this capability.
Namely, these are: GLOBAL source code tag system, GNU id-utils, cscope,
and cflow. As of this writing, they can be found in the following locations:
GLOBAL: http://www.gnu.org/software/global
id-utils: http://www.gnu.org/software/idutils/idutils.html
cscope: http://cscope.sourceforge.net
cflow: ftp://www.ibiblio.org/pub/Linux/devel/lang/c
----------------------------------------------------------------------
13. Why does appending tags to a tag file tag so long?
Sometimes, in an attempt to build a global tag file for all source files in
a large source tree of many directories, someone will make an attempt to run
ctags in append (-a) mode on every directory in the hierarchy. Each time
ctags is invoked, its default behavior is to sort the tag file once the tags
for that execution have been added. As the cumulative tag file grows, the sort
time increases arithmetically.
The best way to avoid this problem (and the most efficient) is to make
use of the --recurse (or -R) option of ctags by executing the following
command in the root of the directory hierarchy (thus running ctags only once):
ctags -R
If you really insist on running ctags separately on each directory, you can
avoid the sort pass each time by specifying the option "--sort=no". Once the
tag file is completely built, use the sort command to manually sort the
final tag file, or let the final invocation of ctags sort the file.
----------------------------------------------------------------------
14. How do I get regex support for Win32?
You need to download the GNU regex package for Win32 from the following
location:
http://people.delphiforums.com/gjc/gnu_regex.html
Then point the makefile macro, REGEX_DIR, found in mk_mvc.mak and mk_bc5.mak,
to the directory created by extracting this archive.
----------------------------------------------------------------------
15. How should I set up tag files for a multi-level directory hierarchy?
There are a few ways of approaching this:
1. A local tag file in each directory containing only the tags for source
files in that directory.
2. One single big, global tag file present in the root directory of your
hierarchy, containing all tags present in all source files in the
hierarchy.
3. A local tag file in each directory containing only the tags for source
files in that directory, in addition to one single global tag file
present in the root directory of your hierarchy, containing all
non-static tags present in all source files in the hierarchy.
4. A local tag file in each directory of the hierarchy, each one
containing all tags present in source files in that directory and all
non-static tags in every directory below it (note that this implies
also having one big tag file in the root directory of the hierarchy).
Each of these approaches has its own set of advantages and disadvantages,
depending upon your particular conditions. Which approach is deemed best
depends upon the following factors:
A. The ability of your editor to use multiple tag files.
If your editor cannot make use of multiple tag files (original vi
implementations could not), then one large tag file is the only way to
go if you ever desire to jump to tags located in other directories. If
you never need to jump to tags in another directory (i.e. the source
in each directory is entirely self-contained), then a local tag file
in each directory will fit your needs.
B. The time is takes for your editor to look up a tag in the tag file.
The significance of this factor depends upon the size of your source
tree and on whether the source files are located on a local or remote
file system. For source and tag files located on a local file system,
looking up a tag is not as big a hit as one might first imagine, since
vi implementations typically perform a binary search on a sorted tag
file. This may or may not be true for the editor you use. For files
located on a remote file system, reading a large file is an expensive
operation.
C. Whether or not you expect the source code to change and the time it
takes to rebuild a tag file to account for changes to the source code.
While Exuberant Ctags is particularly fast in scanning source code
(around 1-2 MB/sec), a large project may still result in objectionable
delays if one wishes to keep their tag file(s) up to date on a
frequent basis, or if the files are located on a remote file system.
D. The presence of duplicate tags in the source code and the ability to
handle them.
The impact of this factor is influenced by the following three issues:
1. How common are duplicate tags in your project?
2. Does your editor provide any facilities for dealing with duplicate
tags?
While standard vi does not, many modern vi implementations, such
as Vim have good facilities for selecting the desired match from
the list of duplicates. If your editor does not support duplicate
tags, then it will typically send you to only one of them, whether
or not that is the one you wanted (and not even notifying you that
there are other potential matches).
3. What is the significance of duplicate tags?
For example, if you have two tags of the same name from entirely
isolated software components, jumping first to the match found
in component B while working in component A may be entirely
misleading, distracting or inconvenient (to keep having to choose
which one if your editor provides you with a list of matches).
However, if you have two tags of the same name for parallel builds
(say two initialization routines for different hosts), you may
always want to specify which one you want.
Of the approaches listed above, I tend to favor Approach 3. My editor of
choice is Vim, which provides a rich set of features for handling multiple
tag files, which partly influences my choice. If you are working with
source files on a remote file system, then I would recommend either
Approach 3 or Approach 4, depending upon the hit when reading the global
tag file.
The advantages of Approach 3 are many (assuming that your editor has
the ability to support both multiple tag files and duplicate tags). All
lookups of tag located in the currect directory are fast and the local
tag file can be quickly and easily regenerated in one second or less
(I have even mapped a keystroke to do this easily). A lookup of a
(necessarily non-static) tag found in another directory fails a lookup in
the local tag file, but is found in the global tag file, which satisfies
all cross-directory lookups. The global tag file can be automatically
regenerated periodically with a cron job (and perhaps the local tag files
also).
Now I give an example of how you would implement Approach 3. Means of
implementing the other approaches can be performed in a similar manner.
Here is a visual representation of an example directory hierarchy:
project
`-----misccomp
| `...
`-----sysint
`-----client
| `-----hdrs
| `-----lib
| `-----src
| `-----test
`-----common
| `-----hdrs
| `-----lib
| `-----src
| `-----test
`-----server
`-----hdrs
`-----lib
`-----src
`-----test
Here is a recommended solution (conceptually) to build the tag files:
1. Within each of the leaf nodes (i.e. hdrs, lib, src, test) build a tag
file using "ctags *.[ch]". This can be easily be done for the whole
hierarchy by making a shell script, call it "dirtags", containing the
following lines:
#!/bin/sh
cd $1
ctags *
Now execute the following command:
find * -type d -exec dirtags {} \;
These tag files are trivial (and extremely quick) to rebuild while
making changes within a directory. The following Vim key mapping is
quite useful to rebuild the tag file in the directory of the current
source file:
:nmap ,t :!(cd %:p:h;ctags *.[ch])&<CR><CR>
2. Build the global tag file:
cd ~/project
ctags --file-scope=no -R
thus constructing a tag file containing only non-static tags for all
source files in all descendent directories.
3. Configure your editor to read the local tag file first, then consult
the global tag file when not found in the local tag file. In Vim,
this is done as follows:
:set tags=./tags,tags,~/project/tags
If you wish to implement Approach 4, you would need to replace the
"dirtags" script of step 1 with the following:
#!/bin/sh
cd $1
ctags *
# Now append the non-static tags from descendent directories
find * -type d -prune -print | ctags -aR --file-scope=no -L-
And replace the configuration of step 3 with this:
:set tags=./tags,./../tags,./../../tags,./../../../tags,tags
As a caveat, it should be noted that step 2 builds a global tag file whose
file names will be relative to the directory in which the global tag file
is being built. This takes advantage of the Vim 'tagrelative' option,
which causes the path to be interpreted a relative to the location of the
tag file instead of the current directory. For standard vi, which always
interprets the paths as relative to the current directory, we need to
build the global tag file with absolute path names. This can be
accomplished by replacing step 2 with the following:
cd ~/project
ctags --file-scope=no -R `pwd`
--
+215
View File
@@ -0,0 +1,215 @@
Custom Installation
===================
These installation instructions are for Unix or Unix-like platforms (or at
least, those platforms which are able to run a Bourne shell script). If you
are attempting to install Exuberant Ctags on some other platform, see the file
INSTALL.oth.
If you are not familiar with using the configure scripts generated by GNU
autoconf, read the "Basic Installation" section below; then return here.
The configure script in this package supports the following custom options:
--disable-etags By default, "make install" will install one
binary, "ctags", one man page, "ctags.1", and
create links to these two files by the names
"etags" and "etags.1". If you do not want to
install the "etags" links, use this option.
--disable-extended-format Ctags now appends "extension flags" to the
end of each tag entry in a manner which is
backwards with original Vi implementation
(they are placed into an EX comment). This
can be disabled via use of the ctags --format
option. This configure option changes the
default behavior of ctags to disable use of
these extension flags (i.e. use the original
tag file format).
--disable-external-sort Use this option to force use of an internal
sort algorithm. On UNIX-like systems, ctags
uses the sort utility of the operating system
by default because it is more memory efficient.
--enable-custom-config=FILE Defines a custom option configuration file to
establish site-wide defaults. Ctags will read
the following files at startup for options:
/etc/ctags.conf, /usr/local/etc/ctags.conf,
$HOME/.ctags, and .ctags. If you need a
different file, set this option to the full
path name of the file you want to be read, and
it will be read immediately before reading
$HOME/.ctags.
--enable-macro-patterns By default, line numbers are used in the tag
file for #define objects, in order to remain
compatible with the original UNIX ctags. This
option will make the default use patterns.
--enable-maintainer-mode Creates a special GNU-specific version of the
makefile which is used to maintain Exuberant
Ctags.
--enable-tmpdir=DIR When the library function mkstemp() is
available, this option allows specifying the
default directory to use for temporary files
generated by ctags. This default can be
changed at run time by setting the environment
variable TMPDIR.
If you wish to change the name of the installed files, edit the makefile
produced by the configure script ("Makefile") before performing the "make
install" step. There are two lines at the top of the file where the names of
the installed files may be customized.
Basic Installation
==================
These are generic installation instructions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, a file
`config.cache' that saves the results of its tests to speed up
reconfiguring, and a file `config.log' containing compiler output
(useful mainly for debugging `configure').
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If at some point `config.cache'
contains results you don't want to keep, you may remove or edit it.
The file `configure.in' is used to create `configure' by a program
called `autoconf'. You only need `configure.in' if you want to change
it or regenerate `configure' using a newer version of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system. If you're
using `csh' on an old version of System V, you might need to type
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
Running `configure' takes awhile. While running, it prints some
messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type `make install' to install the programs and any data files and
documentation.
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. You can give `configure'
initial values for variables by setting them in the environment. Using
a Bourne-compatible shell, you can do that on the command line like
this:
CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
Or on systems that have the `env' program, you can do it like this:
env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
If you have to use a `make' that does not supports the `VPATH'
variable, you have to compile the package for one architecture at a time
in the source code directory. After you have installed the package for
one architecture, use `make distclean' before reconfiguring for another
architecture.
Installation Names
==================
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=PATH' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Operation Controls
==================
`configure' recognizes the following options to control how it
operates.
`--cache-file=FILE'
Use and save the results of the tests in FILE instead of
`./config.cache'. Set FILE to `/dev/null' to disable caching, for
debugging `configure'.
`--help'
Print a summary of the options to `configure', and exit.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`--version'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`configure' also accepts some other, not widely useful, options.
+84
View File
@@ -0,0 +1,84 @@
If you are attempting to install Exuberant Ctags on a Unix-like platform
(one that can at least run a Bourne shell script) see the file INSTALL.
Installation Notes
==================
For non-Unix platforms, simple makefiles are provided:
descrip.mms For VMS using either DEC C or VAX C
mk_bc3.mak For MSDOS using Borland C/C++ 3.x
mk_bc5.mak For Win32 using Borland C++ 5.5
mk_djg.mak For MSDOS using DJGPP Gnu GCC (better to follow Unix install)
mk_manx.mak For Amiga using Aztec/Manx C 5.0
mk_ming.mak For Win32 using Mingw32
mk_mpw.mak For Macintosh using MPW
mk_mvc.mak For Win32 using Microsoft Visual C++
mk_os2.mak For OS/2 using GCC (EMX)
mk_qdos.mak For QDOS using C68
mk_riscos.mak For RISC OS using the GCC SDK <http://hard-mofo.dsvr.net>
mk_sas.mak For Amiga using SAS/C
Special Notes
=============
Win32:
------
Regex support on Win32 is available when compiled to use the Win32 port of
the Gnu regex library, which can be obtained here:
http://people.delphiforums.com/gjc/gnu_regex.html
See the makefiles, mk_mvc.mak or mk_bc5.mak, to learn how to build with
this library.
DJGPP:
------
It is better to follow the standard Unix install on DJGPP, but this requires
that you use BASH and requires a fairly complete installation of GJGPP
packages. You can use mk_djg.mak if you can't run configure.
Macintosh with MPW:
-------------------
To build Ctags on MPW you will have to have the Metrowerks compilers
or you will have to edit the makefiles yourself.
Since the makefile for MPW is called mk_mpw.mak you will have to give
the command: `Make -f mk_mpw.mak CTags` and then select the output
and execute it. Alternatively you could rename this makefile to
CTags.make and issue the command `Build CTags`.
If the build process goes wrong make sure the line endings for the
makefile are set to MacOS (CR instead of LF).
This version of Ctags only accepts and emits unix style paths. This was
done since it was easier to implement (few changes in main source files)
and since I ported Ctags to MPW to use with Pepper which also works with
unix style paths internally. Besides, since we're now moving to MacOS X
anyway, Mac programmers are getting used to unix style paths anyway.
Example, suppose you have a project using PowerPlant which is located in
'HD20:tools:PowerPlant:' and you want a tags file for all powerplant
sources and your projects sources. Go to the root directory of your
project and type:
CTags -R . '/HD20/tools/PowerPlant/'
The '.' in this command means current directory. You will also have to
put quotes around the full unix style path since / has a special meaning
in MPW.
RISC OS:
--------
Regex support on RISC OS is available when compiled to use the RISC OS port
of the GNU regex library, which can be obtained from:
<http://www.sbellon.de/software.html>
Using 'Set RexEx$Path <Obey$Dir>.' in the regex-0/12 directory will ensure
it can be found.
+54
View File
@@ -0,0 +1,54 @@
SubDir HAIKU_TOP src bin ctags ;
SubDirCcFlags -DHAVE_CONFIG_H ;
SUBDIRYACCFLAGS += d ;
SubDirSysHdrs [ FDirName $(SUBDIR) ] ;
BinCommand ctags :
args.c
asm.c
asp.c
awk.c
beta.c
c.c
cobol.c
eiffel.c
entry.c
erlang.c
fortran.c
get.c
html.c
jscript.c
keyword.c
lisp.c
lregex.c
lua.c
main.c
make.c
options.c
parse.c
pascal.c
perl.c
php.c
python.c
read.c
rexx.c
routines.c
ruby.c
scheme.c
sh.c
slang.c
sml.c
sort.c
sql.c
strlist.c
tcl.c
verilog.c
vim.c
yacc.c
vstring.c
:
: ctags.rdef ;
+221
View File
@@ -0,0 +1,221 @@
# $Id: Makefile.in,v 1.8 2003/07/27 22:09:58 darren Exp $
#
# Makefile for UNIX-like platforms.
#
# These are the names of the installed programs, in case you wish to change
# them.
#
CTAGS_PROG = ctags
ETAGS_PROG = etags
# Set this to the path to your shell (must run Bourne shell commands).
#
SHELL = /bin/sh
# GNU Autoconf variables. These are set by the "configure" script when it
# runs.
#
exec_prefix = @exec_prefix@
prefix = @prefix@
bindir = @bindir@
srcdir = @srcdir@
libdir = @libdir@
incdir = @includedir@
mandir = @mandir@
SLINK = @LN_S@
STRIP = @STRIP@
CC = @CC@
DEFS = @DEFS@
CFLAGS = @CFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
EXEEXT = @EXEEXT@
OBJEXT = @OBJEXT@
# If you cannot run the "configure" script to set the variables above, then
# uncomment the defines below and customize them for your environment. If
# your system does not support symbolic (soft) links, then remove the -s
# from SLINK.
#
#srcdir = .
#bindir = /usr/local/bin
#mandir = /usr/local/man
#SLINK = ln -s
#STRIP = strip
#CC = cc
#DEFS = -DHAVE_CONFIG_H
#CFLAGS = -O
#LDFLAGS=
include $(srcdir)/source.mak
#
#--- You should not need to modify anything below this line. ---#
#
.SUFFIXES:
.SUFFIXES: .c .$(OBJEXT)
VPATH = $(srcdir)
INSTALL = cp
INSTALL_PROG = $(INSTALL)
INSTALL_DATA = $(INSTALL)
READ_LIB = readtags.$(OBJEXT)
READ_INC = readtags.h
MANPAGE = ctags.1
AUTO_GEN = configure config.h.in
CONFIG_GEN = config.cache config.log config.status config.run config.h Makefile
#
# names for installed man pages
#
manext = 1
man1dir = $(mandir)/man1
CMAN = $(CTAGS_PROG).$(manext)
EMAN = $(ETAGS_PROG).$(manext)
#
# destinations for installed files
#
CTAGS_EXEC = $(CTAGS_PROG)$(EXEEXT)
ETAGS_EXEC = $(ETAGS_PROG)$(EXEEXT)
DEST_CTAGS = $(bindir)/$(CTAGS_EXEC)
DEST_ETAGS = $(bindir)/$(ETAGS_EXEC)
DEST_READ_LIB = $(libdir)/$(READ_LIB)
DEST_READ_INC = $(incdir)/$(READ_INC)
DEST_CMAN = $(man1dir)/$(CMAN)
DEST_EMAN = $(man1dir)/$(EMAN)
#
# primary rules
#
all: $(CTAGS_EXEC) $(READ_LIB)
$(CTAGS_EXEC): $(OBJECTS)
$(CC) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBS)
dctags$(EXEEXT): debug.c $(SOURCES) $(HEADERS)
$(CC) -I. -I$(srcdir) $(DEFS) -DDEBUG -g $(LDFLAGS) -o $@ debug.c $(SOURCES)
readtags$(EXEEXT): readtags.c readtags.h
$(CC) -DREADTAGS_MAIN -I. -I$(srcdir) $(DEFS) $(CFLAGS) $(LDFLAGS) -o $@ readtags.c
ETYPEREF_OBJS = etyperef.o keyword.o routines.o strlist.o vstring.o
etyperef$(EXEEXT): $(ETYPEREF_OBJS)
$(CC) $(LDFLAGS) -o $@ $(ETYPEREF_OBJS)
etyperef.o: eiffel.c
$(CC) -DTYPE_REFERENCE_TOOL -I. -I$(srcdir) $(DEFS) $(CFLAGS) -o $@ -c eiffel.c
$(OBJECTS): $(HEADERS) config.h
#
# generic install rules
#
install: @install_targets@
install-strip: install
install-ctags: install-cbin install-cman
install-etags: install-ebin install-eman
$(bindir) $(man1dir) $(libdir) $(incdir):
$(srcdir)/mkinstalldirs $@
FORCE:
#
# install the executables
#
install-bin: install-cbin install-ebin install-lib
install-cbin: $(DEST_CTAGS)
install-ebin: $(DEST_ETAGS)
install-lib: $(DEST_READ_LIB) $(DEST_READ_INC)
$(DEST_CTAGS): $(CTAGS_EXEC) $(bindir) FORCE
$(INSTALL_PROG) $(CTAGS_EXEC) $@ && chmod 755 $@
$(DEST_ETAGS):
- if [ -x $(DEST_CTAGS) ]; then \
cd $(bindir) && $(SLINK) $(CTAGS_EXEC) $(ETAGS_EXEC); \
fi
#
# install the man pages
#
install-man: install-cman install-eman
install-cman: $(DEST_CMAN)
install-eman: $(DEST_EMAN)
$(DEST_CMAN): $(man1dir) $(MANPAGE) FORCE
- $(INSTALL_DATA) $(srcdir)/$(MANPAGE) $@ && chmod 644 $@
$(DEST_EMAN):
- if [ -f $(DEST_CMAN) ]; then \
cd $(man1dir) && $(SLINK) $(CMAN) $(EMAN); \
fi
#
# install the library
#
$(DEST_READ_LIB): $(READ_LIB) $(libdir) FORCE
$(INSTALL_PROG) $(READ_LIB) $@ && chmod 644 $@
$(DEST_READ_INC): $(READ_INC) $(incdir) FORCE
$(INSTALL_PROG) $(READ_INC) $@ && chmod 644 $@
#
# rules for uninstalling
#
uninstall: uninstall-bin uninstall-lib uninstall-man
uninstall-bin:
- rm -f $(DEST_CTAGS) $(DEST_ETAGS)
uninstall-lib:
- rm -f $(DEST_READ_LIB) $(DEST_READ_INC)
uninstall-man:
- rm -f $(DEST_CMAN) $(DEST_EMAN)
uninstall-ctags:
- rm -f $(DEST_CTAGS) $(DEST_CMAN)
uninstall-etags:
- rm -f $(DEST_ETAGS) $(DEST_EMAN)
#
# miscellaneous rules
#
tags: $(CTAGS_EXEC)
./$(CTAGS_EXEC) $(srcdir)/*
TAGS: $(CTAGS_EXEC)
./$(CTAGS_EXEC) -e $(srcdir)/*
clean:
rm -f $(OBJECTS) $(CTAGS_EXEC) tags TAGS $(READ_LIB)
rm -f dctags$(EXEEXT) readtags$(EXEEXT)
rm -f etyperef$(EXEEXT) etyperef.$(OBJEXT)
mostlyclean: clean
distclean: clean
rm -f $(CONFIG_GEN)
maintainerclean: distclean
rm -f $(AUTO_GEN)
#
# implicit rules
#
.c.$(OBJEXT):
$(CC) -I. -I$(srcdir) $(DEFS) $(CFLAGS) -c $<
# vi:set tabstop=8:
+796
View File
@@ -0,0 +1,796 @@
Current Version: 5.6
ctags-5.6 (Mon May 29 2006)
* Reformatted code for independence of tab stop setting.
* Changed default configuration to disable installation of etags links.
* Changed --langmap to first unmap each supplied extension from other languages.
* Added support for ASP constants [ASP, Patch #961842].
* Added support for GNU make extensions [Make].
* Added .mk as extension recognized as a make language file [Make].
* Added missing help for list-maps options [Bug #1201826].
* Added new extension field "typeref" [thanks to Bram Moolenaar].
* Extended functionality of Ruby parser with patch from Elliot Hughes [Ruby].
* Fixed creation of TAGS file with etags-include but no files [Bug #941233].
* Fixed problem reading last line of list file (-L) without final newline.
* Fixed infinite loop that could occur on files without final newline [C, Java].
* Fixed incorrect tag for first field of table [SQL].
* Fixed missing tags for functions beginning with underscore [Sh].
* Fixed missing tags for functions with variable arg list [C, Bug #1201689].
* Fixed parsing problem with parentheses in argument list [C, Bug #1085585].
* Fixed problem in preprocessor directive handling [C, Bug #1086609].
ctags-5.5.4 (Thu Mar 25 2004)
* Fixed broken -R option.
ctags-5.5.3 (Sun Mar 14 2004)
* Removed forgotten debug statement [Bug #811704].
* Added support for Perl labels.
* Added support for Perl "use constant" [Perl, Patch #853704, Feature Request
#710017].
* Added support for package qualification of tags, removing useless "package"
tag kind [Perl, Feature Request #448887].
* Added support for "and" keyword [SML, Bug #816636].
* Added support for variables [PHP].
* Fixed problem destroying tag file with certain info options [Bug #845502].
* Fixed portability problem [DJGPP].
* Fixed problem of double characters in signature field [C, Bug #852368].
* Fixed problem manifested by errant preprocessor conditionals [Bug #839162].
* Fixed incorrect line address in tag file for SQL tags [SQL, Bug #823000].
* Fixed incorrect recognition of POD paragraph [Perl, Bug #842077].
* Fixed spurious tags for for C++ member templtates [C++, Bug #849591].
* Fixed missing tags related to template specializations [C++, Bug #872494].
* Fixed spurious local tags for statements following labels [C].
* Fixed missing tags for certain scoped functions [Vim].
* Fixed infinite loop in Fortran parser.
* Fixed missing tags for certain initializers [Fortran, Bug #877956].
* Fixed problem with comment line after continuation character [Fortran,
Bug #858165].
ctags-5.5.2 (Wed Sep 17 2003)
* Added tags for local variables for C-based languages [C/C++/C#/Java/Vera,
Feature Request #449503].
* Fixed compilation problem due to type change made to accomodate change of
return type of _findfirst() in VisualStudio.Net [Win32, Bug #775789].
* Fixed problems with certain bit fields.
ctags-5.5.1 (Wed Jul 30 2003)
* Changed supported tag kinds for Verilog parser during overhaul.
* Restored exit of program after --help, --license, and --version options [Bug
#717311, #751240].
* Removed inclusion of general.h (GPL) from readtags.c (public domain).
* Added support for tags for labels [PL/SQL].
* Added support for tags for constant definitions [PHP].
* Fixed redundant parsing of configuration file [Windows, Bug #768814].
* Fixed missing tags for definitions spanning lines [Verilog, Bug #762027].
* Fixed compilation error for uncommon hosts.
* Fixed missing tags for Korn shell specific function definitions. [Sh,
Bug #769184]
* Fixed missing tags when semicolon separator appears [Fortran, Bug #734933].
* Fixed missing tags when endsubroutine keyword appears [Fortran, Bug #726712].
* Fixed problem with fixed-form line continuation following comment [Fortran,
Bug #726875].
* Fixed missing tags for nested blocks [PL/SQL, Bug #722501].
* Fixed missing tags for function typedefs [C].
* Fixed inability to map empty extension when path contained dot [Bug #742689].
ctags-5.5 (Tue Apr 1 2003)
* Changed kind indicator for methods from 'f' to 'm' [Tcl].
* Changed tags within interfaces to be disabled by default (like prototypes in
C/C++) [Fortran].
* Removed explicit descriptions of individual --<LANG>-types options from
--help output. See new --list-languages and --list-kinds options.
* Removed explicit list of supported languages and supported tag kinds and
mapping patterns from man page. See new --list-languages, --list-kinds, and
--list-maps options.
* Renamed --<LANG>-types option to --<LANG>-kinds (still accepts old name).
* Added --list-kinds option.
* Added --list-maps option.
* Added --list-languages option.
* Added support for dimensioned variables, contributed by Simon Bohlin [ASP].
* Added support for C# language.
* Added support for Erlang language, contributed by Brent Fulgham.
* Added support for HTML language files.
* Added support for JavaScript language files.
* Added support for SML (Standard ML) language, contributed by Venkatesh Prasad.
* Added mapping for .plx to Perl.
* Added tags for autocommand groups [Vim, Patch #664685].
* Added support for numerous language extensions [Fortran].
* Added '$', 'D', and 'd' in column 1 as comment characters [Fortran].
* Added special handling of --options=NONE to disable automatic reading of
options from configuration files or environment.
* Added check for case-insensitive filenames to configure.
* Fixed problem with lower case <SID> tag [Vim, Bug #657327].
* Fixed problem recognizing indented code [Vim, Patch #664685].
* Fixed problem with infinite loop in certain comments [PL/SQL, Bug #629115].
* Fixed problem of incorrect extension field [C, Bug #639639].
* Fixed problem of empty scoping extension field [C, Bug #639644].
* Fixed missing tags for functions split across lines [PHP, Bug #681824].
* Fixed missing tags for nested subprograms using 'contains' [Fortran,
Bug #670433].
* Fixed missing tags when variable has same name as keyword [Fortran].
* Fixed spurious tag when an array-spec occurs within an entity-decl [Fortran].
* Fixed mishandling of multiline raw strings [Python, Bug #699171].
* Fixed missing scope extension field on namespaces [C++, C#, Bug #665086].
* Fixed several bugs causing missed tags [Fortran].
* Fixed problem with --langmap option preventing clearing of map [Bug #688442].
* Fixed recognition of Unicode-8 characters [Java].
* Fixed man page errors and omissions.
* Fixed bug in readFieldValue() in readtags library.
* Fixed bug in option parsing in readtags command-line program.
* Fixed portability problems with DJGPP [Bug #692569].
* Fixed portability problems with Cygwin.
ctags-5.4 (Thu Oct 17 2002)
* Improved ability for tagsOpen() in readtags library to report failure to
open tag file, adding new fields to tagFileInfo structure.
* Improved Cobol support to include data, files, groups, and sections [Cobol].
* Added '$' a valid character for C identifier [VMS].
* Added support for recording routine argument declarations for C-like
languages. See the --fields option and man page section TAG FILE FORMAT for
more information [C, C++, Java].
* Added class and method support to TCL parser [TCL].
* Added support for PL/SQL language.
* Added support for Vera language, inspired by Dave Eggum [Vera].
* Fixed problem terminating Perl POD block [Perl, Bug #612621].
* Fixed problem re whitespace preceding subprogram name [Pascal, Bug #612019].
* Fixed problem with leading spaces before instruction [TCL, Bug #615928].
* Fixed problem with double precision functions [Fortran, Bug #620288].
* Fixed inverted test causing TMPDIR to be used for temporary files when
ctags is setuid instead of when not setuid [Bug #623713].
ctags-5.3.1 (Thu Sep 12 2002)
* Renamed tagsSetSorted() to tagsSetSortType() and "sorted" member of
tagFileInfo structure of readtags library to "sort".
* Added new function, tagsFirst() to readtags library.
* Fixed incorrect tag kinds [Verilog].
* Fixed null tags for unnamed BLOCK DATA statements [Fortran].
* Fixed missing tags for function preceded by "<SID>" [Vim].
* Fixed missing tags for equate statements not in column 1 [Asm, Bug #538629].
* Fixed Ruby parser (why didn't the compiler report my screw-up?) [Ruby].
ctags-5.3 (Wed Jul 17 2002)
* Allowed --etags-include option without input files.
* Changed Asm parser to back to C-based parser to remove redundant tags,
and extending its support for more variants [Asm].
* Changed to using _tempnam() to create temporary files on Windows, allowing
"TMP" environment variable to set temporary directory.
* Changed the -x output to match that of traditional ctags when the --format=1
option is supplied. The new format was also changed slightly to conform more
closely to the original format, with the addition of the extra tag type field.
* Added support for Verilog language, submitted by Nam SungHyun.
* Added support for RISC OS platform, contributed by Andrew Wingate.
* Added support for "#pragma weak", generating macro tags for weak symbols [C].
* Added support for mixins and class methods to Ruby parser, submitted by
Matthias Veit [Ruby].
* Added support to ctags and readtags library for case-folded sorting of tag
files, submitted by Flemming Madsen.
* Added identification of class methods [Python].
* Fixed portability problems [Bugs #541997, #571240].
* Fixed bug in configure script [Solaris, Bug #542966].
* Fixed invalid package name tags [Perl, Bug #535068].
* Fixed failure to output relative paths into etags TAGS files on Win32
[Bug #568365].
* Fixed incorrect line address in cases of line continuation [Fortran].
* Fixed missing tags for certain cases of invalid syntax [C].
* Fixed missing tags in Fortran with HPF extensions [Fortran, Bug #565813].
* Fixed spurious tag for clients portion of feature clause when following
an empty feature clause [Eiffel].
ctags-5.2.3 (Sun Feb 24 2002)
* Fixed portability problem in makefile [Solaris, FreeBSD].
* Fixed infinite loop for certain cases of invalid syntax [Eiffel].
* Changed Asm parser to regex, extending its support for more variants [Asm].
ctags-5.2.2 (Sat Feb 16 2002)
* Fixed spurious tags following empty feature clause [Eiffel].
* Fixed missing tags for classes specifying generic creation routine [Eiffel].
* Fixed missing tags when label not followed by white space [YACC].
* Fixed for portability [Solaris, MacOS X].
* Added support for type reference tool [Eiffel].
ctags-5.2.1 (Sun Jan 20 2002)
* Portability fixes [Mingw32].
* Added "RCS" and "CVS" to list of directories excluded by default.
* Fixed missing tags for function pointers declared const or volatile
[C, Bug #503764].
ctags-5.2 (Sun Dec 23 2001)
* Portability fixes [HP-UX, Solaris, VMS, OS/2].
* Made code compilable by a C++ compiler.
* Changed reading of option files to ignore blank lines.
* Changed and enhanced interface to readtags library (see readtags.h).
* Changed from using addLanguageRegex() to addTagRegex() in regex-based
parsers.
* Added support for Lua language, submitted by Max Ischenko.
* Added instructions to man page on using tags with NEdit.
* Added setargv.obj to link for wildcard expansion [MSVC].
* Added capability to have regex invoke a callback in a regex parser.
* Fixed regex tag problem which left newlines in back-references.
* Fixed missing class-qualified tags [Eiffel].
* Fixed spurious tags for entries in final indexing clause [Eiffel].
* Fixed problem with invalid filenames in preprocessor line directives.
* Fixed bug parsing scoped variables (e.g. "b:variable") [Vim, Bug #487608].
* Fixed problem compiling readtags.c on some hosts.
* Fixed memory overwrite problem in readtags library.
ctags-5.1 (Tue Nov 06 2001)
* Changed name of option configuration files for MSDOS, MSWindows, and OS/2.
* Changed regex support to enforce REG_NEWLINE. This fixes problem where the
newline character was explicity being matched by user patterns [Bug #431477].
* Added new public domain library for reading tag files (see readtags.h).
* Added support for variables and namespaces, provided by Jay Glanville [Vim].
* Added report of non-options in option configuration files and CTAGS
environment variable.
* Added support for YACC language, submitted by Nick Hibma [YACC].
* Added support for Perl packages, submitted by Nick Hibma [Perl].
* Added '$' as valid identifier character for DEC C compiler [VMS, Bug #425147].
* Added compilation date and time to --version output.
* Added configure check for HP-UX to determine if ANSI options needed [HP-UX].
* Removed tags for forward class/struct declarations [C/C++, Bug #432563].
* Eliminated ;" separator from end of tag line when no extension fields are
present.
* Fixed segmentation violation for some Lisp files [Lisp].
* Fixed segmentation violation occurring when file referenced in #line
directive was from an unknown language.
* Fixed loss of sync when parsing bit fields named with C++ reserved word [C].
* Fixed compilation problem on gcc-2.7.2.
* Fixed problem parsing verbatim strings [Eiffel].
* Fixed problem with PHP references [PHP].
* Fixed handling of Perl __DATA__ sections [Perl].
* Fixed problem resulting from white space in tag name due to regex name
specifier.
* Fixed double reading of $HOME/.ctags when current directory is $HOME.
* Fixed problem reading option configuration files using CR-LF newlines.
* Fixed problem preventing output control over tag kinds of regex patterns
[Bug #429869]
* Fixed incorrect parsing of Vim functions with ':' modifiers [Bug #466517].
ctags-5.0.1 (Sun Apr 15 2001)
* Fixed problem checking recursive links [SunOS 4.x].
* Improved security on hosts where mkstemp() is not available.
ctags-5.0 (Sun Mar 18 2001)
* Restructured code to simplify support for new language parsers.
* Changed source code to use ANSI-style function definitions.
* Changed scope-qualified tag entries to omit enumeration name [C/C++].
* Changed reading of files supplied to -I option to read one token per line.
* Changed reading of option files to read one argument per line.
* Changed default extension fields, now controlled by new option --fields.
* Changed detection of etags invocation to accept any name containing "etags".
* Removed -p option, which only caused confusion and is rendered obsolete by
the change immediately above.
* Removed 'A' flag to the --c-types, --eiffel-types, and --java-types
options, replacing its functionality with the new --fields option.
* Removed 'C' flag to the --c-types, --eiffel-types, and --java-types
options, replacing its functionality with the new --extra option.
* Deprecated -i option, which was long ago replaced with the --c-types option.
* Deprecated --file-tags option, now incorporated into new --extra option.
* Deprecated --kind-long option, now incorporated into new --fields option.
* Renamed --lang[uage] option to --language-force.
* Renamed makefiles for non-Unix platforms.
* Improved parsing of assembly language files [Asm].
* Improved parsing of Fortran language files, adding new tag kinds [Fortran].
* Added documentation explaining how to extend ctags with new parsers.
* Added support for regular expressions, using either Posix or Gnu interface.
* Added support for mapping file names to languages using shell patterns.
* Added support for ASP scripts, submitted by Patrick Dehne [ASP].
* Added support for Makefiles [Make].
* Added support for Pascal language [Pascal].
* Added support for PHP scripts, submitted by Jesus Castagnetto [PHP].
* Added support for REXX language [REXX], based on submission by Alexaner Mai.
* Added support for Ruby, submitted by Thaddeus Covert [Ruby].
* Added support for S-Lang, submitted by Francesc Rocher [SLang].
* Added support for Macintosh platform using MPW (by Maarten Hekkelman).
* Added .tk as recognized extension [Tcl].
* Added .cp and .hp as C++ extensions [C++].
* Added .zsh as shell script extension [Sh].
* Added support for trigraphs for C-based languages [C/C++].
* Added language recognition for shell scripts using "#!/usr/bin/env command".
* Added check for recursive directory links.
* Added support for "[" form of verbatim strings [Eiffel].
* Added --exclude option to exclude directories while recursing.
* Added --fields option to specify extension fields to include in output.
* Added --extra option to allow control over extra tags.
* Added --regex-<LANG> option to define language-specific regular expressions.
* Added --<LANG>-types options for all supported languages.
* Added --langdef option to define new languages to be parsed with regex.
* Added --languages option to restrict set of languages scanned for tags.
* Added --tag-relative option to make file paths recorded in tag file relative
to location of tag file itself instead of the current working directory when
file arguments are specified using relative paths.
* Added restriction of permissions of created temporary files when mkstemp()
is not available for security.
* Reimplemented line directive handling to work for all languages.
* Fixed tag generation for packages [Java].
* Fixed Lisp parser [Lisp].
* Fixed Mingw32 port [Win32].
* Fixed bug in procedure name parsing [Tcl].
* Fixed bug resulting in wrong column being checked for paragraphs [Cobol].
* Fixed bug in language dispatch for executable "#!" scripts [Unix].
* Fixed bugs resulting in incorrect scope entries in tag file [C++/Java].
* Fixed warning caused by reinstallation of etags link [Unix].
* Fixed destruction of existing tag file when no files supplied on invocation.
* Fixed problem in Makefile.in which prevented configuring and building in
non-source directory. Also changed Makefile.in to generate and use correct
object and executable file extensions when run on Win32.
ctags-4.0.3 (Sun Jul 16 2000)
* Fixed compiler warnings [Amiga].
* Fixed problem in configure.in causing struct stat st_ino member test to fail.
* Fixed problem with TAGS entries for files using DOS-style (CR-LF) new lines.
* Improved algorithm for locating Perl functions and skipping pods.
* Improved algorithm for locating shell functions [Sh].
* Renamed Makefile.amiga to Makefile.manx [Amiga].
* Added Makefile.sas for SAS C compiler [Amiga].
* Updated Makefile.qdos [QDOS].
* Improved support for DECC compiler [VAX].
ctags-4.0.2 (Mon Jul 10 2000)
* Now silently ignore -w option for backwards compatibility with SVR4 ctags.
* Fixed bug resulting in no extension flags when using --kind-long option.
ctags-4.0.1 (Wed Jun 28 2000)
* Fixed segmentation violation when using --file-tags.
ctags-4.0 (Thu Jun 22 2000)
* Fixed infinite loop on certain syntactically invalid class constructs [C++].
* Fixed problem of incorrect tags for some pure virtual functions [C++].
* Fixed inability to clear all tag types when using --c-types= (all languages).
* Fixed problem of arguments to parameterized class being reported as
ancestors in the "inherits" extension flag.
* Fixed missed tags for typedef-ed function pointers having a PROTO((a,b))
style argument list.
* Fixed missing file tags for referenced files when using --line-directives
option [C/C++].
* Fixed failure to recognize drive-qualified file name as a file name when
supplied as argument to -I option [Win32].
* Fixed problem with missing comma in "inherits" extension flag [Java].
* Fixed problem with incorrect or redundant parents listed for "inherits"
extension flag [Java].
* Added check to avoid recursive symbolic links to directories.
* Added warning message for -i option, which is deprecated and being dropped.
* Added support for Assembler, COBOL, LISP, PERL, and Scheme, taken from Gnu
etags.
* Added support for AWK, Bourne/Korn/Z Shell, Python, TCL, and Vim scripts.
* Added support for the BETA language, submitted by Erik Corry.
* Added ability to determine language from interpreter specified in first line
of executable files if they are not recognized by their extension.
* Added --options option.
* Added ability to specify files having no extension with -h and --langmap
options.
* Added compile time option to separate path components with a unix-style path
separator for sharing tag file across platforms, enabled by defining the
label UNIX_PATH_SEPARATOR [Win32].
* Fixed portability issues [VMS].
ctags-3.5.2 (Mon Apr 24 2000)
* Fixed problem preventing Emacs-style tags from being written to stdout.
ctags-3.5.1 (Sun Apr 23 2000)
* Fixed infinite loop in writing Emacs-style TAGS file on platforms using
tmpnam() instead of mkstemp() [Win32].
* Fixed minor problems in Borland makefiles [Win32].
* Fixed compiler warning [DJGPP].
ctags-3.5 (Fri Apr 14 2000)
* Fixed core dump when including access field in tag file [Java].
* Fixed failure to identify end of statement for block statements [Java].
* Fixed bug with lone "end" in feature adaptation part of inheritance clause
[Eiffel].
* Fixed problem preventing const functions from being recognized as pure
virtual [C/C++].
* Fixed problem with no tags found after certain macro calls [C/C++].
* Fixed bug in descrip.mms build file [VMS].
* Changed to use mkstemp() (when available) to create temporary files for
security reasons and allow configuring default temporary directory, and to
override this directory at run-time by setting TMPDIR environment variable.
* Added support for extracting inheritance information into new "inherits"
extension flag [C++, Java].
* Added Makefile.bc5 for Borland C++ version 5.5 compiler (free version).
* Added new question to FAQ regarding Xemacs.
* Updated FAQ regarding new release of NEdit.
* Renamed Borland 3.1 makefile from Makefile.bcc to Makefile.bc3.
* Renamed Microsoft Visual C++ makefile from Makefile.w32 to Makefile.mvc.
ctags-3.4 (Thu Jan 13 2000)
* Fixed sorting problems when LC_ALL environment variable was set to foreign
locale (not fixed by previous release).
* Fixed nested scoping reported in extension flags and class-qualified tags.
* Eliminated generation of class-qualified tag entries when --c-types=+C
option is in effect but scope is empty (e.g. "::main").
* Added support for default access of class members in Java.
* Added new extension flag "implementation", which indicates if a routine or
class is virtual or abstract.
* Minor changes for OS/2 compilation.
ctags-3.3.3 (Thu Dec 16 1999)
* Changed how input is read for -L and --filter options to permit file names
containing spaces (see man page).
* Fixed scope recorded for C++ class elements, especially in namespaces.
* Fixed spurious tag generated for MODULE PROCEDURE in interfaces [Fortran].
* Fixed sorting problems when LC_ALL environment variable was set to foreign
locale.
* Fixed crash on Windows when compiled with Mingw32 gcc compiler.
* Fixed compilation problems on Cray.
ctags-3.3.2 (Fri Sep 24 1999)
* Fixed compile problem on AIX 4.1.
* Improved recovery from syntax error [Fortran].
* Changed name of configure option (now --enable-custom-config).
* Changed Makefile.bcc to optimize for space, since code size exceeded 64KB.
ctags-3.3.1 (Mon Sep 20 1999)
* Fixed segmentation violation occurring when directory recursion was selected.
* Fixed misleading message when out of memory during internal sort.
ctags-3.3 (Fri Sep 17 1999)
* Fixed missing class-qualified tags [Java].
* Fixed missing tag for functions having function pointer argument [C].
* Fixed parsing of conversion functions [C++].
* Added missing space following "operator" keyword to the tag names generated
for function call operators [C++].
* Fixed string parsing to retry file as free source form upon EOF [Fortran].
* Fixed missing tags following comments [Fortran].
* Fixed missing labels for free source form [Fortran].
* Removed 72 character limit for fixed form source lines, since many compilers
relax this limit and it is commonly taken advantage of. This was sometimes
causing fixed form source to be parsed as free form source [Fortran].
* Changed misleading message when file could not be accessed.
* Changed behavior of --verbose option to display option processing.
* Changed -I option to permit clearing the token list with "-I-".
* Changed --lang option to accept new "auto" parameter.
* Changed --langmap option to accept new "default" parameter.
* Changed --eiffel-types option to accept new 'C' flag to generate
class-qualified tags.
* Changed -h option to accept new "default" parameter.
* Changed option processing. Most options may now appear anywhere on the
command line, affecting only those files which follow them.
* Added ability to specify default options in any of the files /etc/ctags.conf,
/usr/local/etc/ctags.conf, $HOME/.ctags, .ctags, and one optional file,
which can be supplied at configure time.
* Added --filter option.
* Added --filter-terminator option.
ctags-3.2.4 (Thu Jul 01 1999)
* Changed name of macro in Makefile.in to avoid being overriden by CTAGS
environment variable.
ctags-3.2.3 (Mon Jun 21 1999)
* Small portability change for EMX compiler on OS/2.
* Slight change to W32 and BCC makefiles.
ctags-3.2.2 (Sat May 29 1999)
* Fixed endless error loop in the case of unreadable file.
* Fixed redundant include entries in TAGS file when using --etags-include.
ctags-3.2.1 (Wed May 09 1999)
* Fixed problem reading -I token list from file.
* Fixed with "using" declarations which corrupted tag file [C++].
* Fixed configure.in to more reliably recognize existing prototypes.
* Added ability to ignore preprocessor directives in Fortran files.
* Added support for egcs/MingW32 compiler [Win32].
ctags-3.2 (Wed Mar 03 1999)
* Fixed spurious tags related to export specifiers of feature clauses [Eiffel].
* Fixed problem with template in ctor-initialer [C++].
* Fixed typo causing compiler error [MSVC].
* Extended -I option to allow token replacement [thanks to Flemming Madsen].
* Added --etags-include option to support TAGS file includes.
* Added support for QDOS [thanks to Thierry Godefroy].
ctags-3.1.2 (Tue Jan 26 1999)
* Changed extension flags to eliminate space between label and value to remain
true to the intent of the agreement on the extended format made with editor
authors.
* Added --links option to permit ignoring symbolic links.
* Fixed missing tags upon ANSI style variable function argument lists.
* Fixed missing tags for methods with fully qualified type names in argument
list [Java].
* Fixed double tags generated for enumerators followed by comma.
* Fixed missing path prefix for -p option [Win 95/NT].
ctags-3.1 (Wed Jan 20 1999)
* Changed -h and -langmap options to accept a plus sign as the first character
of their arguments to indicate that arguments should be added to current.
* Changed default for member tags to 'on' [C/C++].
* Changed default for local entities to 'off' [Eiffel].
* Added tags for forward class/struct/union/enum declarations when using
-c-types=+x [C/C++].
* Fixed memory overwrite bug causing general protection fault [Win 95/NT].
* Fixed missing tags for methods with throws clause [Java].
* Fixed bad tags generated for null macro names [C].
* Fixed spurious tag for features and entities of BIT type [Eiffel].
* Fixed spurious tags when local entity declaration list was empty [Eiffel].
* Fixed missing tags for contructors and destructors [C++].
* Fixed failure to recognize function when declaration for first argument
was of template type [C++].
ctags-3.0.3 (Mon Dec 21 1998)
* Fixed mistake made in previous version which caused macro tags to be missed.
* Fixed parsing of --langmap option.
ctags-3.0.2 (Mon Dec 21 1998)
* Added tags for names undefined with #undef [C/C++].
* Added tags for renamed features (Eiffel).
* Improved Emacs-style tag file contents (per Ian Zimmerman).
* Fixed problem handling deferred, external, once, obsolete features in Eiffel.
* Fixed porting problem [OSF1 V4.0].
ctags-3.0.1 (Sat Dec 12 1998)
* Fixed problem with certain macros and functions with no declared return type.
* Fixed problem causing endless loop on MSDOS/Win32 by restoring use of binary
mode on opening of source files.
* Fixed porting problems [SunOS 4.1.x and MSVC++ 5.0].
ctags-3.0 (Sun Dec 06 1998)
* Added support for the Eiffel language (everyone should learn Eiffel).
* Added support for the Fortran language.
* Added --c-types option to specify tag types to be included for C/C++.
* Added --eiffel-types option to specify tag types to be included for Eiffel.
* Added --fortran-types option to specify tag types to be included for Fortran.
* Added --file-scope option to place verbose tag description into tag file.
* Added --file-tags option to place tags for source file names into tag file.
* Added --java-types option to specify tag types to be included for Java.
* Added --kind-long option to place verbose tag description into tag file.
* Added --linedirectives option to enable processing of #line directives so
that running ctags on preprocessor output can generate line numbers and file
names which correspond to the original source files.
* Added -V option to enable verbose message for each file considered.
* Added special handling for macros of form "INIT(= value)".
* Added ability to suffix an ignored identifier (-I option) with the '+'
character, thus instructing ctags to also ignore any argument list which
may follow the identifier.
* Changed the -i option, moving Java language options to the new --java-types
option. The -i option is now deprecated in favor of the new language
specific tag type options.
* Changed behavior of handling of ignored identifiers (-I option) to still
generate a tag for any macro definition for that identifier.
* Changed handling of -h option so that include files are no longer assumed to
be C++ files.
* Changed tags for operators to always precede the operator with the string
"operator ", thus making it consistent for all operators. [C++]
* Changed C/C++ parsing, catching many more tricky constructs.
* Changed extension flags to place a space between the label and the value for
readability.
* Fixed core dump which occurred when using -iF (now --file-tags) together
with -e (etags) on a zero-length file.
* Fixed missing or incorrect tags for conversions operators or operator "()".
* Fixed incorrect parent class in extension flags for type declarations of the
form "class Bar { OtherClass::sometype foo; }".
* Fixed missing tags for "friend" and "static" prototypes in header files.
* Fixed problem of external "sort" reporting locale not available on HPUX.
* Fixed -p option.
* Fixed VMS support. It should now work for any source file type.
ctags-2.3.2 (Wed Sep 09 1998)
* Fixed -h option; broken since version 1.7, yet only just reported.
ctags-2.3.1 (Sun Aug 30 1998)
* Fixed improper handling of derived structs.
* Fixed wrong class name tag when a nested-name-specifier was present in class
declaration.
* Added parent information into tag extension flags for data structures to
match that already present for members.
* Add missing documentation for --langmap option in the --help output.
* Eliminated compiler warning [gcc 2.8.1].
ctags-2.3 (Thu Aug 20 1998)
* Eliminated compiler warnings [SGI MIPSpro].
ctags-2.2.7 (Mon Aug 17 1998)
* Fixed porting problem [Borland C++].
ctags-2.2.6 (Wed Aug 12 1998)
* Fixed core dump encountered on some platforms when the CTAGS environment
variable was set but empty.
* Fixed porting problem [MSVC].
* Added directory recursion support for Amiga.
ctags-2.2.3 (Sun Aug 02 1998)
ctags-2.2.2 (Fri Jul 24 1998)
* Fixed porting problems [AIX, HP-UX, OSF/1, SunOS, MSVC].
ctags-2.2.1 (Fri Jul 24 1998)
* Now uses a default directory name of "." when using -R or --recurse option
(e.g. "ctags -R" is equivalent to "ctags -R .").
* Directories named "SCCS" are skipped when using the -R or --recurse option
under Unix.
* Fixed porting problems [HP-UX, IRIX, SunOS, MSDOS/Windows].
ctags-2.2 (Mon Jul 20 1998)
* Added the --recurse and -R options to allow recursing into directories.
This allows running ctags on an entire source directory tree using the
single command "ctags -R <dir>". Currently, this option is only supported on
UNIX, MSDOS, Windows 95/NT, and OS/2. Other platforms will have to wait.
* Changed writing of Emacs-style TAGS file to binary mode [MSDOS/Windows].
* Fixed porting problems [HP-UX, OSF/1].
ctags-2.1.1 (Mon Jul 06 1998)
* Changed -h option to allow only periods to separate extensions.
* Added the --langmap option to allow overriding the default associations
between source language and file extension.
* Added configuration check and code work-around for putenv() prototypes
missing the const from the argument declaration [IRIX 5.2 and CRAY J90].
* Added makefile for VMS.
* Fixed porting problem [HP-UX].
ctags-2.1 (Wed Jul 01 1998)
* Added Java support.
* Eliminated the --keywords option introduced in the 2.0.4, replacing it with
automatic detection of the language (i.e. recognized keywords) based upon
the file extension.
* Added the --lang option for manually overriding the automatic selection of
the language.
* Added new flag 'i' to the -i option to allow generating tags for Java
interfaces.
* Added new flag 'n' to the -i option to allow generating tags for C++
namespaces.
* Added new flag 'x' to the -i option to allow generating tags for extern
variable declarations.
* Added new extension flags, "private", "protected", and "public", which
indicate the visibility of class members when it can be determined.
* Changed behavior of flag 'C' of the -i option to add tags of form
"class.member" for Java.
* Changed how files on command line are handled. Ctags will now only scan
those files whose extensions it knows about unless the --lang option is
specified. This allows running ctags on all files in a directory without
having to be specific (e.g. "ctags *").
* Removed support for duplicate tag warnings and the -w and -W options. These
options are silently ignored for now.
ctags-2.0.4 (Sat May 23 1998)
* Added sorting time to the output of the --totals option.
* Added the --keywords option to allow restricting the recognized
declaration keywords in order to handle legacy source code which uses
newer keywords for variable and parameter names.
* Ignore list now also applies to macro tags.
* /dev/stdout now properly handled as parameter to -f/-o option.
* Fixed problem handling an operator definition in C++ when white space
appeared between the "operator" keyword and the operator (e.g. "=").
* Fixed handling of non-symbolic operators (e.g. "new", "delete", etc.).
* Fixed sort order problem for some locale settings.
* Fixed segmentation violation when using ignore list (-I) on SunOS 4.x.
* Fixed a segmentation violation caused by a stack overwrite when testing a
particular kind of non-standard tag file format.
ctags-2.0.3 (Sun Mar 12 1998)
* Added configure check for "strip" program.
* Added new flag 'C' to the -i option to allow adding extra tags to the tag
file in the form "class::member" for class methods and members.
ctags-2.0.2 (Wed Feb 25 1998)
* Added stripping of installed binary for "install" target.
ctags-2.0.1 (Thu Feb 19 1998)
* Added support for C++.
* Added new flag 'F' to the -i option to allow adding an extra tag for the
basename of each source file supplied to ctags. This provides the ability to
jump to a source file in Vi using ":tag file.c".
* Added new flag 'm' to generate tags for class, structure, and union members
(disabled by default).
* Added several new flags to the -i option to allow finer specification of
which types of tags to include/exclude.
* Added ".hh" extension to the default list of files recognized as header
files.
* Added explicit handling of special gcc construct __attribute((..)),
which could lead to incorrect tag generation.
* Added configure option --disable-extended-format to allow building ctags
with the extended format disabled by default.
* Added configure option --enable-macro-patterns to change the default
behavior of ctags to generate patterns instead of line numbers for macro
(define) tags.
* Changed configure option --enable-internal-sort to --disable-external-sort.
* Changed makefile for OS/2.
* Removed support for the -d, -t and -T options which had been deprecated
for some time.
* Removed ANNOUNCE file in distribution, consolidating it with the README
file.
* Replaced CHANGES file with NEWS for more GNU-like standard distribution.
* Improved the detection of macros of the type generated by Microsoft Visual C
when generating source code. These caused subsequent statements to fail to
have tags generated for them. Still not bullet proof, though.
* Fixed a problem which prevented the use of / as a path separator under MSDOS
and Win 95/NT.
* Fixed problem of blank lines occuring in the tag file.
* Fixed recognition of declarations with parentheses.
* Fixed problem of missing tags for objects within extern "C" blocks.
* Fixed problem in source file counts when using --totals option.
* Extended the length of tag type field in -x output to be more verbose.
* Fixed option initialization error which caused static tags to be excluded.
ctags-1.7 (Mon Oct 13 1997)
* Tag files now use a new extended format which is backwards compatible with
existing Vi implementations, yet provides extended information which can be
used by supporting editors.
* Added documentation pseudo-tags (e.g. !_TAG_FILE_FORMAT) to tag file.
* Added the --excmd option as alternative to the -n and -N options.
* Added the --format option to allow forcing the old-style tag file format.
* Added the --if0 to control how "#if 0" branches are handled.
* Added the --sort option as alternative to -u option.
* Added the --totals option to print statistics of tag generation.
* Added the --version option.
* Improved handling of preprocessor conditionals.
* Code within an #if 0 is now never scanned for non-macro tags by default
since tags within that code could conceivably be overridden by more
desirable tags in the #else branch to follow. Macro tags in these branches
are always included.
* Fixed problem which could leave invalid tag entries in tag file when an
internal re-scan of a source file occurred.
* Fixed problem with internal sort mechanism when appending tags to existing
file.
* Changed external sort command to filter out duplicate identical tags lines
(including the pattern) unless warnings for duplicate tags are enabled.
* Added data to emacs style tag entries to more closely match that produced by
the GNU etags.
* Removed fixed limits on maximum tag line length.
* Correction to Amiga makefile.
* Improvements to Win32 portability with changes to Makefile.w32.
ctags-1.6 (Tue May 13 1997)
* Now using GNU autoconf to permit automatic host configuration.
* Added the -e option to generate Emacs style tag files
* Added ETAGS environment variable to be used when -e option is in effect.
* Added the -p option to supply a default path for source files.
* Fixed problem of incorrect line numbers in tag file when form feeds and
vertical tabs occured in the source file.
* Fixed problem preventing ignoring of identifiers specified via the -I option
when the identifiers were followed by a parameter list in the source code.
* Changed the search patterns generated for #define macros when using -N
option. It now includes the character following the name (or "$" if end of
line) instead of the "\>" used previously. Some editors did not support this
metacharacter for tag searches.
* Removed -u (unique) flag from sort command line invocation to retain exactly
indentical tag patterns in the same file. This is in preparation for editor
support of duplicate tags.
* Fixed problem resulting in no tags generated following a function-like
macro reference outside of a function block.
* Fixed problem of no tags generated for typedef for function or function
pointer.
* Fixed problem of no tags generated after encountering strange function
declarations (e.g. "foo(params) saywhat (void);")
ctags-1.5 (Sat Oct 5 1996)
* Added generation of tags for objects inside C++ extern blocks (e.g.
'extern "C" {...}' construct).
* Added generation of tags for function definitions inside brace-enclosed
("{}") blocks, since function definitions are allowed inside classes and
extern blocks.
* Added the -N option to force patterns to be used for all tags (including
macro tags).
* Changed the search patterns generated for macro definitions to be terminated
with "\>", which allows the pattern to still match even when the #define
line beyond the macro name is changed.
* Fixed problem resulting in no tags generated for files containing a
function-like macro, such as 'MODULE_ID("$Id")', even when ignoring the
keyword. This also fixed a problem that caused tags to be missed for
initialized function pointer definitions.
* Redirected error messages to stdout for MSDOS version.
ctags-1.4 (Sun Aug 18 1996)
* Added recursive parsing of class/struct/enum blocks to look for
class/struct/enum tags and enumeration values.
* Added the -I option to specify keywords to ignore in the source files.
* Fixed problem resulting in no tag generated when declaring a pointer const
or volatile.
* Fixed problem resulting in no tag generated for comma terminated function
declarations.
ctags-1.3 (Sun Jun 16 1996)
* Fixed problem problem which caused "struct tag;" to be misinterpreted as a
variable definition.
* Added the -n option to use line numbers in the tag file instead of patterns.
* Added the -? option as an alternative for the --help option.
ctags-1.2 (Wed Jun 5 1996)
* Fixed a problem caused by an unitialized variable.
ctags-1.1 (Tue Jun 4 1996)
* Fixed problem reading parameter list to the -h option.
ctags-1.0a (Mon Jun 3 1996)
* Added ctags.lsm to distribution
ctags-1.0 (Fri May 31 1996)
* First public release.
vim:tw=78
+73
View File
@@ -0,0 +1,73 @@
Exuberant Ctags
===============
Author: Darren Hiebert <dhiebert at users.sourceforge.net>
http://ctags.sourceforge.net
Instant Messaging:
Yahoo! ID : dbhiebert
AIM ScreenName: darrenhiebert
Exuberant Ctags is a multilanguage reimplementation of the much-underused
ctags(1) program and is intended to be the mother of all ctags programs. It
generates indexes of source code definitions which are used by a number of
editors and tools. The motivation which drove the development of Exuberant
Ctags was the need for a ctags program which supported generation of tags
for all possible C language constructs (which no other ctags offers), and
because most were easily fooled by a number of preprocessor contructs.
Exuberant Ctags offers the following features:
1. It supports the following languages: Assembler, AWK, ASP, BETA,
Bourne/Korn/Z Shell, C, C++, C#, COBOL, Eiffel, Erlang, Fortran, Java, Lisp,
Lua, Makefile, Pascal, Perl, PHP, PL/SQL, Python, REXX, Ruby, Scheme,
S-Lang, SML (Standard ML), Tcl, Vera, Verilog, Vim, and YACC.
2. It is capable of generating tags for virtually all C language constructs.
3. It is very robust in parsing code. In particular, the C/C++ parser is
far less easily fooled by code containing #if preprocessor conditional
constructs, using a conditional path selection algorithm to resolve
complicated situations, and a fall-back algorithm when this one fails.
4. Supports output of Emacs-style TAGS files (i.e. "etags").
5. User-defined languages, using Posix regular expressions.
6. Supports UNIX, MSDOS, Windows 95/98/NT/2000/XP, OS/2, QNX, Amiga, QDOS,
RISC OS, VMS, Macintosh, and Cray. Some pre-compiled binaries are
available on the web site.
Visit the Exuberant Ctags web site:
http://ctags.sourceforge.net
Which brings us to the most obvious question:
Q: Why is it called "Exuberant" ctags?
A: Because one of the meanings of the word is:
exuberant : produced in extreme abundance : PLENTIFUL syn see PROFUSE
Compare the tag file produced by Exuberant Ctags with that produced by any
other ctags and you will see how appropriate the name is.
This source code is distributed according to the terms of the GNU General
Public License. It is provided on an as-is basis and no responsibility is
accepted for its failure to perform as expected. It is worth at least as
much as you paid for it!
Exuberant Ctags was originally derived from and inspired by the ctags
program by Steve Kirkendall ([email protected]) that comes with the Elvis
vi clone (though almost none of the original code remains). This, too, is
freely available.
Please report any problems you find. The two problems I expect to be most
likely are either a tag which you expected but is missing, or a tag created
in error (shouldn't really be a tag). Please include a sample of code (the
definition) for the object which misbehaves.
--
vim:tw=76:sw=4:et:
+127
View File
@@ -0,0 +1,127 @@
/*
* $Id: acconfig.h,v 1.4 2003/04/01 05:02:21 darren Exp $
*
* Copyright (c) 1998-2003, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains input source for generating config.h.in
*/
/* Package name.
*/
#undef PACKAGE
/* Package version.
*/
#undef VERSION
/* Define to the appropriate type if <time.h> does not define this.
*/
#undef clock_t
/* Define to long if <stdio.h> does not define this.
*/
#undef fpos_t
/* Define to the appropriate size for tmpnam() if <stdio.h> does not define
* this.
*/
#undef L_tmpnam
/* Define this macro if the field "st_ino" exists in struct stat in
* <sys/stat.h>.
* */
#undef HAVE_STAT_ST_INO
/* Define remove to unlink if you have unlink(), but not remove().
*/
#undef remove
/* Define this value used by fseek() appropriately if <stdio.h>
* (or <unistd.h> on SunOS 4.1.x) does not define them.
*/
#undef SEEK_SET
/* Define as the maximum integer on your system if not defined <limits.h>.
*/
#undef INT_MAX
/* You can define this label to be a string containing the name of a
* site-specific configuration file containing site-wide default options. The
* files /etc/ctags.conf and /usr/local/etc/ctags.conf are already checked,
* so only define one here if you need a file somewhere else.
*/
#undef CUSTOM_CONFIGURATION_FILE
/* Define this label if you want macro tags (defined lables) to use patterns
* in the EX command by default (original ctags behavior is to use line
* numbers).
*/
#undef MACROS_USE_PATTERNS
/* Define this as desired.
* 1: Original ctags format
* 2: Extended ctags format with extension flags in EX-style comment.
*/
#define DEFAULT_FILE_FORMAT 2
/* Define this label if your system supports starting scripts with a line of
* the form "#! /bin/sh" to select the interpreter to use for the script.
*/
#undef SYS_INTERPRETER
/* Define this label if your system uses case-insensitive file names
*/
#undef CASE_INSENSITIVE_FILENAMES
/* Define this label to use the system sort utility (which is probably more
* efficient) over the internal sorting algorithm.
*/
#ifndef INTERNAL_SORT
# undef EXTERNAL_SORT
#endif
/* If you wish to change the directory in which temporary files are stored,
* define this label to the directory desired.
*/
#undef TMPDIR
/* Define this label if regcomp() is broken.
*/
#undef REGCOMP_BROKEN
/* Define this label if you wish to check the regcomp() function at run time
* for correct behavior. This function is currently broken on Cygwin.
*/
#undef CHECK_REGCOMP
/* This corrects the problem of missing prototypes for certain functions
* in some GNU installations (e.g. SunOS 4.1.x).
*/
#undef __USE_FIXED_PROTOTYPES__
/* Define this is you have a prototype for putenv() in <stdlib.h>, but
* doesn't declare its argument as "const char *".
*/
#undef NON_CONST_PUTENV_PROTOTYPE
/* If you receive error or warning messages indicating that you are missing
* a prototype for, or a type mismatch using, one of the following functions,
* define the appropriate label and remake.
*/
#undef NEED_PROTO_REMOVE
#undef NEED_PROTO_UNLINK
#undef NEED_PROTO_MALLOC
#undef NEED_PROTO_GETENV
#undef NEED_PROTO_FGETPOS
#undef NEED_PROTO_STAT
#undef NEED_PROTO_LSTAT
#undef NEED_PROTO_TRUNCATE
#undef NEED_PROTO_FTRUNCATE
/*----------------------------------------------------------------------------
- Lines below this are automatically generated by autoheader
----------------------------------------------------------------------------*/
/* @TOP@ */
+505
View File
@@ -0,0 +1,505 @@
/*
* $Id: argproc.c,v 1.2 2006/05/30 04:37:11 darren Exp $
*
* Copyright (c) 1989, Mark Pizzolato ([email protected])
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* Provided by Stephen P. Wall <[email protected]>
* Extracted from the VMS port of GNU patch-2.1.
*
* This module provides redirection support for the VAX DECC port of
* Exuberant Ctags.
*/
/*
* @(#)argproc.c 1.0 89/02/01 Mark Pizzolato ([email protected])
*/
#ifndef lint
char argproc_version [] = "@(#)argproc.c VMS uucp Version infopiz-1.0";
#endif
#include <ctype.h>
#include <descrip.h>
#include <dvidef.h>
#include <errno.h>
#include <iodef.h>
#include <lib$routines.h>
#include <starlet.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <syidef.h> /* System Information Definitions */
#define EXIT_OK 1 /* image exit code */
#define EXIT_ERR 0x10000000 /* image exit code */
/*
* getredirection() is intended to aid in porting C programs
* to VMS (Vax-11 C) which does not support '>' and '<'
* I/O redirection, along with a command line pipe mechanism
* using the '|' AND background command execution '&'.
* The piping mechanism will probably work with almost any 'filter' type
* of program. With suitable modification, it may useful for other
* portability problems as well.
*
* Author: Mark Pizzolato [email protected]
* Mods: Steve Wall Don't return a full path unless the
* original filename included a path.
*/
struct list_item
{
struct list_item *next;
char *value;
};
static expand_wild_cards ();
static char *pipe_and_fork ();
int
getredirection (ac, av)
int *ac;
char ***av;
/*
* Process vms redirection arg's. Exit if any error is seen.
* If getredirection() processes an argument, it is erased
* from the vector. getredirection () returns a new argc and argv value.
* In the event that a background command is requested (by a trailing "&"),
* this routine creates a background subprocess, and simply exits the program.
*
* Warning: do not try to simplify the code for vms. The code
* presupposes that getredirection() is called before any data is
* read from stdin or written to stdout.
*
* Normal usage is as follows:
*
* main (argc, argv)
* int argc;
* char *argv [];
* {
* getredirection (&argc, &argv);
* }
*/
{
int argc = *ac; /* Argument Count */
char **argv = *av; /* Argument Vector */
char *ap; /* Argument pointer */
int j; /* argv [] index */
extern int errno; /* Last vms i/o error */
int item_count = 0; /* Count of Items in List */
struct list_item *list_head = 0; /* First Item in List */
struct list_item *list_tail; /* Last Item in List */
char *in = NULL; /* Input File Name */
char *out = NULL; /* Output File Name */
char *outmode = "w"; /* Mode to Open Output File */
int cmargc = 0; /* Piped Command Arg Count */
char **cmargv = NULL;/* Piped Command Arg Vector */
/*
* First handle the case where the last thing on the line ends with
* a '&'. This indicates the desire for the command to be run in a
* subprocess, so we satisfy that desire.
*/
{
extern background_process ();
ap = argv [argc-1];
if (0 == strcmp ("&", ap))
exit (background_process (--argc, argv));
if ('&' == ap [strlen (ap)-1])
{
ap [strlen (ap)-1] = '\0';
exit (background_process (argc, argv));
}
}
/*
* Now we handle the general redirection cases that involve '>', '>>',
* '<', and pipes '|'.
*/
for (j = 0; j < argc; ++j)
{
if (0 == strcmp ("<", argv [j]))
{
if (j+1 >= argc)
{
errno = EINVAL;
perror ("No input file");
exit (EXIT_ERR);
}
in = argv [++j];
continue;
}
if ('<' == *(ap = argv [j]))
{
in = 1 + ap;
continue;
}
if (0 == strcmp (">", ap))
{
if (j+1 >= argc)
{
errno = EINVAL;
perror ("No output file");
exit (EXIT_ERR);
}
out = argv [++j];
continue;
}
if ('>' == *ap)
{
if ('>' == ap [1])
{
outmode = "a";
if ('\0' == ap [2])
out = argv [++j];
else
out = 2 + ap;
}
else
out = 1 + ap;
continue;
}
if (0 == strcmp ("|", argv [j]))
{
if (j+1 >= argc)
{
errno = EPIPE;
perror ("No command to Pipe to");
exit (EXIT_ERR);
}
cmargc = argc- (j+1);
cmargv = &argv [j+1];
argc = j;
continue;
}
if ('|' == *(ap = argv [j]))
{
++argv [j];
cmargc = argc-j;
cmargv = &argv [j];
argc = j;
continue;
}
expand_wild_cards (ap, &list_head, &list_tail, &item_count);
}
/*
* Allocate and fill in the new argument vector, Some Unix's terminate
* the list with an extra null pointer.
*/
argv = *av = calloc (item_count+1, sizeof (char *));
for (j = 0; j < item_count; ++j, list_head = list_head->next)
argv [j] = list_head->value;
*ac = item_count;
if (cmargv != NULL)
{
char subcmd [1024];
if (out != NULL)
{
errno = EINVAL;
perror ("Invalid '|' and '>' specified");
exit (EXIT_ERR);
}
strcpy (subcmd, cmargv [0]);
for (j = 1; j < cmargc; ++j)
{
strcat (subcmd, " \"");
strcat (subcmd, cmargv [j]);
strcat (subcmd, "\"");
}
out = pipe_and_fork (subcmd);
}
if ((in != NULL) && (NULL == freopen (in, "r", stdin, "mbc=32", "mbf=2")))
{
perror (in); /* Can't find file */
exit (EXIT_ERR); /* Is a fatal error */
}
if ((out != NULL) && (NULL == freopen (out, outmode, stdout, "mbc=32", "mbf=2")))
{
perror (ap); /* Error, can't write or append */
exit (EXIT_ERR); /* Is a fatal error */
}
#ifdef DEBUG
fprintf (stderr, "Arglist:\n");
for (j = 0; j < *ac; ++j)
fprintf (stderr, "argv[%d] = '%s'\n", j, argv [j]);
#endif
return 0;
}
static add_item (head, tail, value, count)
struct list_item **head;
struct list_item **tail;
char *value;
int *count;
{
if (*head == 0)
{
if (NULL == (*head = calloc (1, sizeof (**head))))
{
errno = ENOMEM;
perror ("");
exit (EXIT_ERR);
}
*tail = *head;
}
else
if (NULL == ((*tail)->next = calloc (1, sizeof (**head))))
{
errno = ENOMEM;
perror ("");
exit (EXIT_ERR);
}
else
*tail = (*tail)->next;
(*tail)->value = value;
++ (*count);
}
static expand_wild_cards (item, head, tail, count)
char *item;
struct list_item **head;
struct list_item **tail;
int *count;
{
int expcount = 0;
int context = 0;
int status;
int status_value;
char *had_version;
int had_path;
$DESCRIPTOR (filespec, item);
/*$DESCRIPTOR (defaultspec, "SYS$DISK:[]*.*;");*/
$DESCRIPTOR (defaultspec, "");
$DESCRIPTOR (resultspec, "");
if (strcspn (item, "*%") == strlen (item))
{
add_item (head, tail, item, count);
return;
}
resultspec.dsc$b_dtype = DSC$K_DTYPE_T;
resultspec.dsc$b_class = DSC$K_CLASS_D;
resultspec.dsc$a_pointer = NULL;
filespec.dsc$w_length = strlen (item);
/*
* Only return version specs, if the caller specified a version
*/
had_version = strchr (item, ';');
/*
* Only return full path if the caller specified a path
*/
had_path = (strchr (item, ']') || strchr (item, ':'));
while (1 == (1&lib$find_file (&filespec, &resultspec, &context,
&defaultspec, 0, &status_value, &0)))
{
char *string;
char *c;
if (NULL == (string = calloc (1, resultspec.dsc$w_length+1)))
{
errno = ENOMEM;
perror ("");
exit (EXIT_ERR);
}
strncpy (string, resultspec.dsc$a_pointer, resultspec.dsc$w_length);
string [resultspec.dsc$w_length] = '\0';
if (NULL == had_version)
*((char *) strrchr (string, ';')) = '\0';
if (!had_path) {
char *s = strrchr (string, ']');
if ( s == NULL ) s = strrchr (string, ':');
if ( s != NULL ) strcpy (string, s+1);
}
/*
* Be consistent with what the C RTL has already done to the rest of
* the argv items and lowercase all of these names.
*/
for (c = string; *c; ++c)
if (isupper (*c))
*c = tolower (*c);
add_item (head, tail, string, count);
++expcount;
}
if (expcount == 0)
add_item (head, tail, item, count);
lib$sfree1_dd (&resultspec);
lib$find_file_end (&context);
}
static int child_st [2]; /* Event Flag set when child process completes */
static short child_chan;/* I/O Channel for Pipe Mailbox */
static exit_handler (status)
int *status;
{
short iosb [4];
if (0 == child_st [0])
{
#ifdef DEBUG
fprintf (stderr, "Waiting for Child Process to Finnish . . .\n");
#endif
sys$qiow (0, child_chan, IO$_WRITEOF, iosb, 0, 0, 0, 0, 0, 0, 0, 0);
sys$dassgn (child_chan);
fclose (stdout);
sys$synch (0, child_st);
}
}
static sig_child (chan)
int chan;
{
#ifdef DEBUG
fprintf (stderr, "Child Completion AST\n");
#endif
if (child_st [0] == 0)
child_st [0] = 1;
}
static struct exit_control_block
{
struct exit_control_block *flink;
int (*exit_routine) ();
int arg_count;
int *status_address;
int exit_status;
} exit_block =
{
0,
exit_handler,
1,
&exit_block.exit_status,
0
};
static char *pipe_and_fork (cmd)
char *cmd;
{
$DESCRIPTOR (cmddsc, cmd);
static char mbxname [64];
$DESCRIPTOR (mbxdsc, mbxname);
short iosb [4];
int status;
int pid;
struct
{
short dna_buflen;
short dna_itmcod;
char *dna_buffer;
unsigned short *dna_retlen;
int listend;
} itmlst =
{
sizeof (mbxname),
DVI$_DEVNAM,
mbxname,
&mbxdsc.dsc$w_length,
0
};
int mbxsize;
struct
{
short mbf_buflen;
short mbf_itmcod;
int *mbf_maxbuf;
unsigned short *mbf_retlen;
int listend;
} syiitmlst =
{
sizeof (mbxsize),
SYI$_MAXBUF,
&mbxsize,
0,
0
};
cmddsc.dsc$w_length = strlen (cmd);
/*
* Get the SYSGEN parameter MAXBUF, and the smaller of it and 2048 as
* the size of the 'pipe' mailbox.
*/
if (1 == (1& (vaxc$errno = sys$getsyiw (0, 0, 0, &syiitmlst, iosb, 0, 0, 0))))
vaxc$errno = iosb [0];
if (0 == (1&vaxc$errno))
{
errno = EVMSERR;
perror ("Can't get SYSGEN parameter value for MAXBUF");
exit (EXIT_ERR);
}
if (mbxsize > 2048)
mbxsize = 2048;
if (0 == (1& (vaxc$errno = sys$crembx (0, &child_chan, mbxsize, mbxsize, 0, 0, 0))))
{
errno = EVMSERR;
perror ("Can't create pipe mailbox");
exit (EXIT_ERR);
}
if (1 == (1& (vaxc$errno = sys$getdviw (0, child_chan, 0, &itmlst, iosb,
0, 0, 0))))
vaxc$errno = iosb [0];
if (0 == (1&vaxc$errno))
{
errno = EVMSERR;
perror ("Can't get pipe mailbox device name");
exit (EXIT_ERR);
}
mbxname [mbxdsc.dsc$w_length] = '\0';
#ifdef DEBUG
fprintf (stderr, "Pipe Mailbox Name = '%s'\n", mbxname);
#endif
if (0 == (1& (vaxc$errno = lib$spawn (&cmddsc, &mbxdsc, 0, &1,
0, &pid, child_st, &0, sig_child,
&child_chan))))
{
errno = EVMSERR;
perror ("Can't spawn subprocess");
exit (EXIT_ERR);
}
#ifdef DEBUG
fprintf (stderr, "Subprocess's Pid = %08X\n", pid);
#endif
sys$dclexh (&exit_block);
return (mbxname);
}
background_process (argc, argv)
int argc;
char **argv;
{
char command [2048] = "$";
$DESCRIPTOR (value, command);
$DESCRIPTOR (cmd, "BACKGROUND$COMMAND");
$DESCRIPTOR (null, "NLA0:");
int pid;
strcat (command, argv [0]);
while (--argc)
{
strcat (command, " \"");
strcat (command, *(++argv));
strcat (command, "\"");
}
value.dsc$w_length = strlen (command);
if (0 == (1& (vaxc$errno = lib$set_symbol (&cmd, &value))))
{
errno = EVMSERR;
perror ("Can't create symbol for subprocess command");
exit (EXIT_ERR);
}
if (0 == (1& (vaxc$errno = lib$spawn (&cmd, &null, 0, &17, 0, &pid))))
{
errno = EVMSERR;
perror ("Can't spawn subprocess");
exit (EXIT_ERR);
}
#ifdef DEBUG
fprintf (stderr, "%s\n", command);
#endif
fprintf (stderr, "%08X\n", pid);
return (EXIT_OK);
}
/* vi:set tabstop=4 shiftwidth=4: */
+273
View File
@@ -0,0 +1,273 @@
/*
* $Id: args.c,v 1.7 2006/05/30 04:37:11 darren Exp $
*
* Copyright (c) 1999-2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for reading command line arguments.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "args.h"
#include "debug.h"
#include "routines.h"
/*
* FUNCTION DEFINITIONS
*/
static char *nextStringArg (const char** const next)
{
char* result = NULL;
const char* start;
Assert (*next != NULL);
for (start = *next ; isspace ((int) *start) ; ++start)
;
if (*start == '\0')
*next = start;
else
{
size_t length;
const char* end;
for (end = start ; *end != '\0' && ! isspace ((int) *end) ; ++end)
;
length = end - start;
Assert (length > 0);
result = xMalloc (length + 1, char);
strncpy (result, start, length);
result [length] = '\0';
*next = end;
}
return result;
}
static char* nextStringLine (const char** const next)
{
char* result = NULL;
size_t length;
const char* end;
Assert (*next != NULL);
for (end = *next ; *end != '\n' && *end != '\0' ; ++end)
;
length = end - *next;
if (length > 0)
{
result = xMalloc (length + 1, char);
strncpy (result, *next, length);
result [length] = '\0';
}
if (*end == '\n')
++end;
else if (*end == '\r')
{
++end;
if (*end == '\n')
++end;
}
*next = end;
return result;
}
static char* nextString (const Arguments* const current, const char** const next)
{
char* result;
if (current->lineMode)
result = nextStringLine (next);
else
result = nextStringArg (next);
return result;
}
static char* nextFileArg (FILE* const fp)
{
char* result = NULL;
Assert (fp != NULL);
if (! feof (fp))
{
vString* vs = vStringNew ();
int c;
do
c = fgetc (fp);
while (isspace (c));
if (c != EOF)
{
do
{
vStringPut (vs, c);
c = fgetc (fp);
} while (c != EOF && ! isspace (c));
vStringTerminate (vs);
Assert (vStringLength (vs) > 0);
result = xMalloc (vStringLength (vs) + 1, char);
strcpy (result, vStringValue (vs));
}
vStringDelete (vs);
}
return result;
}
static char* nextFileLine (FILE* const fp)
{
char* result = NULL;
if (! feof (fp))
{
vString* vs = vStringNew ();
int c;
Assert (fp != NULL);
c = fgetc (fp);
while (c != EOF)
{
if (c != '\n' && c != '\r')
vStringPut (vs, c);
else if (vStringLength (vs) > 0)
break;
c = fgetc (fp);
}
if (c != EOF || vStringLength (vs) > 0)
{
if (c == '\r')
{
c = fgetc (fp);
if (c != '\n')
c = ungetc (c, fp);
}
vStringTerminate (vs);
result = xMalloc (vStringLength (vs) + 1, char);
strcpy (result, vStringValue (vs));
vStringDelete (vs);
}
}
return result;
}
static char* nextFileString (const Arguments* const current, FILE* const fp)
{
char* result;
if (current->lineMode)
result = nextFileLine (fp);
else
result = nextFileArg (fp);
return result;
}
extern Arguments* argNewFromString (const char* const string)
{
Arguments* result = xMalloc (1, Arguments);
memset (result, 0, sizeof (Arguments));
result->type = ARG_STRING;
result->u.stringArgs.string = string;
result->u.stringArgs.item = string;
result->u.stringArgs.next = string;
result->item = nextString (result, &result->u.stringArgs.next);
return result;
}
extern Arguments* argNewFromArgv (char* const* const argv)
{
Arguments* result = xMalloc (1, Arguments);
memset (result, 0, sizeof (Arguments));
result->type = ARG_ARGV;
result->u.argvArgs.argv = argv;
result->u.argvArgs.item = result->u.argvArgs.argv;
result->item = *result->u.argvArgs.item;
return result;
}
extern Arguments* argNewFromFile (FILE* const fp)
{
Arguments* result = xMalloc (1, Arguments);
memset (result, 0, sizeof (Arguments));
result->type = ARG_FILE;
result->u.fileArgs.fp = fp;
result->item = nextFileString (result, result->u.fileArgs.fp);
return result;
}
extern Arguments* argNewFromLineFile (FILE* const fp)
{
Arguments* result = xMalloc (1, Arguments);
memset (result, 0, sizeof (Arguments));
result->type = ARG_FILE;
result->lineMode = TRUE;
result->u.fileArgs.fp = fp;
result->item = nextFileString (result, result->u.fileArgs.fp);
return result;
}
extern char *argItem (const Arguments* const current)
{
Assert (current != NULL);
Assert (! argOff (current));
return current->item;
}
extern boolean argOff (const Arguments* const current)
{
Assert (current != NULL);
return (boolean) (current->item == NULL);
}
extern void argSetWordMode (Arguments* const current)
{
Assert (current != NULL);
current->lineMode = FALSE;
}
extern void argSetLineMode (Arguments* const current)
{
Assert (current != NULL);
current->lineMode = TRUE;
}
extern void argForth (Arguments* const current)
{
Assert (current != NULL);
Assert (! argOff (current));
switch (current->type)
{
case ARG_STRING:
if (current->item != NULL)
eFree (current->item);
current->u.stringArgs.item = current->u.stringArgs.next;
current->item = nextString (current, &current->u.stringArgs.next);
break;
case ARG_ARGV:
++current->u.argvArgs.item;
current->item = *current->u.argvArgs.item;
break;
case ARG_FILE:
if (current->item != NULL)
eFree (current->item);
current->item = nextFileString (current, current->u.fileArgs.fp);
break;
default:
Assert ("Invalid argument type" == NULL);
break;
}
}
extern void argDelete (Arguments* const current)
{
Assert (current != NULL);
if (current->type == ARG_STRING && current->item != NULL)
eFree (current->item);
memset (current, 0, sizeof (Arguments));
eFree (current);
}
/* vi:set tabstop=4 shiftwidth=4: */
+63
View File
@@ -0,0 +1,63 @@
/*
* $Id: args.h,v 1.5 2006/05/30 04:37:11 darren Exp $
*
* Copyright (c) 1999-2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* Defines external interface to command line argument reading.
*/
#ifndef _ARGS_H
#define _ARGS_H
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <stdio.h>
/*
* DATA DECLARATIONS
*/
typedef enum { ARG_NONE, ARG_STRING, ARG_ARGV, ARG_FILE } argType;
typedef struct sArgs {
argType type;
union {
struct sStringArgs {
const char* string;
const char* next;
const char* item;
} stringArgs;
struct sArgvArgs {
char* const* argv;
char* const* item;
} argvArgs;
struct sFileArgs {
FILE* fp;
} fileArgs;
} u;
char* item;
boolean lineMode;
} Arguments;
/*
* FUNCTION PROTOTYPES
*/
extern Arguments* argNewFromString (const char* const string);
extern Arguments* argNewFromArgv (char* const* const argv);
extern Arguments* argNewFromFile (FILE* const fp);
extern Arguments* argNewFromLineFile (FILE* const fp);
extern char *argItem (const Arguments* const current);
extern boolean argOff (const Arguments* const current);
extern void argSetWordMode (Arguments* const current);
extern void argSetLineMode (Arguments* const current);
extern void argForth (Arguments* const current);
extern void argDelete (Arguments* const current);
#endif /* _ARGS_H */
/* vi:set tabstop=4 shiftwidth=4: */
+388
View File
@@ -0,0 +1,388 @@
/*
* $Id: asm.c,v 1.18 2006/05/30 04:37:11 darren Exp $
*
* Copyright (c) 2000-2003, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for generating tags for assembly language
* files.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#include "debug.h"
#include "keyword.h"
#include "parse.h"
#include "read.h"
#include "routines.h"
#include "vstring.h"
/*
* DATA DECLARATIONS
*/
typedef enum {
K_NONE = -1, K_DEFINE, K_LABEL, K_MACRO, K_TYPE
} AsmKind;
typedef enum {
OP_UNDEFINED = -1,
OP_ALIGN,
OP_COLON_EQUAL,
OP_END,
OP_ENDM,
OP_ENDMACRO,
OP_ENDP,
OP_ENDS,
OP_EQU,
OP_EQUAL,
OP_LABEL,
OP_MACRO,
OP_PROC,
OP_RECORD,
OP_SECTIONS,
OP_SET,
OP_STRUCT,
OP_LAST
} opKeyword;
typedef struct {
const char *operator;
opKeyword keyword;
} asmKeyword;
typedef struct {
opKeyword keyword;
AsmKind kind;
} opKind;
/*
* DATA DEFINITIONS
*/
static langType Lang_asm;
static kindOption AsmKinds [] = {
{ TRUE, 'd', "define", "defines" },
{ TRUE, 'l', "label", "labels" },
{ TRUE, 'm', "macro", "macros" },
{ TRUE, 't', "type", "types (structs and records)" }
};
static const asmKeyword AsmKeywords [] = {
{ "align", OP_ALIGN },
{ "endmacro", OP_ENDMACRO },
{ "endm", OP_ENDM },
{ "end", OP_END },
{ "endp", OP_ENDP },
{ "ends", OP_ENDS },
{ "equ", OP_EQU },
{ "label", OP_LABEL },
{ "macro", OP_MACRO },
{ ":=", OP_COLON_EQUAL },
{ "=", OP_EQUAL },
{ "proc", OP_PROC },
{ "record", OP_RECORD },
{ "sections", OP_SECTIONS },
{ "set", OP_SET },
{ "struct", OP_STRUCT }
};
static const opKind OpKinds [] = {
/* must be ordered same as opKeyword enumeration */
{ OP_ALIGN, K_NONE },
{ OP_COLON_EQUAL, K_DEFINE },
{ OP_END, K_NONE },
{ OP_ENDM, K_NONE },
{ OP_ENDMACRO, K_NONE },
{ OP_ENDP, K_NONE },
{ OP_ENDS, K_NONE },
{ OP_EQU, K_DEFINE },
{ OP_EQUAL, K_DEFINE },
{ OP_LABEL, K_LABEL },
{ OP_MACRO, K_MACRO },
{ OP_PROC, K_LABEL },
{ OP_RECORD, K_TYPE },
{ OP_SECTIONS, K_NONE },
{ OP_SET, K_DEFINE },
{ OP_STRUCT, K_TYPE }
};
/*
* FUNCTION DEFINITIONS
*/
static void buildAsmKeywordHash (void)
{
const size_t count = sizeof (AsmKeywords) / sizeof (AsmKeywords [0]);
size_t i;
for (i = 0 ; i < count ; ++i)
{
const asmKeyword* const p = AsmKeywords + i;
addKeyword (p->operator, Lang_asm, (int) p->keyword);
}
}
static opKeyword analyzeOperator (const vString *const op)
{
static vString *keyword = NULL;
opKeyword result = OP_UNDEFINED;
if (keyword == NULL)
keyword = vStringNew ();
vStringCopyToLower (keyword, op);
result = (opKeyword) lookupKeyword (vStringValue (keyword), Lang_asm);
return result;
}
static boolean isInitialSymbolCharacter (int c)
{
return (boolean) (c != '\0' && (isalpha (c) || strchr ("_$", c) != NULL));
}
static boolean isSymbolCharacter (int c)
{
/* '?' character is allowed in AMD 29K family */
return (boolean) (c != '\0' && (isalnum (c) || strchr ("_$?", c) != NULL));
}
static boolean readPreProc (const unsigned char *const line)
{
boolean result;
const unsigned char *cp = line;
vString *name = vStringNew ();
while (isSymbolCharacter ((int) *cp))
{
vStringPut (name, *cp);
++cp;
}
vStringTerminate (name);
result = (boolean) (strcmp (vStringValue (name), "define") == 0);
if (result)
{
while (isspace ((int) *cp))
++cp;
vStringClear (name);
while (isSymbolCharacter ((int) *cp))
{
vStringPut (name, *cp);
++cp;
}
vStringTerminate (name);
makeSimpleTag (name, AsmKinds, K_DEFINE);
}
vStringDelete (name);
return result;
}
static AsmKind operatorKind (
const vString *const operator,
boolean *const found)
{
AsmKind result = K_NONE;
const opKeyword kw = analyzeOperator (operator);
*found = (boolean) (kw != OP_UNDEFINED);
if (*found)
{
result = OpKinds [kw].kind;
Assert (OpKinds [kw].keyword == kw);
}
return result;
}
/* We must check for "DB", "DB.L", "DCB.W" (68000)
*/
static boolean isDefineOperator (const vString *const operator)
{
const unsigned char *const op =
(unsigned char*) vStringValue (operator);
const size_t length = vStringLength (operator);
const boolean result = (boolean) (length > 0 &&
toupper ((int) *op) == 'D' &&
(length == 2 ||
(length == 4 && (int) op [2] == '.') ||
(length == 5 && (int) op [3] == '.')));
return result;
}
static void makeAsmTag (
const vString *const name,
const vString *const operator,
const boolean labelCandidate,
const boolean nameFollows)
{
if (vStringLength (name) > 0)
{
boolean found;
const AsmKind kind = operatorKind (operator, &found);
if (found)
{
if (kind != K_NONE)
makeSimpleTag (name, AsmKinds, kind);
}
else if (isDefineOperator (operator))
{
if (! nameFollows)
makeSimpleTag (name, AsmKinds, K_DEFINE);
}
else if (labelCandidate)
{
operatorKind (name, &found);
if (! found)
makeSimpleTag (name, AsmKinds, K_LABEL);
}
}
}
static const unsigned char *readSymbol (
const unsigned char *const start,
vString *const sym)
{
const unsigned char *cp = start;
vStringClear (sym);
if (isInitialSymbolCharacter ((int) *cp))
{
while (isSymbolCharacter ((int) *cp))
{
vStringPut (sym, *cp);
++cp;
}
vStringTerminate (sym);
}
return cp;
}
static const unsigned char *readOperator (
const unsigned char *const start,
vString *const operator)
{
const unsigned char *cp = start;
vStringClear (operator);
while (*cp != '\0' && ! isspace ((int) *cp))
{
vStringPut (operator, *cp);
++cp;
}
vStringTerminate (operator);
return cp;
}
static void findAsmTags (void)
{
vString *name = vStringNew ();
vString *operator = vStringNew ();
const unsigned char *line;
boolean inCComment = FALSE;
while ((line = fileReadLine ()) != NULL)
{
const unsigned char *cp = line;
boolean labelCandidate = (boolean) (! isspace ((int) *cp));
boolean nameFollows = FALSE;
const boolean isComment = (boolean)
(*cp != '\0' && strchr (";*@", *cp) != NULL);
/* skip comments */
if (strncmp ((const char*) cp, "/*", (size_t) 2) == 0)
{
inCComment = TRUE;
cp += 2;
}
if (inCComment)
{
do
{
if (strncmp ((const char*) cp, "*/", (size_t) 2) == 0)
{
inCComment = FALSE;
cp += 2;
break;
}
++cp;
} while (*cp != '\0');
}
if (isComment || inCComment)
continue;
/* read preprocessor defines */
if (*cp == '#')
{
++cp;
readPreProc (cp);
continue;
}
/* skip white space */
while (isspace ((int) *cp))
++cp;
/* read symbol */
cp = readSymbol (cp, name);
if (vStringLength (name) > 0 && *cp == ':')
{
labelCandidate = TRUE;
++cp;
}
if (! isspace ((int) *cp) && *cp != '\0')
continue;
/* skip white space */
while (isspace ((int) *cp))
++cp;
/* skip leading dot */
#if 0
if (*cp == '.')
++cp;
#endif
cp = readOperator (cp, operator);
/* attempt second read of symbol */
if (vStringLength (name) == 0)
{
while (isspace ((int) *cp))
++cp;
cp = readSymbol (cp, name);
nameFollows = TRUE;
}
makeAsmTag (name, operator, labelCandidate, nameFollows);
}
vStringDelete (name);
vStringDelete (operator);
}
static void initialize (const langType language)
{
Lang_asm = language;
buildAsmKeywordHash ();
}
extern parserDefinition* AsmParser (void)
{
static const char *const extensions [] = {
"asm", "ASM", "s", "S", NULL
};
static const char *const patterns [] = {
"*.A51",
"*.29[kK]",
"*.[68][68][kKsSxX]",
"*.[xX][68][68]",
NULL
};
parserDefinition* def = parserNew ("Asm");
def->kinds = AsmKinds;
def->kindCount = KIND_COUNT (AsmKinds);
def->extensions = extensions;
def->patterns = patterns;
def->parser = findAsmTags;
def->initialize = initialize;
return def;
}
/* vi:set tabstop=4 shiftwidth=4: */
+211
View File
@@ -0,0 +1,211 @@
/*
* $Id: asp.c,v 1.8 2006/05/30 04:37:11 darren Exp $
*
* Copyright (c) 2000, Patrick Dehne <[email protected]>
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for generating tags for the ASP (Active
* Server Pages) web page scripting language.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#include "parse.h"
#include "read.h"
#include "vstring.h"
/*
* DATA DEFINITIONS
*/
typedef enum {
K_CONST, K_FUNCTION, K_SUB, K_DIM
} aspKind;
static kindOption AspKinds [] = {
{ TRUE, 'c', "constant", "constants"},
{ TRUE, 'f', "function", "functions"},
{ TRUE, 's', "subroutine", "subroutines"},
{ TRUE, 'v', "variable", "variables"}
};
/*
* FUNCTION DEFINITIONS
*/
static void findAspTags (void)
{
vString *name = vStringNew ();
const unsigned char *line;
while ((line = fileReadLine ()) != NULL)
{
const unsigned char *cp = line;
while (*cp != '\0')
{
/* jump over whitespace */
while (isspace ((int)*cp))
cp++;
/* jump over strings */
if (*cp == '"')
{
cp++;
while (*cp!='"' && *cp!='\0')
cp++;
}
/* jump over comments */
else if (*cp == '\'')
break;
/* jump over end function/sub lines */
else if (strncasecmp ((const char*) cp, "end", (size_t) 3)== 0)
{
cp += 3;
if (isspace ((int)*cp))
{
while (isspace ((int)*cp))
++cp;
if (strncasecmp ((const char*) cp, "function", (size_t) 8) == 0)
{
cp+=8;
break;
}
else if (strncasecmp ((const char*) cp, "sub", (size_t) 3) == 0)
{
cp+=3;
break;
}
}
}
/* jump over exit function/sub lines */
else if (strncasecmp ((const char*) cp, "exit", (size_t) 4)==0)
{
cp += 4;
if (isspace ((int) *cp))
{
while (isspace ((int) *cp))
++cp;
if (strncasecmp ((const char*) cp, "function", (size_t) 8) == 0)
{
cp+=8;
break;
}
else if (strncasecmp ((const char*) cp, "sub", (size_t) 3) == 0)
{
cp+=3;
break;
}
}
}
/* function? */
else if (strncasecmp ((const char*) cp, "function", (size_t) 8) == 0)
{
cp += 8;
if (isspace ((int) *cp))
{
while (isspace ((int) *cp))
++cp;
while (isalnum ((int) *cp) || *cp == '_')
{
vStringPut (name, (int) *cp);
++cp;
}
vStringTerminate (name);
makeSimpleTag (name, AspKinds, K_FUNCTION);
vStringClear (name);
}
}
/* sub? */
else if (strncasecmp ((const char*) cp, "sub", (size_t) 3) == 0)
{
cp += 3;
if (isspace ((int) *cp))
{
while (isspace ((int) *cp))
++cp;
while (isalnum ((int) *cp) || *cp == '_')
{
vStringPut (name, (int) *cp);
++cp;
}
vStringTerminate (name);
makeSimpleTag (name, AspKinds, K_SUB);
vStringClear (name);
}
}
/* dim variable? */
else if (strncasecmp ((const char*) cp, "dim", (size_t) 3) == 0)
{
cp += 3;
if (isspace ((int) *cp))
{
while (isspace ((int) *cp))
++cp;
while (isalnum ((int) *cp) || *cp == '_')
{
vStringPut (name, (int) *cp);
++cp;
}
vStringTerminate (name);
makeSimpleTag (name, AspKinds, K_DIM);
vStringClear (name);
}
}
/* const declaration? */
else if (strncasecmp ((const char*) cp, "const", (size_t) 5) == 0)
{
cp += 5;
if (isspace ((int) *cp))
{
while (isspace ((int) *cp))
++cp;
while (isalnum ((int) *cp) || *cp == '_')
{
vStringPut (name, (int) *cp);
++cp;
}
vStringTerminate (name);
makeSimpleTag (name, AspKinds, K_CONST);
vStringClear (name);
}
}
/* nothing relevant */
else if (*cp != '\0')
cp++;
}
}
vStringDelete (name);
}
extern parserDefinition* AspParser (void)
{
static const char *const extensions [] = { "asp", "asa", NULL };
parserDefinition* def = parserNew ("Asp");
def->kinds = AspKinds;
def->kindCount = KIND_COUNT (AspKinds);
def->extensions = extensions;
def->parser = findAspTags;
return def;
}
/* vi:set tabstop=4 shiftwidth=4: */
+81
View File
@@ -0,0 +1,81 @@
/*
* $Id: awk.c,v 1.3 2006/05/30 04:37:11 darren Exp $
*
* Copyright (c) 2000-2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for generating tags for AWK functions.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#include "parse.h"
#include "read.h"
#include "vstring.h"
/*
* DATA DEFINITIONS
*/
typedef enum eAwkKinds {
K_FUNCTION
} awkKind;
static kindOption AwkKinds [] = {
{ TRUE, 'f', "function", "functions" }
};
/*
* FUNCTION DEFINITIONS
*/
static void findAwkTags (void)
{
vString *name = vStringNew ();
const unsigned char *line;
while ((line = fileReadLine ()) != NULL)
{
if (strncmp ((const char*) line, "function", (size_t) 8) == 0 &&
isspace ((int) line [8]))
{
const unsigned char *cp = line + 8;
while (isspace ((int) *cp))
++cp;
while (isalnum ((int) *cp) || *cp == '_')
{
vStringPut (name, (int) *cp);
++cp;
}
vStringTerminate (name);
while (isspace ((int) *cp))
++cp;
if (*cp == '(')
makeSimpleTag (name, AwkKinds, K_FUNCTION);
vStringClear (name);
if (*cp != '\0')
++cp;
}
}
vStringDelete (name);
}
extern parserDefinition* AwkParser ()
{
static const char *const extensions [] = { "awk", "gawk", "mawk", NULL };
parserDefinition* def = parserNew ("Awk");
def->kinds = AwkKinds;
def->kindCount = KIND_COUNT (AwkKinds);
def->extensions = extensions;
def->parser = findAwkTags;
return def;
}
/* vi:set tabstop=4 shiftwidth=4: */
+320
View File
@@ -0,0 +1,320 @@
/*
* $Id: beta.c,v 1.7 2006/05/30 04:37:11 darren Exp $
*
* Copyright (c) 1999-2000, Mjølner Informatics
*
* Written by Erik Corry <[email protected]>
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for generating tags for BETA language
* files.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#include "entry.h"
#include "parse.h"
#include "read.h"
#include "routines.h"
#include "vstring.h"
/*
* MACROS
*/
#define isbident(c) (identarray [(unsigned char) (c)])
/*
* DATA DEFINITIONS
*/
typedef enum {
K_FRAGMENT, K_PATTERN, K_SLOT, K_VIRTUAL
} betaKind;
static kindOption BetaKinds [] = {
{ TRUE, 'f', "fragment", "fragment definitions"},
{ FALSE, 'p', "pattern", "all patterns"},
{ TRUE, 's', "slot", "slots (fragment uses)"},
{ TRUE, 'v', "virtual", "patterns (virtual or rebound)"}
};
/* [A-Z_a-z0-9] */
static const char identarray [256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0-15 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16-31 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 32-47 !"#$%&'()*+'-./ */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 48-63 0123456789:;<=>? */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 64-79 @ABCDEFGHIJKLMNO */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 80-95 PQRSTUVWXYZ [\]^_ */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 96-111 `abcdefghijklmno */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 112-127 pqrstuvwxyz{|}~ */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128- */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* -255 */
/*
* FUNCTION DEFINITIONS
*/
static void makeBetaTag (const char* const name, const betaKind kind)
{
if (BetaKinds [kind].enabled)
{
tagEntryInfo e;
initTagEntry (&e, name);
e.kindName = BetaKinds [kind].name;
e.kind = BetaKinds [kind].letter;
makeTagEntry (&e);
}
}
static void findBetaTags (void)
{
vString *line = vStringNew ();
boolean incomment = FALSE;
boolean inquote = FALSE;
boolean dovirtuals = BetaKinds [K_VIRTUAL].enabled;
boolean dopatterns = BetaKinds [K_PATTERN].enabled;
do
{
boolean foundfragmenthere = FALSE;
/* find fragment definition (line that starts and ends with --) */
int last;
int first;
int c;
vStringClear (line);
while ((c = fileGetc ()) != EOF && c != '\n' && c != '\r')
vStringPut (line, c);
vStringTerminate (line);
last = vStringLength (line) - 1;
first = 0;
/* skip white space at start and end of line */
while (last && isspace ((int) vStringChar (line, last))) last--;
while (first < last && isspace ((int) vStringChar (line, first))) first++;
/* if line still has a reasonable length and ... */
if (last - first > 4 &&
(vStringChar (line, first) == '-' &&
vStringChar (line, first + 1) == '-' &&
vStringChar (line, last) == '-' &&
vStringChar (line, last - 1) == '-'))
{
if (!incomment && !inquote)
{
foundfragmenthere = TRUE;
/* skip past -- and whitespace. Also skip back past 'dopart'
or 'attributes' to the :. We have to do this because there
is no sensible way to include whitespace in a ctags token
so the conventional space after the ':' would mess us up */
last -= 2;
first += 2;
while (last && vStringChar (line, last) != ':') last--;
while (last && (isspace ((int) vStringChar (line, last-1)))) last--;
while (first < last &&
(isspace ((int) vStringChar (line, first)) ||
vStringChar (line, first) == '-'))
first++;
/* If there's anything left it is a fragment title */
if (first < last - 1)
{
vStringChar (line, last) = 0;
if (strcasecmp ("LIB", vStringValue (line) + first) &&
strcasecmp ("PROGRAM", vStringValue (line) + first))
{
makeBetaTag (vStringValue (line) + first, K_FRAGMENT);
}
}
}
} else {
int pos = 0;
int len = vStringLength (line);
if (inquote) goto stringtext;
if (incomment) goto commenttext;
programtext:
for ( ; pos < len; pos++)
{
if (vStringChar (line, pos) == '\'')
{
pos++;
inquote = TRUE;
goto stringtext;
}
if (vStringChar (line, pos) == '{')
{
pos++;
incomment = TRUE;
goto commenttext;
}
if (vStringChar (line, pos) == '(' && pos < len - 1 &&
vStringChar (line, pos+1) == '*')
{
pos +=2;
incomment = TRUE;
goto commenttext;
}
/*
* SLOT definition looks like this:
* <<SLOT nameofslot: dopart>>
* or
* <<SLOT nameofslot: descriptor>>
*/
if (!foundfragmenthere &&
vStringChar (line, pos) == '<' &&
pos+1 < len &&
vStringChar (line, pos+1) == '<' &&
strstr (vStringValue (line) + pos, ">>"))
{
/* Found slot name, get start and end */
int eoname;
char c2;
pos += 2; /* skip past << */
/* skip past space before SLOT */
while (pos < len && isspace ((int) vStringChar (line, pos)))
pos++;
/* skip past SLOT */
if (pos+4 <= len &&
!strncasecmp (vStringValue(line) + pos, "SLOT", (size_t)4))
pos += 4;
/* skip past space after SLOT */
while (pos < len && isspace ((int) vStringChar (line, pos)))
pos++;
eoname = pos;
/* skip to end of name */
while (eoname < len &&
(c2 = vStringChar (line, eoname)) != '>' &&
c2 != ':' &&
!isspace ((int) c2))
eoname++;
if (eoname < len)
{
vStringChar (line, eoname) = 0;
if (strcasecmp ("LIB", vStringValue (line) + pos) &&
strcasecmp ("PROGRAM", vStringValue (line) + pos) &&
strcasecmp ("SLOT", vStringValue (line) + pos))
{
makeBetaTag (vStringValue (line) + pos, K_SLOT);
}
}
if (eoname+1 < len) {
pos = eoname + 1;
} else {
pos = len;
continue;
}
}
/* Only patterns that are virtual, extensions of virtuals or
* final bindings are normally included so as not to overload
* totally.
* That means one of the forms name:: name:< or name::<
*/
if (!foundfragmenthere &&
vStringChar (line, pos) == ':' &&
(dopatterns ||
(dovirtuals &&
(vStringChar (line, pos+1) == ':' ||
vStringChar (line, pos+1) == '<')
)
)
)
{
/* Found pattern name, get start and end */
int eoname = pos;
int soname;
while (eoname && isspace ((int) vStringChar (line, eoname-1)))
eoname--;
foundanothername:
/* terminate right after name */
vStringChar (line, eoname) = 0;
soname = eoname;
while (soname &&
isbident (vStringChar (line, soname-1)))
{
soname--;
}
if (soname != eoname)
{
makeBetaTag (vStringValue (line) + soname, K_PATTERN);
/* scan back past white space */
while (soname &&
isspace ((int) vStringChar (line, soname-1)))
soname--;
if (soname && vStringChar (line, soname-1) == ',')
{
/* we found a new pattern name before comma */
eoname = soname;
goto foundanothername;
}
}
}
}
goto endofline;
commenttext:
for ( ; pos < len; pos++)
{
if (vStringChar (line, pos) == '*' && pos < len - 1 &&
vStringChar (line, pos+1) == ')')
{
pos += 2;
incomment = FALSE;
goto programtext;
}
if (vStringChar (line, pos) == '}')
{
pos++;
incomment = FALSE;
goto programtext;
}
}
goto endofline;
stringtext:
for ( ; pos < len; pos++)
{
if (vStringChar (line, pos) == '\\')
{
if (pos < len - 1) pos++;
}
else if (vStringChar (line, pos) == '\'')
{
pos++;
/* support obsolete '' syntax */
if (pos < len && vStringChar (line, pos) == '\'')
{
continue;
}
inquote = FALSE;
goto programtext;
}
}
}
endofline:
inquote = FALSE; /* This shouldn't really make a difference */
} while (!feof (File.fp));
}
extern parserDefinition* BetaParser (void)
{
static const char *const extensions [] = { "bet", NULL };
parserDefinition* def = parserNew ("BETA");
def->kinds = BetaKinds;
def->kindCount = KIND_COUNT (BetaKinds);
def->extensions = extensions;
def->parser = findBetaTags;
return def;
}
/* vi:set tabstop=4 shiftwidth=4: */
+2838
View File
File diff suppressed because it is too large Load Diff
+50
View File
@@ -0,0 +1,50 @@
/*
* $Id: cobol.c,v 1.6 2006/05/30 04:37:11 darren Exp $
*
* Copyright (c) 2000-2003, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for generating tags for COBOL language
* files.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include "parse.h"
/*
* FUNCTION DEFINITIONS
*/
static void installCobolRegex (const langType language)
{
addTagRegex (language, "^[ \t]*[0-9]+[ \t]+([A-Z0-9][A-Z0-9-]*)[ \t]+(BLANK|OCCURS|IS|JUST|PIC|REDEFINES|RENAMES|SIGN|SYNC|USAGE|VALUE)",
"\\1", "d,data,data items", "i");
addTagRegex (language, "^[ \t]*[FSR]D[ \t]+([A-Z0-9][A-Z0-9-]*)\\.",
"\\1", "f,file,file descriptions (FD, SD, RD)", "i");
addTagRegex (language, "^[ \t]*[0-9]+[ \t]+([A-Z0-9][A-Z0-9-]*)\\.",
"\\1", "g,group,group items", "i");
addTagRegex (language, "^[ \t]*([A-Z0-9][A-Z0-9-]*)\\.",
"\\1", "p,paragraph,paragraphs", "i");
addTagRegex (language, "^[ \t]*PROGRAM-ID\\.[ \t]+([A-Z0-9][A-Z0-9-]*)\\.",
"\\1", "P,program,program ids", "i");
addTagRegex (language, "^[ \t]*([A-Z0-9][A-Z0-9-]*)[ \t]+SECTION\\.",
"\\1", "s,section,sections", "i");
}
extern parserDefinition* CobolParser ()
{
static const char *const extensions [] = {
"cbl", "cob", "CBL", "COB", NULL };
parserDefinition* def = parserNew ("Cobol");
def->extensions = extensions;
def->initialize = installCobolRegex;
def->regex = TRUE;
return def;
}
/* vi:set tabstop=4 shiftwidth=4: */
+275
View File
@@ -0,0 +1,275 @@
/* config.h. Generated by configure. */
/* config.h.in. Generated from configure.in by autoheader. */
/*
* $Id: acconfig.h,v 1.4 2003/04/01 05:02:21 darren Exp $
*
* Copyright (c) 1998-2003, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains input source for generating config.h.in
*/
/* Package name.
*/
/* #undef PACKAGE */
/* Package version.
*/
/* #undef VERSION */
/* Define to the appropriate type if <time.h> does not define this.
*/
/* #undef clock_t */
/* Define to long if <stdio.h> does not define this.
*/
/* #undef fpos_t */
/* Define to the appropriate size for tmpnam() if <stdio.h> does not define
* this.
*/
/* #undef L_tmpnam */
/* Define this macro if the field "st_ino" exists in struct stat in
* <sys/stat.h>.
* */
#define HAVE_STAT_ST_INO 1
/* Define remove to unlink if you have unlink(), but not remove().
*/
/* #undef remove */
/* Define this value used by fseek() appropriately if <stdio.h>
* (or <unistd.h> on SunOS 4.1.x) does not define them.
*/
/* #undef SEEK_SET */
/* Define as the maximum integer on your system if not defined <limits.h>.
*/
/* #undef INT_MAX */
/* You can define this label to be a string containing the name of a
* site-specific configuration file containing site-wide default options. The
* files /etc/ctags.conf and /usr/local/etc/ctags.conf are already checked,
* so only define one here if you need a file somewhere else.
*/
/* #undef CUSTOM_CONFIGURATION_FILE */
/* Define this label if you want macro tags (defined lables) to use patterns
* in the EX command by default (original ctags behavior is to use line
* numbers).
*/
/* #undef MACROS_USE_PATTERNS */
/* Define this as desired.
* 1: Original ctags format
* 2: Extended ctags format with extension flags in EX-style comment.
*/
#define DEFAULT_FILE_FORMAT 2
/* Define this label if your system supports starting scripts with a line of
* the form "#! /bin/sh" to select the interpreter to use for the script.
*/
#define SYS_INTERPRETER 1
/* Define this label if your system uses case-insensitive file names
*/
/* #undef CASE_INSENSITIVE_FILENAMES */
/* Define this label to use the system sort utility (which is probably more
* efficient) over the internal sorting algorithm.
*/
#ifndef INTERNAL_SORT
# define EXTERNAL_SORT 1
#endif
/* If you wish to change the directory in which temporary files are stored,
* define this label to the directory desired.
*/
#define TMPDIR "/tmp"
/* Define this label if regcomp() is broken.
*/
/* #undef REGCOMP_BROKEN */
/* Define this label if you wish to check the regcomp() function at run time
* for correct behavior. This function is currently broken on Cygwin.
*/
/* #undef CHECK_REGCOMP */
/* This corrects the problem of missing prototypes for certain functions
* in some GNU installations (e.g. SunOS 4.1.x).
*/
/* #undef __USE_FIXED_PROTOTYPES__ */
/* Define this is you have a prototype for putenv() in <stdlib.h>, but
* doesn't declare its argument as "const char *".
*/
/* #undef NON_CONST_PUTENV_PROTOTYPE */
/* If you receive error or warning messages indicating that you are missing
* a prototype for, or a type mismatch using, one of the following functions,
* define the appropriate label and remake.
*/
/* #undef NEED_PROTO_REMOVE */
/* #undef NEED_PROTO_UNLINK */
/* #undef NEED_PROTO_MALLOC */
/* #undef NEED_PROTO_GETENV */
/* #undef NEED_PROTO_FGETPOS */
/* #undef NEED_PROTO_STAT */
/* #undef NEED_PROTO_LSTAT */
/* #undef NEED_PROTO_TRUNCATE */
/* #undef NEED_PROTO_FTRUNCATE */
/*----------------------------------------------------------------------------
- Lines below this are automatically generated by autoheader
----------------------------------------------------------------------------*/
/* Define to 1 if you have the `chmod' function. */
/* #undef HAVE_CHMOD */
/* Define to 1 if you have the `chsize' function. */
/* #undef HAVE_CHSIZE */
/* Define to 1 if you have the `clock' function. */
#define HAVE_CLOCK 1
/* Define to 1 if you have the <dirent.h> header file. */
#define HAVE_DIRENT_H 1
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define to 1 if you have the `fgetpos' function. */
#define HAVE_FGETPOS 1
/* Define to 1 if you have the `findfirst' function. */
/* #undef HAVE_FINDFIRST */
/* Define to 1 if you have the `fnmatch' function. */
#define HAVE_FNMATCH 1
/* Define to 1 if you have the <fnmatch.h> header file. */
#define HAVE_FNMATCH_H 1
/* Define to 1 if you have the `ftruncate' function. */
/* #undef HAVE_FTRUNCATE */
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `mkstemp' function. */
#define HAVE_MKSTEMP 1
/* Define to 1 if you have the `opendir' function. */
#define HAVE_OPENDIR 1
/* Define to 1 if you have the `putenv' function. */
/* #undef HAVE_PUTENV */
/* Define to 1 if you have the `regcomp' function. */
#define HAVE_REGCOMP 1
/* Define to 1 if you have the `remove' function. */
#define HAVE_REMOVE 1
/* Define to 1 if you have the `setenv' function. */
#define HAVE_SETENV 1
/* Define to 1 if you have the <stat.h> header file. */
/* #undef HAVE_STAT_H */
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the `strcasecmp' function. */
#define HAVE_STRCASECMP 1
/* Define to 1 if you have the `strerror' function. */
#define HAVE_STRERROR 1
/* Define to 1 if you have the `stricmp' function. */
/* #undef HAVE_STRICMP */
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the `strncasecmp' function. */
#define HAVE_STRNCASECMP 1
/* Define to 1 if you have the `strnicmp' function. */
/* #undef HAVE_STRNICMP */
/* Define to 1 if you have the `strstr' function. */
#define HAVE_STRSTR 1
/* Define to 1 if you have the <sys/dir.h> header file. */
/* #undef HAVE_SYS_DIR_H */
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/times.h> header file. */
#define HAVE_SYS_TIMES_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the `tempnam' function. */
/* #undef HAVE_TEMPNAM */
/* Define to 1 if you have the `times' function. */
/* #undef HAVE_TIMES */
/* Define to 1 if you have the <time.h> header file. */
#define HAVE_TIME_H 1
/* Define to 1 if you have the `truncate' function. */
#define HAVE_TRUNCATE 1
/* Define to 1 if you have the <types.h> header file. */
/* #undef HAVE_TYPES_H */
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have the `_findfirst' function. */
/* #undef HAVE__FINDFIRST */
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT ""
/* Define to the full name of this package. */
#define PACKAGE_NAME ""
/* Define to the full name and version of this package. */
#define PACKAGE_STRING ""
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME ""
/* Define to the version of this package. */
#define PACKAGE_VERSION ""
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
/* Define to `long' if <sys/types.h> does not define. */
/* #undef off_t */
/* Define to `unsigned' if <sys/types.h> does not define. */
/* #undef size_t */
+274
View File
@@ -0,0 +1,274 @@
/* config.h.in. Generated from configure.in by autoheader. */
/*
* $Id: acconfig.h,v 1.4 2003/04/01 05:02:21 darren Exp $
*
* Copyright (c) 1998-2003, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains input source for generating config.h.in
*/
/* Package name.
*/
#undef PACKAGE
/* Package version.
*/
#undef VERSION
/* Define to the appropriate type if <time.h> does not define this.
*/
#undef clock_t
/* Define to long if <stdio.h> does not define this.
*/
#undef fpos_t
/* Define to the appropriate size for tmpnam() if <stdio.h> does not define
* this.
*/
#undef L_tmpnam
/* Define this macro if the field "st_ino" exists in struct stat in
* <sys/stat.h>.
* */
#undef HAVE_STAT_ST_INO
/* Define remove to unlink if you have unlink(), but not remove().
*/
#undef remove
/* Define this value used by fseek() appropriately if <stdio.h>
* (or <unistd.h> on SunOS 4.1.x) does not define them.
*/
#undef SEEK_SET
/* Define as the maximum integer on your system if not defined <limits.h>.
*/
#undef INT_MAX
/* You can define this label to be a string containing the name of a
* site-specific configuration file containing site-wide default options. The
* files /etc/ctags.conf and /usr/local/etc/ctags.conf are already checked,
* so only define one here if you need a file somewhere else.
*/
#undef CUSTOM_CONFIGURATION_FILE
/* Define this label if you want macro tags (defined lables) to use patterns
* in the EX command by default (original ctags behavior is to use line
* numbers).
*/
#undef MACROS_USE_PATTERNS
/* Define this as desired.
* 1: Original ctags format
* 2: Extended ctags format with extension flags in EX-style comment.
*/
#define DEFAULT_FILE_FORMAT 2
/* Define this label if your system supports starting scripts with a line of
* the form "#! /bin/sh" to select the interpreter to use for the script.
*/
#undef SYS_INTERPRETER
/* Define this label if your system uses case-insensitive file names
*/
#undef CASE_INSENSITIVE_FILENAMES
/* Define this label to use the system sort utility (which is probably more
* efficient) over the internal sorting algorithm.
*/
#ifndef INTERNAL_SORT
# undef EXTERNAL_SORT
#endif
/* If you wish to change the directory in which temporary files are stored,
* define this label to the directory desired.
*/
#undef TMPDIR
/* Define this label if regcomp() is broken.
*/
#undef REGCOMP_BROKEN
/* Define this label if you wish to check the regcomp() function at run time
* for correct behavior. This function is currently broken on Cygwin.
*/
#undef CHECK_REGCOMP
/* This corrects the problem of missing prototypes for certain functions
* in some GNU installations (e.g. SunOS 4.1.x).
*/
#undef __USE_FIXED_PROTOTYPES__
/* Define this is you have a prototype for putenv() in <stdlib.h>, but
* doesn't declare its argument as "const char *".
*/
#undef NON_CONST_PUTENV_PROTOTYPE
/* If you receive error or warning messages indicating that you are missing
* a prototype for, or a type mismatch using, one of the following functions,
* define the appropriate label and remake.
*/
#undef NEED_PROTO_REMOVE
#undef NEED_PROTO_UNLINK
#undef NEED_PROTO_MALLOC
#undef NEED_PROTO_GETENV
#undef NEED_PROTO_FGETPOS
#undef NEED_PROTO_STAT
#undef NEED_PROTO_LSTAT
#undef NEED_PROTO_TRUNCATE
#undef NEED_PROTO_FTRUNCATE
/*----------------------------------------------------------------------------
- Lines below this are automatically generated by autoheader
----------------------------------------------------------------------------*/
/* Define to 1 if you have the `chmod' function. */
#undef HAVE_CHMOD
/* Define to 1 if you have the `chsize' function. */
#undef HAVE_CHSIZE
/* Define to 1 if you have the `clock' function. */
#undef HAVE_CLOCK
/* Define to 1 if you have the <dirent.h> header file. */
#undef HAVE_DIRENT_H
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* Define to 1 if you have the `fgetpos' function. */
#undef HAVE_FGETPOS
/* Define to 1 if you have the `findfirst' function. */
#undef HAVE_FINDFIRST
/* Define to 1 if you have the `fnmatch' function. */
#undef HAVE_FNMATCH
/* Define to 1 if you have the <fnmatch.h> header file. */
#undef HAVE_FNMATCH_H
/* Define to 1 if you have the `ftruncate' function. */
#undef HAVE_FTRUNCATE
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `mkstemp' function. */
#undef HAVE_MKSTEMP
/* Define to 1 if you have the `opendir' function. */
#undef HAVE_OPENDIR
/* Define to 1 if you have the `putenv' function. */
#undef HAVE_PUTENV
/* Define to 1 if you have the `regcomp' function. */
#undef HAVE_REGCOMP
/* Define to 1 if you have the `remove' function. */
#undef HAVE_REMOVE
/* Define to 1 if you have the `setenv' function. */
#undef HAVE_SETENV
/* Define to 1 if you have the <stat.h> header file. */
#undef HAVE_STAT_H
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the `strcasecmp' function. */
#undef HAVE_STRCASECMP
/* Define to 1 if you have the `strerror' function. */
#undef HAVE_STRERROR
/* Define to 1 if you have the `stricmp' function. */
#undef HAVE_STRICMP
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the `strncasecmp' function. */
#undef HAVE_STRNCASECMP
/* Define to 1 if you have the `strnicmp' function. */
#undef HAVE_STRNICMP
/* Define to 1 if you have the `strstr' function. */
#undef HAVE_STRSTR
/* Define to 1 if you have the <sys/dir.h> header file. */
#undef HAVE_SYS_DIR_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/times.h> header file. */
#undef HAVE_SYS_TIMES_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the `tempnam' function. */
#undef HAVE_TEMPNAM
/* Define to 1 if you have the `times' function. */
#undef HAVE_TIMES
/* Define to 1 if you have the <time.h> header file. */
#undef HAVE_TIME_H
/* Define to 1 if you have the `truncate' function. */
#undef HAVE_TRUNCATE
/* Define to 1 if you have the <types.h> header file. */
#undef HAVE_TYPES_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the `_findfirst' function. */
#undef HAVE__FINDFIRST
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* Define to `long' if <sys/types.h> does not define. */
#undef off_t
/* Define to `unsigned' if <sys/types.h> does not define. */
#undef size_t
Vendored Executable
+7413
View File
File diff suppressed because it is too large Load Diff
+423
View File
@@ -0,0 +1,423 @@
dnl $Id: configure.in,v 1.13 2006/05/30 04:52:27 darren Exp $
dnl Copyright (c) 1996-2002, Darren Hiebert
dnl
dnl This source code is released for free distribution under the terms
dnl of the GNU General Public License.
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ(1.12)
AC_INIT(ctags.h)
AC_CONFIG_HEADER(config.h)
dnl Report system info
dnl ------------------
echo 'Exuberant Ctags, version 5.6'
uname -mrsv 2>/dev/null
dnl Define convenience macros
dnl -------------------------
dnl CHECK_HEADER_DEFINE(LABEL, HEADER [,ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ] ])
AC_DEFUN(CHECK_HEADER_DEFINE,
[
AC_MSG_CHECKING("if $1 is defined in $2")
AC_EGREP_CPP(yes,
[#include <$2>
#ifdef $1
yes
#endif
], [
AC_MSG_RESULT(yes)
$3
], [
AC_MSG_RESULT(no)
$4
]) ])
dnl Checks for configuration options
dnl --------------------------------
AC_ARG_WITH(posix-regex,
[ --with-posix-regex use Posix regex interface, if available])
AC_ARG_WITH(readlib,
[ --with-readlib include readtags library object during install])
dnl AC_ARG_WITH(perl-regex,
dnl [ --with-perl-regex use Perl pcre interface, if available])
AC_ARG_ENABLE(etags,
[ --enable-etags enable the installation of links for etags])
AC_ARG_ENABLE(extended-format,
[ --disable-extended-format
disable extension flags; use original ctags file
format only],
AC_DEFINE(DEFAULT_FILE_FORMAT, 1), AC_DEFINE(DEFAULT_FILE_FORMAT, 2))
AC_ARG_ENABLE(external-sort,
[ --disable-external-sort use internal sort algorithm instead of sort program])
AC_ARG_ENABLE(custom-config,
[ --enable-custom-config=FILE
enable custom config file for site-wide defaults])
AC_ARG_ENABLE(macro-patterns,
[ --enable-macro-patterns use patterns as default method to locate macros
instead of line numbers])
AC_ARG_ENABLE(maintainer-mode,
[ --enable-maintainer-mode
use maintainer makefile])
AC_ARG_ENABLE(shell-globbing,
[ --enable-shell-globbing=DIR
does shell expand wildcards (yes|no)? [yes]])
AC_ARG_ENABLE(tmpdir,
[ --enable-tmpdir=DIR default directory for temporary files [ARG=/tmp]],
tmpdir_specified=yes)
dnl Process configuration options
dnl -----------------------------
if test "$enable_maintainer_mode" = yes ; then
AC_MSG_RESULT(enabling maintainer mode)
fi
install_targets="install-ctags"
AC_MSG_CHECKING(whether to install link to etags)
if test yes = "$enable_etags"; then
AC_MSG_RESULT(yes)
install_targets="$install_targets install-etags"
else
AC_MSG_RESULT(no)
fi
AC_MSG_CHECKING(whether to install readtags object file)
if test yes = "$with_readlib"; then
AC_MSG_RESULT(yes)
install_targets="$install_targets install-lib"
else
AC_MSG_RESULT(no)
fi
AC_SUBST(install_targets)
if test "$enable_custom_config" = no -o "$enable_custom_config" = yes ; then
AC_MSG_RESULT(no name supplied for custom configuration file)
elif test -n "$enable_custom_config" ; then
AC_DEFINE_UNQUOTED(CUSTOM_CONFIGURATION_FILE, "$enable_custom_config")
AC_MSG_RESULT($enable_custom_config will be used as custom configuration file)
fi
if test "$enable_macro_patterns" = yes ; then
AC_DEFINE(MACROS_USE_PATTERNS)
AC_MSG_RESULT(tag file will use patterns for macros by default)
fi
dnl Checks for programs
dnl -------------------
AC_PROG_CC
case `uname` in
HP-UX)
AC_MSG_CHECKING("HP-UX native compiler")
if test "$CC" = "cc"; then
AC_MSG_RESULT(yes; adding compiler options for ANSI support)
CFLAGS="$CFLAGS -Aa -D_HPUX_SOURCE"
else
AC_MSG_RESULT(no)
fi
;;
SunOS)
if uname -r | grep '5\.' >/dev/null 2>&1; then
AC_MSG_CHECKING("Solaris native compiler")
if test "$CC" = "cc" -a "`which cc`" = "/usr/ucb/cc"; then
AC_MSG_RESULT(yes; adding compiler option for ANSI support)
CC="$CC -Xa"
else
AC_MSG_RESULT(no)
fi
fi
;;
esac
AC_PROG_LN_S
AC_CHECK_PROG(STRIP, strip, strip, :)
dnl Checks for operating environment
dnl --------------------------------
dnl Check for temporary directory
AC_MSG_CHECKING(directory to use for temporary files)
if test -n "$enable_tmpdir"; then
tmpdir="$enable_tmpdir"
elif test -n "$TMPDIR"; then
tmpdir="$TMPDIR"
elif test -n "$TMPDIR"; then
tmpdir="$TMPDIR"
elif test -n "$TMP"; then
tmpdir="$TMP"
elif test -n "$TEMP"; then
tmpdir="$TEMP"
elif test -d "c:/"; then
tmpdir="c:/"
else
tmpdir="/tmp"
fi
if test -d $tmpdir ; then
AC_MSG_RESULT($tmpdir)
AC_DEFINE_UNQUOTED(TMPDIR, "$tmpdir")
else
AC_MSG_ERROR($tmpdir does not exist)
fi
dnl Check whether system supports #! scripts
AC_SYS_INTERPRETER
if test yes = "$interpval"; then
AC_DEFINE(SYS_INTERPRETER)
fi
dnl Test for case-insensitive filenames
AC_MSG_CHECKING("for case-insensitive filenames")
touch conftest.cif
if test -f CONFTEST.CIF; then
AC_MSG_RESULT(yes)
AC_DEFINE(CASE_INSENSITIVE_FILENAMES)
else
AC_MSG_RESULT(no)
fi
rm -f conftest.cif
AC_MSG_CHECKING(selected sort method)
if test no = "$enable_external_sort"; then
AC_MSG_RESULT(simple internal algorithm)
else
AC_MSG_RESULT(external sort utility)
enable_external_sort=no
AC_CHECK_PROG(sort_found, sort, yes, no)
if test "$sort_found" = yes ; then
AC_MSG_CHECKING(if sort accepts our command line)
touch ${tmpdir}/sort.test
sort -u -f -o ${tmpdir}/sort.test ${tmpdir}/sort.test 1>/dev/null 2>&1
if test $? -ne 0 ; then
AC_MSG_RESULT(no)
else
AC_MSG_RESULT(yes)
AC_DEFINE(EXTERNAL_SORT)
enable_external_sort=yes
fi
rm -f ${tmpdir}/sort.test
fi
fi
if test "$enable_external_sort" != yes ; then
AC_MSG_RESULT(using internal sort algorithm as fallback)
fi
dnl Checks for header files
dnl -----------------------
AC_CHECK_HEADERS(dirent.h fcntl.h fnmatch.h stat.h stdlib.h string.h)
AC_CHECK_HEADERS(time.h types.h unistd.h)
AC_CHECK_HEADERS(sys/dir.h sys/stat.h sys/times.h sys/types.h)
dnl Checks for header file macros
dnl -----------------------------
CHECK_HEADER_DEFINE(L_tmpnam, stdio.h,, AC_DEFINE(L_tmpnam, 20))
CHECK_HEADER_DEFINE(INT_MAX, limits.h,,
CHECK_HEADER_DEFINE(MAXINT, limits.h,
AC_DEFINE(INT_MAX, MAXINT), AC_DEFINE(INT_MAX, 32767)))
dnl Checks for typedefs
dnl -------------------
AC_TYPE_SIZE_T
AC_TYPE_OFF_T
AC_MSG_CHECKING("for fpos_t")
AC_EGREP_HEADER(fpos_t, stdio.h, AC_MSG_RESULT(yes),
[
AC_MSG_RESULT(no)
AC_DEFINE(fpos_t, long)
])
AC_MSG_CHECKING("for clock_t")
AC_EGREP_HEADER(clock_t, time.h, AC_MSG_RESULT(yes),
[
AC_MSG_RESULT(no)
AC_DEFINE(clock_t, long)
])
dnl Checks for compiler characteristics
dnl -----------------------------------
dnl AC_CYGWIN
dnl AC_MINGW32
AC_C_CONST
AC_OBJEXT
AC_EXEEXT
AC_MSG_CHECKING(if struct stat contains st_ino)
AC_TRY_COMPILE([#include <sys/stat.h>], [
struct stat st;
stat(".", &st);
if (st.st_ino > 0)
exit(0);
], have_st_ino=yes, have_st_ino=no)
AC_MSG_RESULT($have_st_ino)
if test yes = "$have_st_ino"; then
AC_DEFINE(HAVE_STAT_ST_INO)
fi
dnl Checks for library functions
dnl ----------------------------
AC_CHECK_FUNCS(fnmatch)
AC_CHECK_FUNCS(strstr)
AC_CHECK_FUNCS(strcasecmp stricmp, break)
AC_CHECK_FUNCS(strncasecmp strnicmp, break)
AC_CHECK_FUNCS(fgetpos, have_fgetpos=yes)
dnl SEEK_SET should be in stdio.h, but may be in unistd.h on SunOS 4.1.x
if test "$have_fgetpos" != yes ; then
CHECK_HEADER_DEFINE(SEEK_SET, stdio.h,,
CHECK_HEADER_DEFINE(SEEK_SET, unistd.h,,
AC_DEFINE(SEEK_SET, 0)))
fi
AC_CHECK_FUNCS(mkstemp, have_mkstemp=yes)
if test "$have_mkstemp" != yes ; then
AC_CHECK_FUNCS(tempnam, have_tempnam=yes)
fi
if test "$have_mkstemp" != yes -a "$have_tempnam" != yes; then
AC_CHECK_FUNCS(chmod)
if test "$tmpdir_specified" = yes ; then
AC_MSG_RESULT(use of tmpnam overrides temporary directory selection)
fi
fi
AC_CHECK_FUNCS(opendir findfirst _findfirst, break)
AC_CHECK_FUNCS(strerror)
AC_CHECK_FUNCS(clock times, break)
AC_CHECK_FUNCS(remove, have_remove=yes,
CHECK_HEADER_DEFINE(remove, unistd.h,, AC_DEFINE(remove, unlink)))
AC_CHECK_FUNCS(truncate, have_truncate=yes)
dnl === Cannot nest AC_CHECK_FUNCS() calls
if test "$have_truncate" != yes ; then
AC_CHECK_FUNCS(ftruncate, have_ftruncate=yes)
if test "$have_ftruncate" != yes ; then
AC_CHECK_FUNCS(chsize)
fi
fi
AC_CHECK_FUNCS(setenv, have_setenv=yes)
dnl === Cannot nest AC_CHECK_FUNCS() calls
if test "$have_setenv" != yes ; then
AC_CHECK_FUNCS(putenv, have_putenv=yes)
if test "$have_putenv" = yes ; then
AC_EGREP_HEADER(putenv, stdlib.h, have_putenv_prototype=yes)
if test "$have_putenv_prototype" = yes ; then
AC_MSG_CHECKING("putenv prototype")
AC_EGREP_HEADER([[^A-Za-zo-9_]putenv[ ]*\(.*const.*\)[ ]*;],
stdlib.h, AC_MSG_RESULT(correct),
[
AC_MSG_RESULT(no const)
AC_DEFINE(NON_CONST_PUTENV_PROTOTYPE)
])
fi
fi
fi
dnl
dnl if test yes = "$CYGWIN"; then with_posix_regex=no; fi
if test no != "$with_posix_regex"; then
AC_CHECK_FUNCS(regcomp)
AC_MSG_CHECKING(if regcomp works)
AC_TRY_RUN([
#include <sys/types.h>
#include <regex.h>
main() {
regex_t patbuf;
exit (regcomp (&patbuf, "/hello/", 0) != 0);
}],regcomp_works=yes,regcomp_works=no,AC_DEFINE(CHECK_REGCOMP))
AC_MSG_RESULT($regcomp_works)
if test yes != "$regcomp_works"; then
AC_DEFINE(REGCOMP_BROKEN)
fi
fi
dnl if test yes = "$with_perl_regex"; then
dnl AC_MSG_CHECKING(for Perl regex library)
dnl pcre_candidates="$with_perl_regex $HOME/local/lib* /usr*/local/lib* /usr/lib*"
dnl for lib in $pcre_candidates; do
dnl if test -f $lib/libpcreposix.so; then
dnl pcre_lib="-L$lib -lpcreposix"
dnl break
dnl elif test -f $lib/libpcreposix.a; then
dnl pcre_lib="$lib/libpcreposix.a"
dnl break
dnl fi
dnl done
dnl if test -z "$pcre_lib"; then
dnl AC_MSG_RESULT(not found)
dnl else
dnl AC_MSG_RESULT($lib)
dnl AC_DEFINE(HAVE_REGCOMP)
dnl LDFLAGS="$LDFLAGS $pcre_lib"
dnl have_regex=yes
dnl fi
dnl fi
dnl Checks for missing prototypes
dnl -----------------------------
AC_CHECKING("for missing prototypes")
AC_DEFUN(CHECK_PROTO, [AC_EGREP_HEADER([[^A-Za-z0-9_]$1([ ]+[A-Za-z0-9_]*)?\(], $2,, AC_DEFINE(patsubst([NEED_PROTO_NAME], [NAME], translit($1, [a-z], [A-Z]))) AC_MSG_RESULT(adding prototype for $1))])
if test "$have_remove" = yes ; then
CHECK_PROTO(remove, stdio.h)
else
CHECK_PROTO(unlink, unistd.h)
fi
CHECK_PROTO(malloc, stdlib.h)
CHECK_PROTO(getenv, stdlib.h)
CHECK_PROTO(stat, sys/stat.h)
CHECK_PROTO(lstat, sys/stat.h)
if test "$have_fgetpos" = yes ; then
CHECK_PROTO(fgetpos, stdio.h)
fi
if test "$have_truncate" = yes ; then
CHECK_PROTO(truncate, unistd.h)
fi
if test "$have_ftruncate" = yes ; then
CHECK_PROTO(ftruncate, unistd.h)
fi
dnl Output files
dnl ------------
rm -f Makefile
if test "$enable_maintainer_mode" = yes ; then
AC_MSG_RESULT(creating maintainer Makefile)
ln -s maintainer.mak Makefile
makefile_out=
else
makefile_out=Makefile
fi
AC_OUTPUT($makefile_out)
dnl vim:ts=4:sw=4:
File diff suppressed because it is too large Load Diff
+27
View File
@@ -0,0 +1,27 @@
/*
* $Id: ctags.h,v 1.4 2006/05/30 04:37:11 darren Exp $
*
* Copyright (c) 1996-2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* Program definitions
*/
#ifndef _CTAGS_H
#define _CTAGS_H
/*
* MACROS
*/
#ifndef PROGRAM_VERSION
# define PROGRAM_VERSION "5.6"
#endif
#define PROGRAM_NAME "Exuberant Ctags"
#define PROGRAM_URL "http://ctags.sourceforge.net"
#define AUTHOR_NAME "Darren Hiebert"
#define AUTHOR_EMAIL "[email protected]"
#endif /* _CTAGS_H */
/* vi:set tabstop=4 shiftwidth=4: */
File diff suppressed because it is too large Load Diff
+19
View File
@@ -0,0 +1,19 @@
Begin4
Title: Exuberant Ctags
Version: 5.6
Entered-date: 2006-05-29
Description: An improved ctags with multilanguage support.
Keywords: tag tags ctags etags ftags ptags Exuberant Assembler ASP AWK
Bourne sh BETA C C++ C# COBOL Eiffel Fortran Java JavaScript
Korn ksh Lisp Lua Makefile Pascal Perl PHP PL/SQL Python REXX
Ruby Scheme SLang S-Lang SML Tcl Vera Verilog Vim YACC zsh
source index
Author: [email protected] (Darren Hiebert)
Maintained-by: [email protected] (Darren Hiebert)
Primary-site: http://prdownloads.sourceforge.net/ctags
260K ctags-5.6.tar.gz
Original-site: http://ctags.sourceforge.net
Platforms: UNIX, MSDOS, Windows 95/98/NT/2000/XP, OS/2, QNX, Amiga, QDOS,
RISC OS, VMS, Macintosh, MacOS X, Cray
Copying-policy: Gnu General Public License (GPL)
End
+11
View File
@@ -0,0 +1,11 @@
resource app_version
{
major = 5,
middle = 6,
minor = 0,
variety = B_APPV_FINAL,
internal = 0,
short_info = "ctags",
long_info = "ctags from http://ctags.sourceforge.net/"
};
+40
View File
@@ -0,0 +1,40 @@
Summary: Exuberant Ctags - a multi-language source code indexing tool
Name: ctags
Version: 5.6
Release: 1
License: GPL
Group: Development/Tools
Source: http://prdownloads.sourceforge.net/ctags/ctags-%{version}.tar.gz
URL: http://ctags.sourceforge.net
Buildroot: %{_tmppath}/%{name}-%{version}-root
%description
Exuberant Ctags generates an index (or tag) file of language objects
found in source files for many popular programming languages. This index
makes it easy for text editors and other tools to locate the indexed
items. Exuberant Ctags improves on traditional ctags because of its
multilanguage support, its ability for the user to define new languages
searched by regular expressions, and its ability to generate emacs-style
TAGS files.
Install ctags if you are going to use your system for programming.
%prep
%setup -q
%build
%configure
make
%install
rm -rf $RPM_BUILD_ROOT
%makeinstall
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
%doc COPYING EXTENDING.html FAQ NEWS README ctags.html
%{_bindir}/ctags
%{_mandir}/man1/ctags*
+120
View File
@@ -0,0 +1,120 @@
/*
* $Id: debug.c,v 1.5 2006/05/30 04:37:11 darren Exp $
*
* Copyright (c) 1996-2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains debugging functions.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <ctype.h>
#include <stdarg.h>
#include "debug.h"
#include "options.h"
#include "read.h"
/*
* FUNCTION DEFINITIONS
*/
#ifdef DEBUG
extern void lineBreak (void) {} /* provides a line-specified break point */
extern void debugPrintf (
const enum eDebugLevels level, const char *const format, ... )
{
va_list ap;
va_start (ap, format);
if (debug (level))
vprintf (format, ap);
fflush (stdout);
va_end (ap);
}
extern void debugPutc (const int level, const int c)
{
if (debug (level) && c != EOF)
{
if (c == STRING_SYMBOL) printf ("\"string\"");
else if (c == CHAR_SYMBOL) printf ("'c'");
else putchar (c);
fflush (stdout);
}
}
extern void debugParseNest (const boolean increase, const unsigned int level)
{
debugPrintf (DEBUG_PARSE, "<*%snesting:%d*>", increase ? "++" : "--", level);
}
extern void debugCppNest (const boolean begin, const unsigned int level)
{
debugPrintf (DEBUG_CPP, "<*cpp:%s level %d*>", begin ? "begin":"end", level);
}
extern void debugCppIgnore (const boolean ignore)
{
debugPrintf (DEBUG_CPP, "<*cpp:%s ignore*>", ignore ? "begin":"end");
}
extern void clearString (char *const string, const int length)
{
int i;
for (i = 0 ; i < length ; ++i)
string [i] = '\0';
}
extern void debugEntry (const tagEntryInfo *const tag)
{
const char *const scope = tag->isFileScope ? "{fs}" : "";
if (debug (DEBUG_PARSE))
{
printf ("<#%s%s:%s", scope, tag->kindName, tag->name);
if (tag->extensionFields.scope [0] != NULL &&
tag->extensionFields.scope [1] != NULL)
printf (" [%s:%s]", tag->extensionFields.scope [0],
tag->extensionFields.scope [1]);
if (Option.extensionFields.inheritance &&
tag->extensionFields.inheritance != NULL)
printf (" [inherits:%s]", tag->extensionFields.inheritance);
if (Option.extensionFields.fileScope &&
tag->isFileScope && ! isHeaderFile ())
printf (" [file:]");
if (Option.extensionFields.access &&
tag->extensionFields.access != NULL)
printf (" [access:%s]", tag->extensionFields.access);
if (Option.extensionFields.implementation &&
tag->extensionFields.implementation != NULL)
printf (" [imp:%s]", tag->extensionFields.implementation);
if (Option.extensionFields.typeRef &&
tag->extensionFields.typeRef [0] != NULL &&
tag->extensionFields.typeRef [1] != NULL)
printf (" [%s:%s]", tag->extensionFields.typeRef [0],
tag->extensionFields.typeRef [1]);
printf ("#>");
fflush (stdout);
}
}
#endif
/* vi:set tabstop=4 shiftwidth=4: */
+71
View File
@@ -0,0 +1,71 @@
/*
* $Id: debug.h,v 1.3 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 1998-2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* External interface to debug.c
*/
#ifndef _DEBUG_H
#define _DEBUG_H
/*
* Include files
*/
#include "general.h" /* must always come first */
#ifdef DEBUG
# include <assert.h>
#endif
#include "entry.h"
/*
* Macros
*/
#ifdef DEBUG
# define debug(level) ((Option.debugLevel & (long)(level)) != 0)
# define DebugStatement(x) x
# define PrintStatus(x) if (debug(DEBUG_STATUS)) printf x;
# define Assert(c) assert(c)
#else
# define DebugStatement(x)
# define PrintStatus(x)
# define Assert(c)
# ifndef NDEBUG
# define NDEBUG
# endif
#endif
/*
* Data declarations
*/
/* Defines the debugging levels.
*/
enum eDebugLevels {
DEBUG_READ = 0x01, /* echo raw (filtered) characters */
DEBUG_PARSE = 0x02, /* echo parsing results */
DEBUG_STATUS = 0x04, /* echo file status information */
DEBUG_OPTION = 0x08, /* echo option parsing */
DEBUG_CPP = 0x10, /* echo characters out of pre-processor */
DEBUG_RAW = 0x20 /* echo raw (filtered) characters */
};
/*
* Function prototypes
*/
extern void lineBreak (void);
extern void debugPrintf (const enum eDebugLevels level, const char *const format, ...) __printf__ (2, 3);
extern void debugPutc (const int level, const int c);
extern void debugParseNest (const boolean increase, const unsigned int level);
extern void debugCppNest (const boolean begin, const unsigned int level);
extern void debugCppIgnore (const boolean ignore);
extern void clearString (char *const string, const int length);
extern void debugEntry (const tagEntryInfo *const tag);
#endif /* _DEBUG_H */
/* vi:set tabstop=4 shiftwidth=4: */
+68
View File
@@ -0,0 +1,68 @@
# $Id: descrip.mms,v 1.1 2001/11/02 04:53:43 darren Exp $
#
# Makefile for building CTAGS under OpenVMS
#
# Maintained by by Zoltan Arpadffy <[email protected]>
#
# Edit the lines in the Configuration section below to select.
######################################################################
# Configuration section.
######################################################################
# Compiler selection.
# Comment out if you use the VAXC compiler
######################################################################
DECC = YES
######################################################################
# Uncomment if want a debug version. Resulting executable is DCTAGS.EXE
######################################################################
# DEBUG = YES
######################################################################
# End of configuration section.
#
# Please, do not change anything below without programming experience.
######################################################################
CC = cc
.IFDEF DECC
CC_DEF = $(CC)/decc/prefix=all
.ELSE
CC_DEF = $(CC)
.ENDIF
LD_DEF = link
.IFDEF DEBUG
TARGET = dctags.exe
CFLAGS = /debug/noopt/list/cross_reference/include=[]
LDFLAGS = /debug
.ELSE
TARGET = ctags.exe
CFLAGS = /include=[]
LDFLAGS =
.ENDIF
OBJEXT = obj
.SUFFIXES : .obj .c
.INCLUDE source.mak
EXTRA_OBJS = argproc.obj
all : $(TARGET)
! $@
.c.obj :
$(CC_DEF) $(CFLAGS) $<
$(TARGET) : $(OBJECTS) $(EXTRA_OBJS)
$(LD_DEF) $(LDFLAGS) /exe=$(TARGET) $+
clean :
-@ if F$SEARCH("*.obj") .NES. "" then delete/noconfirm/nolog *.obj.*
-@ if F$SEARCH("*.exe") .NES. "" then delete/noconfirm/nolog *.exe.*
-@ if F$SEARCH("config.h") .NES. "" then delete/noconfirm/nolog config.h.*
+24
View File
@@ -0,0 +1,24 @@
/*
* $Id: e_amiga.h,v 1.1 2002/03/08 22:35:19 darren Exp $
*
* Copyright (c) 2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* Configures ctags for Amiga environment.
*/
#ifndef E_AMIGA_H
#define E_AMIGA_H
#define HAVE_STDLIB_H 1
#define HAVE_SYS_STAT_H 1
#define HAVE_SYS_TYPES_H 1
#define HAVE_TIME_H 1
#define HAVE_CLOCK 1
#define HAVE_FGETPOS 1
#define HAVE_STRERROR 1
#define HAVE_STRICMP 1
#define HAVE_STRNICMP 1
#endif
+47
View File
@@ -0,0 +1,47 @@
/*
* $Id: e_djgpp.h,v 1.5 2003/10/31 04:15:35 darren Exp $
*
* Copyright (c) 2002-2003, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* Configures ctags for DJGPP environment.
*/
#ifndef E_DJGPP_H
#define E_DJGPP_H
#define CASE_INSENSITIVE_FILENAMES 1
#define MSDOS_STYLE_PATH 1
#define HAVE_DIR_H 1
#define HAVE_DIRENT_H 1
#define HAVE_FCNTL_H 1
#define HAVE_FNMATCH_H 1
#define HAVE_STDLIB_H 1
#define HAVE_STRING_H 1
#define HAVE_SYS_DIR_H 1
#define HAVE_SYS_STAT_H 1
#define HAVE_SYS_TIMES_H 1
#define HAVE_SYS_TYPES_H 1
#define HAVE_TIME_H 1
#define HAVE_UNISTD_H 1
#define HAVE_CLOCK 1
#define HAVE_FGETPOS 1
#define HAVE_FNMATCH 1
#define HAVE_MKSTEMP 1
#define HAVE_OPENDIR 1
#define HAVE_REGCOMP 1
#define HAVE_REMOVE 1
#define HAVE_SETENV 1
#define HAVE_STAT_ST_INO 1
#define HAVE_STRCASECMP 1
#define HAVE_STRERROR 1
#define HAVE_STRNCASECMP 1
#define HAVE_STRSTR 1
#define HAVE_TRUNCATE 1
#define NEED_PROTO_LSTAT 1
#define STDC_HEADERS 1
#endif
+143
View File
@@ -0,0 +1,143 @@
/*
* $Id: e_mac.h,v 1.2 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 2001, Maarten L. Hekkelman
*
* Author: Maarten L. Hekkelman <[email protected]>
* http://www.hekkelman.com
*
* This source code is released for free distribution under the terms of the
* GNU General Public License. It is provided on an as-is basis and no
* responsibility is accepted for its failure to perform as expected.
*
* Configures ctags for Macintosh environment.
*/
#ifndef E_MAC_H
#define E_MAC_H
#define BUILD_MPW_TOOL 1
#define MACROS_USE_PATTERNS 1
#define DEFAULT_FILE_FORMAT 2
#define INTERNAL_SORT 1
#define TMPDIR "/tmp"
#define NEED_PROTO_TRUNCATE 1
#define STDC_HEADERS 1
#define HAVE_CLOCK 1
#define HAVE_FGETPOS 1
#define HAVE_OPENDIR 1
#define HAVE_REMOVE 1
#define HAVE_SETENV 1
#define HAVE_STRERROR 1
#define HAVE_STRSTR 1
#define HAVE_FCNTL_H 1
#define HAVE_STDLIB_H 1
#define HAVE_STRING_H 1
#define HAVE_SYS_DIR_H 1
#define HAVE_SYS_TIMES_H 1
#define HAVE_TIME_H 1
#define HAVE_TYPES_H 1
#define HAVE_STDLIB_H 1
#include <time.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
#include <Files.h>
#if BUILD_MPW_TOOL
/*
The following defines are collected from various header files from some
Linux distribution
*/
typedef unsigned long mode_t;
typedef unsigned long ino_t;
typedef unsigned long dev_t;
typedef short nlink_t;
typedef unsigned long uid_t;
typedef unsigned long gid_t;
/* Encoding of the file mode. */
#define S_IFMT 0170000 /* These bits determine file type. */
/* File types. */
#define S_IFDIR 0040000 /* Directory. */
#define S_IFCHR 0020000 /* Character device. */
#define S_IFBLK 0060000 /* Block device. */
#define S_IFREG 0100000 /* Regular file. */
#define S_ISTYPE(mode, mask) (((mode) & S_IFMT) == (mask))
#define S_ISDIR(mode) S_ISTYPE((mode), S_IFDIR)
#define S_ISCHR(mode) S_ISTYPE((mode), S_IFCHR)
#define S_ISBLK(mode) S_ISTYPE((mode), S_IFBLK)
#define S_ISREG(mode) S_ISTYPE((mode), S_IFREG)
struct stat {
dev_t st_dev; /* Device. */
unsigned short int __pad1;
ino_t st_ino; /* File serial number. */
mode_t st_mode; /* File mode. */
nlink_t st_nlink; /* Link count. */
uid_t st_uid; /* User ID of the file's owner. */
gid_t st_gid; /* Group ID of the file's group.*/
off_t st_size; /* Size of file, in bytes. */
unsigned long int st_blksize; /* Optimal block size for I/O. */
long st_blocks; /* Number 512-byte blocks allocated. */
time_t st_atime; /* Time of last access. */
time_t st_mtime; /* Time of last modification. */
time_t st_ctime; /* Time of last status change. */
};
int fstat(int fildes, struct stat *buf);
#else
#include <console.h>
#include <stat.mac.h>
#endif
#ifndef PATH_MAX
#define PATH_MAX 1024
#endif
/*
Our own stat, accepts unix like paths.
*/
int mstat(const char *path, struct stat *buf);
struct dirent {
char d_name[64];
};
typedef struct {
FSSpec file;
int index;
struct dirent ent;
} DIR;
extern DIR* opendir(const char *dirname);
extern struct dirent* readdir(DIR* dirp);
extern int closedir(DIR* dirp);
extern void rewinddir(DIR* dirp);
extern char* getcwd(char*, int);
/*
Our own fopen, accepts unix like paths.
*/
extern FILE* mfopen(const char* file, const char* mode);
/*
Dirty, define the standard functions fopen, stat and lstat to map to our
own routines.
*/
#define fopen mfopen
#define stat(a,b) mstat(a,b)
#define lstat(a,b) mstat(a,b)
#endif
/* vi:set tabstop=4 shiftwidth=4: */
+75
View File
@@ -0,0 +1,75 @@
/*
* $Id: e_msoft.h,v 1.8 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 2002-2003, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* Configures ctags for Microsoft environment.
*/
#ifndef E_MSOFT_H
#define E_MSOFT_H
/* MS-DOS/Windows doesn't allow manipulation of standard error,
* so we send it to stdout instead.
*/
#define errout stdout
#define CASE_INSENSITIVE_FILENAMES 1
#define MANUAL_GLOBBING 1
#define MSDOS_STYLE_PATH 1
#define HAVE_DOS_H 1
#define HAVE_FCNTL_H 1
#define HAVE_IO_H 1
#define HAVE_STDLIB_H 1
#define HAVE_SYS_STAT_H 1
#define HAVE_SYS_TYPES_H 1
#define HAVE_TIME_H 1
#define HAVE_CLOCK 1
#define HAVE_CHSIZE 1
#define HAVE_FGETPOS 1
#define HAVE_STRICMP 1
#define HAVE_STRNICMP 1
#define HAVE_STRSTR 1
#define HAVE_STRERROR 1
#define HAVE_FINDNEXT 1
#define HAVE_TEMPNAM 1
#define tempnam(dir,pfx) _tempnam(dir,pfx)
#define TMPDIR "\\"
#ifdef __BORLANDC__
# define HAVE_DIR_H 1
# define HAVE_DIRENT_H 1
# define HAVE_FINDFIRST 1
#elif defined (_MSC_VER)
# define HAVE__FINDFIRST 1
# define HAVE_DIRECT_H 1
# if _MSC_VER >= 1300
# define findfirst_t intptr_t /* Visual Studio 7 */
# else
# define findfirst_t long /* Visual Studio 6 or earlier */
# endif
#elif defined (__MINGW32__)
# include <_mingw.h>
# if defined (__MSVCRT__) && __MINGW32_MAJOR_VERSION == 1 && __MINGW32_MINOR_VERSION < 2
/* Work-around for broken implementation of fgetpos()/fsetpos() on Mingw32 */
# undef HAVE_FGETPOS
# define NEED_PROTO_FGETPOS 1
# endif
# define HAVE_DIR_H 1
# define HAVE_DIRENT_H 1
# define HAVE__FINDFIRST 1
# define ffblk _finddata_t
# define FA_DIREC _A_SUBDIR
# define ff_name name
#endif
#endif
+37
View File
@@ -0,0 +1,37 @@
/*
* $Id: e_os2.h,v 1.1 2002/03/08 22:35:19 darren Exp $
*
* Copyright (c) 2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* Configures ctags for OS/2 environment.
*/
#ifndef E_OS2_H
#define E_OS2_H
#define UNIX_PATH_SEPARATOR 1
#define CASE_INSENSITIVE_FILENAMES 1
#define HAVE_DIRENT_H 1
#define HAVE_FCNTL_H 1
#define HAVE_IO_H 1
#define HAVE_STDLIB_H 1
#define HAVE_SYS_STAT_H 1
#define HAVE_SYS_TYPES_H 1
#define HAVE_TIME_H 1
#define HAVE_UNISTD_H 1
#define HAVE_CLOCK 1
#define HAVE_CHSIZE 1
#define HAVE_FGETPOS 1
#define HAVE_FTRUNCATE 1
#define HAVE_OPENDIR 1
#define HAVE_REGCOMP 1
#define HAVE_REMOVE 1
#define HAVE_STRERROR 1
#define HAVE_STRICMP 1
#define HAVE_STRNICMP 1
#define HAVE_STRSTR 1
#define HAVE_TRUNCATE 1
#endif
+34
View File
@@ -0,0 +1,34 @@
/*
* $Id: e_qdos.h,v 1.1 2002/03/08 22:35:19 darren Exp $
*
* Copyright (c) 2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* Configures ctags for QDOS environment.
*/
#ifndef E_QDOS_H
#define E_QDOS_H
#define HAVE_DIRENT_H 1
#define HAVE_STDLIB_H 1
#define HAVE_SYS_STAT_H 1
#define HAVE_SYS_TIMES_H 1
#define HAVE_SYS_TYPES_H 1
#define HAVE_TIME_H 1
#define HAVE_UNISTD_H 1
#define STDC_HEADERS 1
#define HAVE_CLOCK 1
#define HAVE_FGETPOS 1
#define HAVE_FTRUNCATE 1
#define HAVE_OPENDIR 1
#define HAVE_PUTENV 1
#define HAVE_REMOVE 1
#define HAVE_STRERROR 1
#define HAVE_STRSTR 1
#define HAVE_TIMES 1
#define HAVE_TRUNCATE 1
#define NON_CONST_PUTENV_PROTOTYPE 1
#endif
+58
View File
@@ -0,0 +1,58 @@
/*
* $Id: e_riscos.h,v 1.1 2002/03/08 22:35:19 darren Exp $
*
* Copyright (c) 2002, Andrew Wingate
*
* Author: Andrew Wingate <[email protected]>
*
* This source code is released for free distribution under the terms of the
* GNU General Public License. It is provided on an as-is basis and no
* responsibility is accepted for its failure to perform as expected.
*
* Configures ctags for RISC OS environment.
*
* We currently use UnixLib. This file is subject to change if
* we move to using SharedCLibrary and libGNU.
*/
#ifndef E_RISCOS_H
#define E_RISCOS_H
#define MACROS_USE_PATTERNS 1
#define DEFAULT_FILE_FORMAT 2
#define INTERNAL_SORT 1 /* Not all systems will have installed sort(1) */
#define TMPDIR "<Wimp$ScrapDir>"
/* Various definitions for UnixLib */
#define STDC_HEADERS 1
#define HAVE_CHMOD 1
#define HAVE_CHSIZE 1
#define HAVE_CLOCK 1
#define HAVE_FGETPOS 1
#define HAVE_FNMATCH 1
#define HAVE_FTRUNCATE 1
#define HAVE_MKSTEMP 1
#define HAVE_OPENDIR 1
#define HAVE_PUTENV 1
#define HAVE_REGCOMP 1 /* Requires RegEx library */
#define HAVE_REMOVE 1
#define HAVE_SETENV 1
#define HAVE_STRERROR 1
#define HAVE_STRICMP 1
#define HAVE_STRNICMP 1
#define HAVE_STRSTR 1
#define HAVE_TIMES 1
#define HAVE_TRUNCATE 1
#define HAVE_DIRENT_H 1
#define HAVE_FCNTL_H 1
#define HAVE_FNMATCH_H 1
#define HAVE_STAT_H 1
#define HAVE_STDLIB_H 1
#define HAVE_STRING_H 1
#define HAVE_SYS_DIR_H 1
#define HAVE_SYS_STAT_H 1
#define HAVE_SYS_TIMES_H 1
#define HAVE_SYS_TYPES_H 1
#define HAVE_TIME_H 1
#define HAVE_UNISTD_H 1
#endif
+31
View File
@@ -0,0 +1,31 @@
/*
* $Id: e_vms.h,v 1.1 2002/03/08 22:35:19 darren Exp $
*
* Copyright (c) 2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* Configures ctags for VMS environment.
*/
#ifndef E_VMS_H
#define E_VMS_H
#define CASE_INSENSITIVE_FILENAMES 1
#define HAVE_STDLIB_H 1
#define HAVE_TIME_H 1
#ifdef VAXC
# define HAVE_STAT_H 1
# define HAVE_TYPES_H 1
#else
# define HAVE_FCNTL_H 1
# define HAVE_SYS_STAT_H 1
# define HAVE_SYS_TYPES_H 1
#endif
#define HAVE_CLOCK 1
#define HAVE_FGETPOS 1
#define HAVE_STRERROR 1
#define HAVE_STRSTR 1
#define HAVE_UNISTD_H 1
#endif
File diff suppressed because it is too large Load Diff
+847
View File
@@ -0,0 +1,847 @@
/*
* $Id: entry.c,v 1.11 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 1996-2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for creating tag entries.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#include <ctype.h> /* to define isspace () */
#include <errno.h>
#if defined (HAVE_SYS_TYPES_H)
# include <sys/types.h> /* to declare off_t on some hosts */
#endif
#if defined (HAVE_TYPES_H)
# include <types.h> /* to declare off_t on some hosts */
#endif
#if defined (HAVE_UNISTD_H)
# include <unistd.h> /* to declare close (), ftruncate (), truncate () */
#endif
/* These header files provide for the functions necessary to do file
* truncation.
*/
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#ifdef HAVE_IO_H
# include <io.h>
#endif
#include "debug.h"
#include "ctags.h"
#include "entry.h"
#include "main.h"
#include "options.h"
#include "read.h"
#include "routines.h"
#include "sort.h"
#include "strlist.h"
/*
* MACROS
*/
#define PSEUDO_TAG_PREFIX "!_"
#define includeExtensionFlags() (Option.tagFileFormat > 1)
/*
* Portability defines
*/
#if !defined(HAVE_TRUNCATE) && !defined(HAVE_FTRUNCATE) && !defined(HAVE_CHSIZE)
# define USE_REPLACEMENT_TRUNCATE
#endif
/* Hack for rediculous practice of Microsoft Visual C++.
*/
#if defined (WIN32) && defined (_MSC_VER)
# define chsize _chsize
# define open _open
# define close _close
# define O_RDWR _O_RDWR
#endif
/*
* DATA DEFINITIONS
*/
tagFile TagFile = {
NULL, /* tag file name */
NULL, /* tag file directory (absolute) */
NULL, /* file pointer */
{ 0, 0 }, /* numTags */
{ 0, 0, 0 }, /* max */
{ NULL, NULL, 0 }, /* etags */
NULL /* vLine */
};
static boolean TagsToStdout = FALSE;
/*
* FUNCTION PROTOTYPES
*/
#ifdef NEED_PROTO_TRUNCATE
extern int truncate (const char *path, off_t length);
#endif
#ifdef NEED_PROTO_FTRUNCATE
extern int ftruncate (int fd, off_t length);
#endif
/*
* FUNCTION DEFINITIONS
*/
extern void freeTagFileResources (void)
{
if (TagFile.directory != NULL)
eFree (TagFile.directory);
vStringDelete (TagFile.vLine);
}
extern const char *tagFileName (void)
{
return TagFile.name;
}
/*
* Pseudo tag support
*/
static void rememberMaxLengths (const size_t nameLength, const size_t lineLength)
{
if (nameLength > TagFile.max.tag)
TagFile.max.tag = nameLength;
if (lineLength > TagFile.max.line)
TagFile.max.line = lineLength;
}
static void writePseudoTag (
const char *const tagName,
const char *const fileName,
const char *const pattern)
{
const int length = fprintf (
TagFile.fp, "%s%s\t%s\t/%s/\n",
PSEUDO_TAG_PREFIX, tagName, fileName, pattern);
++TagFile.numTags.added;
rememberMaxLengths (strlen (tagName), (size_t) length);
}
static void addPseudoTags (void)
{
if (! Option.xref)
{
char format [11];
const char *formatComment = "unknown format";
sprintf (format, "%u", Option.tagFileFormat);
if (Option.tagFileFormat == 1)
formatComment = "original ctags format";
else if (Option.tagFileFormat == 2)
formatComment =
"extended format; --format=1 will not append ;\" to lines";
writePseudoTag ("TAG_FILE_FORMAT", format, formatComment);
writePseudoTag ("TAG_FILE_SORTED",
Option.sorted == SO_FOLDSORTED ? "2" :
(Option.sorted == SO_SORTED ? "1" : "0"),
"0=unsorted, 1=sorted, 2=foldcase");
writePseudoTag ("TAG_PROGRAM_AUTHOR", AUTHOR_NAME, AUTHOR_EMAIL);
writePseudoTag ("TAG_PROGRAM_NAME", PROGRAM_NAME, "");
writePseudoTag ("TAG_PROGRAM_URL", PROGRAM_URL, "official site");
writePseudoTag ("TAG_PROGRAM_VERSION", PROGRAM_VERSION, "");
}
}
static void updateSortedFlag (
const char *const line, FILE *const fp, fpos_t startOfLine)
{
const char *const tab = strchr (line, '\t');
if (tab != NULL)
{
const long boolOffset = tab - line + 1; /* where it should be */
if (line [boolOffset] == '0' || line [boolOffset] == '1')
{
fpos_t nextLine;
if (fgetpos (fp, &nextLine) == -1 || fsetpos (fp, &startOfLine) == -1)
error (WARNING, "Failed to update 'sorted' pseudo-tag");
else
{
fpos_t flagLocation;
int c, d;
do
c = fgetc (fp);
while (c != '\t' && c != '\n');
fgetpos (fp, &flagLocation);
d = fgetc (fp);
if (c == '\t' && (d == '0' || d == '1') &&
d != (int) Option.sorted)
{
fsetpos (fp, &flagLocation);
fputc (Option.sorted == SO_FOLDSORTED ? '2' :
(Option.sorted == SO_SORTED ? '1' : '0'), fp);
}
fsetpos (fp, &nextLine);
}
}
}
}
/* Look through all line beginning with "!_TAG_FILE", and update those which
* require it.
*/
static long unsigned int updatePseudoTags (FILE *const fp)
{
enum { maxEntryLength = 20 };
char entry [maxEntryLength + 1];
unsigned long linesRead = 0;
fpos_t startOfLine;
size_t entryLength;
const char *line;
sprintf (entry, "%sTAG_FILE", PSEUDO_TAG_PREFIX);
entryLength = strlen (entry);
Assert (entryLength < maxEntryLength);
fgetpos (fp, &startOfLine);
line = readLine (TagFile.vLine, fp);
while (line != NULL && line [0] == entry [0])
{
++linesRead;
if (strncmp (line, entry, entryLength) == 0)
{
char tab, classType [16];
if (sscanf (line + entryLength, "%15s%c", classType, &tab) == 2 &&
tab == '\t')
{
if (strcmp (classType, "_SORTED") == 0)
updateSortedFlag (line, fp, startOfLine);
}
fgetpos (fp, &startOfLine);
}
line = readLine (TagFile.vLine, fp);
}
while (line != NULL) /* skip to end of file */
{
++linesRead;
line = readLine (TagFile.vLine, fp);
}
return linesRead;
}
/*
* Tag file management
*/
static boolean isValidTagAddress (const char *const excmd)
{
boolean isValid = FALSE;
if (strchr ("/?", excmd [0]) != NULL)
isValid = TRUE;
else
{
char *address = xMalloc (strlen (excmd) + 1, char);
if (sscanf (excmd, "%[^;\n]", address) == 1 &&
strspn (address,"0123456789") == strlen (address))
isValid = TRUE;
eFree (address);
}
return isValid;
}
static boolean isCtagsLine (const char *const line)
{
enum fieldList { TAG, TAB1, SRC_FILE, TAB2, EXCMD, NUM_FIELDS };
boolean ok = FALSE; /* we assume not unless confirmed */
const size_t fieldLength = strlen (line) + 1;
char *const fields = xMalloc (NUM_FIELDS * fieldLength, char);
if (fields == NULL)
error (FATAL, "Cannot analyze tag file");
else
{
#define field(x) (fields + ((size_t) (x) * fieldLength))
const int numFields = sscanf (
line, "%[^\t]%[\t]%[^\t]%[\t]%[^\r\n]",
field (TAG), field (TAB1), field (SRC_FILE),
field (TAB2), field (EXCMD));
/* There must be exactly five fields: two tab fields containing
* exactly one tab each, the tag must not begin with "#", and the
* file name should not end with ";", and the excmd must be
* accceptable.
*
* These conditions will reject tag-looking lines like:
* int a; <C-comment>
* #define LABEL <C-comment>
*/
if (numFields == NUM_FIELDS &&
strlen (field (TAB1)) == 1 &&
strlen (field (TAB2)) == 1 &&
field (TAG) [0] != '#' &&
field (SRC_FILE) [strlen (field (SRC_FILE)) - 1] != ';' &&
isValidTagAddress (field (EXCMD)))
ok = TRUE;
eFree (fields);
}
return ok;
}
static boolean isEtagsLine (const char *const line)
{
boolean result = FALSE;
if (line [0] == '\f')
result = (boolean) (line [1] == '\n' || line [1] == '\r');
return result;
}
static boolean isTagFile (const char *const filename)
{
boolean ok = FALSE; /* we assume not unless confirmed */
FILE *const fp = fopen (filename, "rb");
if (fp == NULL && errno == ENOENT)
ok = TRUE;
else if (fp != NULL)
{
const char *line = readLine (TagFile.vLine, fp);
if (line == NULL)
ok = TRUE;
else
ok = (boolean) (isCtagsLine (line) || isEtagsLine (line));
fclose (fp);
}
return ok;
}
extern void copyBytes (FILE* const fromFp, FILE* const toFp, const long size)
{
enum { BufferSize = 1000 };
long toRead, numRead;
char* buffer = xMalloc (BufferSize, char);
long remaining = size;
do
{
toRead = (0 < remaining && remaining < BufferSize) ?
remaining : (long) BufferSize;
numRead = fread (buffer, (size_t) 1, (size_t) toRead, fromFp);
if (fwrite (buffer, (size_t)1, (size_t)numRead, toFp) < (size_t)numRead)
error (FATAL | PERROR, "cannot complete write");
if (remaining > 0)
remaining -= numRead;
} while (numRead == toRead && remaining != 0);
eFree (buffer);
}
extern void copyFile (const char *const from, const char *const to, const long size)
{
FILE* const fromFp = fopen (from, "rb");
if (fromFp == NULL)
error (FATAL | PERROR, "cannot open file to copy");
else
{
FILE* const toFp = fopen (to, "wb");
if (toFp == NULL)
error (FATAL | PERROR, "cannot open copy destination");
else
{
copyBytes (fromFp, toFp, size);
fclose (toFp);
}
fclose (fromFp);
}
}
extern void openTagFile (void)
{
setDefaultTagFileName ();
TagsToStdout = isDestinationStdout ();
if (TagFile.vLine == NULL)
TagFile.vLine = vStringNew ();
/* Open the tags file.
*/
if (TagsToStdout)
TagFile.fp = tempFile ("w", &TagFile.name);
else
{
boolean fileExists;
setDefaultTagFileName ();
TagFile.name = eStrdup (Option.tagFileName);
fileExists = doesFileExist (TagFile.name);
if (fileExists && ! isTagFile (TagFile.name))
error (FATAL,
"\"%s\" doesn't look like a tag file; I refuse to overwrite it.",
TagFile.name);
if (Option.etags)
{
if (Option.append && fileExists)
TagFile.fp = fopen (TagFile.name, "a+b");
else
TagFile.fp = fopen (TagFile.name, "w+b");
}
else
{
if (Option.append && fileExists)
{
TagFile.fp = fopen (TagFile.name, "r+");
if (TagFile.fp != NULL)
{
TagFile.numTags.prev = updatePseudoTags (TagFile.fp);
fclose (TagFile.fp);
TagFile.fp = fopen (TagFile.name, "a+");
}
}
else
{
TagFile.fp = fopen (TagFile.name, "w");
if (TagFile.fp != NULL)
addPseudoTags ();
}
}
if (TagFile.fp == NULL)
{
error (FATAL | PERROR, "cannot open tag file");
exit (1);
}
}
if (TagsToStdout)
TagFile.directory = eStrdup (CurrentDirectory);
else
TagFile.directory = absoluteDirname (TagFile.name);
}
#ifdef USE_REPLACEMENT_TRUNCATE
/* Replacement for missing library function.
*/
static int replacementTruncate (const char *const name, const long size)
{
char *tempName = NULL;
FILE *fp = tempFile ("w", &tempName);
fclose (fp);
copyFile (name, tempName, size);
copyFile (tempName, name, WHOLE_FILE);
remove (tempName);
eFree (tempName);
return 0;
}
#endif
static void sortTagFile (void)
{
if (TagFile.numTags.added > 0L)
{
if (Option.sorted != SO_UNSORTED)
{
verbose ("sorting tag file\n");
#ifdef EXTERNAL_SORT
externalSortTags (TagsToStdout);
#else
internalSortTags (TagsToStdout);
#endif
}
else if (TagsToStdout)
catFile (tagFileName ());
}
if (TagsToStdout)
remove (tagFileName ()); /* remove temporary file */
}
static void resizeTagFile (const long newSize)
{
int result;
#ifdef USE_REPLACEMENT_TRUNCATE
result = replacementTruncate (TagFile.name, newSize);
#else
# ifdef HAVE_TRUNCATE
result = truncate (TagFile.name, (off_t) newSize);
# else
const int fd = open (TagFile.name, O_RDWR);
if (fd == -1)
result = -1;
else
{
# ifdef HAVE_FTRUNCATE
result = ftruncate (fd, (off_t) newSize);
# else
# ifdef HAVE_CHSIZE
result = chsize (fd, newSize);
# endif
# endif
close (fd);
}
# endif
#endif
if (result == -1)
fprintf (errout, "Cannot shorten tag file: errno = %d\n", errno);
}
static void writeEtagsIncludes (FILE *const fp)
{
if (Option.etagsInclude)
{
unsigned int i;
for (i = 0 ; i < stringListCount (Option.etagsInclude) ; ++i)
{
vString *item = stringListItem (Option.etagsInclude, i);
fprintf (fp, "\f\n%s,include\n", vStringValue (item));
}
}
}
extern void closeTagFile (const boolean resize)
{
long desiredSize, size;
if (Option.etags)
writeEtagsIncludes (TagFile.fp);
desiredSize = ftell (TagFile.fp);
fseek (TagFile.fp, 0L, SEEK_END);
size = ftell (TagFile.fp);
fclose (TagFile.fp);
if (resize && desiredSize < size)
{
DebugStatement (
debugPrintf (DEBUG_STATUS, "shrinking %s from %ld to %ld bytes\n",
TagFile.name, size, desiredSize); )
resizeTagFile (desiredSize);
}
sortTagFile ();
eFree (TagFile.name);
TagFile.name = NULL;
}
extern void beginEtagsFile (void)
{
TagFile.etags.fp = tempFile ("w+b", &TagFile.etags.name);
TagFile.etags.byteCount = 0;
}
extern void endEtagsFile (const char *const name)
{
const char *line;
fprintf (TagFile.fp, "\f\n%s,%ld\n", name, (long) TagFile.etags.byteCount);
if (TagFile.etags.fp != NULL)
{
rewind (TagFile.etags.fp);
while ((line = readLine (TagFile.vLine, TagFile.etags.fp)) != NULL)
fputs (line, TagFile.fp);
fclose (TagFile.etags.fp);
remove (TagFile.etags.name);
eFree (TagFile.etags.name);
TagFile.etags.fp = NULL;
TagFile.etags.name = NULL;
}
}
/*
* Tag entry management
*/
/* This function copies the current line out to a specified file. It has no
* effect on the fileGetc () function. During copying, any '\' characters
* are doubled and a leading '^' or trailing '$' is also quoted. End of line
* characters (line feed or carriage return) are dropped.
*/
static size_t writeSourceLine (FILE *const fp, const char *const line)
{
size_t length = 0;
const char *p;
/* Write everything up to, but not including, a line end character.
*/
for (p = line ; *p != '\0' ; ++p)
{
const int next = *(p + 1);
const int c = *p;
if (c == CRETURN || c == NEWLINE)
break;
/* If character is '\', or a terminal '$', then quote it.
*/
if (c == BACKSLASH || c == (Option.backward ? '?' : '/') ||
(c == '$' && (next == NEWLINE || next == CRETURN)))
{
putc (BACKSLASH, fp);
++length;
}
putc (c, fp);
++length;
}
return length;
}
/* Writes "line", stripping leading and duplicate white space.
*/
static size_t writeCompactSourceLine (FILE *const fp, const char *const line)
{
boolean lineStarted = FALSE;
size_t length = 0;
const char *p;
int c;
/* Write everything up to, but not including, the newline.
*/
for (p = line, c = *p ; c != NEWLINE && c != '\0' ; c = *++p)
{
if (lineStarted || ! isspace (c)) /* ignore leading spaces */
{
lineStarted = TRUE;
if (isspace (c))
{
int next;
/* Consume repeating white space.
*/
while (next = *(p+1) , isspace (next) && next != NEWLINE)
++p;
c = ' '; /* force space character for any white space */
}
if (c != CRETURN || *(p + 1) != NEWLINE)
{
putc (c, fp);
++length;
}
}
}
return length;
}
static int writeXrefEntry (const tagEntryInfo *const tag)
{
const char *const line =
readSourceLine (TagFile.vLine, tag->filePosition, NULL);
int length;
if (Option.tagFileFormat == 1)
length = fprintf (TagFile.fp, "%-16s %4lu %-16s ", tag->name,
tag->lineNumber, tag->sourceFileName);
else
length = fprintf (TagFile.fp, "%-16s %-10s %4lu %-16s ", tag->name,
tag->kindName, tag->lineNumber, tag->sourceFileName);
length += writeCompactSourceLine (TagFile.fp, line);
putc (NEWLINE, TagFile.fp);
++length;
return length;
}
/* Truncates the text line containing the tag at the character following the
* tag, providing a character which designates the end of the tag.
*/
static void truncateTagLine (
char *const line, const char *const token, const boolean discardNewline)
{
char *p = strstr (line, token);
if (p != NULL)
{
p += strlen (token);
if (*p != '\0' && ! (*p == '\n' && discardNewline))
++p; /* skip past character terminating character */
*p = '\0';
}
}
static int writeEtagsEntry (const tagEntryInfo *const tag)
{
int length;
if (tag->isFileEntry)
length = fprintf (TagFile.etags.fp, "\177%s\001%lu,0\n",
tag->name, tag->lineNumber);
else
{
long seekValue;
char *const line =
readSourceLine (TagFile.vLine, tag->filePosition, &seekValue);
if (tag->truncateLine)
truncateTagLine (line, tag->name, TRUE);
else
line [strlen (line) - 1] = '\0';
length = fprintf (TagFile.etags.fp, "%s\177%s\001%lu,%ld\n", line,
tag->name, tag->lineNumber, seekValue);
}
TagFile.etags.byteCount += length;
return length;
}
static int addExtensionFields (const tagEntryInfo *const tag)
{
const char* const kindKey = Option.extensionFields.kindKey ? "kind:" : "";
boolean first = TRUE;
const char* separator = ";\"";
const char* const empty = "";
int length = 0;
/* "sep" returns a value only the first time it is evaluated */
#define sep (first ? (first = FALSE, separator) : empty)
if (tag->kindName != NULL && (Option.extensionFields.kindLong ||
(Option.extensionFields.kind && tag->kind == '\0')))
length += fprintf (TagFile.fp,"%s\t%s%s", sep, kindKey, tag->kindName);
else if (tag->kind != '\0' && (Option.extensionFields.kind ||
(Option.extensionFields.kindLong && tag->kindName == NULL)))
length += fprintf (TagFile.fp, "%s\t%s%c", sep, kindKey, tag->kind);
if (Option.extensionFields.lineNumber)
length += fprintf (TagFile.fp, "%s\tline:%ld", sep, tag->lineNumber);
if (Option.extensionFields.language && tag->language != NULL)
length += fprintf (TagFile.fp, "%s\tlanguage:%s", sep, tag->language);
if (Option.extensionFields.scope &&
tag->extensionFields.scope [0] != NULL &&
tag->extensionFields.scope [1] != NULL)
length += fprintf (TagFile.fp, "%s\t%s:%s", sep,
tag->extensionFields.scope [0],
tag->extensionFields.scope [1]);
if (Option.extensionFields.typeRef &&
tag->extensionFields.typeRef [0] != NULL &&
tag->extensionFields.typeRef [1] != NULL)
length += fprintf (TagFile.fp, "%s\ttyperef:%s:%s", sep,
tag->extensionFields.typeRef [0],
tag->extensionFields.typeRef [1]);
if (Option.extensionFields.fileScope && tag->isFileScope)
length += fprintf (TagFile.fp, "%s\tfile:", sep);
if (Option.extensionFields.inheritance &&
tag->extensionFields.inheritance != NULL)
length += fprintf (TagFile.fp, "%s\tinherits:%s", sep,
tag->extensionFields.inheritance);
if (Option.extensionFields.access && tag->extensionFields.access != NULL)
length += fprintf (TagFile.fp, "%s\taccess:%s", sep,
tag->extensionFields.access);
if (Option.extensionFields.implementation &&
tag->extensionFields.implementation != NULL)
length += fprintf (TagFile.fp, "%s\timplementation:%s", sep,
tag->extensionFields.implementation);
if (Option.extensionFields.signature &&
tag->extensionFields.signature != NULL)
length += fprintf (TagFile.fp, "%s\tsignature:%s", sep,
tag->extensionFields.signature);
return length;
#undef sep
}
static int writePatternEntry (const tagEntryInfo *const tag)
{
char *const line = readSourceLine (TagFile.vLine, tag->filePosition, NULL);
const int searchChar = Option.backward ? '?' : '/';
boolean newlineTerminated;
int length = 0;
if (tag->truncateLine)
truncateTagLine (line, tag->name, FALSE);
newlineTerminated = (boolean) (line [strlen (line) - 1] == '\n');
length += fprintf (TagFile.fp, "%c^", searchChar);
length += writeSourceLine (TagFile.fp, line);
length += fprintf (TagFile.fp, "%s%c", newlineTerminated ? "$":"", searchChar);
return length;
}
static int writeLineNumberEntry (const tagEntryInfo *const tag)
{
return fprintf (TagFile.fp, "%lu", tag->lineNumber);
}
static int writeCtagsEntry (const tagEntryInfo *const tag)
{
int length = fprintf (TagFile.fp, "%s\t%s\t",
tag->name, tag->sourceFileName);
if (tag->lineNumberEntry)
length += writeLineNumberEntry (tag);
else
length += writePatternEntry (tag);
if (includeExtensionFlags ())
length += addExtensionFields (tag);
length += fprintf (TagFile.fp, "\n");
return length;
}
extern void makeTagEntry (const tagEntryInfo *const tag)
{
Assert (tag->name != NULL);
if (tag->name [0] == '\0')
error (WARNING, "ignoring null tag in %s", vStringValue (File.name));
else
{
int length = 0;
DebugStatement ( debugEntry (tag); )
if (Option.xref)
{
if (! tag->isFileEntry)
length = writeXrefEntry (tag);
}
else if (Option.etags)
length = writeEtagsEntry (tag);
else
length = writeCtagsEntry (tag);
++TagFile.numTags.added;
rememberMaxLengths (strlen (tag->name), (size_t) length);
DebugStatement ( fflush (TagFile.fp); )
}
}
extern void initTagEntry (tagEntryInfo *const e, const char *const name)
{
Assert (File.source.name != NULL);
memset (e, 0, sizeof (tagEntryInfo));
e->lineNumberEntry = (boolean) (Option.locate == EX_LINENUM);
e->lineNumber = getSourceLineNumber ();
e->language = getSourceLanguageName ();
e->filePosition = getInputFilePosition ();
e->sourceFileName = getSourceFileTagPath ();
e->name = name;
}
/* vi:set tabstop=4 shiftwidth=4: */
+103
View File
@@ -0,0 +1,103 @@
/*
* $Id: entry.h,v 1.5 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 1998-2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* External interface to entry.c
*/
#ifndef _ENTRY_H
#define _ENTRY_H
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <stdio.h>
#include "vstring.h"
/*
* MACROS
*/
#define WHOLE_FILE -1L
/*
* DATA DECLARATIONS
*/
/* Maintains the state of the tag file.
*/
typedef struct eTagFile {
char *name;
char *directory;
FILE *fp;
struct sNumTags { unsigned long added, prev; } numTags;
struct sMax { size_t line, tag, file; } max;
struct sEtags {
char *name;
FILE *fp;
size_t byteCount;
} etags;
vString *vLine;
} tagFile;
typedef struct sTagFields {
unsigned int count; /* number of additional extension flags */
const char *const *label; /* list of labels for extension flags */
const char *const *value; /* list of values for extension flags */
} tagFields;
/* Information about the current tag candidate.
*/
typedef struct sTagEntryInfo {
boolean lineNumberEntry; /* pattern or line number entry */
unsigned long lineNumber; /* line number of tag */
fpos_t filePosition; /* file position of line containing tag */
const char* language; /* language of source file */
boolean isFileScope; /* is tag visibile only within source file? */
boolean isFileEntry; /* is this just an entry for a file name? */
boolean truncateLine; /* truncate tag line at end of tag name? */
const char *sourceFileName; /* name of source file */
const char *name; /* name of the tag */
const char *kindName; /* kind of tag */
char kind; /* single character representation of kind */
struct {
const char* access;
const char* fileScope;
const char* implementation;
const char* inheritance;
const char* scope [2]; /* value and key */
const char* signature;
/* type (union/struct/etc.) and name for a variable or typedef. */
const char* typeRef [2]; /* e.g., "struct" and struct name */
} extensionFields; /* list of extension fields*/
} tagEntryInfo;
/*
* GLOBAL VARIABLES
*/
extern tagFile TagFile;
/*
* FUNCTION PROTOTYPES
*/
extern void freeTagFileResources (void);
extern const char *tagFileName (void);
extern void copyBytes (FILE* const fromFp, FILE* const toFp, const long size);
extern void copyFile (const char *const from, const char *const to, const long size);
extern void openTagFile (void);
extern void closeTagFile (const boolean resize);
extern void beginEtagsFile (void);
extern void endEtagsFile (const char *const name);
extern void makeTagEntry (const tagEntryInfo *const tag);
extern void initTagEntry (tagEntryInfo *const e, const char *const name);
#endif /* _ENTRY_H */
/* vi:set tabstop=4 shiftwidth=4: */
+189
View File
@@ -0,0 +1,189 @@
/*
* $Id: erlang.c,v 1.3 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 2003, Brent Fulgham <[email protected]>
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for generating tags for Erlang language
* files. Some of the parsing constructs are based on the Emacs 'etags'
* program by Francesco Potori <[email protected]>
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#include "entry.h"
#include "options.h"
#include "read.h"
#include "routines.h"
#include "vstring.h"
/*
* DATA DEFINITIONS
*/
typedef enum {
K_MACRO, K_FUNCTION, K_MODULE, K_RECORD
} erlangKind;
static kindOption ErlangKinds[] = {
{TRUE, 'd', "macro", "macro definitions"},
{TRUE, 'f', "function", "functions"},
{TRUE, 'm', "module", "modules"},
{TRUE, 'r', "record", "record definitions"},
};
/*
* FUNCTION DEFINITIONS
*/
/* tagEntryInfo and vString should be preinitialized/preallocated but not
* necessary. If successful you will find class name in vString
*/
static boolean isIdentifierFirstCharacter (int c)
{
return (boolean) (isalpha (c));
}
static boolean isIdentifierCharacter (int c)
{
return (boolean) (isalnum (c) || c == '_' || c == ':');
}
static const unsigned char *skipSpace (const unsigned char *cp)
{
while (isspace ((int) *cp))
++cp;
return cp;
}
static const unsigned char *parseIdentifier (
const unsigned char *cp, vString *const identifier)
{
vStringClear (identifier);
while (isIdentifierCharacter ((int) *cp))
{
vStringPut (identifier, (int) *cp);
++cp;
}
vStringTerminate (identifier);
return cp;
}
static void makeMemberTag (
vString *const identifier, erlangKind kind, vString *const module)
{
if (ErlangKinds [kind].enabled && vStringLength (identifier) > 0)
{
tagEntryInfo tag;
initTagEntry (&tag, vStringValue (identifier));
tag.kindName = ErlangKinds[kind].name;
tag.kind = ErlangKinds[kind].letter;
if (module != NULL && vStringLength (module) > 0)
{
tag.extensionFields.scope [0] = "module";
tag.extensionFields.scope [1] = vStringValue (module);
}
makeTagEntry (&tag);
}
}
static void parseModuleTag (const unsigned char *cp, vString *const module)
{
vString *const identifier = vStringNew ();
parseIdentifier (cp, identifier);
makeSimpleTag (identifier, ErlangKinds, K_MODULE);
/* All further entries go in the new module */
vStringCopy (module, identifier);
vStringDelete (identifier);
}
static void parseSimpleTag (const unsigned char *cp, erlangKind kind)
{
vString *const identifier = vStringNew ();
parseIdentifier (cp, identifier);
makeSimpleTag (identifier, ErlangKinds, kind);
vStringDelete (identifier);
}
static void parseFunctionTag (const unsigned char *cp, vString *const module)
{
vString *const identifier = vStringNew ();
parseIdentifier (cp, identifier);
makeMemberTag (identifier, K_FUNCTION, module);
vStringDelete (identifier);
}
/*
* Directives are of the form:
* -module(foo)
* -define(foo, bar)
* -record(graph, {vtab = notable, cyclic = true}).
*/
static void parseDirective (const unsigned char *cp, vString *const module)
{
/*
* A directive will be either a record definition or a directive.
* Record definitions are handled separately
*/
vString *const directive = vStringNew ();
const char *const drtv = vStringValue (directive);
cp = parseIdentifier (cp, directive);
cp = skipSpace (cp);
if (*cp == '(')
++cp;
if (strcmp (drtv, "record") == 0)
parseSimpleTag (cp, K_RECORD);
else if (strcmp (drtv, "define") == 0)
parseSimpleTag (cp, K_MACRO);
else if (strcmp (drtv, "module") == 0)
parseModuleTag (cp, module);
/* Otherwise, it was an import, export, etc. */
vStringDelete (directive);
}
static void findErlangTags (void)
{
vString *const module = vStringNew ();
const unsigned char *line;
while ((line = fileReadLine ()) != NULL)
{
const unsigned char *cp = line;
if (*cp == '%') /* skip initial comment */
continue;
if (*cp == '"') /* strings sometimes start in column one */
continue;
if ( *cp == '-')
{
++cp; /* Move off of the '-' */
parseDirective(cp, module);
}
else if (isIdentifierFirstCharacter ((int) *cp))
parseFunctionTag (cp, module);
}
vStringDelete (module);
}
extern parserDefinition *ErlangParser (void)
{
static const char *const extensions[] = { "erl", "ERL", "hrl", "HRL", NULL };
parserDefinition *def = parserNew ("Erlang");
def->kinds = ErlangKinds;
def->kindCount = KIND_COUNT (ErlangKinds);
def->extensions = extensions;
def->parser = findErlangTags;
return def;
}
/* vi:set tabstop=4 shiftwidth=4: */
File diff suppressed because it is too large Load Diff
+127
View File
@@ -0,0 +1,127 @@
/*
* $Id: general.h,v 1.15 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 1998-2003, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* Provides the general (non-ctags-specific) environment assumed by all.
*/
#ifndef _GENERAL_H
#define _GENERAL_H
/*
* INCLUDE FILES
*/
#if defined (HAVE_CONFIG_H)
# include <config.h>
#elif defined (AMIGA)
# include "e_amiga.h"
#elif defined (DJGPP)
# include "e_djgpp.h"
#elif defined (macintosh)
# include "e_mac.h"
#elif defined (MSDOS) || defined (WIN32)
# include "e_msoft.h"
#elif defined (OS2)
# include "e_os2.h"
#elif defined (QDOS)
# include "e_qdos.h"
#elif defined (RISCOS)
# include "e_riscos.h"
#elif defined (__vms) || defined (VMS)
# include "e_vms.h"
# ifndef VMS
# define VMS 1
# endif
#endif
/*
* MACROS
*/
/* Define standard error destination
*/
#ifndef errout
# define errout stderr
#endif
/* Define regex if supported */
#if (defined (HAVE_REGCOMP) && !defined (REGCOMP_BROKEN))
# define HAVE_REGEX 1
#endif
/* This is a helpful internal feature of later versions (> 2.7) of GCC
* to prevent warnings about unused variables.
*/
#if (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)) && !(defined (__APPLE_CC__) || defined (__GNUG__))
# define __unused__ __attribute__((unused))
# define __printf__(s,f) __attribute__((format (printf, s, f)))
#else
# define __unused__
# define __printf__(s,f)
#endif
/*
* Portability macros
*/
#if !defined(HAVE_STRCASECMP) && !defined(strcasecmp)
# ifdef HAVE_STRICMP
# define strcasecmp(s1,s2) stricmp(s1,s2)
# else
# define strcasecmp(s1,s2) struppercmp(s1,s2)
# endif
#endif
#if !defined(HAVE_STRNCASECMP) && !defined(strncasecmp)
# ifdef HAVE_STRNICMP
# define strncasecmp(s1,s2,n) strnicmp(s1,s2,n)
# else
# define strncasecmp(s1,s2,n) strnuppercmp(s1,s2,n)
# endif
#endif
/*
* DATA DECLARATIONS
*/
#undef FALSE
#undef TRUE
#ifdef VAXC
typedef enum { FALSE, TRUE } booleanType;
typedef int boolean;
#else
# ifdef __cplusplus
typedef bool boolean;
#define FALSE false
#define TRUE true
# else
typedef enum { FALSE, TRUE } boolean;
# endif
#endif
#if ! defined (HAVE_FGETPOS) && ! defined (fpos_t)
# define fpos_t long
#endif
/*
* FUNCTION PROTOTYPES
*/
#if defined (NEED_PROTO_REMOVE) && defined (HAVE_REMOVE)
extern int remove (const char *);
#endif
#if defined (NEED_PROTO_UNLINK) && ! defined (HAVE_REMOVE)
extern void *unlink (const char *);
#endif
#ifdef NEED_PROTO_GETENV
extern char *getenv (const char *);
#endif
#endif /* _GENERAL_H */
/* vi:set tabstop=4 shiftwidth=4: */
+656
View File
@@ -0,0 +1,656 @@
/*
* $Id: get.c,v 1.9 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 1996-2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains the high level source read functions (preprocessor
* directives are handled within this level).
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#include "debug.h"
#include "entry.h"
#include "get.h"
#include "options.h"
#include "read.h"
#include "vstring.h"
/*
* MACROS
*/
#define stringMatch(s1,s2) (strcmp (s1,s2) == 0)
#define isspacetab(c) ((c) == SPACE || (c) == TAB)
/*
* DATA DECLARATIONS
*/
typedef enum { COMMENT_NONE, COMMENT_C, COMMENT_CPLUS } Comment;
enum eCppLimits {
MaxCppNestingLevel = 20,
MaxDirectiveName = 10
};
/* Defines the one nesting level of a preprocessor conditional.
*/
typedef struct sConditionalInfo {
boolean ignoreAllBranches; /* ignoring parent conditional branch */
boolean singleBranch; /* choose only one branch */
boolean branchChosen; /* branch already selected */
boolean ignoring; /* current ignore state */
} conditionalInfo;
enum eState {
DRCTV_NONE, /* no known directive - ignore to end of line */
DRCTV_DEFINE, /* "#define" encountered */
DRCTV_HASH, /* initial '#' read; determine directive */
DRCTV_IF, /* "#if" or "#ifdef" encountered */
DRCTV_PRAGMA, /* #pragma encountered */
DRCTV_UNDEF /* "#undef" encountered */
};
/* Defines the current state of the pre-processor.
*/
typedef struct sCppState {
int ungetch, ungetch2; /* ungotten characters, if any */
boolean resolveRequired; /* must resolve if/else/elif/endif branch */
struct sDirective {
enum eState state; /* current directive being processed */
boolean accept; /* is a directive syntatically permitted? */
vString * name; /* macro name */
unsigned int nestLevel; /* level 0 is not used */
conditionalInfo ifdef [MaxCppNestingLevel];
} directive;
} cppState;
/*
* DATA DEFINITIONS
*/
/* Use brace formatting to detect end of block.
*/
static boolean BraceFormat = FALSE;
static cppState Cpp = {
'\0', '\0', /* ungetch characters */
FALSE, /* resolveRequired */
{
DRCTV_NONE, /* state */
FALSE, /* accept */
NULL, /* tag name */
0, /* nestLevel */
{ {FALSE,FALSE,FALSE,FALSE} } /* ifdef array */
} /* directive */
};
/*
* FUNCTION DEFINITIONS
*/
extern boolean isBraceFormat (void)
{
return BraceFormat;
}
extern unsigned int getDirectiveNestLevel (void)
{
return Cpp.directive.nestLevel;
}
extern void cppInit (const boolean state)
{
BraceFormat = state;
Cpp.ungetch = '\0';
Cpp.ungetch2 = '\0';
Cpp.resolveRequired = FALSE;
Cpp.directive.state = DRCTV_NONE;
Cpp.directive.accept = TRUE;
Cpp.directive.nestLevel = 0;
Cpp.directive.ifdef [0].ignoreAllBranches = FALSE;
Cpp.directive.ifdef [0].singleBranch = FALSE;
Cpp.directive.ifdef [0].branchChosen = FALSE;
Cpp.directive.ifdef [0].ignoring = FALSE;
if (Cpp.directive.name == NULL)
Cpp.directive.name = vStringNew ();
else
vStringClear (Cpp.directive.name);
}
extern void cppTerminate (void)
{
if (Cpp.directive.name != NULL)
{
vStringDelete (Cpp.directive.name);
Cpp.directive.name = NULL;
}
}
extern void cppBeginStatement (void)
{
Cpp.resolveRequired = TRUE;
}
extern void cppEndStatement (void)
{
Cpp.resolveRequired = FALSE;
}
/*
* Scanning functions
*
* This section handles preprocessor directives. It strips out all
* directives and may emit a tag for #define directives.
*/
/* This puts a character back into the input queue for the source File.
* Up to two characters may be ungotten.
*/
extern void cppUngetc (const int c)
{
Assert (Cpp.ungetch2 == '\0');
Cpp.ungetch2 = Cpp.ungetch;
Cpp.ungetch = c;
}
/* Reads a directive, whose first character is given by "c", into "name".
*/
static boolean readDirective (int c, char *const name, unsigned int maxLength)
{
unsigned int i;
for (i = 0 ; i < maxLength - 1 ; ++i)
{
if (i > 0)
{
c = fileGetc ();
if (c == EOF || ! isalpha (c))
{
fileUngetc (c);
break;
}
}
name [i] = c;
}
name [i] = '\0'; /* null terminate */
return (boolean) isspacetab (c);
}
/* Reads an identifier, whose first character is given by "c", into "tag",
* together with the file location and corresponding line number.
*/
static void readIdentifier (int c, vString *const name)
{
vStringClear (name);
do
{
vStringPut (name, c);
} while (c = fileGetc (), (c != EOF && isident (c)));
fileUngetc (c);
vStringTerminate (name);
}
static conditionalInfo *currentConditional (void)
{
return &Cpp.directive.ifdef [Cpp.directive.nestLevel];
}
static boolean isIgnore (void)
{
return Cpp.directive.ifdef [Cpp.directive.nestLevel].ignoring;
}
static boolean setIgnore (const boolean ignore)
{
return Cpp.directive.ifdef [Cpp.directive.nestLevel].ignoring = ignore;
}
static boolean isIgnoreBranch (void)
{
conditionalInfo *const ifdef = currentConditional ();
/* Force a single branch if an incomplete statement is discovered
* en route. This may have allowed earlier branches containing complete
* statements to be followed, but we must follow no further branches.
*/
if (Cpp.resolveRequired && ! BraceFormat)
ifdef->singleBranch = TRUE;
/* We will ignore this branch in the following cases:
*
* 1. We are ignoring all branches (conditional was within an ignored
* branch of the parent conditional)
* 2. A branch has already been chosen and either of:
* a. A statement was incomplete upon entering the conditional
* b. A statement is incomplete upon encountering a branch
*/
return (boolean) (ifdef->ignoreAllBranches ||
(ifdef->branchChosen && ifdef->singleBranch));
}
static void chooseBranch (void)
{
if (! BraceFormat)
{
conditionalInfo *const ifdef = currentConditional ();
ifdef->branchChosen = (boolean) (ifdef->singleBranch ||
Cpp.resolveRequired);
}
}
/* Pushes one nesting level for an #if directive, indicating whether or not
* the branch should be ignored and whether a branch has already been chosen.
*/
static boolean pushConditional (const boolean firstBranchChosen)
{
const boolean ignoreAllBranches = isIgnore (); /* current ignore */
boolean ignoreBranch = FALSE;
if (Cpp.directive.nestLevel < (unsigned int) MaxCppNestingLevel - 1)
{
conditionalInfo *ifdef;
++Cpp.directive.nestLevel;
ifdef = currentConditional ();
/* We take a snapshot of whether there is an incomplete statement in
* progress upon encountering the preprocessor conditional. If so,
* then we will flag that only a single branch of the conditional
* should be followed.
*/
ifdef->ignoreAllBranches = ignoreAllBranches;
ifdef->singleBranch = Cpp.resolveRequired;
ifdef->branchChosen = firstBranchChosen;
ifdef->ignoring = (boolean) (ignoreAllBranches || (
! firstBranchChosen && ! BraceFormat &&
(ifdef->singleBranch || !Option.if0)));
ignoreBranch = ifdef->ignoring;
}
return ignoreBranch;
}
/* Pops one nesting level for an #endif directive.
*/
static boolean popConditional (void)
{
if (Cpp.directive.nestLevel > 0)
--Cpp.directive.nestLevel;
return isIgnore ();
}
static void makeDefineTag (const char *const name)
{
const boolean isFileScope = (boolean) (! isHeaderFile ());
if (includingDefineTags () &&
(! isFileScope || Option.include.fileScope))
{
tagEntryInfo e;
initTagEntry (&e, name);
e.lineNumberEntry = (boolean) (Option.locate != EX_PATTERN);
e.isFileScope = isFileScope;
e.truncateLine = TRUE;
e.kindName = "macro";
e.kind = 'd';
makeTagEntry (&e);
}
}
static void directiveDefine (const int c)
{
if (isident1 (c))
{
readIdentifier (c, Cpp.directive.name);
if (! isIgnore ())
makeDefineTag (vStringValue (Cpp.directive.name));
}
Cpp.directive.state = DRCTV_NONE;
}
static void directivePragma (int c)
{
if (isident1 (c))
{
readIdentifier (c, Cpp.directive.name);
if (stringMatch (vStringValue (Cpp.directive.name), "weak"))
{
/* generate macro tag for weak name */
do
{
c = fileGetc ();
} while (c == SPACE);
if (isident1 (c))
{
readIdentifier (c, Cpp.directive.name);
makeDefineTag (vStringValue (Cpp.directive.name));
}
}
}
Cpp.directive.state = DRCTV_NONE;
}
static boolean directiveIf (const int c)
{
DebugStatement ( const boolean ignore0 = isIgnore (); )
const boolean ignore = pushConditional ((boolean) (c != '0'));
Cpp.directive.state = DRCTV_NONE;
DebugStatement ( debugCppNest (TRUE, Cpp.directive.nestLevel);
if (ignore != ignore0) debugCppIgnore (ignore); )
return ignore;
}
static boolean directiveHash (const int c)
{
boolean ignore = FALSE;
char directive [MaxDirectiveName];
DebugStatement ( const boolean ignore0 = isIgnore (); )
readDirective (c, directive, MaxDirectiveName);
if (stringMatch (directive, "define"))
Cpp.directive.state = DRCTV_DEFINE;
else if (stringMatch (directive, "undef"))
Cpp.directive.state = DRCTV_UNDEF;
else if (strncmp (directive, "if", (size_t) 2) == 0)
Cpp.directive.state = DRCTV_IF;
else if (stringMatch (directive, "elif") ||
stringMatch (directive, "else"))
{
ignore = setIgnore (isIgnoreBranch ());
if (! ignore && stringMatch (directive, "else"))
chooseBranch ();
Cpp.directive.state = DRCTV_NONE;
DebugStatement ( if (ignore != ignore0) debugCppIgnore (ignore); )
}
else if (stringMatch (directive, "endif"))
{
DebugStatement ( debugCppNest (FALSE, Cpp.directive.nestLevel); )
ignore = popConditional ();
Cpp.directive.state = DRCTV_NONE;
DebugStatement ( if (ignore != ignore0) debugCppIgnore (ignore); )
}
else if (stringMatch (directive, "pragma"))
Cpp.directive.state = DRCTV_PRAGMA;
else
Cpp.directive.state = DRCTV_NONE;
return ignore;
}
/* Handles a pre-processor directive whose first character is given by "c".
*/
static boolean handleDirective (const int c)
{
boolean ignore = isIgnore ();
switch (Cpp.directive.state)
{
case DRCTV_NONE: ignore = isIgnore (); break;
case DRCTV_DEFINE: directiveDefine (c); break;
case DRCTV_HASH: ignore = directiveHash (c); break;
case DRCTV_IF: ignore = directiveIf (c); break;
case DRCTV_PRAGMA: directivePragma (c); break;
case DRCTV_UNDEF: directiveDefine (c); break;
}
return ignore;
}
/* Called upon reading of a slash ('/') characters, determines whether a
* comment is encountered, and its type.
*/
static Comment isComment (void)
{
Comment comment;
const int next = fileGetc ();
if (next == '*')
comment = COMMENT_C;
else if (next == '/')
comment = COMMENT_CPLUS;
else
{
fileUngetc (next);
comment = COMMENT_NONE;
}
return comment;
}
/* Skips over a C style comment. According to ANSI specification a comment
* is treated as white space, so we perform this subsitution.
*/
static int skipOverCComment (void)
{
int c = fileGetc ();
while (c != EOF)
{
if (c != '*')
c = fileGetc ();
else
{
const int next = fileGetc ();
if (next != '/')
c = next;
else
{
c = SPACE; /* replace comment with space */
break;
}
}
}
return c;
}
/* Skips over a C++ style comment.
*/
static int skipOverCplusComment (void)
{
int c;
while ((c = fileGetc ()) != EOF)
{
if (c == BACKSLASH)
fileGetc (); /* throw away next character, too */
else if (c == NEWLINE)
break;
}
return c;
}
/* Skips to the end of a string, returning a special character to
* symbolically represent a generic string.
*/
static int skipToEndOfString (void)
{
int c;
while ((c = fileGetc ()) != EOF)
{
if (c == BACKSLASH)
fileGetc (); /* throw away next character, too */
else if (c == DOUBLE_QUOTE)
break;
}
return STRING_SYMBOL; /* symbolic representation of string */
}
/* Skips to the end of the three (possibly four) 'c' sequence, returning a
* special character to symbolically represent a generic character.
* Also detects Vera numbers that include a base specifier (ie. 'b1010).
*/
static int skipToEndOfChar (void)
{
int c;
int count = 0, veraBase = '\0';
while ((c = fileGetc ()) != EOF)
{
++count;
if (c == BACKSLASH)
fileGetc (); /* throw away next character, too */
else if (c == SINGLE_QUOTE)
break;
else if (c == NEWLINE)
{
fileUngetc (c);
break;
}
else if (count == 1 && strchr ("DHOB", toupper (c)) != NULL)
veraBase = c;
else if (veraBase != '\0' && ! isalnum (c))
{
fileUngetc (c);
break;
}
}
return CHAR_SYMBOL; /* symbolic representation of character */
}
/* This function returns the next character, stripping out comments,
* C pre-processor directives, and the contents of single and double
* quoted strings. In short, strip anything which places a burden upon
* the tokenizer.
*/
extern int cppGetc (void)
{
boolean directive = FALSE;
boolean ignore = FALSE;
int c;
if (Cpp.ungetch != '\0')
{
c = Cpp.ungetch;
Cpp.ungetch = Cpp.ungetch2;
Cpp.ungetch2 = '\0';
return c; /* return here to avoid re-calling debugPutc () */
}
else do
{
c = fileGetc ();
process:
switch (c)
{
case EOF:
ignore = FALSE;
directive = FALSE;
break;
case TAB:
case SPACE:
break; /* ignore most white space */
case NEWLINE:
if (directive && ! ignore)
directive = FALSE;
Cpp.directive.accept = TRUE;
break;
case DOUBLE_QUOTE:
Cpp.directive.accept = FALSE;
c = skipToEndOfString ();
break;
case '#':
if (Cpp.directive.accept)
{
directive = TRUE;
Cpp.directive.state = DRCTV_HASH;
Cpp.directive.accept = FALSE;
}
break;
case SINGLE_QUOTE:
Cpp.directive.accept = FALSE;
c = skipToEndOfChar ();
break;
case '/':
{
const Comment comment = isComment ();
if (comment == COMMENT_C)
c = skipOverCComment ();
else if (comment == COMMENT_CPLUS)
{
c = skipOverCplusComment ();
if (c == NEWLINE)
fileUngetc (c);
}
else
Cpp.directive.accept = FALSE;
break;
}
case BACKSLASH:
{
int next = fileGetc ();
if (next == NEWLINE)
continue;
else if (next == '?')
cppUngetc (next);
else
fileUngetc (next);
break;
}
case '?':
{
int next = fileGetc ();
if (next != '?')
fileUngetc (next);
else
{
next = fileGetc ();
switch (next)
{
case '(': c = '['; break;
case ')': c = ']'; break;
case '<': c = '{'; break;
case '>': c = '}'; break;
case '/': c = BACKSLASH; goto process;
case '!': c = '|'; break;
case SINGLE_QUOTE: c = '^'; break;
case '-': c = '~'; break;
case '=': c = '#'; goto process;
default:
fileUngetc (next);
cppUngetc ('?');
break;
}
}
} break;
default:
Cpp.directive.accept = FALSE;
if (directive)
ignore = handleDirective (c);
break;
}
} while (directive || ignore);
DebugStatement ( debugPutc (DEBUG_CPP, c); )
DebugStatement ( if (c == NEWLINE)
debugPrintf (DEBUG_CPP, "%6ld: ", getInputLineNumber () + 1); )
return c;
}
/* vi:set tabstop=4 shiftwidth=4: */
+49
View File
@@ -0,0 +1,49 @@
/*
* $Id: get.h,v 1.4 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 1998-2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* External interface to get.c
*/
#ifndef _GET_H
#define _GET_H
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include "ctags.h" /* to define langType */
/*
* MACROS
*/
/* Is the character valid as a character of a C identifier?
* VMS allows '$' in identifiers.
*/
#define isident(c) (isalnum(c) || (c) == '_' || (c) == '$')
/* Is the character valid as the first character of a C identifier?
* C++ allows '~' in destructors.
* VMS allows '$' in identifiers.
*/
#define isident1(c) (isalpha(c) || (c) == '_' || (c) == '~' || (c) == '$')
/*
* FUNCTION PROTOTYPES
*/
extern boolean isBraceFormat (void);
extern unsigned int getDirectiveNestLevel (void);
extern void cppInit (const boolean state);
extern void cppTerminate (void);
extern void cppBeginStatement (void);
extern void cppEndStatement (void);
extern void cppUngetc (const int c);
extern int cppGetc (void);
#endif /* _GET_H */
/* vi:set tabstop=4 shiftwidth=4: */
+49
View File
@@ -0,0 +1,49 @@
/*
* $Id: html.c,v 1.2 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 2003, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for generating tags for HTML language
* files.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include "parse.h"
/*
* FUNCTION DEFINITIONS
*/
static void installHtmlRegex (const langType language)
{
#define POSSIBLE_ATTRIBUTES "([ \t]+[a-z]+=\"?[^>\"]*\"?)*"
addTagRegex (language,
"<a"
POSSIBLE_ATTRIBUTES
"[ \t]+name=\"?([^>\"]+)\"?"
POSSIBLE_ATTRIBUTES
"[ \t]*>",
"\\2", "a,anchor,named anchors", "i");
addTagRegex (language, "^[ \t]*function[ \t]*([A-Za-z0-9_]+)[ \t]*\\(",
"\\1", "f,function,JavaScript functions", NULL);
}
/* Create parser definition stucture */
extern parserDefinition* HtmlParser (void)
{
static const char *const extensions [] = { "htm", "html", NULL };
parserDefinition *const def = parserNew ("HTML");
def->extensions = extensions;
def->initialize = installHtmlRegex;
def->regex = TRUE;
return def;
}
/* vi:set tabstop=4 shiftwidth=4: */
+40
View File
@@ -0,0 +1,40 @@
/*
* $Id: jscript.c,v 1.2 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 2003, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for generating tags for JavaScript language
* files.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include "parse.h"
/*
* FUNCTION DEFINITIONS
*/
static void installJavaScriptRegex (const langType language)
{
addTagRegex (language, "^[ \t]*function[ \t]*([A-Za-z0-9_]+)[ \t]*\\(",
"\\1", "f,function,functions", NULL);
}
/* Create parser definition stucture */
extern parserDefinition* JavaScriptParser (void)
{
static const char *const extensions [] = { "js", NULL };
parserDefinition *const def = parserNew ("JavaScript");
def->extensions = extensions;
def->initialize = installJavaScriptRegex;
def->regex = TRUE;
return def;
}
/* vi:set tabstop=4 shiftwidth=4: */
+249
View File
@@ -0,0 +1,249 @@
/*
* $Id: keyword.c,v 1.6 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 1998-2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* Manages a keyword hash.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#include "debug.h"
#include "keyword.h"
#include "options.h"
#include "routines.h"
/*
* MACROS
*/
#define HASH_EXPONENT 7 /* must be less than 17 */
/*
* DATA DECLARATIONS
*/
typedef struct sHashEntry {
struct sHashEntry *next;
const char *string;
langType language;
int value;
} hashEntry;
/*
* DATA DEFINITIONS
*/
static const unsigned int TableSize = 1 << HASH_EXPONENT;
static hashEntry **HashTable = NULL;
/*
* FUNCTION DEFINITIONS
*/
static hashEntry **getHashTable (void)
{
static boolean allocated = FALSE;
if (! allocated)
{
unsigned int i;
HashTable = xMalloc (TableSize, hashEntry*);
for (i = 0 ; i < TableSize ; ++i)
HashTable [i] = NULL;
allocated = TRUE;
}
return HashTable;
}
static hashEntry *getHashTableEntry (unsigned long hashedValue)
{
hashEntry **const table = getHashTable ();
hashEntry *entry;
Assert (hashedValue < TableSize);
entry = table [hashedValue];
return entry;
}
static unsigned long hashValue (const char *const string)
{
unsigned long value = 0;
const unsigned char *p;
Assert (string != NULL);
/* We combine the various words of the multiword key using the method
* described on page 512 of Vol. 3 of "The Art of Computer Programming".
*/
for (p = (const unsigned char *) string ; *p != '\0' ; ++p)
{
value <<= 1;
if (value & 0x00000100L)
value = (value & 0x000000ffL) + 1L;
value ^= *p;
}
/* Algorithm from page 509 of Vol. 3 of "The Art of Computer Programming"
* Treats "value" as a 16-bit integer plus 16-bit fraction.
*/
value *= 40503L; /* = 2^16 * 0.6180339887 ("golden ratio") */
value &= 0x0000ffffL; /* keep fractional part */
value >>= 16 - HASH_EXPONENT; /* scale up by hash size and move down */
return value;
}
static hashEntry *newEntry (
const char *const string, langType language, int value)
{
hashEntry *const entry = xMalloc (1, hashEntry);
entry->next = NULL;
entry->string = string;
entry->language = language;
entry->value = value;
return entry;
}
/* Note that it is assumed that a "value" of zero means an undefined keyword
* and clients of this function should observe this. Also, all keywords added
* should be added in lower case. If we encounter a case-sensitive language
* whose keywords are in upper case, we will need to redesign this.
*/
extern void addKeyword (const char *const string, langType language, int value)
{
const unsigned long hashedValue = hashValue (string);
hashEntry *tableEntry = getHashTableEntry (hashedValue);
hashEntry *entry = tableEntry;
if (entry == NULL)
{
hashEntry **const table = getHashTable ();
table [hashedValue] = newEntry (string, language, value);
}
else
{
hashEntry *prev = NULL;
while (entry != NULL)
{
if (language == entry->language &&
strcmp (string, entry->string) == 0)
{
Assert (("Already in table" == NULL));
}
prev = entry;
entry = entry->next;
}
if (entry == NULL)
{
Assert (prev != NULL);
prev->next = newEntry (string, language, value);
}
}
}
extern int lookupKeyword (const char *const string, langType language)
{
const unsigned long hashedValue = hashValue (string);
hashEntry *entry = getHashTableEntry (hashedValue);
int result = -1;
while (entry != NULL)
{
if (language == entry->language && strcmp (string, entry->string) == 0)
{
result = entry->value;
break;
}
entry = entry->next;
}
return result;
}
extern void freeKeywordTable (void)
{
if (HashTable != NULL)
{
unsigned int i;
for (i = 0 ; i < TableSize ; ++i)
{
hashEntry *entry = HashTable [i];
while (entry != NULL)
{
hashEntry *next = entry->next;
eFree (entry);
entry = next;
}
}
eFree (HashTable);
}
}
#ifdef DEBUG
static void printEntry (const hashEntry *const entry)
{
printf (" %-15s %-7s\n", entry->string, getLanguageName (entry->language));
}
static unsigned int printBucket (const unsigned int i)
{
hashEntry **const table = getHashTable ();
hashEntry *entry = table [i];
unsigned int measure = 1;
boolean first = TRUE;
printf ("%2d:", i);
if (entry == NULL)
printf ("\n");
else while (entry != NULL)
{
if (! first)
printf (" ");
else
{
printf (" ");
first = FALSE;
}
printEntry (entry);
entry = entry->next;
measure = 2 * measure;
}
return measure - 1;
}
extern void printKeywordTable (void)
{
unsigned long emptyBucketCount = 0;
unsigned long measure = 0;
unsigned int i;
for (i = 0 ; i < TableSize ; ++i)
{
const unsigned int pass = printBucket (i);
measure += pass;
if (pass == 0)
++emptyBucketCount;
}
printf ("spread measure = %ld\n", measure);
printf ("%ld empty buckets\n", emptyBucketCount);
}
#endif
/* vi:set tabstop=4 shiftwidth=4: */
+33
View File
@@ -0,0 +1,33 @@
/*
* $Id: keyword.h,v 1.3 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 1998-2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* External interface to keyword.c
*/
#ifndef _KEYWORD_H
#define _KEYWORD_H
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include "parse.h"
/*
* FUNCTION PROTOTYPES
*/
extern void addKeyword (const char *const string, langType language, int value);
extern int lookupKeyword (const char *const string, langType language);
extern void freeKeywordTable (void);
#ifdef DEBUG
extern void printKeywordTable (void);
#endif
#endif /* _KEYWORD_H */
/* vi:set tabstop=4 shiftwidth=4: */
+139
View File
@@ -0,0 +1,139 @@
/*
* $Id: lisp.c,v 1.3 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 2000-2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for generating tags for LISP files.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include "parse.h"
#include "read.h"
#include "vstring.h"
/*
* DATA DEFINITIONS
*/
typedef enum {
K_FUNCTION
} lispKind;
static kindOption LispKinds [] = {
{ TRUE, 'f', "function", "functions" }
};
/*
* FUNCTION DEFINITIONS
*/
/*
* lisp tag functions
* look for (def or (DEF, quote or QUOTE
*/
static int L_isdef (const unsigned char *strp)
{
return ( (strp [1] == 'd' || strp [1] == 'D')
&& (strp [2] == 'e' || strp [2] == 'E')
&& (strp [3] == 'f' || strp [3] == 'F'));
}
static int L_isquote (const unsigned char *strp)
{
return ( (*(++strp) == 'q' || *strp == 'Q')
&& (*(++strp) == 'u' || *strp == 'U')
&& (*(++strp) == 'o' || *strp == 'O')
&& (*(++strp) == 't' || *strp == 'T')
&& (*(++strp) == 'e' || *strp == 'E')
&& isspace (*(++strp)));
}
static void L_getit (vString *const name, const unsigned char *dbp)
{
const unsigned char *p;
if (*dbp == '\'') /* Skip prefix quote */
dbp++;
else if (*dbp == '(' && L_isquote (dbp)) /* Skip "(quote " */
{
dbp += 7;
while (isspace (*dbp))
dbp++;
}
for (p=dbp ; *p!='\0' && *p!='(' && !isspace ((int) *p) && *p!=')' ; p++)
vStringPut (name, *p);
vStringTerminate (name);
if (vStringLength (name) > 0)
makeSimpleTag (name, LispKinds, K_FUNCTION);
vStringClear (name);
}
/* Algorithm adapted from from GNU etags.
*/
static void findLispTags (void)
{
vString *name = vStringNew ();
const unsigned char* p;
while ((p = fileReadLine ()) != NULL)
{
if (*p == '(')
{
if (L_isdef (p))
{
while (*p != '\0' && !isspace ((int) *p))
p++;
while (isspace ((int) *p))
p++;
L_getit (name, p);
}
else
{
/* Check for (foo::defmumble name-defined ... */
do
p++;
while (*p != '\0' && !isspace ((int) *p)
&& *p != ':' && *p != '(' && *p != ')');
if (*p == ':')
{
do
p++;
while (*p == ':');
if (L_isdef (p - 1))
{
while (*p != '\0' && !isspace ((int) *p))
p++;
while (isspace (*p))
p++;
L_getit (name, p);
}
}
}
}
}
vStringDelete (name);
}
extern parserDefinition* LispParser (void)
{
static const char *const extensions [] = {
"cl", "clisp", "el", "l", "lisp", "lsp", "ml", NULL
};
parserDefinition* def = parserNew ("Lisp");
def->kinds = LispKinds;
def->kindCount = KIND_COUNT (LispKinds);
def->extensions = extensions;
def->parser = findLispTags;
return def;
}
/* vi:set tabstop=4 shiftwidth=4: */
+696
View File
@@ -0,0 +1,696 @@
/*
* $Id: lregex.c,v 1.7 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 2000-2003, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for applying regular expression matching.
*
* The code for utlizing the Gnu regex package with regards to processing the
* regex option and checking for regex matches was adapted from routines in
* Gnu etags.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#ifdef HAVE_REGCOMP
# include <ctype.h>
# include <stddef.h>
# ifdef HAVE_SYS_TYPES_H
# include <sys/types.h> /* declare off_t (not known to regex.h on FreeBSD) */
# endif
# include "regex.h"
#endif
#include "debug.h"
#include "entry.h"
#include "parse.h"
#include "read.h"
#include "routines.h"
#ifdef HAVE_REGEX
/*
* MACROS
*/
/* Back-references \0 through \9 */
#define BACK_REFERENCE_COUNT 10
#if defined (HAVE_REGCOMP) && !defined (REGCOMP_BROKEN)
# define POSIX_REGEX
#endif
#define REGEX_NAME "Regex"
/*
* DATA DECLARATIONS
*/
#if defined (POSIX_REGEX)
struct sKind {
boolean enabled;
char letter;
char* name;
char* description;
};
enum pType { PTRN_TAG, PTRN_CALLBACK };
typedef struct {
regex_t *pattern;
enum pType type;
union {
struct {
char *name_pattern;
struct sKind kind;
} tag;
struct {
regexCallback function;
} callback;
} u;
} regexPattern;
#endif
typedef struct {
regexPattern *patterns;
unsigned int count;
} patternSet;
/*
* DATA DEFINITIONS
*/
static boolean regexBroken = FALSE;
/* Array of pattern sets, indexed by language */
static patternSet* Sets = NULL;
static int SetUpper = -1; /* upper language index in list */
/*
* FUNCTION DEFINITIONS
*/
static void clearPatternSet (const langType language)
{
if (language < SetUpper)
{
patternSet* const set = Sets + language;
unsigned int i;
for (i = 0 ; i < set->count ; ++i)
{
#if defined (POSIX_REGEX)
regfree (set->patterns [i].pattern);
#endif
eFree (set->patterns [i].pattern);
set->patterns [i].pattern = NULL;
if (set->patterns [i].type == PTRN_TAG)
{
eFree (set->patterns [i].u.tag.name_pattern);
set->patterns [i].u.tag.name_pattern = NULL;
}
}
if (set->patterns != NULL)
eFree (set->patterns);
set->patterns = NULL;
set->count = 0;
}
}
/*
* Regex psuedo-parser
*/
static void makeRegexTag (
const vString* const name, const struct sKind* const kind)
{
if (kind->enabled)
{
tagEntryInfo e;
Assert (name != NULL && vStringLength (name) > 0);
Assert (kind != NULL);
initTagEntry (&e, vStringValue (name));
e.kind = kind->letter;
e.kindName = kind->name;
makeTagEntry (&e);
}
}
/*
* Regex pattern definition
*/
/* Take a string like "/blah/" and turn it into "blah", making sure
* that the first and last characters are the same, and handling
* quoted separator characters. Actually, stops on the occurrence of
* an unquoted separator. Also turns "\t" into a Tab character.
* Returns pointer to terminating separator. Works in place. Null
* terminates name string.
*/
static char* scanSeparators (char* name)
{
char sep = name [0];
char *copyto = name;
boolean quoted = FALSE;
for (++name ; *name != '\0' ; ++name)
{
if (quoted)
{
if (*name == sep)
*copyto++ = sep;
else if (*name == 't')
*copyto++ = '\t';
else
{
/* Something else is quoted, so preserve the quote. */
*copyto++ = '\\';
*copyto++ = *name;
}
quoted = FALSE;
}
else if (*name == '\\')
quoted = TRUE;
else if (*name == sep)
{
break;
}
else
*copyto++ = *name;
}
*copyto = '\0';
return name;
}
/* Parse `regexp', in form "/regex/name/[k,Kind/]flags" (where the separator
* character is whatever the first character of `regexp' is), by breaking it
* up into null terminated strings, removing the separators, and expanding
* '\t' into tabs. When complete, `regexp' points to the line matching
* pattern, a pointer to the name matching pattern is written to `name', a
* pointer to the kinds is written to `kinds' (possibly NULL), and a pointer
* to the trailing flags is written to `flags'. If the pattern is not in the
* correct format, a false value is returned.
*/
static boolean parseTagRegex (
char* const regexp, char** const name,
char** const kinds, char** const flags)
{
boolean result = FALSE;
const int separator = (unsigned char) regexp [0];
*name = scanSeparators (regexp);
if (*regexp == '\0')
error (WARNING, "empty regexp");
else if (**name != separator)
error (WARNING, "%s: incomplete regexp", regexp);
else
{
char* const third = scanSeparators (*name);
if (**name == '\0')
error (WARNING, "%s: regexp missing name pattern", regexp);
if ((*name) [strlen (*name) - 1] == '\\')
error (WARNING, "error in name pattern: \"%s\"", *name);
if (*third != separator)
error (WARNING, "%s: regexp missing final separator", regexp);
else
{
char* const fourth = scanSeparators (third);
if (*fourth == separator)
{
*kinds = third;
scanSeparators (fourth);
*flags = fourth;
}
else
{
*flags = third;
*kinds = NULL;
}
result = TRUE;
}
}
return result;
}
static void addCompiledTagPattern (
const langType language, regex_t* const pattern,
char* const name, const char kind, char* const kindName,
char *const description)
{
patternSet* set;
regexPattern *ptrn;
if (language > SetUpper)
{
int i;
Sets = xRealloc (Sets, (language + 1), patternSet);
for (i = SetUpper + 1 ; i <= language ; ++i)
{
Sets [i].patterns = NULL;
Sets [i].count = 0;
}
SetUpper = language;
}
set = Sets + language;
set->patterns = xRealloc (set->patterns, (set->count + 1), regexPattern);
ptrn = &set->patterns [set->count];
set->count += 1;
ptrn->pattern = pattern;
ptrn->type = PTRN_TAG;
ptrn->u.tag.name_pattern = name;
ptrn->u.tag.kind.enabled = TRUE;
ptrn->u.tag.kind.letter = kind;
ptrn->u.tag.kind.name = kindName;
ptrn->u.tag.kind.description = description;
}
static void addCompiledCallbackPattern (
const langType language, regex_t* const pattern,
const regexCallback callback)
{
patternSet* set;
regexPattern *ptrn;
if (language > SetUpper)
{
int i;
Sets = xRealloc (Sets, (language + 1), patternSet);
for (i = SetUpper + 1 ; i <= language ; ++i)
{
Sets [i].patterns = NULL;
Sets [i].count = 0;
}
SetUpper = language;
}
set = Sets + language;
set->patterns = xRealloc (set->patterns, (set->count + 1), regexPattern);
ptrn = &set->patterns [set->count];
set->count += 1;
ptrn->pattern = pattern;
ptrn->type = PTRN_CALLBACK;
ptrn->u.callback.function = callback;
}
#if defined (POSIX_REGEX)
static regex_t* compileRegex (const char* const regexp, const char* const flags)
{
int cflags = REG_EXTENDED | REG_NEWLINE;
regex_t *result = NULL;
int errcode;
int i;
for (i = 0 ; flags != NULL && flags [i] != '\0' ; ++i)
{
switch ((int) flags [i])
{
case 'b': cflags &= ~REG_EXTENDED; break;
case 'e': cflags |= REG_EXTENDED; break;
case 'i': cflags |= REG_ICASE; break;
default: error (WARNING, "unknown regex flag: '%c'", *flags); break;
}
}
result = xMalloc (1, regex_t);
errcode = regcomp (result, regexp, cflags);
if (errcode != 0)
{
char errmsg[256];
regerror (errcode, result, errmsg, 256);
error (WARNING, "%s", errmsg);
regfree (result);
eFree (result);
result = NULL;
}
return result;
}
#endif
static void parseKinds (
const char* const kinds, char* const kind, char** const kindName,
char **description)
{
*kind = '\0';
*kindName = NULL;
*description = NULL;
if (kinds == NULL || kinds [0] == '\0')
{
*kind = 'r';
*kindName = eStrdup ("regex");
}
else if (kinds [0] != '\0')
{
const char* k = kinds;
if (k [0] != ',' && (k [1] == ',' || k [1] == '\0'))
*kind = *k++;
else
*kind = 'r';
if (*k == ',')
++k;
if (k [0] == '\0')
*kindName = eStrdup ("regex");
else
{
const char *const comma = strchr (k, ',');
if (comma == NULL)
*kindName = eStrdup (k);
else
{
*kindName = (char*) eMalloc (comma - k + 1);
strncpy (*kindName, k, comma - k);
(*kindName) [comma - k] = '\0';
k = comma + 1;
if (k [0] != '\0')
*description = eStrdup (k);
}
}
}
}
static void printRegexKind (const regexPattern *pat, unsigned int i, boolean indent)
{
const struct sKind *const kind = &pat [i].u.tag.kind;
const char *const indentation = indent ? " " : "";
Assert (pat [i].type == PTRN_TAG);
printf ("%s%c %s %s\n", indentation,
kind->letter != '\0' ? kind->letter : '?',
kind->description != NULL ? kind->description : kind->name,
kind->enabled ? "" : " [off]");
}
static void processLanguageRegex (const langType language,
const char* const parameter)
{
if (parameter == NULL || parameter [0] == '\0')
clearPatternSet (language);
else if (parameter [0] != '@')
addLanguageRegex (language, parameter);
else if (! doesFileExist (parameter + 1))
error (WARNING, "cannot open regex file");
else
{
const char* regexfile = parameter + 1;
FILE* const fp = fopen (regexfile, "r");
if (fp == NULL)
error (WARNING | PERROR, regexfile);
else
{
vString* const regex = vStringNew ();
while (readLine (regex, fp))
addLanguageRegex (language, vStringValue (regex));
fclose (fp);
vStringDelete (regex);
}
}
}
/*
* Regex pattern matching
*/
#if defined (POSIX_REGEX)
static vString* substitute (
const char* const in, const char* out,
const int nmatch, const regmatch_t* const pmatch)
{
vString* result = vStringNew ();
const char* p;
for (p = out ; *p != '\0' ; p++)
{
if (*p == '\\' && isdigit ((int) *++p))
{
const int dig = *p - '0';
if (0 < dig && dig < nmatch && pmatch [dig].rm_so != -1)
{
const int diglen = pmatch [dig].rm_eo - pmatch [dig].rm_so;
vStringNCatS (result, in + pmatch [dig].rm_so, diglen);
}
}
else if (*p != '\n' && *p != '\r')
vStringPut (result, *p);
}
vStringTerminate (result);
return result;
}
static void matchTagPattern (const vString* const line,
const regexPattern* const patbuf,
const regmatch_t* const pmatch)
{
vString *const name = substitute (vStringValue (line),
patbuf->u.tag.name_pattern, BACK_REFERENCE_COUNT, pmatch);
vStringStripLeading (name);
vStringStripTrailing (name);
if (vStringLength (name) > 0)
makeRegexTag (name, &patbuf->u.tag.kind);
else
error (WARNING, "%s:%ld: null expansion of name pattern \"%s\"",
getInputFileName (), getInputLineNumber (),
patbuf->u.tag.name_pattern);
vStringDelete (name);
}
static void matchCallbackPattern (
const vString* const line, const regexPattern* const patbuf,
const regmatch_t* const pmatch)
{
regexMatch matches [BACK_REFERENCE_COUNT];
unsigned int count = 0;
int i;
for (i = 0 ; i < BACK_REFERENCE_COUNT && pmatch [i].rm_so != -1 ; ++i)
{
matches [i].start = pmatch [i].rm_so;
matches [i].length = pmatch [i].rm_eo - pmatch [i].rm_so;
++count;
}
patbuf->u.callback.function (vStringValue (line), matches, count);
}
static boolean matchRegexPattern (const vString* const line,
const regexPattern* const patbuf)
{
boolean result = FALSE;
regmatch_t pmatch [BACK_REFERENCE_COUNT];
const int match = regexec (patbuf->pattern, vStringValue (line),
BACK_REFERENCE_COUNT, pmatch, 0);
if (match == 0)
{
result = TRUE;
if (patbuf->type == PTRN_TAG)
matchTagPattern (line, patbuf, pmatch);
else if (patbuf->type == PTRN_CALLBACK)
matchCallbackPattern (line, patbuf, pmatch);
else
{
Assert ("invalid pattern type" == NULL);
result = FALSE;
}
}
return result;
}
#endif
/* PUBLIC INTERFACE */
/* Match against all patterns for specified language. Returns true if at least
* on pattern matched.
*/
extern boolean matchRegex (const vString* const line, const langType language)
{
boolean result = FALSE;
if (language != LANG_IGNORE && language <= SetUpper &&
Sets [language].count > 0)
{
const patternSet* const set = Sets + language;
unsigned int i;
for (i = 0 ; i < set->count ; ++i)
if (matchRegexPattern (line, set->patterns + i))
result = TRUE;
}
return result;
}
extern void findRegexTags (void)
{
/* merely read all lines of the file */
while (fileReadLine () != NULL)
;
}
#endif /* HAVE_REGEX */
extern void addTagRegex (
const langType language __unused__,
const char* const regex __unused__,
const char* const name __unused__,
const char* const kinds __unused__,
const char* const flags __unused__)
{
#ifdef HAVE_REGEX
Assert (regex != NULL);
Assert (name != NULL);
if (! regexBroken)
{
regex_t* const cp = compileRegex (regex, flags);
if (cp != NULL)
{
char kind;
char* kindName;
char* description;
parseKinds (kinds, &kind, &kindName, &description);
addCompiledTagPattern (language, cp, eStrdup (name),
kind, kindName, description);
}
}
#endif
}
extern void addCallbackRegex (
const langType language __unused__,
const char* const regex __unused__,
const char* const flags __unused__,
const regexCallback callback __unused__)
{
#ifdef HAVE_REGEX
Assert (regex != NULL);
if (! regexBroken)
{
regex_t* const cp = compileRegex (regex, flags);
if (cp != NULL)
addCompiledCallbackPattern (language, cp, callback);
}
#endif
}
extern void addLanguageRegex (
const langType language __unused__, const char* const regex __unused__)
{
#ifdef HAVE_REGEX
if (! regexBroken)
{
char *const regex_pat = eStrdup (regex);
char *name, *kinds, *flags;
if (parseTagRegex (regex_pat, &name, &kinds, &flags))
{
addTagRegex (language, regex_pat, name, kinds, flags);
eFree (regex_pat);
}
}
#endif
}
/*
* Regex option parsing
*/
extern boolean processRegexOption (const char *const option,
const char *const parameter __unused__)
{
boolean handled = FALSE;
const char* const dash = strchr (option, '-');
if (dash != NULL && strncmp (option, "regex", dash - option) == 0)
{
#ifdef HAVE_REGEX
langType language;
language = getNamedLanguage (dash + 1);
if (language == LANG_IGNORE)
error (WARNING, "unknown language in --%s option", option);
else
processLanguageRegex (language, parameter);
#else
error (WARNING, "regex support not available; required for --%s option",
option);
#endif
handled = TRUE;
}
return handled;
}
extern void disableRegexKinds (const langType language __unused__)
{
#ifdef HAVE_REGEX
if (language <= SetUpper && Sets [language].count > 0)
{
patternSet* const set = Sets + language;
unsigned int i;
for (i = 0 ; i < set->count ; ++i)
if (set->patterns [i].type == PTRN_TAG)
set->patterns [i].u.tag.kind.enabled = FALSE;
}
#endif
}
extern boolean enableRegexKind (
const langType language __unused__,
const int kind __unused__, const boolean mode __unused__)
{
boolean result = FALSE;
#ifdef HAVE_REGEX
if (language <= SetUpper && Sets [language].count > 0)
{
patternSet* const set = Sets + language;
unsigned int i;
for (i = 0 ; i < set->count ; ++i)
if (set->patterns [i].type == PTRN_TAG &&
set->patterns [i].u.tag.kind.letter == kind)
{
set->patterns [i].u.tag.kind.enabled = mode;
result = TRUE;
}
}
#endif
return result;
}
extern void printRegexKinds (const langType language __unused__, boolean indent)
{
#ifdef HAVE_REGEX
if (language <= SetUpper && Sets [language].count > 0)
{
patternSet* const set = Sets + language;
unsigned int i;
for (i = 0 ; i < set->count ; ++i)
if (set->patterns [i].type == PTRN_TAG)
printRegexKind (set->patterns, i, indent);
}
#endif
}
extern void freeRegexResources (void)
{
#ifdef HAVE_REGEX
int i;
for (i = 0 ; i <= SetUpper ; ++i)
clearPatternSet (i);
if (Sets != NULL)
eFree (Sets);
Sets = NULL;
SetUpper = -1;
#endif
}
/* Check for broken regcomp() on Cygwin */
extern void checkRegex (void)
{
#if defined (HAVE_REGEX) && defined (CHECK_REGCOMP)
regex_t patbuf;
int errcode;
if (regcomp (&patbuf, "/hello/", 0) != 0)
{
error (WARNING, "Disabling broken regex");
regexBroken = TRUE;
}
#endif
}
/* vi:set tabstop=4 shiftwidth=4: */
+133
View File
@@ -0,0 +1,133 @@
/*
* $Id: lua.c,v 1.6 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 2000-2001, Max Ischenko <[email protected]>.
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for generating tags for Lua language.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#include "options.h"
#include "parse.h"
#include "read.h"
#include "vstring.h"
/*
* DATA DEFINITIONS
*/
typedef enum {
K_FUNCTION
} luaKind;
static kindOption LuaKinds [] = {
{ TRUE, 'f', "function", "functions" }
};
/*
* FUNCTION DEFINITIONS
*/
/* for debugging purposes */
static void __unused__ print_string (char *p, char *q)
{
for ( ; p != q; p++)
fprintf (errout, "%c", *p);
fprintf (errout, "\n");
}
/*
* Helper function.
* Returns 1 if line looks like a line of Lua code.
*
* TODO: Recognize UNIX bang notation.
* (Lua treat first line as a comment if it starts with #!)
*
*/
static boolean is_a_code_line (const unsigned char *line)
{
boolean result;
const unsigned char *p = line;
while (isspace ((int) *p))
p++;
if (p [0] == '\0')
result = FALSE;
else if (p [0] == '-' && p [1] == '-')
result = FALSE;
else
result = TRUE;
return result;
}
static void extract_name (const char *begin, const char *end, vString *name)
{
if (begin != NULL && end != NULL && begin < end)
{
const char *cp;
while (isspace ((int) *begin))
begin++;
while (isspace ((int) *end))
end--;
if (begin < end)
{
for (cp = begin ; cp != end; cp++)
vStringPut (name, (int) *cp);
vStringTerminate (name);
makeSimpleTag (name, LuaKinds, K_FUNCTION);
vStringClear (name);
}
}
}
static void findLuaTags (void)
{
vString *name = vStringNew ();
const unsigned char *line;
while ((line = fileReadLine ()) != NULL)
{
const char *p, *q;
if (! is_a_code_line (line))
continue;
p = (const char*) strstr ((const char*) line, "function");
if (p == NULL)
continue;
q = strchr ((const char*) line, '=');
if (q == NULL) {
p = p + 9; /* skip the `function' word */
q = strchr ((const char*) p, '(');
extract_name (p, q, name);
} else {
p = (const char*) &line[0];
extract_name (p, q, name);
}
}
vStringDelete (name);
}
extern parserDefinition* LuaParser (void)
{
static const char* const extensions [] = { "lua", NULL };
parserDefinition* def = parserNew ("Lua");
def->kinds = LuaKinds;
def->kindCount = KIND_COUNT (LuaKinds);
def->extensions = extensions;
def->parser = findLuaTags;
return def;
}
/* vi:set tabstop=4 shiftwidth=4: */
+273
View File
@@ -0,0 +1,273 @@
/*
* $Id: mac.c,v 1.2 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 2001, Maarten L. Hekkelman
*
* Author: Maarten L. Hekkelman <[email protected]>
* http://www.hekkelman.com
*
* This source code is released for free distribution under the terms of the
* GNU General Public License. It is provided on an as-is basis and no
* responsibility is accepted for its failure to perform as expected.
*
* This module contains support functions for Exuberant Ctags on Macintosh.
*/
/*
* INCLUDE FILES
*/
#include "general.h"
#include <Files.h>
#include <TextUtils.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/*
* FUNCTION DEFINITIONS
*/
static int get_path(const char* in_unix_path, unsigned char* out_mac_path)
{
int l = strlen(in_unix_path);
int result = 0;
if (l > 254)
result = -1;
else
{
const char* s = in_unix_path;
char *d = (char*)out_mac_path + 1;
if (*s != '/')
*d++ = ':';
else
++s;
while (*s)
{
if (s[0] == '.' && s[1] == '.' && s[2] == '/')
{
s += 3;
*d++ = ':';
}
else if (s[0] == '.' && s[1] == '/')
s += 2;
else if (s[0] == '/')
{
*d++ = ':';
++s;
while (*s == '/')
++s;
}
else
*d++ = *s++;
}
out_mac_path[0] = (d - (char*)out_mac_path) - 1;
}
return result;
}
DIR *opendir(const char *dirname)
{
DIR* dirp = (DIR*)calloc(1, sizeof(DIR));
if (dirp != NULL)
{
OSErr err;
Str255 s;
CInfoPBRec pb = { 0 };
if (strcmp(dirname, "."))
{
get_path(dirname, s);
pb.hFileInfo.ioNamePtr = s;
}
else
pb.hFileInfo.ioNamePtr = NULL;
err = PBGetCatInfoSync(&pb);
if (err != noErr || (pb.hFileInfo.ioFlAttrib & ioDirMask) == 0)
{
free(dirp);
dirp = NULL;
}
else
{
dirp->file.vRefNum = pb.hFileInfo.ioVRefNum;
dirp->file.parID = pb.hFileInfo.ioDirID;
dirp->file.name[0] = '\0';
dirp->index = 1;
}
}
return dirp;
}
struct dirent *readdir(DIR *dirp)
{
if (dirp)
{
CInfoPBRec pb = { 0 };
pb.hFileInfo.ioVRefNum = dirp->file.vRefNum;
pb.hFileInfo.ioDirID = dirp->file.parID;
pb.hFileInfo.ioFDirIndex = dirp->index++;
pb.hFileInfo.ioNamePtr = dirp->file.name;
if (PBGetCatInfoSync(&pb) != noErr)
return NULL;
memcpy(dirp->ent.d_name, dirp->file.name + 1, dirp->file.name[0]);
dirp->ent.d_name[dirp->file.name[0]] = 0;
return &dirp->ent;
}
return NULL;
}
int closedir(DIR *dirp)
{
if (dirp)
free(dirp);
return 0;
}
void rewinddir(DIR *dirp)
{
if (dirp)
dirp->index = 1;
}
int mstat(const char* file, struct stat* st)
{
CInfoPBRec pb;
unsigned char path[256];
int result = 0;
memset(&pb, 0, sizeof(CInfoPBRec));
if (strcmp(file, ".") == 0)
{
memset(st, 0, sizeof(struct stat));
st->st_mode = S_IFDIR;
st->st_ino = -1;
}
else
{
result = get_path(file, path);
if (result == 0)
{
pb.hFileInfo.ioNamePtr = path;
if (PBGetCatInfoSync(&pb) != noErr)
result = -1;
else
{
memset(st, 0, sizeof(struct stat));
if (pb.hFileInfo.ioFlAttrib & ioDirMask)
st->st_mode = S_IFDIR;
else
st->st_mode = S_IFREG;
st->st_ino = pb.hFileInfo.ioFlStBlk;
st->st_dev = pb.hFileInfo.ioVRefNum;
st->st_nlink = 1;
st->st_size = pb.hFileInfo.ioFlLgLen;
st->st_atime = pb.hFileInfo.ioFlMdDat;
st->st_mtime = pb.hFileInfo.ioFlMdDat;
st->st_ctime = pb.hFileInfo.ioFlCrDat;
}
}
}
return result;
}
#undef fopen
FILE* mfopen(const char* file, const char* mode)
{
unsigned char path[256];
if (get_path(file, path) == 0)
{
int l = path[0];
memmove(path, path + 1, l);
path[l] = 0;
return fopen((char*)path, mode);
}
else
return NULL;
}
char* getcwd(char* out_path, int out_path_len)
{
OSErr err = noErr;
CInfoPBRec pb;
FSSpec cwd;
if (out_path == NULL)
{
if (out_path_len < PATH_MAX)
out_path_len = PATH_MAX;
out_path = (char*)malloc(out_path_len);
}
err = FSMakeFSSpec(0, 0, "\p:", &cwd);
if (cwd.parID == fsRtParID)
{
*out_path = '/';
memcpy(out_path + 1, cwd.name + 1, cwd.name[0]);
out_path[1 + cwd.name[0]] = 0;
}
else
{
/* The object isn't a volume */
/* Is the object a file or a directory? */
char t[PATH_MAX];
char* s;
s = t + PATH_MAX - cwd.name[0] - 1;
memcpy(s, cwd.name + 1, cwd.name[0]);
s[cwd.name[0]] = 0;
/* Get the ancestor directory names */
pb.dirInfo.ioNamePtr = cwd.name;
pb.dirInfo.ioVRefNum = cwd.vRefNum;
pb.dirInfo.ioDrParID = cwd.parID;
do /* loop until we have an error or find the root directory */
{
pb.dirInfo.ioFDirIndex = -1;
pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
err = PBGetCatInfoSync(&pb);
if ( err == noErr )
{
*--s = '/';
s -= cwd.name[0];
memcpy(s, cwd.name + 1, cwd.name[0]);
}
}
while (err == noErr && pb.dirInfo.ioDrDirID != fsRtDirID && s > t + 1);
if (s > t + 1)
{
*--s = '/';
strcpy(out_path, s);
}
else
strcpy(out_path, ".");
}
return out_path;
}
/* vi:set tabstop=4 shiftwidth=4: */
+21
View File
@@ -0,0 +1,21 @@
This file contains a patch to the Linux file /usr/share/magic which will
allow the "file" command to properly identify tags file producted by
Exuberant Ctags. To apply the patch, issue the following command as root:
patch -p0 < magic.diff
*** /usr/share/magic.orig Wed Feb 16 19:04:09 2000
--- /usr/share/magic Mon Aug 14 20:27:01 2000
***************
*** 1155,1160 ****
--- 1155,1164 ----
>84 belong&0x18000000 =0x18000000 undefined fpmode
#------------------------------------------------------------------------------
+ # ctags: file (1) magic for Exuberant Ctags files
+ 0 string !_TAG Exuberant Ctags tag file
+
+ #------------------------------------------------------------------------------
# database: file(1) magic for various databases
#
# extracted from header/code files by Graeme Wilford ([email protected])
+578
View File
@@ -0,0 +1,578 @@
/*
* $Id: main.c,v 1.24 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 1996-2003, Darren Hiebert
*
* Author: Darren Hiebert <[email protected]>
* http://ctags.sourceforge.net
*
* This source code is released for free distribution under the terms of the
* GNU General Public License. It is provided on an as-is basis and no
* responsibility is accepted for its failure to perform as expected.
*
* This is a reimplementation of the ctags (1) program. It is an attempt to
* provide a fully featured ctags program which is free of the limitations
* which most (all?) others are subject to.
*
* This module contains the start-up code and routines to determine the list
* of files to parsed for tags.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
/* To provide timings features if available.
*/
#ifdef HAVE_CLOCK
# ifdef HAVE_TIME_H
# include <time.h>
# endif
#else
# ifdef HAVE_TIMES
# ifdef HAVE_SYS_TIMES_H
# include <sys/times.h>
# endif
# endif
#endif
/* To provide directory searching for recursion feature.
*/
#ifdef AMIGA
# include <dos/dosasl.h> /* for struct AnchorPath */
# include <clib/dos_protos.h> /* function prototypes */
# define ANCHOR_BUF_SIZE 512
# define ANCHOR_SIZE (sizeof (struct AnchorPath) + ANCHOR_BUF_SIZE)
# ifdef __SASC
extern struct DosLibrary *DOSBase;
# include <pragmas/dos_pragmas.h>
# endif
#endif
#ifdef HAVE_DIRENT_H
# ifdef __BORLANDC__
# define boolean BORLAND_boolean
# endif
# ifdef HAVE_SYS_TYPES_H
# include <sys/types.h> /* required by dirent.h */
# endif
# include <dirent.h> /* to declare opendir() */
# undef boolean
#endif
#ifdef HAVE_DIRECT_H
# include <direct.h> /* to _getcwd() */
#endif
#ifdef HAVE_DOS_H
# include <dos.h> /* to declare FA_DIREC */
#endif
#ifdef HAVE_DIR_H
# include <dir.h> /* to declare findfirst() and findnext */
#endif
#ifdef HAVE_IO_H
# include <io.h> /* to declare _findfirst() */
#endif
#include "debug.h"
#include "keyword.h"
#include "main.h"
#include "options.h"
#include "read.h"
#include "routines.h"
/*
* MACROS
*/
#define plural(value) (((unsigned long)(value) == 1L) ? "" : "s")
/*
* DATA DEFINITIONS
*/
static struct { long files, lines, bytes; } Totals = { 0, 0, 0 };
#ifdef AMIGA
# include "ctags.h"
static const char *VERsion = "$VER: "PROGRAM_NAME" "PROGRAM_VERSION" "
# ifdef __SASC
__AMIGADATE__
# else
__DATE__
# endif
" "AUTHOR_NAME" $";
#endif
/*
* FUNCTION PROTOTYPES
*/
static boolean createTagsForEntry (const char *const entryName);
/*
* FUNCTION DEFINITIONS
*/
extern void addTotals (
const unsigned int files, const long unsigned int lines,
const long unsigned int bytes)
{
Totals.files += files;
Totals.lines += lines;
Totals.bytes += bytes;
}
extern boolean isDestinationStdout (void)
{
boolean toStdout = FALSE;
if (Option.xref || Option.filter ||
(Option.tagFileName != NULL && (strcmp (Option.tagFileName, "-") == 0
#if defined (VMS)
|| strcmp (Option.tagFileName, "sys$output") == 0
#else
|| strcmp (Option.tagFileName, "/dev/stdout") == 0
#endif
)))
toStdout = TRUE;
return toStdout;
}
#if defined (HAVE_OPENDIR)
static boolean recurseUsingOpendir (const char *const dirName)
{
boolean resize = FALSE;
DIR *const dir = opendir (dirName);
if (dir == NULL)
error (WARNING | PERROR, "cannot recurse into directory \"%s\"", dirName);
else
{
struct dirent *entry;
while ((entry = readdir (dir)) != NULL)
{
if (strcmp (entry->d_name, ".") != 0 &&
strcmp (entry->d_name, "..") != 0)
{
vString *filePath;
if (strcmp (dirName, ".") == 0)
filePath = vStringNewInit (entry->d_name);
else
filePath = combinePathAndFile (dirName, entry->d_name);
resize |= createTagsForEntry (vStringValue (filePath));
vStringDelete (filePath);
}
}
closedir (dir);
}
return resize;
}
#elif defined (HAVE_FINDFIRST) || defined (HAVE__FINDFIRST)
static boolean createTagsForWildcardEntry (
const char *const pattern, const size_t dirLength,
const char *const entryName)
{
boolean resize = FALSE;
/* we must not recurse into the directories "." or ".." */
if (strcmp (entryName, ".") != 0 && strcmp (entryName, "..") != 0)
{
vString *const filePath = vStringNew ();
vStringNCopyS (filePath, pattern, dirLength);
vStringCatS (filePath, entryName);
resize = createTagsForEntry (vStringValue (filePath));
vStringDelete (filePath);
}
return resize;
}
static boolean createTagsForWildcardUsingFindfirst (const char *const pattern)
{
boolean resize = FALSE;
const size_t dirLength = baseFilename (pattern) - pattern;
#if defined (HAVE_FINDFIRST)
struct ffblk fileInfo;
int result = findfirst (pattern, &fileInfo, FA_DIREC);
while (result == 0)
{
const char *const entry = (const char *) fileInfo.ff_name;
resize |= createTagsForWildcardEntry (pattern, dirLength, entry);
result = findnext (&fileInfo);
}
#elif defined (HAVE__FINDFIRST)
struct _finddata_t fileInfo;
findfirst_t hFile = _findfirst (pattern, &fileInfo);
if (hFile != -1L)
{
do
{
const char *const entry = (const char *) fileInfo.name;
resize |= createTagsForWildcardEntry (pattern, dirLength, entry);
} while (_findnext (hFile, &fileInfo) == 0);
_findclose (hFile);
}
#endif
return resize;
}
#elif defined (AMIGA)
static boolean createTagsForAmigaWildcard (const char *const pattern)
{
boolean resize = FALSE;
struct AnchorPath *const anchor =
(struct AnchorPath *) eMalloc ((size_t) ANCHOR_SIZE);
LONG result;
memset (anchor, 0, (size_t) ANCHOR_SIZE);
anchor->ap_Strlen = ANCHOR_BUF_SIZE;
/* Allow '.' for current directory */
#ifdef APF_DODOT
anchor->ap_Flags = APF_DODOT | APF_DOWILD;
#else
anchor->ap_Flags = APF_DoDot | APF_DoWild;
#endif
result = MatchFirst ((UBYTE *) pattern, anchor);
while (result == 0)
{
resize |= createTagsForEntry ((char *) anchor->ap_Buf);
result = MatchNext (anchor);
}
MatchEnd (anchor);
eFree (anchor);
return resize;
}
#endif
static boolean recurseIntoDirectory (const char *const dirName)
{
boolean resize = FALSE;
if (isRecursiveLink (dirName))
verbose ("ignoring \"%s\" (recursive link)\n", dirName);
else if (! Option.recurse)
verbose ("ignoring \"%s\" (directory)\n", dirName);
else
{
verbose ("RECURSING into directory \"%s\"\n", dirName);
#if defined (HAVE_OPENDIR)
resize = recurseUsingOpendir (dirName);
#elif defined (HAVE_FINDFIRST) || defined (HAVE__FINDFIRST)
{
vString *const pattern = vStringNew ();
vStringCopyS (pattern, dirName);
vStringPut (pattern, OUTPUT_PATH_SEPARATOR);
vStringCatS (pattern, "*.*");
resize = createTagsForWildcardUsingFindfirst (vStringValue (pattern));
vStringDelete (pattern);
}
#elif defined (AMIGA)
{
vString *const pattern = vStringNew ();
if (*dirName != '\0' && strcmp (dirName, ".") != 0)
{
vStringCopyS (pattern, dirName);
if (dirName [strlen (dirName) - 1] != '/')
vStringPut (pattern, '/');
}
vStringCatS (pattern, "#?");
resize = createTagsForAmigaWildcard (vStringValue (pattern));
vStringDelete (pattern);
}
#endif
}
return resize;
}
static boolean createTagsForEntry (const char *const entryName)
{
boolean resize = FALSE;
fileStatus *status = eStat (entryName);
Assert (entryName != NULL);
if (isExcludedFile (entryName))
verbose ("excluding \"%s\"\n", entryName);
else if (status->isSymbolicLink && ! Option.followLinks)
verbose ("ignoring \"%s\" (symbolic link)\n", entryName);
else if (! status->exists)
error (WARNING | PERROR, "cannot open source file \"%s\"", entryName);
else if (status->isDirectory)
resize = recurseIntoDirectory (entryName);
else if (! status->isNormalFile)
verbose ("ignoring \"%s\" (special file)\n", entryName);
else
resize = parseFile (entryName);
return resize;
}
#ifdef MANUAL_GLOBBING
static boolean createTagsForWildcardArg (const char *const arg)
{
boolean resize = FALSE;
vString *const pattern = vStringNewInit (arg);
char *patternS = vStringValue (pattern);
#if defined (HAVE_FINDFIRST) || defined (HAVE__FINDFIRST)
/* We must transform the "." and ".." forms into something that can
* be expanded by the findfirst/_findfirst functions.
*/
if (Option.recurse &&
(strcmp (patternS, ".") == 0 || strcmp (patternS, "..") == 0))
{
vStringPut (pattern, OUTPUT_PATH_SEPARATOR);
vStringCatS (pattern, "*.*");
}
resize |= createTagsForWildcardUsingFindfirst (patternS);
#endif
vStringDelete (pattern);
return resize;
}
#endif
static boolean createTagsForArgs (cookedArgs *const args)
{
boolean resize = FALSE;
/* Generate tags for each argument on the command line.
*/
while (! cArgOff (args))
{
const char *const arg = cArgItem (args);
#ifdef MANUAL_GLOBBING
resize |= createTagsForWildcardArg (arg);
#else
resize |= createTagsForEntry (arg);
#endif
cArgForth (args);
parseOptions (args);
}
return resize;
}
/* Read from an opened file a list of file names for which to generate tags.
*/
static boolean createTagsFromFileInput (FILE *const fp, const boolean filter)
{
boolean resize = FALSE;
if (fp != NULL)
{
cookedArgs *args = cArgNewFromLineFile (fp);
parseOptions (args);
while (! cArgOff (args))
{
resize |= createTagsForEntry (cArgItem (args));
if (filter)
{
if (Option.filterTerminator != NULL)
fputs (Option.filterTerminator, stdout);
fflush (stdout);
}
cArgForth (args);
parseOptions (args);
}
cArgDelete (args);
}
return resize;
}
/* Read from a named file a list of file names for which to generate tags.
*/
static boolean createTagsFromListFile (const char *const fileName)
{
boolean resize;
Assert (fileName != NULL);
if (strcmp (fileName, "-") == 0)
resize = createTagsFromFileInput (stdin, FALSE);
else
{
FILE *const fp = fopen (fileName, "r");
if (fp == NULL)
error (FATAL | PERROR, "cannot open list file \"%s\"", fileName);
resize = createTagsFromFileInput (fp, FALSE);
fclose (fp);
}
return resize;
}
#if defined (HAVE_CLOCK)
# define CLOCK_AVAILABLE
# ifndef CLOCKS_PER_SEC
# define CLOCKS_PER_SEC 1000000
# endif
#elif defined (HAVE_TIMES)
# define CLOCK_AVAILABLE
# define CLOCKS_PER_SEC 60
static clock_t clock (void)
{
struct tms buf;
times (&buf);
return (buf.tms_utime + buf.tms_stime);
}
#else
# define clock() (clock_t)0
#endif
static void printTotals (const clock_t *const timeStamps)
{
const unsigned long totalTags = TagFile.numTags.added +
TagFile.numTags.prev;
fprintf (errout, "%ld file%s, %ld line%s (%ld kB) scanned",
Totals.files, plural (Totals.files),
Totals.lines, plural (Totals.lines),
Totals.bytes/1024L);
#ifdef CLOCK_AVAILABLE
{
const double interval = ((double) (timeStamps [1] - timeStamps [0])) /
CLOCKS_PER_SEC;
fprintf (errout, " in %.01f seconds", interval);
if (interval != (double) 0.0)
fprintf (errout, " (%lu kB/s)",
(unsigned long) (Totals.bytes / interval) / 1024L);
}
#endif
fputc ('\n', errout);
fprintf (errout, "%lu tag%s added to tag file",
TagFile.numTags.added, plural (TagFile.numTags.added));
if (Option.append)
fprintf (errout, " (now %lu tags)", totalTags);
fputc ('\n', errout);
if (totalTags > 0 && Option.sorted != SO_UNSORTED)
{
fprintf (errout, "%lu tag%s sorted", totalTags, plural (totalTags));
#ifdef CLOCK_AVAILABLE
fprintf (errout, " in %.02f seconds",
((double) (timeStamps [2] - timeStamps [1])) / CLOCKS_PER_SEC);
#endif
fputc ('\n', errout);
}
#ifdef DEBUG
fprintf (errout, "longest tag line = %lu\n",
(unsigned long) TagFile.max.line);
#endif
}
static boolean etagsInclude (void)
{
return (boolean)(Option.etags && Option.etagsInclude != NULL);
}
static void makeTags (cookedArgs *args)
{
clock_t timeStamps [3];
boolean resize = FALSE;
boolean files = (boolean)(! cArgOff (args) || Option.fileList != NULL
|| Option.filter);
if (! files)
{
if (filesRequired ())
error (FATAL, "No files specified. Try \"%s --help\".",
getExecutableName ());
else if (! Option.recurse && ! etagsInclude ())
return;
}
#define timeStamp(n) timeStamps[(n)]=(Option.printTotals ? clock():(clock_t)0)
if (! Option.filter)
openTagFile ();
timeStamp (0);
if (! cArgOff (args))
{
verbose ("Reading command line arguments\n");
resize = createTagsForArgs (args);
}
if (Option.fileList != NULL)
{
verbose ("Reading list file\n");
resize = (boolean) (createTagsFromListFile (Option.fileList) || resize);
}
if (Option.filter)
{
verbose ("Reading filter input\n");
resize = (boolean) (createTagsFromFileInput (stdin, TRUE) || resize);
}
if (! files && Option.recurse)
resize = recurseIntoDirectory (".");
timeStamp (1);
if (! Option.filter)
closeTagFile (resize);
timeStamp (2);
if (Option.printTotals)
printTotals (timeStamps);
#undef timeStamp
}
/*
* Start up code
*/
extern int main (int __unused__ argc, char **argv)
{
cookedArgs *args;
#ifdef VMS
extern int getredirection (int *ac, char ***av);
/* do wildcard expansion and I/O redirection */
getredirection (&argc, &argv);
#endif
#ifdef AMIGA
/* This program doesn't work when started from the Workbench */
if (argc == 0)
exit (1);
#endif
#ifdef __EMX__
_wildcard (&argc, &argv); /* expand wildcards in argument list */
#endif
#if defined (macintosh) && BUILD_MPW_TOOL == 0
argc = ccommand (&argv);
#endif
setCurrentDirectory ();
setExecutableName (*argv++);
checkRegex ();
args = cArgNewFromArgv (argv);
previewFirstOption (args);
testEtagsInvocation ();
initializeParsing ();
initOptions ();
readOptionConfiguration ();
verbose ("Reading initial options from command line\n");
parseOptions (args);
checkOptions ();
makeTags (args);
/* Clean up.
*/
cArgDelete (args);
freeKeywordTable ();
freeRoutineResources ();
freeSourceFileResources ();
freeTagFileResources ();
freeOptionResources ();
freeParserResources ();
freeRegexResources ();
exit (0);
return 0;
}
/* vi:set tabstop=4 shiftwidth=4: */
+32
View File
@@ -0,0 +1,32 @@
/*
* $Id: main.h,v 1.8 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 1998-2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* External interface to main.c
*/
#ifndef _MAIN_H
#define _MAIN_H
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <stdio.h>
#include "vstring.h"
/*
* FUNCTION PROTOTYPES
*/
extern void addTotals (const unsigned int files, const long unsigned int lines, const long unsigned int bytes);
extern boolean isDestinationStdout (void);
extern int main (int argc, char **argv);
#endif /* _MAIN_H */
/* vi:set tabstop=4 shiftwidth=4: */
+401
View File
@@ -0,0 +1,401 @@
# $Id: maintainer.mak,v 1.36 2006/05/30 04:37:12 darren Exp $
#
# Copyright (c) 1996-2002, Darren Hiebert
#
# Development makefile for Exuberant Ctags, used to build releases.
# Requires GNU make.
OBJEXT = o
include source.mak
DSOURCES = $(SOURCES) debug.c
DOS_VER_FILES= ctags.h ctags.1 ctags.lsm NEWS
VERSION_FILES= $(DOS_VER_FILES) configure.in ctags.spec
LIB_FILES = readtags.c readtags.h
ENVIRONMENT_MAKEFILES = \
mk_bc3.mak mk_bc5.mak mk_djg.mak mk_manx.mak mk_ming.mak \
mk_mpw.mak mk_mvc.mak mk_os2.mak mk_qdos.mak mk_sas.mak \
COMMON_FILES = COPYING EXTENDING.html FAQ INSTALL.oth NEWS README \
$(ENVIRONMENT_MAKEFILES) source.mak \
$(DSOURCES) $(HEADERS) $(LIB_FILES) \
$(ENVIRONMENT_SOURCES) $(ENVIRONMENT_HEADERS)
UNIX_FILES = $(COMMON_FILES) \
.indent.pro INSTALL acconfig.h configure.in \
Makefile.in maintainer.mak testing.mak \
descrip.mms mkinstalldirs magic.diff \
ctags.1 ctags.lsm
DOS_FILES = $(COMMON_FILES)
CVS_FILES = $(UNIX_FILES)
WARNINGS = -Wall -W -Wpointer-arith -Wcast-align -Wwrite-strings \
-Wmissing-prototypes -Wmissing-declarations \
-Wnested-externs -Wcast-qual -Wshadow -pedantic \
-Wstrict-prototypes \
# -Wtraditional -Wconversion -Werror
ERRFILE = errors
REDIR = 2>&1 | tee $(ERRFILE)
RPM_ROOT= $(HOME)/Rpm
CTAGS_DOSDIR = win32
WEB_ARCHIVE_DIR = releases
CTAGS_WEBSITE = website
DEP_DIR = .deps
CC = gcc
INCLUDE = -I.
DEFS = -DHAVE_CONFIG_H
COMP_FLAGS = $(INCLUDE) $(DEFS) $(CFLAGS)
PROF_OPT= -O3 -march=i686
#OPT = $(PROF_OPT) -fomit-frame-pointer
OPT = $(PROF_OPT)
DCFLAGS = $(COMP_FLAGS) -DDEBUG -DINTERNAL_SORT
LD = gcc
LDFLAGS =
readtags.err: DCFLAGS += -DREADTAGS_MAIN
AUTO_GEN = configure config.h.in
CONFIG_GEN = config.cache config.log config.status config.run config.h Makefile
PROF_GEN = gmon.out
COV_GEN = *.da *.gcov
#
# Targets
#
ifeq ($(findstring clean,$(MAKECMDGOALS)),)
ifneq ($(MAKECMDGOALS),setup)
ifeq ($(wildcard config.h),)
ctags dctags ctags.prof ctags.cov:
$(MAKE) config.h
$(MAKE) $(MAKECMDGOALS)
else
all: dctags tags syntax.vim
-include $(DSOURCES:%.c=$(DEP_DIR)/%.d) $(DEP_DIR)/readtags.d
#
# Executable targets
#
ctags: $(SOURCES:.c=.o)
@ echo "-- Linking $@"
@ $(LD) -o $@ $(LDFLAGS) $^
dctags: $(SOURCES:.c=.od) debug.od
@ echo "-- Building $@"
$(LD) -o $@ $(LDFLAGS) $^
mctags: $(SOURCES:.c=.om) debug.om safe_malloc.om
@ echo "-- Building $@"
$(LD) -o $@ $(LDFLAGS) $^
ctags.prof: $(SOURCES) $(HEADERS) Makefile
$(CC) -pg $(PROF_OPT) $(COMP_FLAGS) $(WARNINGS) $(SOURCES) -o $@
ctags.cov: $(SOURCES) $(HEADERS) Makefile
$(CC) -fprofile-arcs -ftest-coverage $(COMP_FLAGS) $(WARNINGS) $(SOURCES) -o $@
gcov: $(SOURCES:.c=.c.gcov)
readtags: readtags.[ch]
$(CC) -g $(COMP_FLAGS) -DDEBUG -DREADTAGS_MAIN -o $@ readtags.c
readtags.o: readtags.c readtags.h
$(CC) $(COMP_FLAGS) -c readtags.c
etyperef: etyperef.o keyword.o routines.o strlist.o vstring.o
$(CC) -o $@ $^
etyperef.o: eiffel.c
$(CC) -DTYPE_REFERENCE_TOOL $(OPT) $(COMP_FLAGS) -o $@ -c $<
endif
endif
endif
ctags32.exe: $(SOURCES) $(HEADERS)
gcc-dos -DMSDOS -O2 -Wall -s -o $@ $(SOURCES)
#
# Support targets
#
FORCE:
config.h.in: acconfig.h configure.in
autoheader
@ touch $@
configure: configure.in
autoconf
config.status: configure
./config.status --recheck
config.h: config.h.in config.status
./config.status
touch $@
depclean:
rm -f $(DEP_DIR)/*.d
profclean:
rm -f $(PROF_GEN)
gcovclean:
rm -f $(COV_GEN)
clean: depclean profclean gcovclean clean-test
rm -f *.[ois] *.o[dm] ctags dctags mctags ctags*.exe readtags etyperef \
ctags.html ctags.prof ctags.cov *.bb *.bbg tags TAGS syntax.vim \
$(ERRFILE)
distclean: clean
rm -f $(CONFIG_GEN)
maintainer-clean maintclean: distclean
rm -f $(AUTO_GEN)
ctags.man: ctags.1
groff -Tascii -mandoc $< | sed 's/.//g' > $@
ctags.html: ctags.1
man2html $< > $@
tags: $(DSOURCES) $(HEADERS) $(LIB_FILES) Makefile *.mak
@ echo "-- Building tag file"
@ ctags *
#
# Create a Vim syntax file for all typedefs
#
syntax: syntax.vim
syntax.vim: $(DSOURCES) $(HEADERS) $(LIB_FILES)
@ echo "-- Generating syntax file"
@ ctags --c-types=cgstu --file-scope -o- $^ |\
awk '{print $$1}' | sort -u | fmt |\
awk '{printf("syntax keyword Typedef\t%s\n", $$0)}' > $@
#
# Testing
#
include testing.mak
#
# CVS management
#
status:
@ cvs -n -q update
cvs-retag-%: CVS_TAG_OPTIONS := -F
cvs-tag-% cvs-retag-%: cvs-tagcheck-%
@ echo "---------- Tagging release `echo $* | sed 's/\./_/g'`"
@ cvs tag -c $(CVS_TAG_OPTIONS) Ctags-`echo $* | sed 's/\./_/g'`
cvs-tagcheck-%:
@ if test -z "$(CVS_TAG_OPTIONS)"; then \
if cvs update -p -r Ctags-`echo $* | sed 's/\./_/g'` maintainer.mak >/dev/null 2>&1 ;then \
echo "release-$* already exists; use rerelease-$*" >&2 ;\
exit 1 ;\
fi ;\
fi
cvs-files:
@ls -1 $(CVS_FILES)
#
# Web site files
#
website-%: website-man-% website-index-% $(CTAGS_WEBSITE)/news.html \
$(CTAGS_WEBSITE)/EXTENDING.html
:
website-man-%: ctags.1 Makefile
@ echo "---------- Generating $(CTAGS_WEBSITE)/ctags.html"
umask 022 ; \
man2html $< | sed -e "s/@@VERSION@@/$*/g" \
-e 's%<A HREF="mailto:[^"]*">\([^@]*\)@\([^<]*\)</A>%\1\ at \2%' \
> $(CTAGS_WEBSITE)/ctags.html
website-index-%: index.html Makefile
@ echo "---------- Generating $(CTAGS_WEBSITE)/index.html"
umask 022 ; \
sed -e "s/@@VERSION@@/$*/g" \
-e "s/@@DOS_VERSION@@/`echo $* | sed 's/\.//g'`/g" \
-e "s/@@DATE@@/`date +'%d %B %Y'`/" \
$< > $(CTAGS_WEBSITE)/index.html
$(CTAGS_WEBSITE)/EXTENDING.html: EXTENDING.html
@ echo "---------- Generating $(CTAGS_WEBSITE)/EXTENDING.html"
cp $< $@ && chmod 644 $@
$(CTAGS_WEBSITE)/news.html: NEWS Makefile
@ echo "---------- Generating $(CTAGS_WEBSITE)/news.html"
umask 022 ; \
sed -e 's/</\&lt;/g' -e 's/>/\&gt;/g' \
-e 's@^Current Version:.*$$@<html><head><title>Exuberant Ctags: Change Notes</title></head><body><h1>Change Notes</h1><pre>@' \
-e 's@\(^ctags-.* (.*)\)$$@<b>\1</b>@' \
-e 's@^vim:.*$$@</pre><hr><a href="http:index.html">Back to <strong>Exuberant Ctags</strong></a></body></html>@' \
$< > $@
#
# Release management
#
ctags-%.lsm: ctags.lsm
sed -e "s/@@VERSION@@/$*/" -e "s/@@LSMDATE@@/`date +'%Y-%m-%d'`/" $< > $@
ctags-%.tar.gz: $(UNIX_FILES) $(VERSION_FILES)
@ echo "---------- Building tar ball"
if [ -d ctags-$* ] ;then rm -fr ctags-$** ;fi
mkdir ctags-$*
cp -p $(UNIX_FILES) ctags-$*/
for file in $(VERSION_FILES) ;do \
rm -f ctags-$*/$${file} ;\
sed -e "s/@@VERSION@@/$*/" \
-e "s/@@LSMDATE@@/`date +'%Y-%m-%d'`/" \
$${file} > ctags-$*/$${file} ;\
done
chmod 644 ctags-$*/*
chmod 755 ctags-$*/mkinstalldirs
(cd ctags-$* ;\
autoheader ;\
chmod 644 config.h.in ;\
autoconf ;\
chmod 755 configure ;\
rm -fr autom4te.cache ;\
man2html ctags.1 > ctags.html ;\
)
tar -zcf $@ ctags-$*
ctags-%.tar.Z: ctags-%.tar.gz
tar -Zcf $@ ctags-$*
$(CTAGS_DOSDIR)/ctags%: FORCE
if [ -d $(CTAGS_DOSDIR)/ctags$* ] ;\
then rm -fr $(CTAGS_DOSDIR)/ctags$*/* ;\
else mkdir -p $(CTAGS_DOSDIR)/ctags$* ;\
fi
dos1-%: $(DOS_FILES)
for file in $^ ;do \
unix2dos < $${file} > $(CTAGS_DOSDIR)/ctags$*/$${file} ;\
done
cd $(CTAGS_DOSDIR); sed -e "s/@@DOS_VERSION@@/$*/" makefile.in > makefile
dos2-%: $(DOS_VER_FILES)
for file in $^ ;do \
rm -f $(CTAGS_DOSDIR)/ctags`echo $*|sed 's/\.//g'`/$${file} ;\
sed -e "s/@@VERSION@@/$*/" \
-e "s/@@LSMDATE@@/`date +'%d%b%y' | tr 'a-z' 'A-Z'`/" $${file} |\
unix2dos > $(CTAGS_DOSDIR)/ctags`echo $*|sed 's/\.//g'`/$${file} ;\
done ;\
cd $(CTAGS_DOSDIR)/ctags`echo $*|sed 's/\.//g'` ; man2html ctags.1 > ctags.html
dos-%:
@ echo "---------- Building MSDOS release directory"
$(MAKE) $(CTAGS_DOSDIR)/ctags`echo $*|sed 's/\.//g'` \
dos1-`echo $*|sed 's/\.//g'` dos2-$*
$(RPM_ROOT)/SOURCES $(RPM_ROOT)/SPECS:
mkdir -p $@
rpm-%: ctags-%.tar.gz ctags.spec $(RPM_ROOT)/SOURCES $(RPM_ROOT)/SPECS
@ echo "---------- Building RPM"
cp -p ctags-$*.tar.gz $(RPM_ROOT)/SOURCES/
sed -e "s/@@VERSION@@/$*/" ctags.spec > $(RPM_ROOT)/SPECS/ctags-$*.spec
(cd $(RPM_ROOT)/SPECS; CC=gcc rpmbuild -ba ctags-$*.spec)
rm -fr $(RPM_ROOT)/BUILD/ctags-$*
ctags32-%: ctags-%.tar.gz
@ echo "---------- Building DPMS binary for MSDOS"
(cd ctags-$*; $(MAKE) -f ../Makefile ctags32.exe; mv ctags32.exe ..)
rm -f $(CTAGS_DOSDIR)/ctags32.exe
mcopy ctags32.exe $(CTAGS_DOSDIR)
#
# Prevent make from deleting these automatically
#
.PRECIOUS: ctags-%.tar.gz ctags-%.tar.Z
cleanrelease-%:
rm -f ctags-$*.tar.gz
rm -fr ctags-$*
rm -fr $(CTAGS_DOSDIR)/ctags`echo $*|sed 's/\.//g'`
rm -f $(RPM_ROOT)/SOURCES/ctags-$*.tar.gz
rm -f $(RPM_ROOT)/RPMS/i386/ctags-$*-1.i386.rpm
rm -f $(RPM_ROOT)/SRPMS/ctags-$*-1.src.rpm
rm -f $(RPM_ROOT)/SPECS/ctags-$*.spec
internal-release-%: ctags-%.tar.gz dos-% rpm-% website-%
@ echo "---------- Copying files to web archive"
cp -p ctags-$*.tar.* $(WEB_ARCHIVE_DIR)
cp -p $(RPM_ROOT)/RPMS/i386/ctags-$*-1.i386.rpm $(WEB_ARCHIVE_DIR)
cp -p $(RPM_ROOT)/SRPMS/ctags-$*-1.src.rpm $(WEB_ARCHIVE_DIR)
cp -p ctags-$*/ctags.lsm $(WEB_ARCHIVE_DIR)/ctags-$*.lsm
chmod o+r $(WEB_ARCHIVE_DIR)/*
@ echo "---------- Release $* completed"
release-%: cvs-tag-% internal-release-%
:
rerelease-%: cvs-retag-% internal-release-%
:
#
# Dependency file generation
#
$(DEP_DIR)/%.d: %.c maintainer.mak
@ if [ ! -d $(DEP_DIR) ] ;then mkdir -p $(DEP_DIR) ;fi
@ $(CC) -M $(DCFLAGS) $< | sed 's/\($*\.o\)\([ :]\)/\1 $*.od $*.om $(@F)\2/g' > $@
%.inc: %.c Makefile
-@ $(CC) -MM $(DCFLAGS) $<
#
# Compilation rules
#
%.o: %.c
@ echo "-- Compiling $<"
@ $(CC) $(COMP_FLAGS) -DEXTERNAL_SORT $(OPT) $(WARNINGS) -Wuninitialized -c $<
%.od: %.c
@ echo "-- Compiling (debug) $<"
@ $(CC) -g $(DCFLAGS) $(WARNINGS) -o $*.od -c $<
%.om: %.c
@ echo "-- Compiling (safe alloc) $<"
@ $(CC) -g -DTRAP_MEMORY_CALLS $(DCFLAGS) $(WARNINGS) -o $*.om -c $<
%.i: %.c FORCE
$(CC) $(DCFLAGS) $(WARNINGS) -Wuninitialized -O -E $< > $@
%.ic: %.c FORCE
$(CC) $(DCFLAGS) $(WARNINGS) -Wuninitialized -O -E $< | noblanks > $@
%.s: %.c FORCE
$(CC) $(DCFLAGS) $(WARNINGS) -S $< > $@
%.err: %.c
@ $(CC) $(DCFLAGS) $(WARNINGS) -Wuninitialized -O -c $<
@ rm $*.o
%.c.gcov: %.da
@ gcov $*.c
%.sproto: %.c
@ genproto -s -m __ARGS $<
%.proto: %.c
@ genproto -e -m __ARGS $<
# vi:ts=4 sw=4
+211
View File
@@ -0,0 +1,211 @@
/*
* $Id: make.c,v 1.6 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 2000-2005, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for generating tags for makefiles.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#include <ctype.h>
#include "options.h"
#include "parse.h"
#include "read.h"
#include "vstring.h"
/*
* DATA DEFINITIONS
*/
typedef enum {
K_MACRO
} shKind;
static kindOption MakeKinds [] = {
{ TRUE, 'm', "macro", "macros"}
};
/*
* FUNCTION DEFINITIONS
*/
static int nextChar (void)
{
int c = fileGetc ();
if (c == '\\')
{
c = fileGetc ();
if (c == '\n')
c = fileGetc ();
}
return c;
}
static void skipLine (void)
{
int c;
do
c = nextChar ();
while (c != EOF && c != '\n');
if (c == '\n')
fileUngetc (c);
}
static int skipToNonWhite (void)
{
int c;
do
c = nextChar ();
while (c != '\n' && isspace (c));
return c;
}
static boolean isIdentifier (int c)
{
return (boolean)(c != '\0' && (isalnum (c) || strchr (".-_", c) != NULL));
}
static void readIdentifier (const int first, vString *const id)
{
int c = first;
vStringClear (id);
while (isIdentifier (c))
{
vStringPut (id, c);
c = nextChar ();
}
fileUngetc (c);
vStringTerminate (id);
}
static void skipToMatch (const char *const pair)
{
const int begin = pair [0], end = pair [1];
const unsigned long inputLineNumber = getInputLineNumber ();
int matchLevel = 1;
int c = '\0';
while (matchLevel > 0)
{
c = nextChar ();
if (c == begin)
++matchLevel;
else if (c == end)
--matchLevel;
else if (c == '\n')
break;
}
if (c == EOF)
verbose ("%s: failed to find match for '%c' at line %lu\n",
getInputFileName (), begin, inputLineNumber);
}
static void findMakeTags (void)
{
vString *name = vStringNew ();
boolean newline = TRUE;
boolean in_define = FALSE;
boolean in_rule = FALSE;
boolean variable_possible = TRUE;
int c;
while ((c = nextChar ()) != EOF)
{
if (newline)
{
if (in_rule)
{
if (c == '\t')
{
skipLine (); /* skip rule */
continue;
}
else
in_rule = FALSE;
}
variable_possible = (boolean)(!in_rule);
newline = FALSE;
}
if (c == '\n')
newline = TRUE;
else if (isspace (c))
continue;
else if (c == '#')
skipLine ();
else if (c == '(')
skipToMatch ("()");
else if (c == '{')
skipToMatch ("{}");
else if (c == ':')
{
variable_possible = TRUE;
in_rule = TRUE;
}
else if (variable_possible && isIdentifier (c))
{
readIdentifier (c, name);
if (strcmp (vStringValue (name), "endef") == 0)
in_define = FALSE;
else if (in_define)
skipLine ();
else if (strcmp (vStringValue (name), "define") == 0 &&
isIdentifier (c))
{
in_define = TRUE;
c = skipToNonWhite ();
readIdentifier (c, name);
makeSimpleTag (name, MakeKinds, K_MACRO);
skipLine ();
}
else {
c = skipToNonWhite ();
if (strchr (":?+", c) != NULL)
{
boolean append = (boolean)(c == '+');
if (c == ':')
in_rule = TRUE;
c = nextChar ();
if (c != '=')
fileUngetc (c);
else if (append)
{
skipLine ();
continue;
}
}
if (c == '=')
{
makeSimpleTag (name, MakeKinds, K_MACRO);
in_rule = FALSE;
skipLine ();
}
}
}
else
variable_possible = FALSE;
}
vStringDelete (name);
}
extern parserDefinition* MakefileParser (void)
{
static const char *const patterns [] = { "[Mm]akefile", NULL };
static const char *const extensions [] = { "mak", "mk", NULL };
parserDefinition* const def = parserNew ("Make");
def->kinds = MakeKinds;
def->kindCount = KIND_COUNT (MakeKinds);
def->patterns = patterns;
def->extensions = extensions;
def->parser = findMakeTags;
return def;
}
/* vi:set tabstop=4 shiftwidth=4: */
+46
View File
@@ -0,0 +1,46 @@
# $Id: mk_bc3.mak,v 1.2 2003/02/24 02:27:53 darren Exp $
#
# Simple makefile for Borland C++ 3.1
!include source.mak
# Adjust the paths to your location of the borland C files
BCCLOC = c:\borlandc
CC = $(BCCLOC)\bin\bcc
INC = -I$(BCCLOC)\include
LIB = -L$(BCCLOC)\lib
# Add this file for wildcard expansion (does NOT work with 4.0!)
#EXTRA = $(BCCLOC)\lib\wildargs.obj
# The following compile options can be changed for better machines.
# replace -1- with -2 to produce code for a 80286 or higher
# replace -1- with -3 to produce code for a 80386 or higher
# add -v for source debugging
OPTIMIZE= -1- -O1
CFLAGS = -DMSDOS -ml -d -w-ccc -w-par -w-pia -w-rch -w-sus $(INC)
LFLAGS = $(LIB) $(EXTRA)
EXTRA_LIBS =
ctags.exe: $(SOURCES) respbc3
$(CC) $(OPTIMIZE) -e$@ @respbc3
debug: dctags.exe
dctags.exe: $(SOURCES) respbc3 debug.c
$(CC) -DDEBUG -v -e$@ @respbc3 debug.c
respbc3: mk_bc3.mak
copy &&|
$(CFLAGS)
$(LFLAGS)
$(SOURCES)
$(EXTRA_LIBS)
| $@
clean:
del *.exe
del *.obj
del respbc3
del tags
+76
View File
@@ -0,0 +1,76 @@
# $Id: mk_bc5.mak,v 1.5 2003/09/19 04:02:39 darren Exp $
#
# Makefile for Win32 using Borland C++ compiler, version 5.5 (free version)
!include source.mak
BCC = bcc32
# You can obtain an Win32 version of the Gnu regex support library from
# http://people.delphiforums.com/gjc/gnu_regex.html
# Point REGEX_DIR to the directory created when you extract the archive.
# If you just run gnu_regex.exe in this directory, then you can just
# uncomment the REGEX_DIR macro below and everything should work.
#REGEX_DIR = gnu_regex_dist
!ifdef REGEX_DIR
EXTRA_INC = -I$(REGEX_DIR)
# Uncomment the following macro to dynamically link against the regex DLL;
# otherwise link statically against regex.
# WARNING: Borland C++ does not successfully link dynamically.
#REGEX_DLL=1
!ifdef REGEX_DLL
REGEX_DEFINE = -DHAVE_REGCOMP
EXTRA_LIBS = $(REGEX_DIR)\gnu_regex.lib
LDFLAGS = -tWCR
!else
REGEX_DEFINE = -DHAVE_REGCOMP -DREGEX_MALLOC -DSTDC_HEADERS=1
EXTRA_LIBS = regex.obj
!endif
!endif
DEFINES = -DWIN32 $(REGEX_DEFINE)
INCLUDES = $(EXTRA_INC)
WARNINGS = -w-aus -w-par -w-pia -w-pro -w-sus
CFLAGS = -d -DSTRICT -lTpe -lap
# Optimizations if your platform supports all of them.
OPT = -O2 -OS -lGt
# Allows multithreading
#MT_OPT = -tWM -lcw32mt
ctags: ctags.exe
ctags.exe: $(SOURCES) respbc5 $(EXTRA_LIBS)
$(BCC) $(OPT) $(MT_OPT) -e$@ $(LDFLAGS) @respbc5
readtags.exe: readtags.c
$(BCC) $(CFLAGS) $(OPT) $(MT_OPT) -e$@ $(DEFINES) -DREADTAGS_MAIN readtags.c $(LDFLAGS)
# Debug version
dctags.exe: $(SOURCES) respbc5 $(EXTRA_LIBS)
$(BCC) -DDEBUG -e$@ $(LDFLAGS) @respbc5 debug.c
regex.obj:
$(BCC) -c -o$@ -w- $(DEFINES) -Dconst= $(INCLUDES) $(REGEX_DIR)\regex.c
respbc5: $(SOURCES) $(HEADERS) mk_bc5.mak
echo $(DEFINES) $(INCLUDES) > $@
echo $(WARNINGS) >> $@
echo $(CFLAGS) >> $@
echo $(SOURCES) $(EXTRA_LIBS) >> $@
mostlyclean:
- del *.obj
- del *.tds
- del dctags.exe
- del respbc5
- del tags
clean: mostlyclean
- del ctags.exe
+18
View File
@@ -0,0 +1,18 @@
# $Id: mk_djg.mak,v 1.2 2003/03/31 04:53:22 darren Exp $
#
# The most simplistic Makefile, for DJGPP Version 2 on Windows
#
# Rather than using this makefile, it is preferable to run "configure", then
# "make" under BASH on DJGPP (i.e. the standard means of building a package on
# Unix), but you have to have a fuller complement of DJGPP packages installed
# to do this.
include source.mak
CFLAGS = -O2 -Wall -DMSDOS
ctags.exe: $(SOURCES)
gcc $(CFLAGS) -s -o ctags.exe $(SOURCES) -lpc
clean:
del ctags.exe
+65
View File
@@ -0,0 +1,65 @@
# $Id: mk_manx.mak,v 1.9 2003/02/13 02:59:30 darren Exp $
#
# Makefile for ctags on the Amiga, using Aztec/Manx C 5.0 or later
OBJEXT = o
OBJECTS = \
args.$(OBJEXT) \
asm.$(OBJEXT) \
asp.$(OBJEXT) \
awk.$(OBJEXT) \
beta.$(OBJEXT) \
c.$(OBJEXT) \
cobol.$(OBJEXT) \
eiffel.$(OBJEXT) \
entry.$(OBJEXT) \
erlang.$(OBJEXT) \
fortran.$(OBJEXT) \
get.$(OBJEXT) \
keyword.$(OBJEXT) \
lisp.$(OBJEXT) \
lregex.$(OBJEXT) \
lua.$(OBJEXT) \
main.$(OBJEXT) \
make.$(OBJEXT) \
options.$(OBJEXT) \
parse.$(OBJEXT) \
pascal.$(OBJEXT) \
perl.$(OBJEXT) \
php.$(OBJEXT) \
python.$(OBJEXT) \
read.$(OBJEXT) \
rexx.$(OBJEXT) \
routines.$(OBJEXT) \
ruby.$(OBJEXT) \
scheme.$(OBJEXT) \
sh.$(OBJEXT) \
slang.$(OBJEXT) \
sort.$(OBJEXT) \
sml.$(OBJEXT) \
sql.$(OBJEXT) \
strlist.$(OBJEXT) \
tcl.$(OBJEXT) \
verilog.$(OBJEXT) \
vim.$(OBJEXT) \
vstring.$(OBJEXT) \
yacc.$(OBJEXT)
CC = cc
#>>>>> choose between debugging (-bs) or optimizing (-so)
OPTIONS = -so
#OPTIONS = -bs
#>>>>>> choose -g for debugging
LN_DEBUG =
#LN_DEBUG = -g
CFLAGS = $(OPTIONS) -wapruq -ps -qf -DAMIGA -Dconst=
Ctags: $(OBJECTS)
ln +q -m $(LN_DEBUG) -o Ctags $(OBJECTS) -lc16 -lm16
.c.o:
$(CC) $(CFLAGS) -o $*.o $*.c
+26
View File
@@ -0,0 +1,26 @@
# $Id: mk_ming.mak,v 1.1 2001/11/02 04:53:43 darren Exp $
#
# Makefile for Exuberant Ctags under Win32 with Mingw32 compiler
#
# Note that only the crtdll variant of the compiler is supported.
# The msvcrt variant has broken implementations of fgetpos() and fsetpos().
include source.mak
CFLAGS = -Wall
DEFINES = -DWIN32
CC = gcc
ctags: ctags.exe
ctags.exe: OPT = -O4
ctags.exe: LDFLAGS = -s
dctags.exe: OPT = -g
ctags.exe dctags.exe: $(SOURCES)
$(CC) $(LDFLAGS) $(OPT) $(CFLAGS) $(DEFINES) -o $@ $(SOURCES)
clean:
- del ctags.exe
- del dctags.exe
- del tags
+130
View File
@@ -0,0 +1,130 @@
# $Id: mk_mpw.mak,v 1.9 2003/02/13 02:59:30 darren Exp $
#
# Makefile for Macintosh using MPW
#
# Created by: Maarten L. Hekkelman <[email protected]>
HEADERS =
args.h ctags.h debug.h entry.h general.h get.h keyword.h ¶
main.h options.h parse.h parsers.h read.h routines.h sort.h ¶
strlist.h vstring.h mac.h
SOURCES =
args.c ¶
asm.c ¶
asp.c ¶
awk.c ¶
beta.c ¶
c.c ¶
cobol.c ¶
eiffel.c ¶
entry.c ¶
erlang.c ¶
fortran.c ¶
get.c ¶
keyword.c ¶
lisp.c ¶
lregex.c ¶
lua.c ¶
main.c ¶
make.c ¶
options.c ¶
parse.c ¶
pascal.c ¶
perl.c ¶
php.c ¶
python.c ¶
read.c ¶
rexx.c ¶ ¶
routines.c ¶
ruby.c ¶
scheme.c ¶
sh.c ¶
slang.c ¶
sort.c ¶
sml.c ¶
sql.c ¶
strlist.c ¶
tcl.c ¶
verilog.c ¶
vim.c ¶
vstring.c ¶
yacc.c ¶
mac.c
OBJ =
args.o ¶
asm.o ¶
asp.o ¶
awk.o ¶
beta.o ¶
c.o ¶
cobol.o ¶
eiffel.o ¶
entry.o ¶
erlang.o ¶
fortran.o ¶
get.o ¶
keyword.o ¶
lisp.o ¶
lregex.o ¶
lua.o ¶
main.o ¶
make.o ¶
options.o ¶
parse.o ¶
pascal.o ¶
perl.o ¶
php.o ¶
python.o ¶
read.o ¶
rexx.o ¶
routines.o ¶
ruby.o ¶
scheme.o ¶
sh.o ¶
slang.o ¶
sort.o ¶
sml.o ¶
sql.o ¶
strlist.o ¶
tcl.o ¶
verilog.o ¶
vim.o ¶
vstring.o ¶
yacc.o ¶
mac.o
LIBS =
{PPCLibraries}PPCToolLibs.o ¶
{SharedLibraries}MathLib ¶
{SharedLibraries}InterfaceLib ¶
{SharedLibraries}StdCLib ¶
{MWPPCLibraries}'MSL StdCRuntime.Lib'
CC = mwcppc
LD = mwlinkppc
# Using -nodefaults to avoid having {MWCIncludes} in our include paths
# Needed since we're building a MPW Tool and not an application.
COptions = -nodefaults -i : -i- -i {CIncludes} -opt full
LOptions = -xm m -stacksize 128
all Ä CTags
CTags Ä TurnOfEcho {OBJ}
{LD} {LOptions} -o CTags {OBJ} {LIBS}
{OBJ} Ä {HEADERS}
tags Ä CTags
:CTags -p. {SOURCES} {HEADERS}
clean Ä
Delete -y -i {OBJ} {CTags} tags
.o Ä .c
{CC} {depDir}{default}.c -o {targDir}{default}.o {COptions}
TurnOfEcho Ä
set echo 0
+61
View File
@@ -0,0 +1,61 @@
# $Id: mk_mvc.mak,v 1.7 2003/09/19 04:02:39 darren Exp $
#
# Makefile for Win32 using Microsoft Visual C++ compiler
include source.mak
# You can obtain an Win32 version of the Gnu regex support library from
# http://people.delphiforums.com/gjc/gnu_regex.html
# Point REGEX_DIR to the directory created when you extract the archive.
# If you just run gnu_regex.exe in this directory, then you can just
# uncomment the REGEX_DIR macro below and everything should work.
#REGEX_DIR = gnu_regex_dist
!ifdef REGEX_DIR
EXTRA_INC = -I$(REGEX_DIR)
# Uncomment the following macro to dynamically link against the regex DLL;
# otherwise link statically against regex.
#REGEX_DLL=1
!ifdef REGEX_DLL
REGEX_DEFINE = -DHAVE_REGCOMP
EXTRA_LIBS = $(REGEX_DIR)\gnu_regex.lib
!else
REGEX_DEFINE = -DHAVE_REGCOMP -DREGEX_MALLOC -DSTDC_HEADERS=1
EXTRA_LIBS = regex.obj
!endif
!endif
DEFINES = -DWIN32 $(REGEX_DEFINE)
INCLUDES = $(EXTRA_INC)
OPT = /O2 /G5
ctags: ctags.exe
ctags.exe: $(SOURCES) respmvc $(EXTRA_LIBS)
cl $(OPT) /Fe$@ @respmvc /link setargv.obj
readtags.exe: readtags.c
cl /clr $(OPT) /Fe$@ $(DEFINES) -DREADTAGS_MAIN readtags.c /link setargv.obj
# Debug version
dctags.exe: $(SOURCES) respmvc $(EXTRA_LIBS)
cl /Zi -DDEBUG /Fe$@ @respmvc debug.c /link setargv.obj
regex.obj:
cl /c $(OPT) /Fo$@ $(DEFINES) -Dconst= $(INCLUDES) $(REGEX_DIR)\regex.c
respmvc: $(SOURCES) $(HEADERS) mk_mvc.mak
echo $(DEFINES) $(INCLUDES) $(SOURCES) $(EXTRA_LIBS) > $@
mostlyclean:
- del *.obj
- del dctags.exe
- del respmvc
- del tags
clean: mostlyclean
- del ctags.exe
+104
View File
@@ -0,0 +1,104 @@
# $Id: mk_os2.mak,v 1.3 2002/01/27 21:20:55 darren Exp $
#
# A Makefile for OS/2 using EMX/gcc
# You may want to use the OS/2 port of autoconf for building
# and comment-out the according statements in this Makefile.
# You need a library to provide regex support.
# libExt might do this, but currently (2/2001) it doesn't work well
# together with ctags ...
#
# Provided and supported by
# Alexander Mai
# <[email protected]> or <[email protected]>
default:
@echo "Enter $(MAKE) -f mk_os2.mak target"
@echo "where target is one of:"
@echo " small (small executable req. EMX runtime)"
@echo " debug (executable for debugging purposes)"
@echo " release (stand-alone executable)"
@echo " clean (remove all files built)"
# Use this to create a small binary
# (requires EMX runtime libraries)
small:
$(MAKE) -f mk_os2.mak all \
CC="gcc" \
CFLAGS="-O5 -mpentium -Wall" \
LFLAGS="-Zcrtdll -s" \
LIBS="-lregex" \
OBJEXT="o"
# Use this to create a binary for debugging purposes
# (requires EMX runtime libraries)
debug:
$(MAKE) -f mk_os2.mak all \
CC="gcc" \
CFLAGS="-O0 -Wall -g" \
LFLAGS="-Zcrtdll -g" \
LIBS="-lregex" \
OBJEXT="o"
# Use this to create a stand-alone binary for distribution
# (requires link386 for linking but no EMX runtime libraries)
release:
$(MAKE) -f mk_os2.mak all \
CC="gcc" \
CFLAGS="-g -O5 -mpentium -Wall" \
LFLAGS="-s -Zomf -Zsys -Zlinker /PM:VIO" \
LIBS="-lregex" \
OBJEXT="obj"
# Use the line below if you have created config.h
# (manually or by running configure)
# Otherwise use built-in defaults (#ifdef OS2)!
# DEFINES=-DHAVE_CONFIG_H
DEFINES=-DOS2
# General rules and definitions
.SUFFIXES: .c .exe .h .o .obj
include source.mak
all: ctags.exe readtags.exe readtags.a readtags.lib
ctags: ctags.exe
etags: etags.exe
ctags.exe: $(OBJECTS)
$(CC) $(CFLAGS) $(LFLAGS) -o $@ $^ $(LIBS)
etags.exe: ctags.exe
@copy $< $@
# The readtags executable
readtags.exe: readtags.c
$(CC) $(CFLAGS) $(DEFINES) $(LFLAGS) -DREADTAGS_MAIN -o $@ $^ $(LIBS)
# We build a.out and omf version of the readtags library
readtags.o: readtags.c
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $^
readtags.a: readtags.o
if exist $@ del $@
ar rc $@ $^
readtags.lib: readtags.a
emxomf $<
.c.o:
$(CC) $(CFLAGS) $(DEFINES) -I. -c $< -o $@
.c.obj:
$(CC) $(CFLAGS) -Zomf $(DEFINES) -I. -c $< -o $@
# Delete all files that are not part of the source distribution
clean:
@if exist ctags.exe del ctags.exe
@if exist etags.exe del etags.exe
@if exist readtags.exe del readtags.exe
@if exist readtags.a del readtags.a
@if exist readtags.lib del readtags.lib
@if exist *.obj del *.obj
@if exist *.o del *.o
+100
View File
@@ -0,0 +1,100 @@
# $Id: mk_qdos.mak,v 1.10 2003/02/13 02:59:30 darren Exp $
#
# Makefile for ctags on QDOS/SMS systems and C68 v4.24
# Submitted by Thierry Godefroy <[email protected]>
# Directories:
T = ram1_
P = drv1_C68_
# Programs name:
CC = $(P)cc
AS = $(P)as68
ASM = $(P)qmac
LD = $(P)ld
# Programs flags:
CCFLAGS = -tmp$(T) -v -Y$(P) -I$(P)include_ -O
ASFLAGS = -V
ASMFLAGS = -nolist
LDFLAGS = -v -L$(P)lib_ -bufp150K\
# Target name:
EXEC = ctags
# Additional libraries:
LIBS =
# Target dependencies:
OBJEXT = o
HEADERS = e_qdos.h \
args.h ctags.h debug.h entry.h general.h get.h keyword.h \
main.h options.h parse.h parsers.h read.h routines.h sort.h \
strlist.h vstring.h
OBJECTS = qdos.$(OBJEXT) \
args.$(OBJEXT) \
asm.$(OBJEXT) \
asp.$(OBJEXT) \
awk.$(OBJEXT) \
beta.$(OBJEXT) \
c.$(OBJEXT) \
cobol.$(OBJEXT) \
eiffel.$(OBJEXT) \
entry.$(OBJEXT) \
erlang.$(OBJEXT) \
fortran.$(OBJEXT) \
get.$(OBJEXT) \
keyword.$(OBJEXT) \
lisp.$(OBJEXT) \
lregex.$(OBJEXT) \
lua.$(OBJEXT) \
main.$(OBJEXT) \
make.$(OBJEXT) \
options.$(OBJEXT) \
parse.$(OBJEXT) \
pascal.$(OBJEXT) \
perl.$(OBJEXT) \
php.$(OBJEXT) \
python.$(OBJEXT) \
read.$(OBJEXT) \
rexx.$(OBJEXT) \
routines.$(OBJEXT) \
ruby.$(OBJEXT) \
scheme.$(OBJEXT) \
sh.$(OBJEXT) \
slang.$(OBJEXT) \
sort.$(OBJEXT) \
sml.$(OBJEXT) \
sql.$(OBJEXT) \
strlist.$(OBJEXT) \
tcl.$(OBJEXT) \
verilog.$(OBJEXT) \
vim.$(OBJEXT) \
vstring.$(OBJEXT) \
yacc.$(OBJEXT)
$(EXEC) : $(OBJECTS)
$(LD) -o$(EXEC) $(LDFLAGS) $(OBJECTS) $(LIBS)
$(OBJECTS): $(HEADERS)
# Construction rules:
_c_o :
$(CC) -c $(CCFLAGS) $<
_s_o :
$(AS) $(ASFLAGS) $< $@
_asm_rel :
$(ASM) $< $(ASMFLAGS)
#end
+63
View File
@@ -0,0 +1,63 @@
# $Id: mk_sas.mak,v 1.9 2003/02/13 02:59:30 darren Exp $
#
# Makefile for SAS/C Amiga Compiler
# Submitted by Stefan Haubenthal <[email protected]>
CFLAGS= def AMIGA opt parm r sint
OBJEXT = o
OBJECTS = \
args.$(OBJEXT) \
asm.$(OBJEXT) \
asp.$(OBJEXT) \
awk.$(OBJEXT) \
beta.$(OBJEXT) \
c.$(OBJEXT) \
cobol.$(OBJEXT) \
eiffel.$(OBJEXT) \
entry.$(OBJEXT) \
erlang.$(OBJEXT) \
fortran.$(OBJEXT) \
get.$(OBJEXT) \
keyword.$(OBJEXT) \
lisp.$(OBJEXT) \
lregex.$(OBJEXT) \
lua.$(OBJEXT) \
main.$(OBJEXT) \
make.$(OBJEXT) \
options.$(OBJEXT) \
parse.$(OBJEXT) \
pascal.$(OBJEXT) \
perl.$(OBJEXT) \
php.$(OBJEXT) \
python.$(OBJEXT) \
read.$(OBJEXT) \
rexx.$(OBJEXT) \
routines.$(OBJEXT) \
ruby.$(OBJEXT) \
scheme.$(OBJEXT) \
sh.$(OBJEXT) \
slang.$(OBJEXT) \
sort.$(OBJEXT) \
sml.$(OBJEXT) \
sql.$(OBJEXT) \
strlist.$(OBJEXT) \
tcl.$(OBJEXT) \
verilog.$(OBJEXT) \
vim.$(OBJEXT) \
vstring.$(OBJEXT) \
yacc.$(OBJEXT)
ctags: $(OBJECTS)
sc link to $@ $(OBJECTS) math s sint
.c.o:
$(CC) $(CFLAGS) -o $*.o $*.c
clean:
-delete $(OBJECTS) ctags.lnk
archive: clean
@-delete force RAM:ctags.lha
lha -r a RAM:ctags // ctags
+40
View File
@@ -0,0 +1,40 @@
#! /bin/sh
# mkinstalldirs --- make directory hierarchy
# Author: Noah Friedman <[email protected]>
# Created: 1993-05-16
# Public domain
# $Id: mkinstalldirs,v 1.1 2001/11/02 04:53:43 darren Exp $
errstatus=0
for file
do
set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
shift
pathcomp=
for d
do
pathcomp="$pathcomp$d"
case "$pathcomp" in
-* ) pathcomp=./$pathcomp ;;
esac
if test ! -d "$pathcomp"; then
echo "mkdir $pathcomp" 1>&2
mkdir "$pathcomp" || lasterr=$?
if test ! -d "$pathcomp"; then
errstatus=$lasterr
fi
fi
pathcomp="$pathcomp/"
done
done
exit $errstatus
# mkinstalldirs ends here
File diff suppressed because it is too large Load Diff
+154
View File
@@ -0,0 +1,154 @@
/*
* $Id: options.h,v 1.12 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 1998-2003, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* Defines external interface to option processing.
*/
#ifndef _OPTIONS_H
#define _OPTIONS_H
#if defined(OPTION_WRITE) || defined(VAXC)
# define CONST_OPTION
#else
# define CONST_OPTION const
#endif
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <stdarg.h>
#include "args.h"
#include "parse.h"
#include "strlist.h"
#include "vstring.h"
/*
* DATA DECLARATIONS
*/
typedef enum { OPTION_NONE, OPTION_SHORT, OPTION_LONG } optionType;
typedef struct sCookedArgs {
/* private */
Arguments* args;
char *shortOptions;
char simple[2];
boolean isOption;
boolean longOption;
const char* parameter;
/* public */
char* item;
} cookedArgs;
typedef enum eLocate {
EX_MIX, /* line numbers for defines, patterns otherwise */
EX_LINENUM, /* -n only line numbers in tag file */
EX_PATTERN /* -N only patterns in tag file */
} exCmd;
typedef enum sortType {
SO_UNSORTED,
SO_SORTED,
SO_FOLDSORTED
} sortType;
struct sInclude {
boolean fileNames; /* include tags for source file names */
boolean qualifiedTags; /* include tags for qualified class members */
boolean fileScope; /* include tags of file scope only */
};
struct sExtFields { /* extension field content control */
boolean access;
boolean fileScope;
boolean implementation;
boolean inheritance;
boolean kind;
boolean kindKey;
boolean kindLong;
boolean language;
boolean lineNumber;
boolean scope;
boolean signature;
boolean typeRef;
};
/* This stores the command line options.
*/
typedef struct sOptionValues {
struct sInclude include;/* --extra extra tag inclusion */
struct sExtFields extensionFields;/* --fields extension field control */
stringList* ignore; /* -I name of file containing tokens to ignore */
boolean append; /* -a append to "tags" file */
boolean backward; /* -B regexp patterns search backwards */
boolean etags; /* -e output Emacs style tags file */
exCmd locate; /* --excmd EX command used to locate tag */
boolean recurse; /* -R recurse into directories */
sortType sorted; /* -u,--sort sort tags */
boolean verbose; /* -V verbose */
boolean xref; /* -x generate xref output instead */
char *fileList; /* -L name of file containing names of files */
char *tagFileName; /* -o name of tags file */
stringList* headerExt; /* -h header extensions */
stringList* etagsInclude;/* --etags-include list of TAGS files to include*/
unsigned int tagFileFormat;/* --format tag file format (level) */
boolean if0; /* --if0 examine code within "#if 0" branch */
boolean kindLong; /* --kind-long */
langType language; /* --lang specified language override */
boolean followLinks; /* --link follow symbolic links? */
boolean filter; /* --filter behave as filter: files in, tags out */
char* filterTerminator; /* --filter-terminator string to output */
boolean tagRelative; /* --tag-relative file paths relative to tag file */
boolean printTotals; /* --totals print cumulative statistics */
boolean lineDirectives; /* --linedirectives process #line directives */
#ifdef DEBUG
long debugLevel; /* -D debugging output */
unsigned long breakLine;/* -b source line at which to call lineBreak() */
#endif
} optionValues;
/*
* GLOBAL VARIABLES
*/
extern CONST_OPTION optionValues Option;
/*
* FUNCTION PROTOTYPES
*/
extern void verbose (const char *const format, ...) __printf__ (1, 2);
extern void freeList (stringList** const pString);
extern void setDefaultTagFileName (void);
extern void checkOptions (void);
extern boolean filesRequired (void);
extern void testEtagsInvocation (void);
extern cookedArgs* cArgNewFromString (const char* string);
extern cookedArgs* cArgNewFromArgv (char* const* const argv);
extern cookedArgs* cArgNewFromFile (FILE* const fp);
extern cookedArgs* cArgNewFromLineFile (FILE* const fp);
extern void cArgDelete (cookedArgs* const current);
extern boolean cArgOff (cookedArgs* const current);
extern boolean cArgIsOption (cookedArgs* const current);
extern const char* cArgItem (cookedArgs* const current);
extern void cArgForth (cookedArgs* const current);
extern boolean isExcludedFile (const char* const name);
extern boolean isIncludeFile (const char *const fileName);
extern boolean isIgnoreToken (const char *const name, boolean *const pIgnoreParens, const char **const replacement);
extern void parseOption (cookedArgs* const cargs);
extern void parseOptions (cookedArgs* const cargs);
extern void previewFirstOption (cookedArgs* const cargs);
extern void readOptionConfiguration (void);
extern void initOptions (void);
extern void freeOptionResources (void);
#endif /* _OPTIONS_H */
/* vi:set tabstop=4 shiftwidth=4: */
+678
View File
@@ -0,0 +1,678 @@
/*
* $Id: parse.c,v 1.16 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 1996-2003, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for managing source languages and
* dispatching files to the appropriate language parser.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#ifdef HAVE_FNMATCH_H
#include <fnmatch.h>
#endif
#include "debug.h"
#include "entry.h"
#include "main.h"
#define OPTION_WRITE
#include "options.h"
#include "parsers.h"
#include "read.h"
#include "routines.h"
#include "vstring.h"
/*
* DATA DEFINITIONS
*/
static parserDefinitionFunc* BuiltInParsers[] = { PARSER_LIST };
static parserDefinition** LanguageTable = NULL;
static unsigned int LanguageCount = 0;
/*
* FUNCTION DEFINITIONS
*/
extern void makeSimpleTag (
const vString* const name, kindOption* const kinds, const int kind)
{
if (kinds [kind].enabled && name != NULL && vStringLength (name) > 0)
{
tagEntryInfo e;
initTagEntry (&e, vStringValue (name));
e.kindName = kinds [kind].name;
e.kind = kinds [kind].letter;
makeTagEntry (&e);
}
}
/*
* parserDescription mapping management
*/
extern parserDefinition* parserNew (const char* name)
{
parserDefinition* result = xCalloc (1, parserDefinition);
result->name = eStrdup (name);
return result;
}
extern const char *getLanguageName (const langType language)
{
const char* result;
if (language == LANG_IGNORE)
result = "unknown";
else
{
Assert (0 <= language && language < (int) LanguageCount);
result = LanguageTable [language]->name;
}
return result;
}
extern langType getNamedLanguage (const char *const name)
{
langType result = LANG_IGNORE;
unsigned int i;
Assert (name != NULL);
for (i = 0 ; i < LanguageCount && result == LANG_IGNORE ; ++i)
{
const parserDefinition* const lang = LanguageTable [i];
if (lang->name != NULL)
if (strcasecmp (name, lang->name) == 0)
result = i;
}
return result;
}
static langType getExtensionLanguage (const char *const extension)
{
langType result = LANG_IGNORE;
unsigned int i;
for (i = 0 ; i < LanguageCount && result == LANG_IGNORE ; ++i)
{
stringList* const exts = LanguageTable [i]->currentExtensions;
if (exts != NULL && stringListExtensionMatched (exts, extension))
result = i;
}
return result;
}
static langType getPatternLanguage (const char *const fileName)
{
langType result = LANG_IGNORE;
const char* base = baseFilename (fileName);
unsigned int i;
for (i = 0 ; i < LanguageCount && result == LANG_IGNORE ; ++i)
{
stringList* const ptrns = LanguageTable [i]->currentPatterns;
if (ptrns != NULL && stringListFileMatched (ptrns, base))
result = i;
}
return result;
}
#ifdef SYS_INTERPRETER
/* The name of the language interpreter, either directly or as the argument
* to "env".
*/
static vString* determineInterpreter (const char* const cmd)
{
vString* const interpreter = vStringNew ();
const char* p = cmd;
do
{
vStringClear (interpreter);
for ( ; isspace ((int) *p) ; ++p)
; /* no-op */
for ( ; *p != '\0' && ! isspace ((int) *p) ; ++p)
vStringPut (interpreter, (int) *p);
vStringTerminate (interpreter);
} while (strcmp (vStringValue (interpreter), "env") == 0);
return interpreter;
}
static langType getInterpreterLanguage (const char *const fileName)
{
langType result = LANG_IGNORE;
FILE* const fp = fopen (fileName, "r");
if (fp != NULL)
{
vString* const vLine = vStringNew ();
const char* const line = readLine (vLine, fp);
if (line != NULL && line [0] == '#' && line [1] == '!')
{
const char* const lastSlash = strrchr (line, '/');
const char *const cmd = lastSlash != NULL ? lastSlash+1 : line+2;
vString* const interpreter = determineInterpreter (cmd);
result = getExtensionLanguage (vStringValue (interpreter));
vStringDelete (interpreter);
}
vStringDelete (vLine);
fclose (fp);
}
return result;
}
#endif
extern langType getFileLanguage (const char *const fileName)
{
langType language = Option.language;
if (language == LANG_AUTO)
{
language = getExtensionLanguage (fileExtension (fileName));
if (language == LANG_IGNORE)
language = getPatternLanguage (fileName);
#ifdef SYS_INTERPRETER
if (language == LANG_IGNORE)
{
fileStatus *status = eStat (fileName);
if (status->isExecutable)
language = getInterpreterLanguage (fileName);
}
#endif
}
return language;
}
extern void printLanguageMap (const langType language)
{
boolean first = TRUE;
unsigned int i;
stringList* map = LanguageTable [language]->currentPatterns;
Assert (0 <= language && language < (int) LanguageCount);
for (i = 0 ; map != NULL && i < stringListCount (map) ; ++i)
{
printf ("%s(%s)", (first ? "" : " "),
vStringValue (stringListItem (map, i)));
first = FALSE;
}
map = LanguageTable [language]->currentExtensions;
for (i = 0 ; map != NULL && i < stringListCount (map) ; ++i)
{
printf ("%s.%s", (first ? "" : " "),
vStringValue (stringListItem (map, i)));
first = FALSE;
}
}
extern void installLanguageMapDefault (const langType language)
{
parserDefinition* lang;
Assert (0 <= language && language < (int) LanguageCount);
lang = LanguageTable [language];
if (lang->currentPatterns != NULL)
stringListDelete (lang->currentPatterns);
if (lang->currentExtensions != NULL)
stringListDelete (lang->currentExtensions);
if (lang->patterns == NULL)
lang->currentPatterns = stringListNew ();
else
{
lang->currentPatterns =
stringListNewFromArgv (lang->patterns);
}
if (lang->extensions == NULL)
lang->currentExtensions = stringListNew ();
else
{
lang->currentExtensions =
stringListNewFromArgv (lang->extensions);
}
if (Option.verbose)
printLanguageMap (language);
verbose ("\n");
}
extern void installLanguageMapDefaults (void)
{
unsigned int i;
for (i = 0 ; i < LanguageCount ; ++i)
{
verbose (" %s: ", getLanguageName (i));
installLanguageMapDefault (i);
}
}
extern void clearLanguageMap (const langType language)
{
Assert (0 <= language && language < (int) LanguageCount);
stringListClear (LanguageTable [language]->currentPatterns);
stringListClear (LanguageTable [language]->currentExtensions);
}
extern void addLanguagePatternMap (const langType language, const char* ptrn)
{
vString* const str = vStringNewInit (ptrn);
parserDefinition* lang;
Assert (0 <= language && language < (int) LanguageCount);
lang = LanguageTable [language];
if (lang->currentPatterns == NULL)
lang->currentPatterns = stringListNew ();
stringListAdd (lang->currentPatterns, str);
}
extern boolean removeLanguageExtensionMap (const char *const extension)
{
boolean result = FALSE;
unsigned int i;
for (i = 0 ; i < LanguageCount && ! result ; ++i)
{
stringList* const exts = LanguageTable [i]->currentExtensions;
if (exts != NULL && stringListRemoveExtension (exts, extension))
{
verbose (" (removed from %s)", getLanguageName (i));
result = TRUE;
}
}
return result;
}
extern void addLanguageExtensionMap (
const langType language, const char* extension)
{
vString* const str = vStringNewInit (extension);
Assert (0 <= language && language < (int) LanguageCount);
removeLanguageExtensionMap (extension);
stringListAdd (LanguageTable [language]->currentExtensions, str);
}
extern void enableLanguage (const langType language, const boolean state)
{
Assert (0 <= language && language < (int) LanguageCount);
LanguageTable [language]->enabled = state;
}
extern void enableLanguages (const boolean state)
{
unsigned int i;
for (i = 0 ; i < LanguageCount ; ++i)
enableLanguage (i, state);
}
static void initializeParsers (void)
{
unsigned int i;
for (i = 0 ; i < LanguageCount ; ++i)
if (LanguageTable [i]->initialize != NULL)
(LanguageTable [i]->initialize) ((langType) i);
}
extern void initializeParsing (void)
{
unsigned int builtInCount;
unsigned int i;
builtInCount = sizeof (BuiltInParsers) / sizeof (BuiltInParsers [0]);
LanguageTable = xMalloc (builtInCount, parserDefinition*);
verbose ("Installing parsers: ");
for (i = 0 ; i < builtInCount ; ++i)
{
parserDefinition* const def = (*BuiltInParsers [i]) ();
if (def != NULL)
{
boolean accepted = FALSE;
if (def->name == NULL || def->name[0] == '\0')
error (FATAL, "parser definition must contain name\n");
else if (def->regex)
{
#ifdef HAVE_REGEX
def->parser = findRegexTags;
accepted = TRUE;
#endif
}
else if ((def->parser == NULL) == (def->parser2 == NULL))
error (FATAL,
"%s parser definition must define one and only one parsing routine\n",
def->name);
else
accepted = TRUE;
if (accepted)
{
verbose ("%s%s", i > 0 ? ", " : "", def->name);
def->id = LanguageCount++;
LanguageTable [def->id] = def;
}
}
}
verbose ("\n");
enableLanguages (TRUE);
initializeParsers ();
}
extern void freeParserResources (void)
{
unsigned int i;
for (i = 0 ; i < LanguageCount ; ++i)
{
parserDefinition* const lang = LanguageTable [i];
freeList (&lang->currentPatterns);
freeList (&lang->currentExtensions);
eFree (lang->name);
lang->name = NULL;
eFree (lang);
}
if (LanguageTable != NULL)
eFree (LanguageTable);
LanguageTable = NULL;
LanguageCount = 0;
}
/*
* Option parsing
*/
extern void processLanguageDefineOption (
const char *const option, const char *const parameter __unused__)
{
#ifdef HAVE_REGEX
if (parameter [0] == '\0')
error (WARNING, "No language specified for \"%s\" option", option);
else if (getNamedLanguage (parameter) != LANG_IGNORE)
error (WARNING, "Language \"%s\" already defined", parameter);
else
{
unsigned int i = LanguageCount++;
parserDefinition* const def = parserNew (parameter);
def->parser = findRegexTags;
def->currentPatterns = stringListNew ();
def->currentExtensions = stringListNew ();
def->regex = TRUE;
def->enabled = TRUE;
def->id = i;
LanguageTable = xRealloc (LanguageTable, i + 1, parserDefinition*);
LanguageTable [i] = def;
}
#else
error (WARNING, "regex support not available; required for --%s option",
option);
#endif
}
static kindOption *langKindOption (const langType language, const int flag)
{
unsigned int i;
kindOption* result = NULL;
const parserDefinition* lang;
Assert (0 <= language && language < (int) LanguageCount);
lang = LanguageTable [language];
for (i=0 ; i < lang->kindCount && result == NULL ; ++i)
if (lang->kinds [i].letter == flag)
result = &lang->kinds [i];
return result;
}
static void disableLanguageKinds (const langType language)
{
const parserDefinition* lang;
Assert (0 <= language && language < (int) LanguageCount);
lang = LanguageTable [language];
if (lang->regex)
disableRegexKinds (language);
else
{
unsigned int i;
for (i = 0 ; i < lang->kindCount ; ++i)
lang->kinds [i].enabled = FALSE;
}
}
static boolean enableLanguageKind (
const langType language, const int kind, const boolean mode)
{
boolean result = FALSE;
if (LanguageTable [language]->regex)
result = enableRegexKind (language, kind, mode);
else
{
kindOption* const opt = langKindOption (language, kind);
if (opt != NULL)
{
opt->enabled = mode;
result = TRUE;
}
}
return result;
}
static void processLangKindOption (
const langType language, const char *const option,
const char *const parameter)
{
const char *p = parameter;
boolean mode = TRUE;
int c;
Assert (0 <= language && language < (int) LanguageCount);
if (*p != '+' && *p != '-')
disableLanguageKinds (language);
while ((c = *p++) != '\0') switch (c)
{
case '+': mode = TRUE; break;
case '-': mode = FALSE; break;
default:
if (! enableLanguageKind (language, c, mode))
error (WARNING, "Unsupported parameter '%c' for --%s option",
c, option);
break;
}
}
extern boolean processKindOption (
const char *const option, const char *const parameter)
{
boolean handled = FALSE;
const char* const dash = strchr (option, '-');
if (dash != NULL &&
(strcmp (dash + 1, "kinds") == 0 || strcmp (dash + 1, "types") == 0))
{
langType language;
vString* langName = vStringNew ();
vStringNCopyS (langName, option, dash - option);
language = getNamedLanguage (vStringValue (langName));
if (language == LANG_IGNORE)
error (WARNING, "Unknown language specified in \"%s\" option", option);
else
processLangKindOption (language, option, parameter);
vStringDelete (langName);
handled = TRUE;
}
return handled;
}
static void printLanguageKind (const kindOption* const kind, boolean indent)
{
const char *const indentation = indent ? " " : "";
printf ("%s%c %s%s\n", indentation, kind->letter,
kind->description != NULL ? kind->description :
(kind->name != NULL ? kind->name : ""),
kind->enabled ? "" : " [off]");
}
static void printKinds (langType language, boolean indent)
{
const parserDefinition* lang;
Assert (0 <= language && language < (int) LanguageCount);
lang = LanguageTable [language];
if (lang->kinds != NULL || lang->regex)
{
unsigned int i;
for (i = 0 ; i < lang->kindCount ; ++i)
printLanguageKind (lang->kinds + i, indent);
printRegexKinds (language, indent);
}
}
extern void printLanguageKinds (const langType language)
{
if (language == LANG_AUTO)
{
unsigned int i;
for (i = 0 ; i < LanguageCount ; ++i)
{
const parserDefinition* const lang = LanguageTable [i];
printf ("%s%s\n", lang->name, lang->enabled ? "" : " [disabled]");
printKinds (i, TRUE);
}
}
else
printKinds (language, FALSE);
}
static void printMaps (const langType language)
{
const parserDefinition* lang;
unsigned int i;
Assert (0 <= language && language < (int) LanguageCount);
lang = LanguageTable [language];
printf ("%-8s", lang->name);
if (lang->currentExtensions != NULL)
for (i = 0 ; i < stringListCount (lang->currentExtensions) ; ++i)
printf (" *.%s", vStringValue (
stringListItem (lang->currentExtensions, i)));
if (lang->currentPatterns != NULL)
for (i = 0 ; i < stringListCount (lang->currentPatterns) ; ++i)
printf (" %s", vStringValue (
stringListItem (lang->currentPatterns, i)));
putchar ('\n');
}
extern void printLanguageMaps (const langType language)
{
if (language == LANG_AUTO)
{
unsigned int i;
for (i = 0 ; i < LanguageCount ; ++i)
printMaps (i);
}
else
printMaps (language);
}
static void printLanguage (const langType language)
{
const parserDefinition* lang;
Assert (0 <= language && language < (int) LanguageCount);
lang = LanguageTable [language];
if (lang->kinds != NULL || lang->regex)
printf ("%s%s\n", lang->name, lang->enabled ? "" : " [disabled]");
}
extern void printLanguageList (void)
{
unsigned int i;
for (i = 0 ; i < LanguageCount ; ++i)
printLanguage (i);
}
/*
* File parsing
*/
static void makeFileTag (const char *const fileName)
{
if (Option.include.fileNames)
{
tagEntryInfo tag;
initTagEntry (&tag, baseFilename (fileName));
tag.isFileEntry = TRUE;
tag.lineNumberEntry = TRUE;
tag.lineNumber = 1;
tag.kindName = "file";
tag.kind = 'F';
makeTagEntry (&tag);
}
}
static boolean createTagsForFile (
const char *const fileName, const langType language,
const unsigned int passCount)
{
boolean retried = FALSE;
Assert (0 <= language && language < (int) LanguageCount);
if (fileOpen (fileName, language))
{
const parserDefinition* const lang = LanguageTable [language];
if (Option.etags)
beginEtagsFile ();
makeFileTag (fileName);
if (lang->parser != NULL)
lang->parser ();
else if (lang->parser2 != NULL)
retried = lang->parser2 (passCount);
if (Option.etags)
endEtagsFile (getSourceFileTagPath ());
fileClose ();
}
return retried;
}
static boolean createTagsWithFallback (
const char *const fileName, const langType language)
{
const unsigned long numTags = TagFile.numTags.added;
fpos_t tagFilePosition;
unsigned int passCount = 0;
boolean tagFileResized = FALSE;
fgetpos (TagFile.fp, &tagFilePosition);
while (createTagsForFile (fileName, language, ++passCount))
{
/* Restore prior state of tag file.
*/
fsetpos (TagFile.fp, &tagFilePosition);
TagFile.numTags.added = numTags;
tagFileResized = TRUE;
}
return tagFileResized;
}
extern boolean parseFile (const char *const fileName)
{
boolean tagFileResized = FALSE;
langType language = Option.language;
if (Option.language == LANG_AUTO)
language = getFileLanguage (fileName);
Assert (language != LANG_AUTO);
if (language == LANG_IGNORE)
verbose ("ignoring %s (unknown language)\n", fileName);
else if (! LanguageTable [language]->enabled)
verbose ("ignoring %s (language disabled)\n", fileName);
else
{
if (Option.filter)
openTagFile ();
tagFileResized = createTagsWithFallback (fileName, language);
if (Option.filter)
closeTagFile (tagFileResized);
addTotals (1, 0L, 0L);
return tagFileResized;
}
return tagFileResized;
}
/* vi:set tabstop=4 shiftwidth=4 nowrap: */
+129
View File
@@ -0,0 +1,129 @@
/*
* $Id: parse.h,v 1.16 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 1998-2003, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* Private definitions for parsing support.
*/
#ifndef _PARSE_H
#define _PARSE_H
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include "parsers.h" /* contains list of parsers */
#include "strlist.h"
/*
* MACROS
*/
#define KIND_COUNT(kindTable) (sizeof(kindTable)/sizeof(kindOption))
#define LANG_AUTO (-1)
#define LANG_IGNORE (-2)
/*
* DATA DECLARATIONS
*/
typedef int langType;
typedef void (*createRegexTag) (const vString* const name);
typedef void (*simpleParser) (void);
typedef boolean (*rescanParser) (const unsigned int passCount);
typedef void (*parserInitialize) (langType language);
typedef struct sKindOption {
boolean enabled; /* are tags for kind enabled? */
int letter; /* kind letter */
const char* name; /* kind name */
const char* description; /* displayed in --help output */
} kindOption;
typedef struct {
/* defined by parser */
char* name; /* name of language */
kindOption* kinds; /* tag kinds handled by parser */
unsigned int kindCount; /* size of `kinds' list */
const char *const *extensions; /* list of default extensions */
const char *const *patterns; /* list of default file name patterns */
parserInitialize initialize; /* initialization routine, if needed */
simpleParser parser; /* simple parser (common case) */
rescanParser parser2; /* rescanning parser (unusual case) */
boolean regex; /* is this a regex parser? */
/* used internally */
unsigned int id; /* id assigned to language */
boolean enabled; /* currently enabled? */
stringList* currentPatterns; /* current list of file name patterns */
stringList* currentExtensions; /* current list of extensions */
} parserDefinition;
typedef parserDefinition* (parserDefinitionFunc) (void);
typedef struct {
size_t start; /* character index in line where match starts */
size_t length; /* length of match */
} regexMatch;
typedef void (*regexCallback) (const char *line, const regexMatch *matches, unsigned int count);
/*
* FUNCTION PROTOTYPES
*/
/* Each parsers' definition function is called. The routine is expected to
* return a structure allocated using parserNew(). This structure must,
* at minimum, set the `parser' field.
*/
extern parserDefinitionFunc PARSER_LIST;
/* Legacy interface */
extern boolean includingDefineTags (void);
/* Language processing and parsing */
extern void makeSimpleTag (const vString* const name, kindOption* const kinds, const int kind);
extern parserDefinition* parserNew (const char* name);
extern const char *getLanguageName (const langType language);
extern langType getNamedLanguage (const char *const name);
extern langType getFileLanguage (const char *const fileName);
extern void installLanguageMapDefault (const langType language);
extern void installLanguageMapDefaults (void);
extern void clearLanguageMap (const langType language);
extern boolean removeLanguageExtensionMap (const char *const extension);
extern void addLanguageExtensionMap (const langType language, const char* extension);
extern void addLanguagePatternMap (const langType language, const char* ptrn);
extern void printLanguageMap (const langType language);
extern void printLanguageMaps (const langType language);
extern void enableLanguages (const boolean state);
extern void enableLanguage (const langType language, const boolean state);
extern void initializeParsing (void);
extern void freeParserResources (void);
extern void processLanguageDefineOption (const char *const option, const char *const parameter);
extern boolean processKindOption (const char *const option, const char *const parameter);
extern void printKindOptions (void);
extern void printLanguageKinds (const langType language);
extern void printLanguageList (void);
extern boolean parseFile (const char *const fileName);
/* Regex interface */
#ifdef HAVE_REGEX
extern void findRegexTags (void);
extern boolean matchRegex (const vString* const line, const langType language);
#endif
extern boolean processRegexOption (const char *const option, const char *const parameter);
extern void addLanguageRegex (const langType language, const char* const regex);
extern void addTagRegex (const langType language, const char* const regex, const char* const name, const char* const kinds, const char* const flags);
extern void addCallbackRegex (const langType language, const char *const regex, const char *const flags, const regexCallback callback);
extern void disableRegexKinds (const langType language);
extern boolean enableRegexKind (const langType language, const int kind, const boolean mode);
extern void printRegexKinds (const langType language, boolean indent);
extern void freeRegexResources (void);
extern void checkRegex (void);
#endif /* _PARSE_H */
/* vi:set tabstop=4 shiftwidth=4: */
+55
View File
@@ -0,0 +1,55 @@
/*
* $Id: parsers.h,v 1.12 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 2000-2003, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* External interface to all language parsing modules.
*
* To add a new language parser, you need only modify this single source
* file to add the name of the parser definition function.
*/
#ifndef _PARSERS_H
#define _PARSERS_H
/* Add the name of any new parser definition function here */
#define PARSER_LIST \
AsmParser, \
AspParser, \
AwkParser, \
BetaParser, \
CParser, \
CppParser, \
CsharpParser, \
CobolParser, \
EiffelParser, \
ErlangParser, \
FortranParser, \
HtmlParser, \
JavaParser, \
JavaScriptParser, \
LispParser, \
LuaParser, \
MakefileParser, \
PascalParser, \
PerlParser, \
PhpParser, \
PythonParser, \
RexxParser, \
RubyParser, \
SchemeParser, \
ShParser, \
SlangParser, \
SmlParser, \
SqlParser, \
TclParser, \
VeraParser, \
VerilogParser, \
VimParser, \
YaccParser
#endif /* _PARSERS_H */
/* vi:set tabstop=4 shiftwidth=4: */
+266
View File
@@ -0,0 +1,266 @@
/*
* $Id: pascal.c,v 1.6 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 2001-2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for generating tags for the Pascal language,
* including some extensions for Object Pascal.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#include "entry.h"
#include "parse.h"
#include "read.h"
#include "vstring.h"
/*
* DATA DEFINITIONS
*/
typedef enum {
K_FUNCTION, K_PROCEDURE
} pascalKind;
static kindOption PascalKinds [] = {
{ TRUE, 'f', "function", "functions"},
{ TRUE, 'p', "procedure", "procedures"}
};
/*
* FUNCTION DEFINITIONS
*/
static void createPascalTag (
tagEntryInfo* const tag, const vString* const name, const int kind)
{
if (PascalKinds [kind].enabled && name != NULL && vStringLength (name) > 0)
{
initTagEntry (tag, vStringValue (name));
tag->kindName = PascalKinds [kind].name;
tag->kind = PascalKinds [kind].letter;
}
else
initTagEntry (tag, NULL);
}
static void makePascalTag (const tagEntryInfo* const tag)
{
if (tag->name != NULL)
makeTagEntry (tag);
}
static const unsigned char* dbp;
#define starttoken(c) (isalpha ((int) c) || (int) c == '_')
#define intoken(c) (isalnum ((int) c) || (int) c == '_' || (int) c == '.')
#define endtoken(c) (! intoken (c) && ! isdigit ((int) c))
static boolean tail (const char *cp)
{
boolean result = FALSE;
register int len = 0;
while (*cp != '\0' && tolower ((int) *cp) == tolower ((int) dbp [len]))
cp++, len++;
if (*cp == '\0' && !intoken (dbp [len]))
{
dbp += len;
result = TRUE;
}
return result;
}
/* Algorithm adapted from from GNU etags.
* Locates tags for procedures & functions. Doesn't do any type- or
* var-definitions. It does look for the keyword "extern" or "forward"
* immediately following the procedure statement; if found, the tag is
* skipped.
*/
static void findPascalTags (void)
{
vString *name = vStringNew ();
tagEntryInfo tag;
pascalKind kind = K_FUNCTION;
/* each of these flags is TRUE iff: */
boolean incomment = FALSE; /* point is inside a comment */
int comment_char = '\0'; /* type of current comment */
boolean inquote = FALSE; /* point is inside '..' string */
boolean get_tagname = FALSE;/* point is after PROCEDURE/FUNCTION
keyword, so next item = potential tag */
boolean found_tag = FALSE; /* point is after a potential tag */
boolean inparms = FALSE; /* point is within parameter-list */
boolean verify_tag = FALSE;
/* point has passed the parm-list, so the next token will determine
* whether this is a FORWARD/EXTERN to be ignored, or whether it is a
* real tag
*/
dbp = fileReadLine ();
while (dbp != NULL)
{
int c = *dbp++;
if (c == '\0') /* if end of line */
{
dbp = fileReadLine ();
if (dbp == NULL || *dbp == '\0')
continue;
if (!((found_tag && verify_tag) || get_tagname))
c = *dbp++;
/* only if don't need *dbp pointing to the beginning of
* the name of the procedure or function
*/
}
if (incomment)
{
if (comment_char == '{' && c == '}')
incomment = FALSE;
else if (comment_char == '(' && c == '*' && *dbp == ')')
{
dbp++;
incomment = FALSE;
}
continue;
}
else if (inquote)
{
if (c == '\'')
inquote = FALSE;
continue;
}
else switch (c)
{
case '\'':
inquote = TRUE; /* found first quote */
continue;
case '{': /* found open { comment */
incomment = TRUE;
comment_char = c;
continue;
case '(':
if (*dbp == '*') /* found open (* comment */
{
incomment = TRUE;
comment_char = c;
dbp++;
}
else if (found_tag) /* found '(' after tag, i.e., parm-list */
inparms = TRUE;
continue;
case ')': /* end of parms list */
if (inparms)
inparms = FALSE;
continue;
case ';':
if (found_tag && !inparms) /* end of proc or fn stmt */
{
verify_tag = TRUE;
break;
}
continue;
}
if (found_tag && verify_tag && *dbp != ' ')
{
/* check if this is an "extern" declaration */
if (*dbp == '\0')
continue;
if (tolower ((int) *dbp == 'e'))
{
if (tail ("extern")) /* superfluous, really! */
{
found_tag = FALSE;
verify_tag = FALSE;
}
}
else if (tolower ((int) *dbp) == 'f')
{
if (tail ("forward")) /* check for forward reference */
{
found_tag = FALSE;
verify_tag = FALSE;
}
}
if (found_tag && verify_tag) /* not external proc, so make tag */
{
found_tag = FALSE;
verify_tag = FALSE;
makePascalTag (&tag);
continue;
}
}
if (get_tagname) /* grab name of proc or fn */
{
const unsigned char *cp;
if (*dbp == '\0')
continue;
/* grab block name */
while (isspace ((int) *dbp))
++dbp;
for (cp = dbp ; *cp != '\0' && !endtoken (*cp) ; cp++)
continue;
vStringNCopyS (name, (const char*) dbp, cp - dbp);
createPascalTag (&tag, name, kind);
dbp = cp; /* set dbp to e-o-token */
get_tagname = FALSE;
found_tag = TRUE;
/* and proceed to check for "extern" */
}
else if (!incomment && !inquote && !found_tag)
{
switch (tolower ((int) c))
{
case 'c':
if (tail ("onstructor"))
{
get_tagname = TRUE;
kind = K_PROCEDURE;
}
break;
case 'd':
if (tail ("estructor"))
{
get_tagname = TRUE;
kind = K_PROCEDURE;
}
break;
case 'p':
if (tail ("rocedure"))
{
get_tagname = TRUE;
kind = K_PROCEDURE;
}
break;
case 'f':
if (tail ("unction"))
{
get_tagname = TRUE;
kind = K_FUNCTION;
}
break;
}
} /* while not eof */
}
}
extern parserDefinition* PascalParser (void)
{
static const char *const extensions [] = { "p", "pas", NULL };
parserDefinition* def = parserNew ("Pascal");
def->extensions = extensions;
def->kinds = PascalKinds;
def->kindCount = KIND_COUNT (PascalKinds);
def->parser = findPascalTags;
return def;
}
/* vi:set tabstop=4 shiftwidth=4: */
+213
View File
@@ -0,0 +1,213 @@
/*
* $Id: perl.c,v 1.14 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 2000-2003, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for generating tags for PERL language
* files.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#include "options.h"
#include "read.h"
#include "routines.h"
#include "vstring.h"
/*
* DATA DEFINITIONS
*/
typedef enum {
K_NONE = -1,
K_CONSTANT,
K_LABEL,
K_SUBROUTINE
} perlKind;
static kindOption PerlKinds [] = {
{ TRUE, 'c', "constant", "constants" },
{ TRUE, 'l', "label", "labels" },
{ TRUE, 's', "subroutine", "subroutines" }
};
/*
* FUNCTION DEFINITIONS
*/
static boolean isIdentifier1 (int c)
{
return (boolean) (isalpha (c) || c == '_');
}
static boolean isIdentifier (int c)
{
return (boolean) (isalnum (c) || c == '_');
}
static boolean isPodWord (const char *word)
{
boolean result = FALSE;
if (isalpha (*word))
{
const char *const pods [] = {
"head1", "head2", "head3", "head4", "over", "item", "back",
"pod", "begin", "end", "for"
};
const size_t count = sizeof (pods) / sizeof (pods [0]);
const char *white = strpbrk (word, " \t");
const size_t len = (white!=NULL) ? (size_t)(white-word) : strlen (word);
char *const id = (char*) eMalloc (len + 1);
size_t i;
strncpy (id, word, len);
id [len] = '\0';
for (i = 0 ; i < count && ! result ; ++i)
{
if (strcmp (id, pods [i]) == 0)
result = TRUE;
}
eFree (id);
}
return result;
}
/* Algorithm adapted from from GNU etags.
* Perl support by Bart Robinson <lomew@cs.utah.edu>
* Perl sub names: look for /^ [ \t\n]sub [ \t\n]+ [^ \t\n{ (]+/
*/
static void findPerlTags (void)
{
vString *name = vStringNew ();
vString *package = NULL;
boolean skipPodDoc = FALSE;
const unsigned char *line;
while ((line = fileReadLine ()) != NULL)
{
boolean spaceRequired = FALSE;
boolean qualified = FALSE;
const unsigned char *cp = line;
perlKind kind = K_NONE;
if (skipPodDoc)
{
if (strncmp ((const char*) line, "=cut", (size_t) 4) == 0)
skipPodDoc = FALSE;
continue;
}
else if (line [0] == '=')
{
skipPodDoc = isPodWord ((const char*)line + 1);
continue;
}
else if (strcmp ((const char*) line, "__DATA__") == 0)
break;
else if (strcmp ((const char*) line, "__END__") == 0)
break;
else if (line [0] == '#')
continue;
while (isspace (*cp))
cp++;
if (strncmp((const char*) cp, "sub", (size_t) 3) == 0)
{
cp += 3;
kind = K_SUBROUTINE;
spaceRequired = TRUE;
qualified = TRUE;
}
else if (strncmp((const char*) cp, "use", (size_t) 3) == 0)
{
cp += 3;
if (!isspace(*cp))
continue;
while (*cp && isspace (*cp))
++cp;
if (strncmp((const char*) cp, "constant", (size_t) 8) != 0)
continue;
cp += 8;
kind = K_CONSTANT;
spaceRequired = TRUE;
qualified = TRUE;
}
else if (strncmp((const char*) cp, "package", (size_t) 7) == 0)
{
cp += 7;
if (package == NULL)
package = vStringNew ();
else
vStringClear (package);
while (isspace (*cp))
cp++;
while ((int) *cp != ';' && !isspace ((int) *cp))
{
vStringPut (package, (int) *cp);
cp++;
}
vStringCatS (package, "::");
}
else
{
if (isIdentifier1 (*cp))
{
const unsigned char *p = cp;
while (isIdentifier (*p))
++p;
if ((int) *p == ':')
kind = K_LABEL;
}
}
if (kind != K_NONE)
{
if (spaceRequired && !isspace (*cp))
continue;
while (isspace (*cp))
cp++;
while (isIdentifier (*cp))
{
vStringPut (name, (int) *cp);
cp++;
}
vStringTerminate (name);
if (vStringLength (name) > 0)
{
makeSimpleTag (name, PerlKinds, kind);
if (Option.include.qualifiedTags && qualified &&
package != NULL && vStringLength (package) > 0)
{
vString *const qualifiedName = vStringNew ();
vStringCopy (qualifiedName, package);
vStringCat (qualifiedName, name);
makeSimpleTag (qualifiedName, PerlKinds, kind);
vStringDelete (qualifiedName);
}
}
vStringClear (name);
}
}
vStringDelete (name);
if (package != NULL)
vStringDelete (package);
}
extern parserDefinition* PerlParser (void)
{
static const char *const extensions [] = { "pl", "pm", "plx", "perl", NULL };
parserDefinition* def = parserNew ("Perl");
def->kinds = PerlKinds;
def->kindCount = KIND_COUNT (PerlKinds);
def->extensions = extensions;
def->parser = findPerlTags;
return def;
}
/* vi:set tabstop=4 shiftwidth=4: */
+171
View File
@@ -0,0 +1,171 @@
/*
* $Id: php.c,v 1.6 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 2000, Jesus Castagnetto <jmcastagnetto@zkey.com>
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for generating tags for the PHP web page
* scripting language. Only recognizes functions and classes, not methods or
* variables.
*
* Parsing PHP defines by Pavel Hlousek <pavel.hlousek@seznam.cz>, Apr 2003.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#include "parse.h"
#include "read.h"
#include "vstring.h"
/*
* DATA DEFINITIONS
*/
typedef enum {
K_CLASS, K_DEFINE, K_FUNCTION, K_VARIABLE
} phpKind;
static kindOption PhpKinds [] = {
{ TRUE, 'c', "class", "classes" },
{ TRUE, 'd', "define", "constant definitions" },
{ TRUE, 'f', "function", "functions" },
{ TRUE, 'v', "variable", "variables" }
};
/*
* FUNCTION DEFINITIONS
*/
static boolean isLetter(const int c)
{
return (boolean)(isalpha(c) || (c >= 127 && c <= 255));
}
static boolean isVarChar1(const int c)
{
return (boolean)(isLetter (c) || c == '_');
}
static boolean isVarChar(const int c)
{
return (boolean)(isVarChar1 (c) || isdigit (c));
}
static void findPhpTags (void)
{
vString *name = vStringNew ();
const unsigned char *line;
while ((line = fileReadLine ()) != NULL)
{
const unsigned char *cp = line;
while (isspace (*cp))
cp++;
if (*(const char*)cp == '$' && isVarChar1 (*(const char*)(cp+1)))
{
cp += 1;
vStringClear (name);
while (isVarChar ((int) *cp))
{
vStringPut (name, (int) *cp);
++cp;
}
while (isspace ((int) *cp))
++cp;
if (*(const char*) cp == '=')
{
vStringTerminate (name);
makeSimpleTag (name, PhpKinds, K_VARIABLE);
vStringClear (name);
}
}
else if (strncmp ((const char*) cp, "function", (size_t) 8) == 0 &&
isspace ((int) cp [8]))
{
cp += 8;
while (isspace ((int) *cp))
++cp;
if (*cp == '&') /* skip reference character */
cp++;
vStringClear (name);
while (isalnum ((int) *cp) || *cp == '_')
{
vStringPut (name, (int) *cp);
++cp;
}
vStringTerminate (name);
makeSimpleTag (name, PhpKinds, K_FUNCTION);
vStringClear (name);
}
else if (strncmp ((const char*) cp, "class", (size_t) 5) == 0 &&
isspace ((int) cp [5]))
{
cp += 5;
while (isspace ((int) *cp))
++cp;
vStringClear (name);
while (isalnum ((int) *cp) || *cp == '_')
{
vStringPut (name, (int) *cp);
++cp;
}
vStringTerminate (name);
makeSimpleTag (name, PhpKinds, K_CLASS);
vStringClear (name);
}
else if (strncmp ((const char*) cp, "define", (size_t) 6) == 0 &&
! isalnum ((int) cp [6]))
{
cp += 6;
while (isspace ((int) *cp))
++cp;
if (*cp != '(')
continue;
++cp;
while (isspace ((int) *cp))
++cp;
if ((*cp == '\'') || (*cp == '"'))
++cp;
else if (! ((*cp == '_') || isalnum ((int) *cp)))
continue;
vStringClear (name);
while (isalnum ((int) *cp) || *cp == '_')
{
vStringPut (name, (int) *cp);
++cp;
}
vStringTerminate (name);
makeSimpleTag (name, PhpKinds, K_DEFINE);
vStringClear (name);
}
}
vStringDelete (name);
}
extern parserDefinition* PhpParser (void)
{
static const char *const extensions [] = { "php", "php3", "phtml", NULL };
parserDefinition* def = parserNew ("PHP");
def->kinds = PhpKinds;
def->kindCount = KIND_COUNT (PhpKinds);
def->extensions = extensions;
def->parser = findPhpTags;
return def;
}
/* vi:set tabstop=4 shiftwidth=4: */
+223
View File
@@ -0,0 +1,223 @@
/*
* $Id: python.c,v 1.9 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 2000-2003, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for generating tags for Python language
* files.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#include "entry.h"
#include "options.h"
#include "read.h"
#include "routines.h"
#include "vstring.h"
/*
* DATA DEFINITIONS
*/
typedef enum {
K_CLASS, K_FUNCTION, K_MEMBER
} pythonKind;
static kindOption PythonKinds[] = {
{TRUE, 'c', "class", "classes"},
{TRUE, 'f', "function", "functions"},
{TRUE, 'm', "member", "class members"}
};
/*
* FUNCTION DEFINITIONS
*/
/* tagEntryInfo and vString should be preinitialized/preallocated but not
* necessary. If successful you will find class name in vString
*/
static boolean isIdentifierFirstCharacter (int c)
{
return (boolean) (isalpha (c) || c == '_');
}
static boolean isIdentifierCharacter (int c)
{
return (boolean) (isalnum (c) || c == '_');
}
static void makeFunctionTag (vString *const function, vString *const class)
{
tagEntryInfo tag;
initTagEntry (&tag, vStringValue (function));
if (vStringLength (class) > 0)
{
tag.kindName = "member";
tag.kind = 'm';
tag.extensionFields.scope [0] = "class";
tag.extensionFields.scope [1] = vStringValue (class);
}
else
{
tag.kindName = "function";
tag.kind = 'f';
}
if (strncmp (vStringValue (function), "__", 2) == 0 &&
strcmp (vStringValue (function), "__init__") != 0)
{
tag.extensionFields.access = "private";
tag.isFileScope = TRUE;
}
else
{
tag.extensionFields.access = "public";
}
makeTagEntry (&tag);
if (vStringLength (class) > 0 && Option.include.qualifiedTags)
{
vString *tagname = vStringNew ();
vStringCat (tagname, class);
vStringPut (tagname, '.');
vStringCat (tagname, function);
tag.name = vStringValue (tagname);
makeTagEntry (&tag);
vStringDelete (tagname);
}
}
static void makeClassTag (vString *const class, vString *const inheritance)
{
tagEntryInfo tag;
initTagEntry (&tag, vStringValue (class));
tag.kindName = "class";
tag.kind = 'c';
tag.extensionFields.inheritance = vStringValue (inheritance);
makeTagEntry (&tag);
}
static const unsigned char *skipSpace (const unsigned char *cp)
{
while (isspace ((int) *cp))
++cp;
return cp;
}
static const unsigned char *parseIdentifier (
const unsigned char *cp, vString *const identifier)
{
vStringClear (identifier);
while (isIdentifierCharacter ((int) *cp))
{
vStringPut (identifier, (int) *cp);
++cp;
}
vStringTerminate (identifier);
return cp;
}
static void parseClass (const unsigned char *cp, vString *const class)
{
vString *const inheritance = vStringNew ();
vStringClear (inheritance);
cp = parseIdentifier (cp, class);
cp = skipSpace (cp);
if (*cp == '(')
{
++cp;
while (*cp != ')' && *cp != '\0')
{
vStringPut (inheritance, *cp);
++cp;
}
vStringTerminate (inheritance);
}
makeClassTag (class, inheritance);
vStringDelete (inheritance);
}
static void parseFunction (const unsigned char *cp, vString *const class)
{
vString *const identifier = vStringNew ();
cp = parseIdentifier (cp, identifier);
makeFunctionTag (identifier, class);
vStringDelete (identifier);
}
static void findPythonTags (void)
{
vString *const class = vStringNew ();
vString *const identifier = vStringNew ();
const unsigned char *line;
int class_indent = 0;
boolean longStringLiteral = FALSE;
while ((line = fileReadLine ()) != NULL)
{
const unsigned char *cp = line;
int indent;
cp = skipSpace (cp);
indent = cp - line;
if (*cp == '#' || *cp == '\0') /* skip comment or blank line */
continue;
if (longStringLiteral)
{
cp = (const unsigned char*) strstr ((const char*) cp, "\"\"\"");
if (cp == NULL)
continue;
else
{
longStringLiteral = FALSE;
cp += 3;
}
}
if (isIdentifierFirstCharacter ((int) *cp))
{
if (indent <= class_indent)
vStringClear (class);
cp = parseIdentifier (cp, identifier);
if (isspace ((int) *cp))
{
cp = skipSpace (cp);
if (strcmp (vStringValue (identifier), "def") == 0)
parseFunction (cp, class);
else if (strcmp (vStringValue (identifier), "class") == 0)
{
parseClass (cp, class);
class_indent = indent;
}
}
}
if ((cp = (const unsigned char*) strstr ((const char*)cp, "\"\"\"")) != NULL)
{
cp += 3;
cp = (const unsigned char*) strstr ((const char*) cp, "\"\"\"");
if (cp == NULL)
longStringLiteral = TRUE;
}
}
vStringDelete (identifier);
vStringDelete (class);
}
extern parserDefinition *PythonParser (void)
{
static const char *const extensions[] = { "py", "python", NULL };
parserDefinition *def = parserNew ("Python");
def->kinds = PythonKinds;
def->kindCount = KIND_COUNT (PythonKinds);
def->extensions = extensions;
def->parser = findPythonTags;
return def;
}
/* vi:set tabstop=4 shiftwidth=4: */
+106
View File
@@ -0,0 +1,106 @@
/*
* $Id: qdos.c,v 1.2 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 1999, Thierry Godefroy <godefroy@imaginet.fr>
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions to handle wildcard expansion and file name
* conversion under QDOS.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <qdos.h>
#include <string.h>
#include <errno.h>
#include "ctags.h"
/* Translate the filenames from UNIX to QDOS conventions on open calls */
int (*_Open) (const char *, int, ...) = qopen;
long _stack = 24576; /* Plenty of stack space */
long _memincr = 10240; /* Big increments to cut fragmentation */
char _prog_name [] = "ctags";
char _version [] = PROGRAM_VERSION;
char _copyright [32] = __DATE__;
char *_endmsg = "\nPress a key to exit.";
int custom_expand (char * param, char ***argvptr, int *argcptr);
int (*_cmdwildcard) () = custom_expand;
struct WINDOWDEF _condetails = { 208, 1, 0, 7, 512, 256, 0, 0};
void (*_consetup) () = consetup_title;
/* custom cmdexpand: also expands directory names */
#define FILEBUF_INIT 1024 /* Initial allocation size for buffer */
#define FILEBUF_INCR 1024 /* Increment size for buffer */
int custom_expand (char * param, char ***argvptr, int *argcptr)
{
int count,sl;
size_t bufsize;
char *filenamebuf;
char *ptr,*safeptr;
/*
* Check to see if we should do wild card expansion.
* We only perform wildcard expansion if the parameter
* was not a string and if it contains one of the
* wild card characters.
*
* We also do not expand any option that starts with '-'
* as we then assume that it is a unix stylew option.
*/
if ((*param == '-') || (strpbrk (param,"*?") == NULL) ) {
return 0;
}
if ((filenamebuf = malloc (bufsize = FILEBUF_INIT)) == NULL) {
return -1;
}
TRYAGAIN:
count = getfnl (param, filenamebuf, bufsize, QDR_ALL);
if (count == -1 && errno == ENOMEM) {
/*
* We have overflowed the buffer, so we try
* to get a bigger buffer and try again.
*/
bufsize += FILEBUF_INCR;
if ((filenamebuf = realloc (filenamebuf, bufsize)) == NULL) {
return -1;
} else {
goto TRYAGAIN;
}
}
/*
* If no files were found, then return unexpanded.
*/
if (count == 0) {
free (filenamebuf);
return 0;
}
/*
* Files were found, so add these to the list instead
* of the original parameter typed by the user.
*/
for ( ptr=filenamebuf ; count > 0 ; count -- ) {
*argvptr = (char **) realloc (*argvptr, (size_t) (((*argcptr) + 2) * sizeof (char *)));
safeptr= (char *) malloc ((size_t) (sl=strlen (ptr) + 1));
if (safeptr == NULL || *argvptr == NULL) {
return -1;
}
(void) memcpy (safeptr,ptr, (size_t) sl);
(*argvptr) [*argcptr] = safeptr;
*argcptr += 1;
ptr += sl;
}
free (filenamebuf);
return *argcptr;
}
/* vi:set tabstop=4 shiftwidth=4: */
+545
View File
@@ -0,0 +1,545 @@
/*
* $Id: read.c,v 1.7 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 1996-2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains low level source and tag file read functions (newline
* conversion for source files are performed at this level).
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#include <ctype.h>
#define FILE_WRITE
#include "read.h"
#include "debug.h"
#include "entry.h"
#include "main.h"
#include "routines.h"
#include "options.h"
/*
* DATA DEFINITIONS
*/
inputFile File; /* globally read through macros */
static fpos_t StartOfLine; /* holds deferred position of start of line */
/*
* FUNCTION DEFINITIONS
*/
extern void freeSourceFileResources (void)
{
vStringDelete (File.name);
vStringDelete (File.path);
vStringDelete (File.source.name);
vStringDelete (File.line);
}
/*
* Source file access functions
*/
static void setInputFileName (const char *const fileName)
{
const char *const head = fileName;
const char *const tail = baseFilename (head);
if (File.name != NULL)
vStringDelete (File.name);
File.name = vStringNewInit (fileName);
if (File.path != NULL)
vStringDelete (File.path);
if (tail == head)
File.path = NULL;
else
{
const size_t length = tail - head - 1;
File.path = vStringNew ();
vStringNCopyS (File.path, fileName, length);
}
}
static void setSourceFileParameters (vString *const fileName)
{
if (File.source.name != NULL)
vStringDelete (File.source.name);
File.source.name = fileName;
if (File.source.tagPath != NULL)
eFree (File.source.tagPath);
if (! Option.tagRelative || isAbsolutePath (vStringValue (fileName)))
File.source.tagPath = eStrdup (vStringValue (fileName));
else
File.source.tagPath =
relativeFilename (vStringValue (fileName), TagFile.directory);
if (vStringLength (fileName) > TagFile.max.file)
TagFile.max.file = vStringLength (fileName);
File.source.isHeader = isIncludeFile (vStringValue (fileName));
File.source.language = getFileLanguage (vStringValue (fileName));
}
static boolean setSourceFileName (vString *const fileName)
{
boolean result = FALSE;
if (getFileLanguage (vStringValue (fileName)) != LANG_IGNORE)
{
vString *pathName;
if (isAbsolutePath (vStringValue (fileName)) || File.path == NULL)
pathName = vStringNewCopy (fileName);
else
pathName = combinePathAndFile (
vStringValue (File.path), vStringValue (fileName));
setSourceFileParameters (pathName);
result = TRUE;
}
return result;
}
/*
* Line directive parsing
*/
static int skipWhite (void)
{
int c;
do
c = getc (File.fp);
while (c == ' ' || c == '\t');
return c;
}
static unsigned long readLineNumber (void)
{
unsigned long lNum = 0;
int c = skipWhite ();
while (c != EOF && isdigit (c))
{
lNum = (lNum * 10) + (c - '0');
c = getc (File.fp);
}
ungetc (c, File.fp);
if (c != ' ' && c != '\t')
lNum = 0;
return lNum;
}
/* While ANSI only permits lines of the form:
* # line n "filename"
* Earlier compilers generated lines of the form
* # n filename
* GNU C will output lines of the form:
* # n "filename"
* So we need to be fairly flexible in what we accept.
*/
static vString *readFileName (void)
{
vString *const fileName = vStringNew ();
boolean quoteDelimited = FALSE;
int c = skipWhite ();
if (c == '"')
{
c = getc (File.fp); /* skip double-quote */
quoteDelimited = TRUE;
}
while (c != EOF && c != '\n' &&
(quoteDelimited ? (c != '"') : (c != ' ' && c != '\t')))
{
vStringPut (fileName, c);
c = getc (File.fp);
}
if (c == '\n')
ungetc (c, File.fp);
vStringPut (fileName, '\0');
return fileName;
}
static boolean parseLineDirective (void)
{
boolean result = FALSE;
int c = skipWhite ();
DebugStatement ( const char* lineStr = ""; )
if (isdigit (c))
{
ungetc (c, File.fp);
result = TRUE;
}
else if (c == 'l' && getc (File.fp) == 'i' &&
getc (File.fp) == 'n' && getc (File.fp) == 'e')
{
c = getc (File.fp);
if (c == ' ' || c == '\t')
{
DebugStatement ( lineStr = "line"; )
result = TRUE;
}
}
if (result)
{
const unsigned long lNum = readLineNumber ();
if (lNum == 0)
result = FALSE;
else
{
vString *const fileName = readFileName ();
if (vStringLength (fileName) == 0)
{
File.source.lineNumber = lNum - 1; /* applies to NEXT line */
DebugStatement ( debugPrintf (DEBUG_RAW, "#%s %ld", lineStr, lNum); )
}
else if (setSourceFileName (fileName))
{
File.source.lineNumber = lNum - 1; /* applies to NEXT line */
DebugStatement ( debugPrintf (DEBUG_RAW, "#%s %ld \"%s\"",
lineStr, lNum, vStringValue (fileName)); )
}
if (Option.include.fileNames && vStringLength (fileName) > 0 &&
lNum == 1)
{
tagEntryInfo tag;
initTagEntry (&tag, baseFilename (vStringValue (fileName)));
tag.isFileEntry = TRUE;
tag.lineNumberEntry = TRUE;
tag.lineNumber = 1;
tag.kindName = "file";
tag.kind = 'F';
makeTagEntry (&tag);
}
vStringDelete (fileName);
result = TRUE;
}
}
return result;
}
/*
* Source file I/O operations
*/
/* This function opens a source file, and resets the line counter. If it
* fails, it will display an error message and leave the File.fp set to NULL.
*/
extern boolean fileOpen (const char *const fileName, const langType language)
{
#ifdef VMS
const char *const openMode = "r";
#else
const char *const openMode = "rb";
#endif
boolean opened = FALSE;
/* If another file was already open, then close it.
*/
if (File.fp != NULL)
{
fclose (File.fp); /* close any open source file */
File.fp = NULL;
}
File.fp = fopen (fileName, openMode);
if (File.fp == NULL)
error (WARNING | PERROR, "cannot open \"%s\"", fileName);
else
{
opened = TRUE;
setInputFileName (fileName);
fgetpos (File.fp, &StartOfLine);
fgetpos (File.fp, &File.filePosition);
File.currentLine = NULL;
File.language = language;
File.lineNumber = 0L;
File.eof = FALSE;
File.newLine = TRUE;
if (File.line != NULL)
vStringClear (File.line);
setSourceFileParameters (vStringNewInit (fileName));
File.source.lineNumber = 0L;
verbose ("OPENING %s as %s language %sfile\n", fileName,
getLanguageName (language),
File.source.isHeader ? "include " : "");
}
return opened;
}
extern void fileClose (void)
{
if (File.fp != NULL)
{
/* The line count of the file is 1 too big, since it is one-based
* and is incremented upon each newline.
*/
if (Option.printTotals)
{
fileStatus *status = eStat (vStringValue (File.name));
addTotals (0, File.lineNumber - 1L, status->size);
}
fclose (File.fp);
File.fp = NULL;
}
}
extern boolean fileEOF (void)
{
return File.eof;
}
/* Action to take for each encountered source newline.
*/
static void fileNewline (void)
{
File.filePosition = StartOfLine;
File.newLine = FALSE;
File.lineNumber++;
File.source.lineNumber++;
DebugStatement ( if (Option.breakLine == File.lineNumber) lineBreak (); )
DebugStatement ( debugPrintf (DEBUG_RAW, "%6ld: ", File.lineNumber); )
}
/* This function reads a single character from the stream, performing newline
* canonicalization.
*/
static int iFileGetc (void)
{
int c;
readnext:
c = getc (File.fp);
/* If previous character was a newline, then we're starting a line.
*/
if (File.newLine && c != EOF)
{
fileNewline ();
if (c == '#' && Option.lineDirectives)
{
if (parseLineDirective ())
goto readnext;
else
{
fsetpos (File.fp, &StartOfLine);
c = getc (File.fp);
}
}
}
if (c == EOF)
File.eof = TRUE;
else if (c == NEWLINE)
{
File.newLine = TRUE;
fgetpos (File.fp, &StartOfLine);
}
else if (c == CRETURN)
{
/* Turn line breaks into a canonical form. The three commonly
* used forms if line breaks: LF (UNIX), CR (MacIntosh), and
* CR-LF (MS-DOS) are converted into a generic newline.
*/
const int next = getc (File.fp); /* is CR followed by LF? */
if (next != NEWLINE)
ungetc (next, File.fp);
c = NEWLINE; /* convert CR into newline */
File.newLine = TRUE;
fgetpos (File.fp, &StartOfLine);
}
DebugStatement ( debugPutc (DEBUG_RAW, c); )
return c;
}
extern void fileUngetc (int c)
{
File.ungetch = c;
}
static vString *iFileGetLine (void)
{
vString *result = NULL;
int c;
if (File.line == NULL)
File.line = vStringNew ();
vStringClear (File.line);
do
{
c = iFileGetc ();
if (c != EOF)
vStringPut (File.line, c);
if (c == '\n' || (c == EOF && vStringLength (File.line) > 0))
{
vStringTerminate (File.line);
#ifdef HAVE_REGEX
if (vStringLength (File.line) > 0)
matchRegex (File.line, File.source.language);
#endif
result = File.line;
break;
}
} while (c != EOF);
Assert (result != NULL || File.eof);
return result;
}
/* Do not mix use of fileReadLine () and fileGetc () for the same file.
*/
extern int fileGetc (void)
{
int c;
/* If there is an ungotten character, then return it. Don't do any
* other processing on it, though, because we already did that the
* first time it was read through fileGetc ().
*/
if (File.ungetch != '\0')
{
c = File.ungetch;
File.ungetch = '\0';
return c; /* return here to avoid re-calling debugPutc () */
}
do
{
if (File.currentLine != NULL)
{
c = *File.currentLine++;
if (c == '\0')
File.currentLine = NULL;
}
else
{
vString* const line = iFileGetLine ();
if (line != NULL)
File.currentLine = (unsigned char*) vStringValue (line);
if (File.currentLine == NULL)
c = EOF;
else
c = '\0';
}
} while (c == '\0');
DebugStatement ( debugPutc (DEBUG_READ, c); )
return c;
}
/* An alternative interface to fileGetc (). Do not mix use of fileReadLine()
* and fileGetc() for the same file. The returned string does not contain
* the terminating newline. A NULL return value means that all lines in the
* file have been read and we are at the end of file.
*/
extern const unsigned char *fileReadLine (void)
{
vString* const line = iFileGetLine ();
const unsigned char* result = NULL;
if (line != NULL)
{
result = (const unsigned char*) vStringValue (line);
vStringStripNewline (line);
DebugStatement ( debugPrintf (DEBUG_READ, "%s\n", result); )
}
return result;
}
/*
* Source file line reading with automatic buffer sizing
*/
extern char *readLine (vString *const vLine, FILE *const fp)
{
char *result = NULL;
vStringClear (vLine);
if (fp == NULL) /* to free memory allocated to buffer */
error (FATAL, "NULL file pointer");
else
{
boolean reReadLine;
/* If reading the line places any character other than a null or a
* newline at the last character position in the buffer (one less
* than the buffer size), then we must resize the buffer and
* reattempt to read the line.
*/
do
{
char *const pLastChar = vStringValue (vLine) + vStringSize (vLine) -2;
fpos_t startOfLine;
fgetpos (fp, &startOfLine);
reReadLine = FALSE;
*pLastChar = '\0';
result = fgets (vStringValue (vLine), (int) vStringSize (vLine), fp);
if (result == NULL)
{
if (! feof (fp))
error (FATAL | PERROR, "Failure on attempt to read file");
}
else if (*pLastChar != '\0' &&
*pLastChar != '\n' && *pLastChar != '\r')
{
/* buffer overflow */
reReadLine = vStringAutoResize (vLine);
if (reReadLine)
fsetpos (fp, &startOfLine);
else
error (FATAL | PERROR, "input line too big; out of memory");
}
else
{
char* eol;
vStringSetLength (vLine);
/* canonicalize new line */
eol = vStringValue (vLine) + vStringLength (vLine) - 1;
if (*eol == '\r')
*eol = '\n';
else if (*(eol - 1) == '\r' && *eol == '\n')
{
*(eol - 1) = '\n';
*eol = '\0';
--vLine->length;
}
}
} while (reReadLine);
}
return result;
}
/* Places into the line buffer the contents of the line referenced by
* "location".
*/
extern char *readSourceLine (
vString *const vLine, fpos_t location, long *const pSeekValue)
{
fpos_t orignalPosition;
char *result;
fgetpos (File.fp, &orignalPosition);
fsetpos (File.fp, &location);
if (pSeekValue != NULL)
*pSeekValue = ftell (File.fp);
result = readLine (vLine, File.fp);
if (result == NULL)
error (FATAL, "Unexpected end of file: %s", vStringValue (File.name));
fsetpos (File.fp, &orignalPosition);
return result;
}
/* vi:set tabstop=4 shiftwidth=4: */
+115
View File
@@ -0,0 +1,115 @@
/*
* $Id: read.h,v 1.5 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 1998-2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* External interface to read.c
*/
#ifndef _READ_H
#define _READ_H
#if defined(FILE_WRITE) || defined(VAXC)
# define CONST_FILE
#else
# define CONST_FILE const
#endif
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <stdio.h>
#include <ctype.h>
#include "parse.h"
#include "vstring.h"
/*
* MACROS
*/
#define getInputLineNumber() File.lineNumber
#define getInputFileName() vStringValue (File.source.name)
#define getInputFilePosition() File.filePosition
#define getSourceFileName() vStringValue (File.source.name)
#define getSourceFileTagPath() File.source.tagPath
#define getSourceLanguage() File.source.language
#define getSourceLanguageName() getLanguageName (File.source.language)
#define getSourceLineNumber() File.source.lineNumber
#define isLanguage(lang) (boolean)((lang) == File.source.language)
#define isHeaderFile() File.source.isHeader
/*
* DATA DECLARATIONS
*/
enum eCharacters {
/* white space characters */
SPACE = ' ',
NEWLINE = '\n',
CRETURN = '\r',
FORMFEED = '\f',
TAB = '\t',
VTAB = '\v',
/* some hard to read characters */
DOUBLE_QUOTE = '"',
SINGLE_QUOTE = '\'',
BACKSLASH = '\\',
STRING_SYMBOL = ('S' + 0x80),
CHAR_SYMBOL = ('C' + 0x80)
};
/* Maintains the state of the current source file.
*/
typedef struct sInputFile {
vString *name; /* name of input file */
vString *path; /* path of input file (if any) */
vString *line; /* last line read from file */
const unsigned char* currentLine; /* current line being worked on */
FILE *fp; /* stream used for reading the file */
unsigned long lineNumber; /* line number in the input file */
fpos_t filePosition; /* file position of current line */
int ungetch; /* a single character that was ungotten */
boolean eof; /* have we reached the end of file? */
boolean newLine; /* will the next character begin a new line? */
langType language; /* language of input file */
/* Contains data pertaining to the original source file in which the tag
* was defined. This may be different from the input file when #line
* directives are processed (i.e. the input file is preprocessor output).
*/
struct sSource {
vString *name; /* name to report for source file */
char *tagPath; /* path of source file relative to tag file */
unsigned long lineNumber;/* line number in the source file */
boolean isHeader; /* is source file a header file? */
langType language; /* language of source file */
} source;
} inputFile;
/*
* GLOBAL VARIABLES
*/
extern CONST_FILE inputFile File;
/*
* FUNCTION PROTOTYPES
*/
extern void freeSourceFileResources (void);
extern boolean fileOpen (const char *const fileName, const langType language);
extern boolean fileEOF (void);
extern void fileClose (void);
extern int fileGetc (void);
extern void fileUngetc (int c);
extern const unsigned char *fileReadLine (void);
extern char *readLine (vString *const vLine, FILE *const fp);
extern char *readSourceLine (vString *const vLine, fpos_t location, long *const pSeekValue);
#endif /* _READ_H */
/* vi:set tabstop=4 shiftwidth=4: */
+958
View File
@@ -0,0 +1,958 @@
/*
* $Id: readtags.c,v 1.25 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 1996-2003, Darren Hiebert
*
* This source code is released into the public domain.
*
* This module contains functions for reading tag files.
*/
/*
* INCLUDE FILES
*/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h> /* to declare off_t */
#include "readtags.h"
/*
* MACROS
*/
#define TAB '\t'
/*
* DATA DECLARATIONS
*/
typedef struct {
size_t size;
char *buffer;
} vstring;
/* Information about current tag file */
struct sTagFile {
/* has the file been opened and this structure initialized? */
short initialized;
/* format of tag file */
short format;
/* how is the tag file sorted? */
sortType sortMethod;
/* pointer to file structure */
FILE* fp;
/* file position of first character of `line' */
off_t pos;
/* size of tag file in seekable positions */
off_t size;
/* last line read */
vstring line;
/* name of tag in last line read */
vstring name;
/* defines tag search state */
struct {
/* file position of last match for tag */
off_t pos;
/* name of tag last searched for */
const char *name;
/* length of name for partial matches */
size_t nameLength;
/* peforming partial match */
short partial;
/* ignoring case */
short ignorecase;
} search;
/* miscellaneous extension fields */
struct {
/* number of entries in `list' */
unsigned short max;
/* list of key value pairs */
tagExtensionField *list;
} fields;
/* buffers to be freed at close */
struct {
/* name of program author */
char *author;
/* name of program */
char *name;
/* URL of distribution */
char *url;
/* program version */
char *version;
} program;
};
/*
* DATA DEFINITIONS
*/
const char *const EmptyString = "";
const char *const PseudoTagPrefix = "!_";
/*
* FUNCTION DEFINITIONS
*/
/*
* Compare two strings, ignoring case.
* Return 0 for match, < 0 for smaller, > 0 for bigger
* Make sure case is folded to uppercase in comparison (like for 'sort -f')
* This makes a difference when one of the chars lies between upper and lower
* ie. one of the chars [ \ ] ^ _ ` for ascii. (The '_' in particular !)
*/
static int struppercmp (const char *s1, const char *s2)
{
int result;
do
{
result = toupper ((int) *s1) - toupper ((int) *s2);
} while (result == 0 && *s1++ != '\0' && *s2++ != '\0');
return result;
}
static int strnuppercmp (const char *s1, const char *s2, size_t n)
{
int result;
do
{
result = toupper ((int) *s1) - toupper ((int) *s2);
} while (result == 0 && --n > 0 && *s1++ != '\0' && *s2++ != '\0');
return result;
}
static int growString (vstring *s)
{
int result = 0;
size_t newLength;
char *newLine;
if (s->size == 0)
{
newLength = 128;
newLine = (char*) malloc (newLength);
*newLine = '\0';
}
else
{
newLength = 2 * s->size;
newLine = (char*) realloc (s->buffer, newLength);
}
if (newLine == NULL)
perror ("string too large");
else
{
s->buffer = newLine;
s->size = newLength;
result = 1;
}
return result;
}
/* Copy name of tag out of tag line */
static void copyName (tagFile *const file)
{
size_t length;
const char *end = strchr (file->line.buffer, '\t');
if (end == NULL)
{
end = strchr (file->line.buffer, '\n');
if (end == NULL)
end = strchr (file->line.buffer, '\r');
}
if (end != NULL)
length = end - file->line.buffer;
else
length = strlen (file->line.buffer);
while (length >= file->name.size)
growString (&file->name);
strncpy (file->name.buffer, file->line.buffer, length);
file->name.buffer [length] = '\0';
}
static int readTagLineRaw (tagFile *const file)
{
int result = 1;
int reReadLine;
/* If reading the line places any character other than a null or a
* newline at the last character position in the buffer (one less than
* the buffer size), then we must resize the buffer and reattempt to read
* the line.
*/
do
{
char *const pLastChar = file->line.buffer + file->line.size - 2;
char *line;
file->pos = ftell (file->fp);
reReadLine = 0;
*pLastChar = '\0';
line = fgets (file->line.buffer, (int) file->line.size, file->fp);
if (line == NULL)
{
/* read error */
if (! feof (file->fp))
perror ("readTagLine");
result = 0;
}
else if (*pLastChar != '\0' &&
*pLastChar != '\n' && *pLastChar != '\r')
{
/* buffer overflow */
growString (&file->line);
fseek (file->fp, file->pos, SEEK_SET);
reReadLine = 1;
}
else
{
size_t i = strlen (file->line.buffer);
while (i > 0 &&
(file->line.buffer [i - 1] == '\n' || file->line.buffer [i - 1] == '\r'))
{
file->line.buffer [i - 1] = '\0';
--i;
}
}
} while (reReadLine && result);
if (result)
copyName (file);
return result;
}
static int readTagLine (tagFile *const file)
{
int result;
do
{
result = readTagLineRaw (file);
} while (result && *file->name.buffer == '\0');
return result;
}
static tagResult growFields (tagFile *const file)
{
tagResult result = TagFailure;
unsigned short newCount = 2 * file->fields.max;
tagExtensionField *newFields = (tagExtensionField*)
realloc (file->fields.list, newCount * sizeof (tagExtensionField));
if (newFields == NULL)
perror ("too many extension fields");
else
{
file->fields.list = newFields;
file->fields.max = newCount;
result = TagSuccess;
}
return result;
}
static void parseExtensionFields (tagFile *const file, tagEntry *const entry,
char *const string)
{
char *p = string;
while (p != NULL && *p != '\0')
{
while (*p == TAB)
*p++ = '\0';
if (*p != '\0')
{
char *colon;
char *field = p;
p = strchr (p, TAB);
if (p != NULL)
*p++ = '\0';
colon = strchr (field, ':');
if (colon == NULL)
entry->kind = field;
else
{
const char *key = field;
const char *value = colon + 1;
*colon = '\0';
if (strcmp (key, "kind") == 0)
entry->kind = value;
else if (strcmp (key, "file") == 0)
entry->fileScope = 1;
else if (strcmp (key, "line") == 0)
entry->address.lineNumber = atol (value);
else
{
if (entry->fields.count == file->fields.max)
growFields (file);
file->fields.list [entry->fields.count].key = key;
file->fields.list [entry->fields.count].value = value;
++entry->fields.count;
}
}
}
}
}
static void parseTagLine (tagFile *file, tagEntry *const entry)
{
int i;
char *p = file->line.buffer;
char *tab = strchr (p, TAB);
int fieldsPresent = 0;
entry->fields.list = NULL;
entry->fields.count = 0;
entry->kind = NULL;
entry->fileScope = 0;
entry->name = p;
if (tab != NULL)
{
*tab = '\0';
p = tab + 1;
entry->file = p;
tab = strchr (p, TAB);
if (tab != NULL)
{
*tab = '\0';
p = tab + 1;
if (*p == '/' || *p == '?')
{
/* parse pattern */
int delimiter = *(unsigned char*) p;
entry->address.lineNumber = 0;
entry->address.pattern = p;
do
{
p = strchr (p + 1, delimiter);
} while (p != NULL && *(p - 1) == '\\');
if (p == NULL)
{
/* invalid pattern */
}
else
++p;
}
else if (isdigit ((int) *(unsigned char*) p))
{
/* parse line number */
entry->address.pattern = p;
entry->address.lineNumber = atol (p);
while (isdigit ((int) *(unsigned char*) p))
++p;
}
else
{
/* invalid pattern */
}
fieldsPresent = (strncmp (p, ";\"", 2) == 0);
*p = '\0';
if (fieldsPresent)
parseExtensionFields (file, entry, p + 2);
}
}
if (entry->fields.count > 0)
entry->fields.list = file->fields.list;
for (i = entry->fields.count ; i < file->fields.max ; ++i)
{
file->fields.list [i].key = NULL;
file->fields.list [i].value = NULL;
}
}
static char *duplicate (const char *str)
{
char *result = NULL;
if (str != NULL)
{
result = (char*) malloc (strlen (str) + 1);
if (result == NULL)
perror (NULL);
else
strcpy (result, str);
}
return result;
}
static void readPseudoTags (tagFile *const file, tagFileInfo *const info)
{
fpos_t startOfLine;
const size_t prefixLength = strlen (PseudoTagPrefix);
if (info != NULL)
{
info->file.format = 1;
info->file.sort = TAG_UNSORTED;
info->program.author = NULL;
info->program.name = NULL;
info->program.url = NULL;
info->program.version = NULL;
}
while (1)
{
fgetpos (file->fp, &startOfLine);
if (! readTagLine (file))
break;
if (strncmp (file->line.buffer, PseudoTagPrefix, prefixLength) != 0)
break;
else
{
tagEntry entry;
const char *key, *value;
parseTagLine (file, &entry);
key = entry.name + prefixLength;
value = entry.file;
if (strcmp (key, "TAG_FILE_SORTED") == 0)
file->sortMethod = (sortType) atoi (value);
else if (strcmp (key, "TAG_FILE_FORMAT") == 0)
file->format = atoi (value);
else if (strcmp (key, "TAG_PROGRAM_AUTHOR") == 0)
file->program.author = duplicate (value);
else if (strcmp (key, "TAG_PROGRAM_NAME") == 0)
file->program.name = duplicate (value);
else if (strcmp (key, "TAG_PROGRAM_URL") == 0)
file->program.url = duplicate (value);
else if (strcmp (key, "TAG_PROGRAM_VERSION") == 0)
file->program.version = duplicate (value);
if (info != NULL)
{
info->file.format = file->format;
info->file.sort = file->sortMethod;
info->program.author = file->program.author;
info->program.name = file->program.name;
info->program.url = file->program.url;
info->program.version = file->program.version;
}
}
}
fsetpos (file->fp, &startOfLine);
}
static void gotoFirstLogicalTag (tagFile *const file)
{
fpos_t startOfLine;
const size_t prefixLength = strlen (PseudoTagPrefix);
rewind (file->fp);
while (1)
{
fgetpos (file->fp, &startOfLine);
if (! readTagLine (file))
break;
if (strncmp (file->line.buffer, PseudoTagPrefix, prefixLength) != 0)
break;
}
fsetpos (file->fp, &startOfLine);
}
static tagFile *initialize (const char *const filePath, tagFileInfo *const info)
{
tagFile *result = (tagFile*) malloc (sizeof (tagFile));
if (result != NULL)
{
memset (result, 0, sizeof (tagFile));
growString (&result->line);
growString (&result->name);
result->fields.max = 20;
result->fields.list = (tagExtensionField*) malloc (
result->fields.max * sizeof (tagExtensionField));
result->fp = fopen (filePath, "r");
if (result->fp == NULL)
{
free (result);
result = NULL;
info->status.error_number = errno;
}
else
{
fseek (result->fp, 0, SEEK_END);
result->size = ftell (result->fp);
rewind (result->fp);
readPseudoTags (result, info);
info->status.opened = 1;
result->initialized = 1;
}
}
return result;
}
static void terminate (tagFile *const file)
{
fclose (file->fp);
free (file->line.buffer);
free (file->name.buffer);
free (file->fields.list);
if (file->program.author != NULL)
free (file->program.author);
if (file->program.name != NULL)
free (file->program.name);
if (file->program.url != NULL)
free (file->program.url);
if (file->program.version != NULL)
free (file->program.version);
memset (file, 0, sizeof (tagFile));
free (file);
}
static tagResult readNext (tagFile *const file, tagEntry *const entry)
{
tagResult result = TagFailure;
if (file == NULL || ! file->initialized)
result = TagFailure;
else if (! readTagLine (file))
result = TagFailure;
else
{
if (entry != NULL)
parseTagLine (file, entry);
result = TagSuccess;
}
return result;
}
static const char *readFieldValue (
const tagEntry *const entry, const char *const key)
{
const char *result = NULL;
int i;
if (strcmp (key, "kind") == 0)
result = entry->kind;
else if (strcmp (key, "file") == 0)
result = EmptyString;
else for (i = 0 ; i < entry->fields.count && result == NULL ; ++i)
if (strcmp (entry->fields.list [i].key, key) == 0)
result = entry->fields.list [i].value;
return result;
}
static int readTagLineSeek (tagFile *const file, const off_t pos)
{
int result = 0;
if (fseek (file->fp, pos, SEEK_SET) == 0)
{
result = readTagLine (file); /* read probable partial line */
if (pos > 0 && result)
result = readTagLine (file); /* read complete line */
}
return result;
}
static int nameComparison (tagFile *const file)
{
int result;
if (file->search.ignorecase)
{
if (file->search.partial)
result = strnuppercmp (file->search.name, file->name.buffer,
file->search.nameLength);
else
result = struppercmp (file->search.name, file->name.buffer);
}
else
{
if (file->search.partial)
result = strncmp (file->search.name, file->name.buffer,
file->search.nameLength);
else
result = strcmp (file->search.name, file->name.buffer);
}
return result;
}
static void findFirstNonMatchBefore (tagFile *const file)
{
#define JUMP_BACK 512
int more_lines;
int comp;
off_t start = file->pos;
off_t pos = start;
do
{
if (pos < (off_t) JUMP_BACK)
pos = 0;
else
pos = pos - JUMP_BACK;
more_lines = readTagLineSeek (file, pos);
comp = nameComparison (file);
} while (more_lines && comp == 0 && pos > 0 && pos < start);
}
static tagResult findFirstMatchBefore (tagFile *const file)
{
tagResult result = TagFailure;
int more_lines;
off_t start = file->pos;
findFirstNonMatchBefore (file);
do
{
more_lines = readTagLine (file);
if (nameComparison (file) == 0)
result = TagSuccess;
} while (more_lines && result != TagSuccess && file->pos < start);
return result;
}
static tagResult findBinary (tagFile *const file)
{
tagResult result = TagFailure;
off_t lower_limit = 0;
off_t upper_limit = file->size;
off_t last_pos = 0;
off_t pos = upper_limit / 2;
while (result != TagSuccess)
{
if (! readTagLineSeek (file, pos))
{
/* in case we fell off end of file */
result = findFirstMatchBefore (file);
break;
}
else if (pos == last_pos)
{
/* prevent infinite loop if we backed up to beginning of file */
break;
}
else
{
const int comp = nameComparison (file);
last_pos = pos;
if (comp < 0)
{
upper_limit = pos;
pos = lower_limit + ((upper_limit - lower_limit) / 2);
}
else if (comp > 0)
{
lower_limit = pos;
pos = lower_limit + ((upper_limit - lower_limit) / 2);
}
else if (pos == 0)
result = TagSuccess;
else
result = findFirstMatchBefore (file);
}
}
return result;
}
static tagResult findSequential (tagFile *const file)
{
tagResult result = TagFailure;
if (file->initialized)
{
while (result == TagFailure && readTagLine (file))
{
if (nameComparison (file) == 0)
result = TagSuccess;
}
}
return result;
}
static tagResult find (tagFile *const file, tagEntry *const entry,
const char *const name, const int options)
{
tagResult result = TagFailure;
file->search.name = name;
file->search.nameLength = strlen (name);
file->search.partial = (options & TAG_PARTIALMATCH) != 0;
file->search.ignorecase = (options & TAG_IGNORECASE) != 0;
fseek (file->fp, 0, SEEK_END);
file->size = ftell (file->fp);
rewind (file->fp);
if ((file->sortMethod == TAG_SORTED && !file->search.ignorecase) ||
(file->sortMethod == TAG_FOLDSORTED && file->search.ignorecase))
{
#ifdef DEBUG
printf ("<performing binary search>\n");
#endif
result = findBinary (file);
}
else
{
#ifdef DEBUG
printf ("<performing sequential search>\n");
#endif
result = findSequential (file);
}
if (result != TagSuccess)
file->search.pos = file->size;
else
{
file->search.pos = file->pos;
if (entry != NULL)
parseTagLine (file, entry);
}
return result;
}
static tagResult findNext (tagFile *const file, tagEntry *const entry)
{
tagResult result = TagFailure;
if ((file->sortMethod == TAG_SORTED && !file->search.ignorecase) ||
(file->sortMethod == TAG_FOLDSORTED && file->search.ignorecase))
{
result = tagsNext (file, entry);
if (result == TagSuccess && nameComparison (file) != 0)
result = TagFailure;
}
else
{
result = findSequential (file);
if (result == TagSuccess && entry != NULL)
parseTagLine (file, entry);
}
return result;
}
/*
* EXTERNAL INTERFACE
*/
extern tagFile *tagsOpen (const char *const filePath, tagFileInfo *const info)
{
return initialize (filePath, info);
}
extern tagResult tagsSetSortType (tagFile *const file, const sortType type)
{
tagResult result = TagFailure;
if (file != NULL && file->initialized)
{
file->sortMethod = type;
result = TagSuccess;
}
return result;
}
extern tagResult tagsFirst (tagFile *const file, tagEntry *const entry)
{
tagResult result = TagFailure;
if (file != NULL && file->initialized)
{
gotoFirstLogicalTag (file);
result = readNext (file, entry);
}
return result;
}
extern tagResult tagsNext (tagFile *const file, tagEntry *const entry)
{
tagResult result = TagFailure;
if (file != NULL && file->initialized)
result = readNext (file, entry);
return result;
}
extern const char *tagsField (const tagEntry *const entry, const char *const key)
{
const char *result = NULL;
if (entry != NULL)
result = readFieldValue (entry, key);
return result;
}
extern tagResult tagsFind (tagFile *const file, tagEntry *const entry,
const char *const name, const int options)
{
tagResult result = TagFailure;
if (file != NULL && file->initialized)
result = find (file, entry, name, options);
return result;
}
extern tagResult tagsFindNext (tagFile *const file, tagEntry *const entry)
{
tagResult result = TagFailure;
if (file != NULL && file->initialized)
result = findNext (file, entry);
return result;
}
extern tagResult tagsClose (tagFile *const file)
{
tagResult result = TagFailure;
if (file != NULL && file->initialized)
{
terminate (file);
result = TagSuccess;
}
return result;
}
/*
* TEST FRAMEWORK
*/
#ifdef READTAGS_MAIN
static const char *TagFileName = "tags";
static const char *ProgramName;
static int extensionFields;
static int SortOverride;
static sortType SortMethod;
static void printTag (const tagEntry *entry)
{
int i;
int first = 1;
const char* separator = ";\"";
const char* const empty = "";
/* "sep" returns a value only the first time it is evaluated */
#define sep (first ? (first = 0, separator) : empty)
printf ("%s\t%s\t%s",
entry->name, entry->file, entry->address.pattern);
if (extensionFields)
{
if (entry->kind != NULL && entry->kind [0] != '\0')
printf ("%s\tkind:%s", sep, entry->kind);
if (entry->fileScope)
printf ("%s\tfile:", sep);
#if 0
if (entry->address.lineNumber > 0)
printf ("%s\tline:%lu", sep, entry->address.lineNumber);
#endif
for (i = 0 ; i < entry->fields.count ; ++i)
printf ("%s\t%s:%s", sep, entry->fields.list [i].key,
entry->fields.list [i].value);
}
putchar ('\n');
#undef sep
}
static void findTag (const char *const name, const int options)
{
tagFileInfo info;
tagEntry entry;
tagFile *const file = tagsOpen (TagFileName, &info);
if (file == NULL)
{
fprintf (stderr, "%s: cannot open tag file: %s: %s\n",
ProgramName, strerror (info.status.error_number), name);
exit (1);
}
else
{
if (SortOverride)
tagsSetSortType (file, SortMethod);
if (tagsFind (file, &entry, name, options) == TagSuccess)
{
do
{
printTag (&entry);
} while (tagsFindNext (file, &entry) == TagSuccess);
}
tagsClose (file);
}
}
static void listTags (void)
{
tagFileInfo info;
tagEntry entry;
tagFile *const file = tagsOpen (TagFileName, &info);
if (file == NULL)
{
fprintf (stderr, "%s: cannot open tag file: %s: %s\n",
ProgramName, strerror (info.status.error_number), TagFileName);
exit (1);
}
else
{
while (tagsNext (file, &entry) == TagSuccess)
printTag (&entry);
tagsClose (file);
}
}
const char *const Usage =
"Find tag file entries matching specified names.\n\n"
"Usage: %s [-ilp] [-s[0|1]] [-t file] [name(s)]\n\n"
"Options:\n"
" -e Include extension fields in output.\n"
" -i Perform case-insensitive matching.\n"
" -l List all tags.\n"
" -p Perform partial matching.\n"
" -s[0|1|2] Override sort detection of tag file.\n"
" -t file Use specified tag file (default: \"tags\").\n"
"Note that options are acted upon as encountered, so order is significant.\n";
extern int main (int argc, char **argv)
{
int options = 0;
int actionSupplied = 0;
int i;
ProgramName = argv [0];
if (argc == 1)
{
fprintf (stderr, Usage, ProgramName);
exit (1);
}
for (i = 1 ; i < argc ; ++i)
{
const char *const arg = argv [i];
if (arg [0] != '-')
{
findTag (arg, options);
actionSupplied = 1;
}
else
{
size_t j;
for (j = 1 ; arg [j] != '\0' ; ++j)
{
switch (arg [j])
{
case 'e': extensionFields = 1; break;
case 'i': options |= TAG_IGNORECASE; break;
case 'p': options |= TAG_PARTIALMATCH; break;
case 'l': listTags (); actionSupplied = 1; break;
case 't':
if (arg [j+1] != '\0')
{
TagFileName = arg + j + 1;
j += strlen (TagFileName);
}
else if (i + 1 < argc)
TagFileName = argv [++i];
else
{
fprintf (stderr, Usage, ProgramName);
exit (1);
}
break;
case 's':
SortOverride = 1;
++j;
if (arg [j] == '\0')
SortMethod = TAG_SORTED;
else if (strchr ("012", arg[j]) != NULL)
SortMethod = (sortType) (arg[j] - '0');
else
{
fprintf (stderr, Usage, ProgramName);
exit (1);
}
break;
default:
fprintf (stderr, "%s: unknown option: %c\n",
ProgramName, arg[j]);
exit (1);
break;
}
}
}
}
if (! actionSupplied)
{
fprintf (stderr,
"%s: no action specified: specify tag name(s) or -l option\n",
ProgramName);
exit (1);
}
return 0;
}
#endif
/* vi:set tabstop=4 shiftwidth=4: */
+252
View File
@@ -0,0 +1,252 @@
/*
* $Id: readtags.h,v 1.13 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 1996-2003, Darren Hiebert
*
* This source code is released for the public domain.
*
* This file defines the public interface for looking up tag entries in tag
* files.
*
* The functions defined in this interface are intended to provide tag file
* support to a software tool. The tag lookups provided are sufficiently fast
* enough to permit opening a sorted tag file, searching for a matching tag,
* then closing the tag file each time a tag is looked up (search times are
* on the order of hundreths of a second, even for huge tag files). This is
* the recommended use of this library for most tool applications. Adhering
* to this approach permits a user to regenerate a tag file at will without
* the tool needing to detect and resynchronize with changes to the tag file.
* Even for an unsorted 24MB tag file, tag searches take about one second.
*/
#ifndef READTAGS_H
#define READTAGS_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* MACROS
*/
/* Options for tagsSetSortType() */
typedef enum {
TAG_UNSORTED, TAG_SORTED, TAG_FOLDSORTED
} sortType ;
/* Options for tagsFind() */
#define TAG_FULLMATCH 0x0
#define TAG_PARTIALMATCH 0x1
#define TAG_OBSERVECASE 0x0
#define TAG_IGNORECASE 0x2
/*
* DATA DECLARATIONS
*/
typedef enum { TagFailure = 0, TagSuccess = 1 } tagResult;
struct sTagFile;
typedef struct sTagFile tagFile;
/* This structure contains information about the tag file. */
typedef struct {
struct {
/* was the tag file successfully opened? */
int opened;
/* errno value when 'opened' is false */
int error_number;
} status;
/* information about the structure of the tag file */
struct {
/* format of tag file (1 = original, 2 = extended) */
short format;
/* how is the tag file sorted? */
sortType sort;
} file;
/* information about the program which created this tag file */
struct {
/* name of author of generating program (may be null) */
const char *author;
/* name of program (may be null) */
const char *name;
/* URL of distribution (may be null) */
const char *url;
/* program version (may be null) */
const char *version;
} program;
} tagFileInfo;
/* This structure contains information about an extension field for a tag.
* These exist at the end of the tag in the form "key:value").
*/
typedef struct {
/* the key of the extension field */
const char *key;
/* the value of the extension field (may be an empty string) */
const char *value;
} tagExtensionField;
/* This structure contains information about a specific tag. */
typedef struct {
/* name of tag */
const char *name;
/* path of source file containing definition of tag */
const char *file;
/* address for locating tag in source file */
struct {
/* pattern for locating source line
* (may be NULL if not present) */
const char *pattern;
/* line number in source file of tag definition
* (may be zero if not known) */
unsigned long lineNumber;
} address;
/* kind of tag (may by name, character, or NULL if not known) */
const char *kind;
/* is tag of file-limited scope? */
short fileScope;
/* miscellaneous extension fields */
struct {
/* number of entries in `list' */
unsigned short count;
/* list of key value pairs */
tagExtensionField *list;
} fields;
} tagEntry;
/*
* FUNCTION PROTOTYPES
*/
/*
* This function must be called before calling other functions in this
* library. It is passed the path to the tag file to read and a (possibly
* null) pointer to a structure which, if not null, will be populated with
* information about the tag file. If successful, the function will return a
* handle which must be supplied to other calls to read information from the
* tag file, and info.status.opened will be set to true. If unsuccessful,
* info.status.opened will be set to false and info.status.error_number will
* be set to the errno value representing the system error preventing the tag
* file from being successfully opened.
*/
extern tagFile *tagsOpen (const char *const filePath, tagFileInfo *const info);
/*
* This function allows the client to override the normal automatic detection
* of how a tag file is sorted. Permissible values for `type' are
* TAG_UNSORTED, TAG_SORTED, TAG_FOLDSORTED. Tag files in the new extended
* format contain a key indicating whether or not they are sorted. However,
* tag files in the original format do not contain such a key even when
* sorted, preventing this library from taking advantage of fast binary
* lookups. If the client knows that such an unmarked tag file is indeed
* sorted (or not), it can override the automatic detection. Note that
* incorrect lookup results will result if a tag file is marked as sorted when
* it actually is not. The function will return TagSuccess if called on an
* open tag file or TagFailure if not.
*/
extern tagResult tagsSetSortType (tagFile *const file, const sortType type);
/*
* Reads the first tag in the file, if any. It is passed the handle to an
* opened tag file and a (possibly null) pointer to a structure which, if not
* null, will be populated with information about the first tag file entry.
* The function will return TagSuccess another tag entry is found, or
* TagFailure if not (i.e. it reached end of file).
*/
extern tagResult tagsFirst (tagFile *const file, tagEntry *const entry);
/*
* Step to the next tag in the file, if any. It is passed the handle to an
* opened tag file and a (possibly null) pointer to a structure which, if not
* null, will be populated with information about the next tag file entry. The
* function will return TagSuccess another tag entry is found, or TagFailure
* if not (i.e. it reached end of file). It will always read the first tag in
* the file immediately after calling tagsOpen().
*/
extern tagResult tagsNext (tagFile *const file, tagEntry *const entry);
/*
* Retrieve the value associated with the extension field for a specified key.
* It is passed a pointer to a structure already populated with values by a
* previous call to tagsNext(), tagsFind(), or tagsFindNext(), and a string
* containing the key of the desired extension field. If no such field of the
* specified key exists, the function will return null.
*/
extern const char *tagsField (const tagEntry *const entry, const char *const key);
/*
* Find the first tag matching `name'. The structure pointed to by `entry'
* will be populated with information about the tag file entry. If a tag file
* is sorted using the C locale, a binary search algorithm is used to search
* the tag file, resulting in very fast tag lookups, even in huge tag files.
* Various options controlling the matches can be combined by bit-wise or-ing
* certain values together. The available values are:
*
* TAG_PARTIALMATCH
* Tags whose leading characters match `name' will qualify.
*
* TAG_FULLMATCH
* Only tags whose full lengths match `name' will qualify.
*
* TAG_IGNORECASE
* Matching will be performed in a case-insenstive manner. Note that
* this disables binary searches of the tag file.
*
* TAG_OBSERVECASE
* Matching will be performed in a case-senstive manner. Note that
* this enables binary searches of the tag file.
*
* The function will return TagSuccess if a tag matching the name is found, or
* TagFailure if not.
*/
extern tagResult tagsFind (tagFile *const file, tagEntry *const entry, const char *const name, const int options);
/*
* Find the next tag matching the name and options supplied to the most recent
* call to tagsFind() for the same tag file. The structure pointed to by
* `entry' will be populated with information about the tag file entry. The
* function will return TagSuccess if another tag matching the name is found,
* or TagFailure if not.
*/
extern tagResult tagsFindNext (tagFile *const file, tagEntry *const entry);
/*
* Call tagsTerminate() at completion of reading the tag file, which will
* close the file and free any internal memory allocated. The function will
* return TagFailure is no file is currently open, TagSuccess otherwise.
*/
extern tagResult tagsClose (tagFile *const file);
#ifdef __cplusplus
};
#endif
#endif
/* vi:set tabstop=4 shiftwidth=4: */
+39
View File
@@ -0,0 +1,39 @@
/*
* $Id: rexx.c,v 1.6 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 2001-2003, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for generating tags for the REXX language
* (http://www.rexxla.org, http://www2.hursley.ibm.com/rexx).
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* always include first */
#include "parse.h" /* always include */
/*
* FUNCTION DEFINITIONS
*/
static void installRexxRegex (const langType language)
{
addTagRegex (language, "^([A-Za-z0-9@#$\\.!?_]+)[ \t]*:",
"\\1", "s,subroutine,subroutines", NULL);
}
extern parserDefinition* RexxParser (void)
{
static const char *const extensions [] = { "cmd", "rexx", "rx", NULL };
parserDefinition* const def = parserNew ("REXX");
def->extensions = extensions;
def->initialize = installRexxRegex;
def->regex = TRUE;
return def;
}
/* vi:set tabstop=4 shiftwidth=4: */
+881
View File
@@ -0,0 +1,881 @@
/*
* $Id: routines.c,v 1.22 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 2002-2003, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains a lose assortment of shared functions.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#ifdef HAVE_STDLIB_H
# include <stdlib.h> /* to declare malloc (), realloc () */
#endif
#include <ctype.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <stdio.h> /* to declare tempnam(), and SEEK_SET (hopefully) */
#ifdef HAVE_FCNTL_H
# include <fcntl.h> /* to declar O_RDWR, O_CREAT, O_EXCL */
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h> /* to declare mkstemp () */
#endif
/* To declare "struct stat" and stat ().
*/
#if defined (HAVE_SYS_TYPES_H)
# include <sys/types.h>
#else
# if defined (HAVE_TYPES_H)
# include <types.h>
# endif
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#else
# ifdef HAVE_STAT_H
# include <stat.h>
# endif
#endif
#ifdef HAVE_DOS_H
# include <dos.h> /* to declare MAXPATH */
#endif
#ifdef HAVE_DIRECT_H
# include <direct.h> /* to _getcwd */
#endif
#ifdef HAVE_DIR_H
# include <dir.h> /* to declare findfirst() and findnext() */
#endif
#ifdef HAVE_IO_H
# include <io.h> /* to declare open() */
#endif
#include "debug.h"
#include "routines.h"
#ifdef TRAP_MEMORY_CALLS
# include "safe_malloc.h"
#endif
/*
* MACROS
*/
#ifndef TMPDIR
# define TMPDIR "/tmp"
#endif
/* File type tests.
*/
#ifndef S_ISREG
# if defined (S_IFREG) && ! defined (AMIGA)
# define S_ISREG(mode) ((mode) & S_IFREG)
# else
# define S_ISREG(mode) TRUE /* assume regular file */
# endif
#endif
#ifndef S_ISLNK
# ifdef S_IFLNK
# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
# else
# define S_ISLNK(mode) FALSE /* assume no soft links */
# endif
#endif
#ifndef S_ISDIR
# ifdef S_IFDIR
# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
# else
# define S_ISDIR(mode) FALSE /* assume no soft links */
# endif
#endif
#ifndef S_IFMT
# define S_IFMT 0
#endif
#ifndef S_IXUSR
# define S_IXUSR 0
#endif
#ifndef S_IXGRP
# define S_IXGRP 0
#endif
#ifndef S_IXOTH
# define S_IXOTH 0
#endif
#ifndef S_IRUSR
# define S_IRUSR 0400
#endif
#ifndef S_IWUSR
# define S_IWUSR 0200
#endif
#ifndef S_ISUID
# define S_ISUID 0
#endif
/* Hack for rediculous practice of Microsoft Visual C++.
*/
#if defined (WIN32)
# if defined (_MSC_VER)
# define stat _stat
# define getcwd _getcwd
# define currentdrive() (_getdrive() + 'A' - 1)
# define PATH_MAX _MAX_PATH
# elif defined (__BORLANDC__)
# define PATH_MAX MAXPATH
# define currentdrive() (getdisk() + 'A')
# elif defined (DJGPP)
# define currentdrive() (getdisk() + 'A')
# else
# define currentdrive() 'C'
# endif
#endif
#ifndef PATH_MAX
# define PATH_MAX 256
#endif
/*
* Miscellaneous macros
*/
#define selected(var,feature) (((int)(var) & (int)(feature)) == (int)feature)
/*
* DATA DEFINITIONS
*/
#if defined (MSDOS_STYLE_PATH)
const char *const PathDelimiters = ":/\\";
#elif defined (VMS)
const char *const PathDelimiters = ":]>";
#endif
char *CurrentDirectory;
static const char *ExecutableProgram;
static const char *ExecutableName;
/*
* FUNCTION PROTOTYPES
*/
#ifdef NEED_PROTO_STAT
extern int stat (const char *, struct stat *);
#endif
#ifdef NEED_PROTO_LSTAT
extern int lstat (const char *, struct stat *);
#endif
#if defined (MSDOS) || defined (WIN32) || defined (VMS) || defined (__EMX__) || defined (AMIGA)
# define lstat(fn,buf) stat(fn,buf)
#endif
/*
* FUNCTION DEFINITIONS
*/
extern void freeRoutineResources (void)
{
if (CurrentDirectory != NULL)
eFree (CurrentDirectory);
}
extern void setExecutableName (const char *const path)
{
ExecutableProgram = path;
ExecutableName = baseFilename (path);
#ifdef VAXC
{
/* remove filetype from executable name */
char *p = strrchr (ExecutableName, '.');
if (p != NULL)
*p = '\0';
}
#endif
}
extern const char *getExecutableName (void)
{
return ExecutableName;
}
extern void error (
const errorSelection selection, const char *const format, ...)
{
va_list ap;
va_start (ap, format);
fprintf (errout, "%s: %s", getExecutableName (),
selected (selection, WARNING) ? "Warning: " : "");
vfprintf (errout, format, ap);
if (selected (selection, PERROR))
#ifdef HAVE_STRERROR
fprintf (errout, " : %s", strerror (errno));
#else
perror (" ");
#endif
fputs ("\n", errout);
va_end (ap);
if (selected (selection, FATAL))
exit (1);
}
/*
* Memory allocation functions
*/
extern void *eMalloc (const size_t size)
{
void *buffer = malloc (size);
if (buffer == NULL)
error (FATAL, "out of memory");
return buffer;
}
extern void *eCalloc (const size_t count, const size_t size)
{
void *buffer = calloc (count, size);
if (buffer == NULL)
error (FATAL, "out of memory");
return buffer;
}
extern void *eRealloc (void *const ptr, const size_t size)
{
void *buffer;
if (ptr == NULL)
buffer = eMalloc (size);
else
{
buffer = realloc (ptr, size);
if (buffer == NULL)
error (FATAL, "out of memory");
}
return buffer;
}
extern void eFree (void *const ptr)
{
Assert (ptr != NULL);
free (ptr);
}
/*
* String manipulation functions
*/
/*
* Compare two strings, ignoring case.
* Return 0 for match, < 0 for smaller, > 0 for bigger
* Make sure case is folded to uppercase in comparison (like for 'sort -f')
* This makes a difference when one of the chars lies between upper and lower
* ie. one of the chars [ \ ] ^ _ ` for ascii. (The '_' in particular !)
*/
extern int struppercmp (const char *s1, const char *s2)
{
int result;
do
{
result = toupper ((int) *s1) - toupper ((int) *s2);
} while (result == 0 && *s1++ != '\0' && *s2++ != '\0');
return result;
}
extern int strnuppercmp (const char *s1, const char *s2, size_t n)
{
int result;
do
{
result = toupper ((int) *s1) - toupper ((int) *s2);
} while (result == 0 && --n > 0 && *s1++ != '\0' && *s2++ != '\0');
return result;
}
#ifndef HAVE_STRSTR
extern char* strstr (const char *str, const char *substr)
{
const size_t length = strlen (substr);
const char *match = NULL;
const char *p;
for (p = str ; *p != '\0' && match == NULL ; ++p)
if (strncmp (p, substr, length) == 0)
match = p;
return (char*) match;
}
#endif
extern char* eStrdup (const char* str)
{
char* result = xMalloc (strlen (str) + 1, char);
strcpy (result, str);
return result;
}
extern void toLowerString (char* str)
{
while (*str != '\0')
{
*str = tolower ((int) *str);
++str;
}
}
extern void toUpperString (char* str)
{
while (*str != '\0')
{
*str = toupper ((int) *str);
++str;
}
}
/* Newly allocated string containing lower case conversion of a string.
*/
extern char* newLowerString (const char* str)
{
char* const result = xMalloc (strlen (str) + 1, char);
int i = 0;
do
result [i] = tolower ((int) str [i]);
while (str [i++] != '\0');
return result;
}
/* Newly allocated string containing upper case conversion of a string.
*/
extern char* newUpperString (const char* str)
{
char* const result = xMalloc (strlen (str) + 1, char);
int i = 0;
do
result [i] = toupper ((int) str [i]);
while (str [i++] != '\0');
return result;
}
/*
* File system functions
*/
extern void setCurrentDirectory (void)
{
#ifndef AMIGA
char* buf;
#endif
if (CurrentDirectory == NULL)
CurrentDirectory = xMalloc ((size_t) (PATH_MAX + 1), char);
#ifdef AMIGA
strcpy (CurrentDirectory, ".");
#else
buf = getcwd (CurrentDirectory, PATH_MAX);
if (buf == NULL)
perror ("");
#endif
if (CurrentDirectory [strlen (CurrentDirectory) - (size_t) 1] !=
PATH_SEPARATOR)
{
sprintf (CurrentDirectory + strlen (CurrentDirectory), "%c",
OUTPUT_PATH_SEPARATOR);
}
}
#ifdef AMIGA
static boolean isAmigaDirectory (const char *const name)
{
boolean result = FALSE;
struct FileInfoBlock *const fib = xMalloc (1, struct FileInfoBlock);
if (fib != NULL)
{
const BPTR flock = Lock ((UBYTE *) name, (long) ACCESS_READ);
if (flock != (BPTR) NULL)
{
if (Examine (flock, fib))
result = ((fib->fib_DirEntryType >= 0) ? TRUE : FALSE);
UnLock (flock);
}
eFree (fib);
}
return result;
}
#endif
/* For caching of stat() calls */
extern fileStatus *eStat (const char *const fileName)
{
struct stat status;
static fileStatus file;
if (file.name == NULL || strcmp (fileName, file.name) != 0)
{
if (file.name != NULL)
eFree (file.name);
file.name = eStrdup (fileName);
if (lstat (file.name, &status) != 0)
file.exists = FALSE;
else
{
file.isSymbolicLink = (boolean) S_ISLNK (status.st_mode);
if (file.isSymbolicLink && stat (file.name, &status) != 0)
file.exists = FALSE;
else
{
file.exists = TRUE;
#ifdef AMIGA
file.isDirectory = isAmigaDirectory (file.name);
#else
file.isDirectory = (boolean) S_ISDIR (status.st_mode);
#endif
file.isNormalFile = (boolean) (S_ISREG (status.st_mode));
file.isExecutable = (boolean) ((status.st_mode &
(S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
file.isSetuid = (boolean) ((status.st_mode & S_ISUID) != 0);
file.size = status.st_size;
}
}
}
return &file;
}
extern boolean doesFileExist (const char *const fileName)
{
fileStatus *status = eStat (fileName);
return status->exists;
}
extern boolean isRecursiveLink (const char* const dirName)
{
boolean result = FALSE;
fileStatus *status = eStat (dirName);
if (status->isSymbolicLink)
{
char* const path = absoluteFilename (dirName);
while (path [strlen (path) - 1] == PATH_SEPARATOR)
path [strlen (path) - 1] = '\0';
while (! result && strlen (path) > (size_t) 1)
{
char *const separator = strrchr (path, PATH_SEPARATOR);
if (separator == NULL)
break;
else if (separator == path) /* backed up to root directory */
*(separator + 1) = '\0';
else
*separator = '\0';
result = isSameFile (path, dirName);
}
eFree (path);
}
return result;
}
#ifndef HAVE_FGETPOS
extern int fgetpos (FILE *stream, fpos_t *pos)
{
int result = 0;
*pos = ftell (stream);
if (*pos == -1L)
result = -1;
return result;
}
extern int fsetpos (FILE *stream, fpos_t const *pos)
{
return fseek (stream, *pos, SEEK_SET);
}
#endif
/*
* Pathname manipulation (O/S dependent!!!)
*/
static boolean isPathSeparator (const int c)
{
boolean result;
#if defined (MSDOS_STYLE_PATH) || defined (VMS)
result = (boolean) (strchr (PathDelimiters, c) != NULL);
#else
result = (boolean) (c == PATH_SEPARATOR);
#endif
return result;
}
#if ! defined (HAVE_STAT_ST_INO)
static void canonicalizePath (char *const path __unused__)
{
#if defined (MSDOS_STYLE_PATH)
char *p;
for (p = path ; *p != '\0' ; ++p)
if (isPathSeparator (*p) && *p != ':')
*p = PATH_SEPARATOR;
#endif
}
#endif
extern boolean isSameFile (const char *const name1, const char *const name2)
{
boolean result = FALSE;
#if defined (HAVE_STAT_ST_INO)
struct stat stat1, stat2;
if (stat (name1, &stat1) == 0 && stat (name2, &stat2) == 0)
result = (boolean) (stat1.st_ino == stat2.st_ino);
#else
{
char *const n1 = absoluteFilename (name1);
char *const n2 = absoluteFilename (name2);
canonicalizePath (n1);
canonicalizePath (n2);
# if defined (CASE_INSENSITIVE_FILENAMES)
result = (boolean) (strcasecmp (n1, n2) == 0);
#else
result = (boolean) (strcmp (n1, n2) == 0);
#endif
free (n1);
free (n2);
}
#endif
return result;
}
extern const char *baseFilename (const char *const filePath)
{
#if defined (MSDOS_STYLE_PATH) || defined (VMS)
const char *tail = NULL;
unsigned int i;
/* Find whichever of the path delimiters is last.
*/
for (i = 0 ; i < strlen (PathDelimiters) ; ++i)
{
const char *sep = strrchr (filePath, PathDelimiters [i]);
if (sep > tail)
tail = sep;
}
#else
const char *tail = strrchr (filePath, PATH_SEPARATOR);
#endif
if (tail == NULL)
tail = filePath;
else
++tail; /* step past last delimiter */
#ifdef VAXC
{
/* remove version number from filename */
char *p = strrchr ((char *) tail, ';');
if (p != NULL)
*p = '\0';
}
#endif
return tail;
}
extern const char *fileExtension (const char *const fileName)
{
const char *extension;
const char *pDelimiter = NULL;
const char *const base = baseFilename (fileName);
#ifdef QDOS
pDelimiter = strrchr (base, '_');
#endif
if (pDelimiter == NULL)
pDelimiter = strrchr (base, '.');
if (pDelimiter == NULL)
extension = "";
else
extension = pDelimiter + 1; /* skip to first char of extension */
return extension;
}
extern boolean isAbsolutePath (const char *const path)
{
boolean result = FALSE;
#if defined (MSDOS_STYLE_PATH)
if (isPathSeparator (path [0]))
result = TRUE;
else if (isalpha (path [0]) && path [1] == ':')
{
if (isPathSeparator (path [2]))
result = TRUE;
else
/* We don't support non-absolute file names with a drive
* letter, like `d:NAME' (it's too much hassle).
*/
error (FATAL,
"%s: relative file names with drive letters not supported",
path);
}
#elif defined (VMS)
result = (boolean) (strchr (path, ':') != NULL);
#else
result = isPathSeparator (path [0]);
#endif
return result;
}
extern vString *combinePathAndFile (
const char *const path, const char *const file)
{
vString *const filePath = vStringNew ();
#ifdef VMS
const char *const directoryId = strstr (file, ".DIR;1");
if (directoryId == NULL)
{
const char *const versionId = strchr (file, ';');
vStringCopyS (filePath, path);
if (versionId == NULL)
vStringCatS (filePath, file);
else
vStringNCatS (filePath, file, versionId - file);
vStringCopyToLower (filePath, filePath);
}
else
{
/* File really is a directory; append it to the path.
* Gotcha: doesn't work with logical names.
*/
vStringNCopyS (filePath, path, strlen (path) - 1);
vStringPut (filePath, '.');
vStringNCatS (filePath, file, directoryId - file);
if (strchr (path, '[') != NULL)
vStringPut (filePath, ']');
else
vStringPut (filePath, '>');
vStringTerminate (filePath);
}
#else
const int lastChar = path [strlen (path) - 1];
boolean terminated = isPathSeparator (lastChar);
vStringCopyS (filePath, path);
if (! terminated)
{
vStringPut (filePath, OUTPUT_PATH_SEPARATOR);
vStringTerminate (filePath);
}
vStringCatS (filePath, file);
#endif
return filePath;
}
/* Return a newly-allocated string whose contents concatenate those of
* s1, s2, s3.
* Routine adapted from Gnu etags.
*/
static char* concat (const char *s1, const char *s2, const char *s3)
{
int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
char *result = xMalloc (len1 + len2 + len3 + 1, char);
strcpy (result, s1);
strcpy (result + len1, s2);
strcpy (result + len1 + len2, s3);
result [len1 + len2 + len3] = '\0';
return result;
}
/* Return a newly allocated string containing the absolute file name of FILE
* given CWD (which should end with a slash).
* Routine adapted from Gnu etags.
*/
extern char* absoluteFilename (const char *file)
{
char *slashp, *cp;
char *res = NULL;
if (isAbsolutePath (file))
{
#ifdef MSDOS_STYLE_PATH
if (file [1] == ':')
res = eStrdup (file);
else
{
char drive [3];
sprintf (drive, "%c:", currentdrive ());
res = concat (drive, file, "");
}
#else
res = eStrdup (file);
#endif
}
else
res = concat (CurrentDirectory, file, "");
/* Delete the "/dirname/.." and "/." substrings. */
slashp = strchr (res, PATH_SEPARATOR);
while (slashp != NULL && slashp [0] != '\0')
{
if (slashp[1] == '.')
{
if (slashp [2] == '.' &&
(slashp [3] == PATH_SEPARATOR || slashp [3] == '\0'))
{
cp = slashp;
do
cp--;
while (cp >= res && ! isAbsolutePath (cp));
if (cp < res)
cp = slashp;/* the absolute name begins with "/.." */
#ifdef MSDOS_STYLE_PATH
/* Under MSDOS and NT we get `d:/NAME' as absolute file name,
* so the luser could say `d:/../NAME'. We silently treat this
* as `d:/NAME'.
*/
else if (cp [0] != PATH_SEPARATOR)
cp = slashp;
#endif
strcpy (cp, slashp + 3);
slashp = cp;
continue;
}
else if (slashp [2] == PATH_SEPARATOR || slashp [2] == '\0')
{
strcpy (slashp, slashp + 2);
continue;
}
}
slashp = strchr (slashp + 1, PATH_SEPARATOR);
}
if (res [0] == '\0')
return eStrdup ("/");
else
{
#ifdef MSDOS_STYLE_PATH
/* Canonicalize drive letter case. */
if (res [1] == ':' && islower (res [0]))
res [0] = toupper (res [0]);
#endif
return res;
}
}
/* Return a newly allocated string containing the absolute file name of dir
* where `file' resides given `CurrentDirectory'.
* Routine adapted from Gnu etags.
*/
extern char* absoluteDirname (char *file)
{
char *slashp, *res;
char save;
slashp = strrchr (file, PATH_SEPARATOR);
if (slashp == NULL)
res = eStrdup (CurrentDirectory);
else
{
save = slashp [1];
slashp [1] = '\0';
res = absoluteFilename (file);
slashp [1] = save;
}
return res;
}
/* Return a newly allocated string containing the file name of FILE relative
* to the absolute directory DIR (which should end with a slash).
* Routine adapted from Gnu etags.
*/
extern char* relativeFilename (const char *file, const char *dir)
{
const char *fp, *dp;
char *absdir, *res;
int i;
/* Find the common root of file and dir (with a trailing slash). */
absdir = absoluteFilename (file);
fp = absdir;
dp = dir;
while (*fp++ == *dp++)
continue;
fp--;
dp--; /* back to the first differing char */
do
{ /* look at the equal chars until path sep */
if (fp == absdir)
return absdir; /* first char differs, give up */
fp--;
dp--;
} while (*fp != PATH_SEPARATOR);
/* Build a sequence of "../" strings for the resulting relative file name.
*/
i = 0;
while ((dp = strchr (dp + 1, PATH_SEPARATOR)) != NULL)
i += 1;
res = xMalloc (3 * i + strlen (fp + 1) + 1, char);
res [0] = '\0';
while (i-- > 0)
strcat (res, "../");
/* Add the file name relative to the common root of file and dir. */
strcat (res, fp + 1);
free (absdir);
return res;
}
extern FILE *tempFile (const char *const mode, char **const pName)
{
char *name;
FILE *fp;
int fd;
#if defined(HAVE_MKSTEMP)
const char *const pattern = "tags.XXXXXX";
const char *tmpdir = NULL;
fileStatus *file = eStat (ExecutableProgram);
if (! file->isSetuid)
tmpdir = getenv ("TMPDIR");
if (tmpdir == NULL)
tmpdir = TMPDIR;
name = xMalloc (strlen (tmpdir) + 1 + strlen (pattern) + 1, char);
sprintf (name, "%s%c%s", tmpdir, OUTPUT_PATH_SEPARATOR, pattern);
fd = mkstemp (name);
#elif defined(HAVE_TEMPNAM)
name = tempnam (TMPDIR, "tags");
if (name == NULL)
error (FATAL | PERROR, "cannot allocate temporary file name");
fd = open (name, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
#else
name = xMalloc (L_tmpnam, char);
if (tmpnam (name) != name)
error (FATAL | PERROR, "cannot assign temporary file name");
fd = open (name, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
#endif
if (fd == -1)
error (FATAL | PERROR, "cannot open temporary file");
fp = fdopen (fd, mode);
if (fp == NULL)
error (FATAL | PERROR, "cannot open temporary file");
DebugStatement (
debugPrintf (DEBUG_STATUS, "opened temporary file %s\n", name); )
Assert (*pName == NULL);
*pName = name;
return fp;
}
/* vi:set tabstop=4 shiftwidth=4: */
+132
View File
@@ -0,0 +1,132 @@
/*
* $Id: routines.h,v 1.11 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* External interface to routines.c
*/
#ifndef _ROUTINES_H
#define _ROUTINES_H
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
/*
* MACROS
*/
#define xMalloc(n,Type) (Type *)eMalloc((size_t)(n) * sizeof (Type))
#define xCalloc(n,Type) (Type *)eCalloc((size_t)(n), sizeof (Type))
#define xRealloc(p,n,Type) (Type *)eRealloc((p), (n) * sizeof (Type))
/*
* Portability macros
*/
#ifndef PATH_SEPARATOR
# if defined (MSDOS_STYLE_PATH)
# define PATH_SEPARATOR '\\'
# elif defined (QDOS)
# define PATH_SEPARATOR '_'
# else
# define PATH_SEPARATOR '/'
# endif
#endif
#if defined (MSDOS_STYLE_PATH) && defined (UNIX_PATH_SEPARATOR)
# define OUTPUT_PATH_SEPARATOR '/'
#else
# define OUTPUT_PATH_SEPARATOR PATH_SEPARATOR
#endif
/*
* DATA DECLARATIONS
*/
#if defined (MSDOS_STYLE_PATH) || defined (VMS)
extern const char *const PathDelimiters;
#endif
extern char *CurrentDirectory;
typedef int errorSelection;
enum eErrorTypes { FATAL = 1, WARNING = 2, PERROR = 4 };
typedef struct {
/* Name of file for which status is valid */
char* name;
/* Does file exist? If not, members below do not contain valid data. */
boolean exists;
/* is file path a symbolic link to another file? */
boolean isSymbolicLink;
/* Is file (pointed to) a directory? */
boolean isDirectory;
/* Is file (pointed to) a normal file? */
boolean isNormalFile;
/* Is file (pointed to) executable? */
boolean isExecutable;
/* Is file (pointed to) setuid? */
boolean isSetuid;
/* Size of file (pointed to) */
unsigned long size;
} fileStatus;
/*
* FUNCTION PROTOTYPES
*/
extern void freeRoutineResources (void);
extern void setExecutableName (const char *const path);
extern const char *getExecutableName (void);
extern void error (const errorSelection selection, const char *const format, ...) __printf__ (2, 3);
/* Memory allocation functions */
#ifdef NEED_PROTO_MALLOC
extern void *malloc (size_t);
extern void *realloc (void *ptr, size_t);
#endif
extern void *eMalloc (const size_t size);
extern void *eCalloc (const size_t count, const size_t size);
extern void *eRealloc (void *const ptr, const size_t size);
extern void eFree (void *const ptr);
/* String manipulation functions */
extern int struppercmp (const char *s1, const char *s2);
extern int strnuppercmp (const char *s1, const char *s2, size_t n);
#ifndef HAVE_STRSTR
extern char* strstr (const char *str, const char *substr);
#endif
extern char* eStrdup (const char* str);
extern void toLowerString (char* str);
extern void toUpperString (char* str);
extern char* newLowerString (const char* str);
extern char* newUpperString (const char* str);
/* File system functions */
extern void setCurrentDirectory (void);
extern fileStatus *eStat (const char *const fileName);
extern boolean doesFileExist (const char *const fileName);
extern boolean isRecursiveLink (const char* const dirName);
extern boolean isSameFile (const char *const name1, const char *const name2);
#if defined(NEED_PROTO_FGETPOS)
extern int fgetpos (FILE *stream, fpos_t *pos);
extern int fsetpos (FILE *stream, fpos_t *pos);
#endif
extern const char *baseFilename (const char *const filePath);
extern const char *fileExtension (const char *const fileName);
extern boolean isAbsolutePath (const char *const path);
extern vString *combinePathAndFile (const char *const path, const char *const file);
extern char* absoluteFilename (const char *file);
extern char* absoluteDirname (char *file);
extern char* relativeFilename (const char *file, const char *dir);
extern FILE *tempFile (const char *const mode, char **const pName);
#endif /* _ROUTINES_H */
/* vi:set tabstop=4 shiftwidth=4: */
+398
View File
@@ -0,0 +1,398 @@
/*
* $Id: ruby.c,v 1.6 2006/05/30 04:37:12 darren Exp $
*
* Copyright (c) 2000-2001, Thaddeus Covert <sahuagin@mediaone.net>
* Copyright (c) 2002 Matthias Veit <matthias_veit@yahoo.de>
* Copyright (c) 2004 Elliott Hughes <enh@acm.org>
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for generating tags for Ruby language
* files.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#include "entry.h"
#include "parse.h"
#include "read.h"
#include "vstring.h"
/*
* DATA DECLARATIONS
*/
typedef enum {
K_UNDEFINED = -1, K_CLASS, K_METHOD, K_MODULE, K_SINGLETON
} rubyKind;
/*
* DATA DEFINITIONS
*/
static kindOption RubyKinds [] = {
{ TRUE, 'c', "class", "classes" },
{ TRUE, 'f', "method", "methods" },
{ TRUE, 'm', "module", "modules" },
{ TRUE, 'F', "singleton method", "singleton methods" }
};
static stringList* nesting = 0;
/*
* FUNCTION DEFINITIONS
*/
/*
* Returns a string describing the scope in 'list'.
* We record the current scope as a list of entered scopes.
* Scopes corresponding to 'if' statements and the like are
* represented by empty strings. Scopes corresponding to
* modules and classes are represented by the name of the
* module or class.
*/
static vString* stringListToScope (const stringList* list)
{
unsigned int i;
unsigned int chunks_output = 0;
vString* result = vStringNew ();
const unsigned int max = stringListCount (list);
for (i = 0; i < max; ++i)
{
vString* chunk = stringListItem (list, i);
if (vStringLength (chunk) > 0)
{
vStringCatS (result, (chunks_output++ > 0) ? "." : "");
vStringCatS (result, vStringValue (chunk));
}
}
return result;
}
/*
* Attempts to advance 's' past 'literal'.
* Returns TRUE if it did, FALSE (and leaves 's' where
* it was) otherwise.
*/
static boolean canMatch (const unsigned char** s, const char* literal)
{
const int literal_length = strlen (literal);
const unsigned char next_char = *(*s + literal_length);
if (strncmp ((const char*) *s, literal, literal_length) != 0)
{
return FALSE;
}
/* Additionally check that we're at the end of a token. */
if ( ! (next_char == 0 || isspace (next_char) || next_char == '('))
{
return FALSE;
}
*s += literal_length;
return TRUE;
}
/*
* Attempts to advance 'cp' past a Ruby operator method name. Returns
* TRUE if successful (and copies the name into 'name'), FALSE otherwise.
*/
static boolean parseRubyOperator (vString* name, const unsigned char** cp)
{
static const char* RUBY_OPERATORS[] = {
"[]", "[]=",
"**",
"!", "~", "+@", "-@",
"*", "/", "%",
"+", "-",
">>", "<<",
"&",
"^", "|",
"<=", "<", ">", ">=",
"<=>", "==", "===", "!=", "=~", "!~",
0
};
int i;
for (i = 0; RUBY_OPERATORS[i] != 0; ++i)
{
if (canMatch (cp, RUBY_OPERATORS[i]))
{
vStringCatS (name, RUBY_OPERATORS[i]);
return TRUE;
}
}
return FALSE;
}
/*
* Emits a tag for the given 'name' of kind 'kind' at the current nesting.
*/
static void emitRubyTag (vString* name, rubyKind kind)
{
tagEntryInfo tag;
vString* scope;
vStringTerminate (name);
scope = stringListToScope (nesting);
initTagEntry (&tag, vStringValue (name));
if (vStringLength (scope) > 0) {
tag.extensionFields.scope [0] = "class";
tag.extensionFields.scope [1] = vStringValue (scope);
}
tag.kindName = RubyKinds [kind].name;
tag.kind = RubyKinds [kind].letter;
makeTagEntry (&tag);
stringListAdd (nesting, vStringNewCopy (name));
vStringClear (name);
vStringDelete (scope);
}
/* Tests whether 'ch' is a character in 'list'. */
static boolean charIsIn (char ch, const char* list)
{
return (strchr (list, ch) != 0);
}
/* Advances 'cp' over leading whitespace. */
static void skipWhitespace (const unsigned char** cp)
{
while (isspace (**cp))
{
++*cp;
}
}
/*
* Copies the characters forming an identifier from *cp into
* name, leaving *cp pointing to the character after the identifier.
*/
static rubyKind parseIdentifier (
const unsigned char** cp, vString* name, rubyKind kind)
{
/* Method names are slightly different to class and variable names.
* A method name may optionally end with a question mark, exclamation
* point or equals sign. These are all part of the name.
* A method name may also contain a period if it's a singleton method.
*/
const char* also_ok = (kind == K_METHOD) ? "_.?!=" : "_";
skipWhitespace (cp);
/* Check for an anonymous (singleton) class such as "class << HTTP". */
if (kind == K_CLASS && **cp == '<' && *(*cp + 1) == '<')
{
return K_UNDEFINED;
}
/* Check for operators such as "def []=(key, val)". */
if (kind == K_METHOD || kind == K_SINGLETON)
{
if (parseRubyOperator (name, cp))
{
return kind;
}
}
/* Copy the identifier into 'name'. */
while (**cp != 0 && (isalnum (**cp) || charIsIn (**cp, also_ok)))
{
char last_char = **cp;
vStringPut (name, last_char);
++*cp;
if (kind == K_METHOD)
{
/* Recognize singleton methods. */
if (last_char == '.')
{
vStringTerminate (name);
vStringClear (name);
return parseIdentifier (cp, name, K_SINGLETON);
}
/* Recognize characters which mark the end of a method name. */
if (charIsIn (last_char, "?!="))
{
break;
}
}
}
return kind;
}
static void readAndEmitTag (const unsigned char** cp, rubyKind expected_kind)
{
if (isspace (**cp))
{
vString *name = vStringNew ();
rubyKind actual_kind = parseIdentifier (cp, name, expected_kind);
if (actual_kind == K_UNDEFINED || vStringLength (name) == 0)
{
/*
* What kind of tags should we create for code like this?
*
* %w(self.clfloor clfloor).each do |name|
* module_eval <<-"end;"
* def #{name}(x, y=1)
* q, r = x.divmod(y)
* q = q.to_i
* return q, r
* end
* end;
* end
*
* Or this?
*
* class << HTTP
*
* For now, we don't create any.
*/
}
else
{
emitRubyTag (name, actual_kind);
}
vStringDelete (name);
}
}
static void enterUnnamedScope (void)
{
stringListAdd (nesting, vStringNewInit (""));
}
static void findRubyTags (void)
{
const unsigned char *line;
boolean inMultiLineComment = FALSE;
nesting = stringListNew ();
/* FIXME: this whole scheme is wrong, because Ruby isn't line-based.
* You could perfectly well write:
*
* def
* method
* puts("hello")
* end
*
* if you wished, and this function would fail to recognize anything.
*/
while ((line = fileReadLine ()) != NULL)
{
const unsigned char *cp = line;
if (canMatch (&cp, "=begin"))
{
inMultiLineComment = TRUE;
continue;
}
if (canMatch (&cp, "=end"))
{
inMultiLineComment = FALSE;
continue;
}
skipWhitespace (&cp);
/* Avoid mistakenly starting a scope for modifiers such as
*
* return if <exp>
*
* FIXME: this is fooled by code such as
*
* result = if <exp>
* <a>
* else
* <b>
* end
*
* FIXME: we're also fooled if someone does something heinous such as
*
* puts("hello") \
* unless <exp>
*/
if (canMatch (&cp, "case") || canMatch (&cp, "for") ||
canMatch (&cp, "if") || canMatch (&cp, "unless") ||
canMatch (&cp, "while"))
{
enterUnnamedScope ();
}
/*
* "module M", "class C" and "def m" should only be at the beginning
* of a line.
*/
if (canMatch (&cp, "module"))
{
readAndEmitTag (&cp, K_MODULE);
}
else if (canMatch (&cp, "class"))
{
readAndEmitTag (&cp, K_CLASS);
}
else if (canMatch (&cp, "def"))
{
readAndEmitTag (&cp, K_METHOD);
}
while (*cp != '\0')
{
/* FIXME: we don't cope with here documents, or string literals,
* or regular expression literals, or ... you get the idea.
* Hopefully, the restriction above that insists on seeing
* definitions at the starts of lines should keep us out of
* mischief.
*/
if (inMultiLineComment || isspace (*cp))
{
++cp;
}
else if (*cp == '#')
{
/* FIXME: this is wrong, but there *probably* won't be a
* definition after an interpolated string (where # doesn't
* mean 'comment').
*/
break;
}
else if (canMatch (&cp, "begin") || canMatch (&cp, "do"))
{
enterUnnamedScope ();
}
else if (canMatch (&cp, "end") && stringListCount (nesting) > 0)
{
/* Leave the most recent scope. */
vStringDelete (stringListLast (nesting));
stringListRemoveLast (nesting);
}
else if (*cp != '\0')
{
do
++cp;
while (isalnum (*cp) || *cp == '_');
}
}
}
stringListDelete (nesting);
}
extern parserDefinition* RubyParser (void)
{
static const char *const extensions [] = { "rb", "ruby", NULL };
parserDefinition* def = parserNew ("Ruby");
def->kinds = RubyKinds;
def->kindCount = KIND_COUNT (RubyKinds);
def->extensions = extensions;
def->parser = findRubyTags;
return def;
}
/* vi:set tabstop=4 shiftwidth=4: */
+111
View File
@@ -0,0 +1,111 @@
/*
* $Id: scheme.c,v 1.3 2006/05/30 04:37:13 darren Exp $
*
* Copyright (c) 2000-2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for generating tags for Scheme language
* files.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#include "parse.h"
#include "read.h"
#include "vstring.h"
/*
* DATA DEFINITIONS
*/
typedef enum {
K_FUNCTION, K_SET
} schemeKind;
static kindOption SchemeKinds [] = {
{ TRUE, 'f', "function", "functions" },
{ TRUE, 's', "set", "sets" }
};
/*
* FUNCTION DEFINITIONS
*/
/* Algorithm adapted from from GNU etags.
* Scheme tag functions
* look for (def... xyzzy
* look for (def... (xyzzy
* look for (def ... ((... (xyzzy ....
* look for (set! xyzzy
*/
static void readIdentifier (vString *const name, const unsigned char *cp)
{
const unsigned char *p;
vStringClear (name);
/* Go till you get to white space or a syntactic break */
for (p = cp; *p != '\0' && *p != '(' && *p != ')' && !isspace (*p); p++)
vStringPut (name, (int) *p);
vStringTerminate (name);
}
static void findSchemeTags (void)
{
vString *name = vStringNew ();
const unsigned char *line;
while ((line = fileReadLine ()) != NULL)
{
const unsigned char *cp = line;
if (cp [0] == '(' &&
(cp [1] == 'D' || cp [1] == 'd') &&
(cp [2] == 'E' || cp [2] == 'e') &&
(cp [3] == 'F' || cp [3] == 'f'))
{
while (!isspace (*cp))
cp++;
/* Skip over open parens and white space */
while (*cp != '\0' && (isspace (*cp) || *cp == '('))
cp++;
readIdentifier (name, cp);
makeSimpleTag (name, SchemeKinds, K_FUNCTION);
}
if (cp [0] == '(' &&
(cp [1] == 'S' || cp [1] == 's') &&
(cp [2] == 'E' || cp [2] == 'e') &&
(cp [3] == 'T' || cp [3] == 't') &&
(cp [4] == '!' || cp [4] == '!') &&
(isspace (cp [5])))
{
while (*cp != '\0' && !isspace (*cp))
cp++;
/* Skip over white space */
while (isspace (*cp))
cp++;
readIdentifier (name, cp);
makeSimpleTag (name, SchemeKinds, K_SET);
}
}
vStringDelete (name);
}
extern parserDefinition* SchemeParser (void)
{
static const char *const extensions [] = {
"SCM", "SM", "sch", "scheme", "scm", "sm", NULL
};
parserDefinition* def = parserNew ("Scheme");
def->kinds = SchemeKinds;
def->kindCount = KIND_COUNT (SchemeKinds);
def->extensions = extensions;
def->parser = findSchemeTags;
return def;
}
/* vi:set tabstop=4 shiftwidth=4: */
+115
View File
@@ -0,0 +1,115 @@
/*
* $Id: sh.c,v 1.6 2006/05/30 04:37:13 darren Exp $
*
* Copyright (c) 2000-2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for generating tags for scripts for the
* Bourne shell (and its derivatives, the Korn and Z shells).
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#include "parse.h"
#include "read.h"
#include "routines.h"
#include "vstring.h"
/*
* DATA DEFINITIONS
*/
typedef enum {
K_FUNCTION
} shKind;
static kindOption ShKinds [] = {
{ TRUE, 'f', "function", "functions"}
};
/*
* FUNCTION DEFINITIONS
*/
/* Reject any tag "main" from a file named "configure". These appear in
* here-documents in GNU autoconf scripts and will add a haystack to the
* needle.
*/
static boolean hackReject (const vString* const tagName)
{
const char *const scriptName = baseFilename (vStringValue (File.name));
boolean result = (boolean) (
strcmp (scriptName, "configure") == 0 &&
strcmp (vStringValue (tagName), "main") == 0);
return result;
}
static void findShTags (void)
{
vString *name = vStringNew ();
const unsigned char *line;
while ((line = fileReadLine ()) != NULL)
{
const unsigned char* cp = line;
boolean functionFound = FALSE;
if (line [0] == '#')
continue;
while (isspace (*cp))
cp++;
if (strncmp ((const char*) cp, "function", (size_t) 8) == 0 &&
isspace ((int) cp [8]))
{
functionFound = TRUE;
cp += 8;
if (! isspace ((int) *cp))
continue;
while (isspace ((int) *cp))
++cp;
}
if (! (isalnum ((int) *cp) || *cp == '_'))
continue;
while (isalnum ((int) *cp) || *cp == '_')
{
vStringPut (name, (int) *cp);
++cp;
}
vStringTerminate (name);
while (isspace ((int) *cp))
++cp;
if (*cp++ == '(')
{
while (isspace ((int) *cp))
++cp;
if (*cp == ')' && ! hackReject (name))
functionFound = TRUE;
}
if (functionFound)
makeSimpleTag (name, ShKinds, K_FUNCTION);
vStringClear (name);
}
vStringDelete (name);
}
extern parserDefinition* ShParser (void)
{
static const char *const extensions [] = {
"sh", "SH", "bsh", "bash", "ksh", "zsh", NULL
};
parserDefinition* def = parserNew ("Sh");
def->kinds = ShKinds;
def->kindCount = KIND_COUNT (ShKinds);
def->extensions = extensions;
def->parser = findShTags;
return def;
}
/* vi:set tabstop=4 shiftwidth=4: */
+41
View File
@@ -0,0 +1,41 @@
/*
* $Id: slang.c,v 1.5 2006/05/30 04:37:13 darren Exp $
*
* Copyright (c) 2000-2001, Francesc Rocher
*
* Author: Francesc Rocher <f.rocher@computer.org>.
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for generating tags for S-Lang files.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include "parse.h"
/*
* FUNCTION DEFINITIONS
*/
static void installSlangRegex (const langType language)
{
addTagRegex (language,
"^.*define[ \t]+([A-Z_][A-Z0-9_]*)[^;]*$",
"\\1", "f,function,functions", "i");
addTagRegex (language,
"^[ \t]*implements[ \t]+\\([ \t]*\"([^\"]*)\"[ \t]*\\)[ \t]*;",
"\\1", "n,namespace,namespaces", NULL);
}
extern parserDefinition* SlangParser (void)
{
static const char *const extensions [] = { "sl", NULL };
parserDefinition* const def = parserNew ("SLang");
def->extensions = extensions;
def->initialize = installSlangRegex;
def->regex = TRUE;
return def;
}
+211
View File
@@ -0,0 +1,211 @@
/*
* $Id: sml.c,v 1.7 2006/05/30 04:37:13 darren Exp $
*
* Copyright (c) 2002, Venkatesh Prasad Ranganath and Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for generating tags for SML language files.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#include "entry.h"
#include "parse.h"
#include "read.h"
#include "vstring.h"
/*
* DATA DECLARATIONS
*/
typedef enum {
K_AND = -2,
K_NONE = -1,
K_EXCEPTION,
K_FUNCTION,
K_FUNCTOR,
K_SIGNATURE,
K_STRUCTURE,
K_TYPE,
K_VAL
} smlKind;
/*
* DATA DEFINITIONS
*/
static kindOption SmlKinds[] = {
{ TRUE, 'e', "exception", "exception declarations" },
{ TRUE, 'f', "function", "function definitions" },
{ TRUE, 'c', "functor", "functor definitions" },
{ TRUE, 's', "signature", "signature declarations" },
{ TRUE, 'r', "structure", "structure declarations" },
{ TRUE, 't', "type", "type definitions" },
{ TRUE, 'v', "value", "value bindings" }
};
static struct {
const char *keyword;
smlKind kind;
} SmlKeywordTypes [] = {
{ "abstype", K_TYPE },
{ "and", K_AND },
{ "datatype", K_TYPE },
{ "exception", K_EXCEPTION },
{ "functor", K_FUNCTOR },
{ "fun", K_FUNCTION },
{ "signature", K_SIGNATURE },
{ "structure", K_STRUCTURE },
{ "type", K_TYPE },
{ "val", K_VAL }
};
static unsigned int CommentLevel = 0;
/*
* FUNCTION DEFINITIONS
*/
static void makeSmlTag (smlKind type, vString *name)
{
tagEntryInfo tag;
initTagEntry (&tag, vStringValue (name));
tag.kindName = SmlKinds [type].name;
tag.kind = SmlKinds [type].letter;
makeTagEntry (&tag);
}
static const unsigned char *skipSpace (const unsigned char *cp)
{
while (isspace ((int) *cp))
++cp;
return cp;
}
static boolean isIdentifier (int c)
{
boolean result = FALSE;
/* Consider '_' as an delimiter to aid user in tracking it's usage. */
const char *const alternateIdentifiers = "!%&$#+-<>=/?@\\~'^|*_";
if (isalnum (c))
result = TRUE;
else if (c != '\0' && strchr (alternateIdentifiers, c) != NULL)
result = TRUE;
return result;
}
static const unsigned char *parseIdentifier (
const unsigned char *cp, vString *const identifier)
{
boolean stringLit = FALSE;
vStringClear (identifier);
while (*cp != '\0' && (!isIdentifier ((int) *cp) || stringLit))
{
int oneback = *cp;
cp++;
if (oneback == '(' && *cp == '*' && stringLit == FALSE)
{
CommentLevel++;
return ++cp;
}
if (*cp == '"' && oneback != '\\')
{
stringLit = TRUE;
continue;
}
if (stringLit && *cp == '"' && oneback != '\\')
stringLit = FALSE;
}
if (strcmp ((const char *) cp, "") == 0 || cp == NULL)
return cp;
while (isIdentifier ((int) *cp))
{
vStringPut (identifier, (int) *cp);
cp++;
}
vStringTerminate (identifier);
return cp;
}
static smlKind findNextIdentifier (const unsigned char **cp)
{
smlKind result = K_NONE;
vString *const identifier = vStringNew ();
unsigned int count = sizeof (SmlKeywordTypes) / sizeof (SmlKeywordTypes [0]);
unsigned int i;
*cp = parseIdentifier (*cp, identifier);
for (i = 0 ; i < count && result == K_NONE ; ++i)
{
const char *id = vStringValue (identifier);
if (strcmp (id, SmlKeywordTypes [i].keyword) == 0)
result = SmlKeywordTypes [i].kind;
}
return result;
}
static void findSmlTags (void)
{
vString *const identifier = vStringNew ();
const unsigned char *line;
smlKind lastTag = K_NONE;
while ((line = fileReadLine ()) != NULL)
{
const unsigned char *cp = skipSpace (line);
do
{
smlKind foundTag;
if (CommentLevel != 0)
{
cp = (const unsigned char *) strstr ((const char *) cp, "*)");
if (cp == NULL)
continue;
else
{
--CommentLevel;
cp += 2;
}
}
foundTag = findNextIdentifier (&cp);
if (foundTag != K_NONE)
{
cp = skipSpace (cp);
cp = parseIdentifier (cp, identifier);
if (foundTag == K_AND)
makeSmlTag (lastTag, identifier);
else
{
makeSmlTag (foundTag, identifier);
lastTag = foundTag;
}
}
if (strstr ((const char *) cp, "(*") != NULL)
{
cp += 2;
cp = (const unsigned char *) strstr ((const char *) cp, "*)");
if (cp == NULL)
++CommentLevel;
}
} while (cp != NULL && strcmp ((const char *) cp, "") != 0);
}
vStringDelete (identifier);
}
extern parserDefinition *SmlParser (void)
{
static const char *const extensions[] = { "sml", "sig", NULL };
parserDefinition *def = parserNew ("SML");
def->kinds = SmlKinds;
def->kindCount = KIND_COUNT (SmlKinds);
def->extensions = extensions;
def->parser = findSmlTags;
return def;
}
/* vi:set tabstop=4 shiftwidth=4: */
+234
View File
@@ -0,0 +1,234 @@
/*
* $Id: sort.c,v 1.5 2006/05/30 04:37:13 darren Exp $
*
* Copyright (c) 1996-2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions to sort the tag entries.
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#if defined (HAVE_STDLIB_H)
# include <stdlib.h> /* to declare malloc () */
#endif
#include <string.h>
#include <stdio.h>
#include "debug.h"
#include "entry.h"
#include "options.h"
#include "read.h"
#include "routines.h"
#include "sort.h"
#ifdef TRAP_MEMORY_CALLS
# include "safe_malloc.h"
#endif
/*
* FUNCTION DEFINITIONS
*/
extern void catFile (const char *const name)
{
FILE *const fp = fopen (name, "r");
if (fp != NULL)
{
int c;
while ((c = getc (fp)) != EOF)
putchar (c);
fflush (stdout);
fclose (fp);
}
}
#ifdef EXTERNAL_SORT
#ifdef NON_CONST_PUTENV_PROTOTYPE
# define PE_CONST
#else
# define PE_CONST const
#endif
extern void externalSortTags (const boolean toStdout)
{
const char *const sortNormalCommand = "sort -u -o";
const char *const sortFoldedCommand = "sort -u -f -o";
const char *sortCommand =
Option.sorted == SO_FOLDSORTED ? sortFoldedCommand : sortNormalCommand;
PE_CONST char *const sortOrder1 = "LC_COLLATE=C";
PE_CONST char *const sortOrder2 = "LC_ALL=C";
const size_t length = 4 + strlen (sortOrder1) + strlen (sortOrder2) +
strlen (sortCommand) + (2 * strlen (tagFileName ()));
char *const cmd = (char *) malloc (length + 1);
int ret = -1;
if (cmd != NULL)
{
/* Ensure ASCII value sort order.
*/
#ifdef HAVE_SETENV
setenv ("LC_COLLATE", "C", 1);
setenv ("LC_ALL", "C", 1);
sprintf (cmd, "%s %s %s", sortCommand, tagFileName (), tagFileName ());
#else
# ifdef HAVE_PUTENV
putenv (sortOrder1);
putenv (sortOrder2);
sprintf (cmd, "%s %s %s", sortCommand, tagFileName (), tagFileName ());
# else
sprintf (cmd, "%s %s %s %s %s", sortOrder1, sortOrder2, sortCommand,
tagFileName (), tagFileName ());
# endif
#endif
verbose ("system (\"%s\")\n", cmd);
ret = system (cmd);
free (cmd);
}
if (ret != 0)
error (FATAL | PERROR, "cannot sort tag file");
else if (toStdout)
catFile (tagFileName ());
}
#else
/*
* These functions provide a basic internal sort. No great memory
* optimization is performed (e.g. recursive subdivided sorts),
* so have lots of memory if you have large tag files.
*/
static void failedSort (FILE *const fp, const char* msg)
{
const char* const cannotSort = "cannot sort tag file";
if (fp != NULL)
fclose (fp);
if (msg == NULL)
error (FATAL | PERROR, cannotSort);
else
error (FATAL, "%s: %s", msg, cannotSort);
}
static int compareTagsFolded(const void *const one, const void *const two)
{
const char *const line1 = *(const char* const*) one;
const char *const line2 = *(const char* const*) two;
return struppercmp (line1, line2);
}
static int compareTags (const void *const one, const void *const two)
{
const char *const line1 = *(const char* const*) one;
const char *const line2 = *(const char* const*) two;
return strcmp (line1, line2);
}
static void writeSortedTags (
char **const table, const size_t numTags, const boolean toStdout)
{
FILE *fp;
size_t i;
/* Write the sorted lines back into the tag file.
*/
if (toStdout)
fp = stdout;
else
{
fp = fopen (tagFileName (), "w");
if (fp == NULL)
failedSort (fp, NULL);
}
for (i = 0 ; i < numTags ; ++i)
{
/* Here we filter out identical tag *lines* (including search
* pattern) if this is not an xref file.
*/
if (i == 0 || Option.xref || strcmp (table [i], table [i-1]) != 0)
if (fputs (table [i], fp) == EOF)
failedSort (fp, NULL);
}
if (toStdout)
fflush (fp);
else
fclose (fp);
}
extern void internalSortTags (const boolean toStdout)
{
vString *vLine = vStringNew ();
FILE *fp = NULL;
const char *line;
size_t i;
int (*cmpFunc)(const void *, const void *);
/* Allocate a table of line pointers to be sorted.
*/
size_t numTags = TagFile.numTags.added + TagFile.numTags.prev;
const size_t tableSize = numTags * sizeof (char *);
char **const table = (char **) malloc (tableSize); /* line pointers */
DebugStatement ( size_t mallocSize = tableSize; ) /* cumulative total */
cmpFunc = Option.sorted == SO_FOLDSORTED ? compareTagsFolded : compareTags;
if (table == NULL)
failedSort (fp, "out of memory");
/* Open the tag file and place its lines into allocated buffers.
*/
fp = fopen (tagFileName (), "r");
if (fp == NULL)
failedSort (fp, NULL);
for (i = 0 ; i < numTags && ! feof (fp) ; )
{
line = readLine (vLine, fp);
if (line == NULL)
{
if (! feof (fp))
failedSort (fp, NULL);
break;
}
else if (*line == '\0' || strcmp (line, "\n") == 0)
; /* ignore blank lines */
else
{
const size_t stringSize = strlen (line) + 1;
table [i] = (char *) malloc (stringSize);
if (table [i] == NULL)
failedSort (fp, "out of memory");
DebugStatement ( mallocSize += stringSize; )
strcpy (table [i], line);
++i;
}
}
numTags = i;
fclose (fp);
vStringDelete (vLine);
/* Sort the lines.
*/
qsort (table, numTags, sizeof (*table), cmpFunc);
writeSortedTags (table, numTags, toStdout);
PrintStatus (("sort memory: %ld bytes\n", (long) mallocSize));
for (i = 0 ; i < numTags ; ++i)
free (table [i]);
free (table);
}
#endif
/* vi:set tabstop=4 shiftwidth=4: */
+32
View File
@@ -0,0 +1,32 @@
/*
* $Id: sort.h,v 1.3 2006/05/30 04:37:13 darren Exp $
*
* Copyright (c) 1998-2002, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* External interface to sort.c
*/
#ifndef _SORT_H
#define _SORT_H
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
/*
* FUNCTION PROTOTYPES
*/
extern void catFile (const char *const name);
#ifdef EXTERNAL_SORT
extern void externalSortTags (const boolean toStdout);
#else
extern void internalSortTags (const boolean toStdout);
#endif
#endif /* _SORT_H */
/* vi:set tabstop=4 shiftwidth=4: */
+103
View File
@@ -0,0 +1,103 @@
# $Id: source.mak,v 1.15 2003/04/01 05:02:13 darren Exp $
#
# Shared macros
HEADERS = \
args.h ctags.h debug.h entry.h general.h get.h keyword.h \
main.h options.h parse.h parsers.h read.h routines.h sort.h \
strlist.h vstring.h
SOURCES = \
args.c \
asm.c \
asp.c \
awk.c \
beta.c \
c.c \
cobol.c \
eiffel.c \
entry.c \
erlang.c \
fortran.c \
get.c \
html.c \
jscript.c \
keyword.c \
lisp.c \
lregex.c \
lua.c \
main.c \
make.c \
options.c \
parse.c \
pascal.c \
perl.c \
php.c \
python.c \
read.c \
rexx.c \
routines.c \
ruby.c \
scheme.c \
sh.c \
slang.c \
sml.c \
sort.c \
sql.c \
strlist.c \
tcl.c \
verilog.c \
vim.c \
yacc.c \
vstring.c
ENVIRONMENT_HEADERS = \
e_amiga.h e_djgpp.h e_mac.h e_msoft.h e_os2.h e_qdos.h e_riscos.h e_vms.h
ENVIRONMENT_SOURCES = \
argproc.c mac.c qdos.c
OBJECTS = \
args.$(OBJEXT) \
asm.$(OBJEXT) \
asp.$(OBJEXT) \
awk.$(OBJEXT) \
beta.$(OBJEXT) \
c.$(OBJEXT) \
cobol.$(OBJEXT) \
eiffel.$(OBJEXT) \
entry.$(OBJEXT) \
erlang.$(OBJEXT) \
fortran.$(OBJEXT) \
get.$(OBJEXT) \
html.$(OBJEXT) \
jscript.$(OBJEXT) \
keyword.$(OBJEXT) \
lisp.$(OBJEXT) \
lregex.$(OBJEXT) \
lua.$(OBJEXT) \
main.$(OBJEXT) \
make.$(OBJEXT) \
options.$(OBJEXT) \
parse.$(OBJEXT) \
pascal.$(OBJEXT) \
perl.$(OBJEXT) \
php.$(OBJEXT) \
python.$(OBJEXT) \
read.$(OBJEXT) \
rexx.$(OBJEXT) \
routines.$(OBJEXT) \
ruby.$(OBJEXT) \
scheme.$(OBJEXT) \
sh.$(OBJEXT) \
slang.$(OBJEXT) \
sml.$(OBJEXT) \
sort.$(OBJEXT) \
sql.$(OBJEXT) \
strlist.$(OBJEXT) \
tcl.$(OBJEXT) \
verilog.$(OBJEXT) \
vim.$(OBJEXT) \
yacc.$(OBJEXT) \
vstring.$(OBJEXT)

Some files were not shown because too many files have changed in this diff Show More