Change license
This commit is contained in:
340
third_party/ctags/COPYING
vendored
340
third_party/ctags/COPYING
vendored
@@ -1,340 +0,0 @@
|
||||
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.
|
||||
1195
third_party/ctags/README.txt
vendored
1195
third_party/ctags/README.txt
vendored
File diff suppressed because it is too large
Load Diff
35
third_party/ctags/ant.c
vendored
35
third_party/ctags/ant.c
vendored
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2008, David Fishburn
|
||||
*
|
||||
* 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 Ant language files.
|
||||
*/
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/parse.h"
|
||||
|
||||
/*
|
||||
* FUNCTION DEFINITIONS
|
||||
*/
|
||||
|
||||
static void installAntRegex(const langType language) {
|
||||
addTagRegex(language, "^[ \t]*<[ \t]*project[^>]+name=\"([^\"]+)\".*", "\\1",
|
||||
"p,project,projects", NULL);
|
||||
addTagRegex(language, "^[ \t]*<[ \t]*target[^>]+name=\"([^\"]+)\".*", "\\1",
|
||||
"t,target,targets", NULL);
|
||||
}
|
||||
|
||||
extern parserDefinition* AntParser() {
|
||||
static const char* const extensions[] = {"build.xml", NULL};
|
||||
parserDefinition* const def = parserNew("Ant");
|
||||
def->extensions = extensions;
|
||||
def->initialize = installAntRegex;
|
||||
def->regex = TRUE;
|
||||
return def;
|
||||
}
|
||||
|
||||
/* vi:set tabstop=4 shiftwidth=4: */
|
||||
238
third_party/ctags/args.c
vendored
238
third_party/ctags/args.c
vendored
@@ -1,238 +0,0 @@
|
||||
/*
|
||||
* $Id: args.c 536 2007-06-02 06:09:00Z elliotth $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/ctags/args.h"
|
||||
#include "third_party/ctags/debug.h"
|
||||
#include "third_party/ctags/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);
|
||||
vStringStripTrailing(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, ¤t->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: */
|
||||
47
third_party/ctags/args.h
vendored
47
third_party/ctags/args.h
vendored
@@ -1,47 +0,0 @@
|
||||
#ifndef _ARGS_H
|
||||
#define _ARGS_H
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "libc/stdio/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 */
|
||||
298
third_party/ctags/asm.c
vendored
298
third_party/ctags/asm.c
vendored
@@ -1,298 +0,0 @@
|
||||
/*
|
||||
* $Id: asm.c 536 2007-06-02 06:09:00Z elliotth $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/debug.h"
|
||||
#include "third_party/ctags/keyword.h"
|
||||
#include "third_party/ctags/parse.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/routines.h"
|
||||
#include "third_party/ctags/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) {
|
||||
vString *keyword = vStringNew();
|
||||
opKeyword result;
|
||||
|
||||
vStringCopyToLower(keyword, op);
|
||||
result = (opKeyword)lookupKeyword(vStringValue(keyword), Lang_asm);
|
||||
vStringDelete(keyword);
|
||||
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: */
|
||||
255
third_party/ctags/asp.c
vendored
255
third_party/ctags/asp.c
vendored
@@ -1,255 +0,0 @@
|
||||
/*
|
||||
* $Id: asp.c 711 2009-07-04 16:52:11Z dhiebert $
|
||||
*
|
||||
* Copyright (c) 2000, Patrick Dehne <patrick@steidle.net>
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/parse.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/vstring.h"
|
||||
|
||||
/*
|
||||
* DATA DEFINITIONS
|
||||
*/
|
||||
typedef enum { K_CONST, K_CLASS, K_FUNCTION, K_SUB, K_DIM } aspKind;
|
||||
|
||||
static kindOption AspKinds[] = {{TRUE, 'd', "constant", "constants"},
|
||||
{TRUE, 'c', "class", "classes"},
|
||||
{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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* class member? */
|
||||
else if (strncasecmp((const char *)cp, "public", (size_t)6) == 0) {
|
||||
cp += 6;
|
||||
if (isspace((int)*cp)) {
|
||||
while (isspace((int)*cp)) ++cp;
|
||||
if (strncasecmp((const char *)cp, "function", (size_t)8) == 0) {
|
||||
cp += 8;
|
||||
while (isspace((int)*cp)) ++cp;
|
||||
while (isalnum((int)*cp) || *cp == '_') {
|
||||
vStringPut(name, (int)*cp);
|
||||
++cp;
|
||||
}
|
||||
vStringTerminate(name);
|
||||
makeSimpleTag(name, AspKinds, K_FUNCTION);
|
||||
vStringClear(name);
|
||||
} else if (strncasecmp((const char *)cp, "sub", (size_t)3) == 0) {
|
||||
cp += 3;
|
||||
while (isspace((int)*cp)) ++cp;
|
||||
while (isalnum((int)*cp) || *cp == '_') {
|
||||
vStringPut(name, (int)*cp);
|
||||
++cp;
|
||||
}
|
||||
vStringTerminate(name);
|
||||
makeSimpleTag(name, AspKinds, K_SUB);
|
||||
vStringClear(name);
|
||||
} else {
|
||||
while (isalnum((int)*cp) || *cp == '_') {
|
||||
vStringPut(name, (int)*cp);
|
||||
++cp;
|
||||
}
|
||||
vStringTerminate(name);
|
||||
makeSimpleTag(name, AspKinds, K_DIM);
|
||||
vStringClear(name);
|
||||
}
|
||||
}
|
||||
} else if (strncasecmp((const char *)cp, "private", (size_t)7) == 0) {
|
||||
cp += 7;
|
||||
if (isspace((int)*cp)) {
|
||||
while (isspace((int)*cp)) ++cp;
|
||||
if (strncasecmp((const char *)cp, "function", (size_t)8) == 0) {
|
||||
cp += 8;
|
||||
while (isspace((int)*cp)) ++cp;
|
||||
while (isalnum((int)*cp) || *cp == '_') {
|
||||
vStringPut(name, (int)*cp);
|
||||
++cp;
|
||||
}
|
||||
vStringTerminate(name);
|
||||
makeSimpleTag(name, AspKinds, K_FUNCTION);
|
||||
vStringClear(name);
|
||||
} else if (strncasecmp((const char *)cp, "sub", (size_t)3) == 0) {
|
||||
cp += 3;
|
||||
while (isspace((int)*cp)) ++cp;
|
||||
while (isalnum((int)*cp) || *cp == '_') {
|
||||
vStringPut(name, (int)*cp);
|
||||
++cp;
|
||||
}
|
||||
vStringTerminate(name);
|
||||
makeSimpleTag(name, AspKinds, K_SUB);
|
||||
vStringClear(name);
|
||||
} else {
|
||||
while (isalnum((int)*cp) || *cp == '_') {
|
||||
vStringPut(name, (int)*cp);
|
||||
++cp;
|
||||
}
|
||||
vStringTerminate(name);
|
||||
makeSimpleTag(name, AspKinds, K_DIM);
|
||||
vStringClear(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
/* class declaration? */
|
||||
else if (strncasecmp((const char *)cp, "class", (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_CLASS);
|
||||
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: */
|
||||
63
third_party/ctags/awk.c
vendored
63
third_party/ctags/awk.c
vendored
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* $Id: awk.c 443 2006-05-30 04:37:13Z darren $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/ctags/parse.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/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: */
|
||||
175
third_party/ctags/basic.c
vendored
175
third_party/ctags/basic.c
vendored
@@ -1,175 +0,0 @@
|
||||
/*
|
||||
* $Id:$
|
||||
*
|
||||
* Copyright (c) 2000-2006, Darren Hiebert, Elias Pschernig
|
||||
*
|
||||
* 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 BlitzBasic
|
||||
* (BlitzMax), PureBasic and FreeBasic language files. For now, this is kept
|
||||
* quite simple - but feel free to ask for more things added any time -
|
||||
* patches are of course most welcome.
|
||||
*/
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/options.h"
|
||||
#include "third_party/ctags/parse.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/routines.h"
|
||||
#include "third_party/ctags/vstring.h"
|
||||
|
||||
/*
|
||||
* DATA DEFINITIONS
|
||||
*/
|
||||
typedef enum {
|
||||
K_CONST,
|
||||
K_FUNCTION,
|
||||
K_LABEL,
|
||||
K_TYPE,
|
||||
K_VARIABLE,
|
||||
K_ENUM
|
||||
} BasicKind;
|
||||
|
||||
typedef struct {
|
||||
char const *token;
|
||||
BasicKind kind;
|
||||
int skip;
|
||||
} KeyWord;
|
||||
|
||||
static kindOption BasicKinds[] = {
|
||||
{TRUE, 'c', "constant", "constants"}, {TRUE, 'f', "function", "functions"},
|
||||
{TRUE, 'l', "label", "labels"}, {TRUE, 't', "type", "types"},
|
||||
{TRUE, 'v', "variable", "variables"}, {TRUE, 'g', "enum", "enumerations"},
|
||||
};
|
||||
|
||||
static KeyWord blitzbasic_keywords[] = {
|
||||
{"const", K_CONST, 0}, {"global", K_VARIABLE, 0},
|
||||
{"dim", K_VARIABLE, 0}, {"function", K_FUNCTION, 0},
|
||||
{"type", K_TYPE, 0}, {NULL, 0, 0},
|
||||
};
|
||||
|
||||
static KeyWord purebasic_keywords[] = {
|
||||
{"newlist", K_VARIABLE, 0},
|
||||
{"global", K_VARIABLE, 0},
|
||||
{"dim", K_VARIABLE, 0},
|
||||
{"procedure", K_FUNCTION, 0},
|
||||
{"interface", K_TYPE, 0},
|
||||
{"structure", K_TYPE, 0},
|
||||
{NULL, 0, 0},
|
||||
};
|
||||
|
||||
static KeyWord freebasic_keywords[] = {
|
||||
{"const", K_CONST, 0},
|
||||
{"dim as", K_VARIABLE, 1},
|
||||
{"dim", K_VARIABLE, 0},
|
||||
{"common", K_VARIABLE, 0},
|
||||
{"function", K_FUNCTION, 0},
|
||||
{"sub", K_FUNCTION, 0},
|
||||
{"private sub", K_FUNCTION, 0},
|
||||
{"public sub", K_FUNCTION, 0},
|
||||
{"private function", K_FUNCTION, 0},
|
||||
{"public function", K_FUNCTION, 0},
|
||||
{"type", K_TYPE, 0},
|
||||
{"enum", K_ENUM, 0},
|
||||
{NULL, 0, 0},
|
||||
};
|
||||
|
||||
/*
|
||||
* FUNCTION DEFINITIONS
|
||||
*/
|
||||
|
||||
/* Match the name of a tag (function, variable, type, ...) starting at pos. */
|
||||
static char const *extract_name(char const *pos, vString *name) {
|
||||
while (isspace(*pos)) pos++;
|
||||
vStringClear(name);
|
||||
for (; *pos && !isspace(*pos) && *pos != '(' && *pos != ','; pos++)
|
||||
vStringPut(name, *pos);
|
||||
vStringTerminate(name);
|
||||
return pos;
|
||||
}
|
||||
|
||||
/* Match a keyword starting at p (case insensitive). */
|
||||
static int match_keyword(const char *p, KeyWord const *kw) {
|
||||
vString *name;
|
||||
size_t i;
|
||||
int j;
|
||||
for (i = 0; i < strlen(kw->token); i++) {
|
||||
if (tolower(p[i]) != kw->token[i]) return 0;
|
||||
}
|
||||
name = vStringNew();
|
||||
p += i;
|
||||
for (j = 0; j < 1 + kw->skip; j++) {
|
||||
p = extract_name(p, name);
|
||||
}
|
||||
makeSimpleTag(name, BasicKinds, kw->kind);
|
||||
vStringDelete(name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Match a "label:" style label. */
|
||||
static void match_colon_label(char const *p) {
|
||||
char const *end = p + strlen(p) - 1;
|
||||
while (isspace(*end)) end--;
|
||||
if (*end == ':') {
|
||||
vString *name = vStringNew();
|
||||
vStringNCatS(name, p, end - p);
|
||||
makeSimpleTag(name, BasicKinds, K_LABEL);
|
||||
vStringDelete(name);
|
||||
}
|
||||
}
|
||||
|
||||
/* Match a ".label" style label. */
|
||||
static void match_dot_label(char const *p) {
|
||||
if (*p == '.') {
|
||||
vString *name = vStringNew();
|
||||
extract_name(p + 1, name);
|
||||
makeSimpleTag(name, BasicKinds, K_LABEL);
|
||||
vStringDelete(name);
|
||||
}
|
||||
}
|
||||
|
||||
static void findBasicTags(void) {
|
||||
const char *line;
|
||||
const char *extension = fileExtension(vStringValue(File.name));
|
||||
KeyWord *keywords;
|
||||
|
||||
if (strcmp(extension, "bb") == 0)
|
||||
keywords = blitzbasic_keywords;
|
||||
else if (strcmp(extension, "pb") == 0)
|
||||
keywords = purebasic_keywords;
|
||||
else
|
||||
keywords = freebasic_keywords;
|
||||
|
||||
while ((line = (const char *)fileReadLine()) != NULL) {
|
||||
const char *p = line;
|
||||
KeyWord const *kw;
|
||||
|
||||
while (isspace(*p)) p++;
|
||||
|
||||
/* Empty line? */
|
||||
if (!*p) continue;
|
||||
|
||||
/* In Basic, keywords always are at the start of the line. */
|
||||
for (kw = keywords; kw->token; kw++)
|
||||
if (match_keyword(p, kw)) break;
|
||||
|
||||
/* Is it a label? */
|
||||
if (strcmp(extension, "bb") == 0)
|
||||
match_dot_label(p);
|
||||
else
|
||||
match_colon_label(p);
|
||||
}
|
||||
}
|
||||
|
||||
parserDefinition *BasicParser(void) {
|
||||
static char const *extensions[] = {"bas", "bi", "bb", "pb", NULL};
|
||||
parserDefinition *def = parserNew("Basic");
|
||||
def->kinds = BasicKinds;
|
||||
def->kindCount = KIND_COUNT(BasicKinds);
|
||||
def->extensions = extensions;
|
||||
def->parser = findBasicTags;
|
||||
return def;
|
||||
}
|
||||
|
||||
/* vi:set tabstop=4 shiftwidth=4: */
|
||||
273
third_party/ctags/beta.c
vendored
273
third_party/ctags/beta.c
vendored
@@ -1,273 +0,0 @@
|
||||
/*
|
||||
* $Id: beta.c 536 2007-06-02 06:09:00Z elliotth $
|
||||
*
|
||||
* Copyright (c) 1999-2000, Mjlner Informatics
|
||||
*
|
||||
* Written by Erik Corry <corry@mjolner.dk>
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/ctags/entry.h"
|
||||
#include "third_party/ctags/parse.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/routines.h"
|
||||
#include "third_party/ctags/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)"}};
|
||||
|
||||
/* clang-format off */
|
||||
/* [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 */
|
||||
/* clang-format on */
|
||||
|
||||
/*
|
||||
* 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));
|
||||
vStringDelete(line);
|
||||
}
|
||||
|
||||
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: */
|
||||
2966
third_party/ctags/c.c
vendored
2966
third_party/ctags/c.c
vendored
File diff suppressed because it is too large
Load Diff
47
third_party/ctags/cobol.c
vendored
47
third_party/ctags/cobol.c
vendored
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* $Id: cobol.c 443 2006-05-30 04:37:13Z darren $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/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: */
|
||||
283
third_party/ctags/config.h
vendored
283
third_party/ctags/config.h
vendored
@@ -1,283 +0,0 @@
|
||||
/* config.h. Generated from config.h.in by configure. */
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define this label if your system uses case-insensitive file names */
|
||||
/* #undef CASE_INSENSITIVE_FILENAMES */
|
||||
|
||||
/* 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 */
|
||||
|
||||
/* 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 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 to use the system sort utility (which is probably more
|
||||
* efficient) over the internal sorting algorithm.
|
||||
*/
|
||||
#ifndef INTERNAL_SORT
|
||||
#define EXTERNAL_SORT 1
|
||||
#endif
|
||||
|
||||
/* 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 this macro if the field "st_ino" exists in struct stat in
|
||||
<sys/stat.h>. */
|
||||
#define HAVE_STAT_ST_INO 1
|
||||
|
||||
/* 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. */
|
||||
#define HAVE_SYS_DIR_H 1
|
||||
|
||||
/* 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 as the maximum integer on your system if not defined <limits.h>. */
|
||||
/* #undef INT_MAX */
|
||||
|
||||
/* Define to the appropriate size for tmpnam() if <stdio.h> does not define
|
||||
this. */
|
||||
/* #undef L_tmpnam */
|
||||
|
||||
/* 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 */
|
||||
|
||||
/* If you receive error or warning messages indicating that you are missing a
|
||||
prototype for, or a type mismatch using, the following function, define
|
||||
this label and remake. */
|
||||
/* #undef NEED_PROTO_FGETPOS */
|
||||
|
||||
/* If you receive error or warning messages indicating that you are missing a
|
||||
prototype for, or a type mismatch using, the following function, define
|
||||
this label and remake. */
|
||||
/* #undef NEED_PROTO_FTRUNCATE */
|
||||
|
||||
/* If you receive error or warning messages indicating that you are missing a
|
||||
prototype for, or a type mismatch using, the following function, define
|
||||
this label and remake. */
|
||||
/* #undef NEED_PROTO_GETENV */
|
||||
|
||||
/* If you receive error or warning messages indicating that you are missing a
|
||||
prototype for, or a type mismatch using, the following function, define
|
||||
this label and remake. */
|
||||
/* #undef NEED_PROTO_LSTAT */
|
||||
|
||||
/* If you receive error or warning messages indicating that you are missing a
|
||||
prototype for, or a type mismatch using, the following function, define
|
||||
this label and remake. */
|
||||
/* #undef NEED_PROTO_MALLOC */
|
||||
|
||||
/* If you receive error or warning messages indicating that you are missing a
|
||||
prototype for, or a type mismatch using, the following function, define
|
||||
this label and remake. */
|
||||
/* #undef NEED_PROTO_REMOVE */
|
||||
|
||||
/* If you receive error or warning messages indicating that you are missing a
|
||||
prototype for, or a type mismatch using, the following function, define
|
||||
this label and remake. */
|
||||
/* #undef NEED_PROTO_STAT */
|
||||
|
||||
/* If you receive error or warning messages indicating that you are missing a
|
||||
prototype for, or a type mismatch using, the following function, define
|
||||
this label and remake. */
|
||||
/* #undef NEED_PROTO_TRUNCATE */
|
||||
|
||||
/* If you receive error or warning messages indicating that you are missing a
|
||||
prototype for, or a type mismatch using, the following function, define
|
||||
this label and remake. */
|
||||
/* #undef NEED_PROTO_UNLINK */
|
||||
|
||||
/* 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 */
|
||||
|
||||
/* Package name. */
|
||||
/* #undef PACKAGE */
|
||||
|
||||
/* 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 home page for this package. */
|
||||
#define PACKAGE_URL ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION ""
|
||||
|
||||
/* Define this label if regcomp() is broken. */
|
||||
/* #undef REGCOMP_BROKEN */
|
||||
|
||||
/* 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 to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* 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
|
||||
|
||||
/* If you wish to change the directory in which temporary files are stored,
|
||||
define this label to the directory desired. */
|
||||
#define TMPDIR kTmpPath
|
||||
|
||||
/* Package version. */
|
||||
/* #undef VERSION */
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
/* #undef _FILE_OFFSET_BITS */
|
||||
|
||||
/* Define for large files, on AIX-style hosts. */
|
||||
/* #undef _LARGE_FILES */
|
||||
|
||||
/* 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 to the appropriate type if <time.h> does not define this. */
|
||||
/* #undef clock_t */
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
|
||||
/* Define to long if <stdio.h> does not define this. */
|
||||
/* #undef fpos_t */
|
||||
|
||||
/* Define to `long int' if <sys/types.h> does not define. */
|
||||
/* #undef off_t */
|
||||
|
||||
/* Define remove to unlink if you have unlink(), but not remove(). */
|
||||
/* #undef remove */
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
/* #undef size_t */
|
||||
26
third_party/ctags/ctags.h
vendored
26
third_party/ctags/ctags.h
vendored
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* $Id: ctags.h 702 2009-03-14 03:52:21Z dhiebert $
|
||||
*
|
||||
* 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.9~svn20110310"
|
||||
#endif
|
||||
#define PROGRAM_NAME "Exuberant Ctags"
|
||||
#define PROGRAM_URL "http://ctags.sourceforge.net"
|
||||
#define PROGRAM_COPYRIGHT "Copyright (C) 1996-2009"
|
||||
#define AUTHOR_NAME "Darren Hiebert"
|
||||
#define AUTHOR_EMAIL "dhiebert@users.sourceforge.net"
|
||||
|
||||
#endif /* _CTAGS_H */
|
||||
60
third_party/ctags/ctags.mk
vendored
60
third_party/ctags/ctags.mk
vendored
@@ -1,60 +0,0 @@
|
||||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
THIRD_PARTY_CTAGS_FILES := $(wildcard third_party/ctags/*)
|
||||
THIRD_PARTY_CTAGS_HDRS = $(filter %.h,$(THIRD_PARTY_CTAGS_FILES))
|
||||
THIRD_PARTY_CTAGS_SRCS = $(filter %.c,$(THIRD_PARTY_CTAGS_FILES))
|
||||
|
||||
THIRD_PARTY_CTAGS_BINS = \
|
||||
o/$(MODE)/third_party/ctags/ctags.com
|
||||
|
||||
THIRD_PARTY_CTAGS_CHECKS = \
|
||||
o/$(MODE)/third_party/ctags/ctags.pkg \
|
||||
$(THIRD_PARTY_CTAGS_HDRS:%=o/$(MODE)/%.ok)
|
||||
|
||||
THIRD_PARTY_CTAGS_DIRECTDEPS = \
|
||||
LIBC_CALLS \
|
||||
LIBC_CALLS_HEFTY \
|
||||
LIBC_FMT \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_TIME \
|
||||
LIBC_UNICODE \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_REGEX
|
||||
|
||||
THIRD_PARTY_CTAGS_DEPS := \
|
||||
$(call uniq,$(foreach x,$(THIRD_PARTY_CTAGS_DIRECTDEPS),$($(x))))
|
||||
|
||||
o/$(MODE)/third_party/ctags/ctags.srcs.a: \
|
||||
third_party/ctags/ \
|
||||
$(THIRD_PARTY_CTAGS_SRCS:%=o/$(MODE)/%.zip.o)
|
||||
|
||||
o/$(MODE)/third_party/ctags/ctags.com.dbg: \
|
||||
o/$(MODE)/third_party/ctags/ctags.pkg \
|
||||
o/$(MODE)/third_party/ctags/ctags.srcs.a \
|
||||
$(THIRD_PARTY_CTAGS_DEPS) \
|
||||
$(THIRD_PARTY_CTAGS_SRCS:%.c=o/$(MODE)/%.o) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/third_party/ctags/ctags.pkg: \
|
||||
$(THIRD_PARTY_CTAGS_SRCS:%.c=o/$(MODE)/%.o) \
|
||||
o/$(MODE)/third_party/ctags/ctags.srcs.pkg \
|
||||
$(foreach x,$(THIRD_PARTY_CTAGS_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/third_party/ctags/ctags.srcs.pkg: \
|
||||
$(THIRD_PARTY_CTAGS_SRCS:%=o/$(MODE)/%.zip.o) \
|
||||
$(foreach x,$(THIRD_PARTY_CTAGS_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
.PHONY: o/$(MODE)/third_party/ctags
|
||||
o/$(MODE)/third_party/ctags: \
|
||||
$(THIRD_PARTY_CTAGS_BINS) \
|
||||
$(THIRD_PARTY_CTAGS_CHECKS)
|
||||
53
third_party/ctags/debug.h
vendored
53
third_party/ctags/debug.h
vendored
@@ -1,53 +0,0 @@
|
||||
#ifndef _DEBUG_H
|
||||
#define _DEBUG_H
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/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 debugEntry(const tagEntryInfo *const tag);
|
||||
|
||||
#endif /* _DEBUG_H */
|
||||
35
third_party/ctags/dosbatch.c
vendored
35
third_party/ctags/dosbatch.c
vendored
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2009, David Fishburn
|
||||
*
|
||||
* 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 DOS Batch language
|
||||
* files.
|
||||
*/
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/parse.h"
|
||||
|
||||
/*
|
||||
* FUNCTION DEFINITIONS
|
||||
*/
|
||||
|
||||
static void installDosBatchRegex(const langType language) {
|
||||
addTagRegex(language, "^:([A-Za-z_0-9]+)", "\\1", "l,label,labels", NULL);
|
||||
addTagRegex(language, "set[ \t]+([A-Za-z_0-9]+)[ \t]*=", "\\1",
|
||||
"v,variable,variables", NULL);
|
||||
}
|
||||
|
||||
extern parserDefinition* DosBatchParser() {
|
||||
static const char* const extensions[] = {"bat", "cmd", NULL};
|
||||
parserDefinition* const def = parserNew("DosBatch");
|
||||
def->extensions = extensions;
|
||||
def->initialize = installDosBatchRegex;
|
||||
def->regex = TRUE;
|
||||
return def;
|
||||
}
|
||||
|
||||
/* vi:set tabstop=4 shiftwidth=4: */
|
||||
1304
third_party/ctags/eiffel.c
vendored
1304
third_party/ctags/eiffel.c
vendored
File diff suppressed because it is too large
Load Diff
736
third_party/ctags/entry.c
vendored
736
third_party/ctags/entry.c
vendored
@@ -1,736 +0,0 @@
|
||||
/*
|
||||
* $Id: entry.c 766 2010-09-11 18:59:45Z dhiebert $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/weirdtypes.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/ctags/ctags.h"
|
||||
#include "third_party/ctags/debug.h"
|
||||
#include "third_party/ctags/entry.h"
|
||||
#include "third_party/ctags/main.h"
|
||||
#include "third_party/ctags/options.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/routines.h"
|
||||
#include "third_party/ctags/sort.h"
|
||||
#include "third_party/ctags/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 (line == NULL) error(FATAL, "bad tag in %s", vStringValue(File.name));
|
||||
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: */
|
||||
93
third_party/ctags/entry.h
vendored
93
third_party/ctags/entry.h
vendored
@@ -1,93 +0,0 @@
|
||||
#ifndef _ENTRY_H
|
||||
#define _ENTRY_H
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "third_party/ctags/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: */
|
||||
164
third_party/ctags/erlang.c
vendored
164
third_party/ctags/erlang.c
vendored
@@ -1,164 +0,0 @@
|
||||
/*
|
||||
* $Id: erlang.c 443 2006-05-30 04:37:13Z darren $
|
||||
*
|
||||
* Copyright (c) 2003, Brent Fulgham <bfulgham@debian.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 Erlang language
|
||||
* files. Some of the parsing constructs are based on the Emacs 'etags'
|
||||
* program by Francesco Potori <pot@gnu.org>
|
||||
*/
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/ctags/entry.h"
|
||||
#include "third_party/ctags/options.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/routines.h"
|
||||
#include "third_party/ctags/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: */
|
||||
2105
third_party/ctags/flex.c
vendored
2105
third_party/ctags/flex.c
vendored
File diff suppressed because it is too large
Load Diff
2026
third_party/ctags/fortran.c
vendored
2026
third_party/ctags/fortran.c
vendored
File diff suppressed because it is too large
Load Diff
90
third_party/ctags/general.h
vendored
90
third_party/ctags/general.h
vendored
@@ -1,90 +0,0 @@
|
||||
#ifndef _GENERAL_H
|
||||
#define _GENERAL_H
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/ctags/config.h"
|
||||
|
||||
/* 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(__GNUG__)
|
||||
#define __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
|
||||
|
||||
/* vi:set tabstop=4 shiftwidth=4: */
|
||||
#endif /* _GENERAL_H */
|
||||
614
third_party/ctags/get.c
vendored
614
third_party/ctags/get.c
vendored
@@ -1,614 +0,0 @@
|
||||
/*
|
||||
* $Id: get.c 559 2007-06-17 03:30:09Z elliotth $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/ctags/debug.h"
|
||||
#include "third_party/ctags/entry.h"
|
||||
#include "third_party/ctags/get.h"
|
||||
#include "third_party/ctags/options.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/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 */
|
||||
boolean hasAtLiteralStrings; /* supports @"c:\" strings */
|
||||
struct sDirective {
|
||||
enum eState state; /* current directive being processed */
|
||||
boolean accept; /* is a directive syntactically 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 */
|
||||
FALSE, /* hasAtLiteralStrings */
|
||||
{
|
||||
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, const boolean hasAtLiteralStrings) {
|
||||
BraceFormat = state;
|
||||
|
||||
Cpp.ungetch = '\0';
|
||||
Cpp.ungetch2 = '\0';
|
||||
Cpp.resolveRequired = FALSE;
|
||||
Cpp.hasAtLiteralStrings = hasAtLiteralStrings;
|
||||
|
||||
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 substitution.
|
||||
*/
|
||||
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(boolean ignoreBackslash) {
|
||||
int c;
|
||||
|
||||
while ((c = fileGetc()) != EOF) {
|
||||
if (c == BACKSLASH && !ignoreBackslash)
|
||||
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(FALSE);
|
||||
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:
|
||||
if (c == '@' && Cpp.hasAtLiteralStrings) {
|
||||
int next = fileGetc();
|
||||
if (next == DOUBLE_QUOTE) {
|
||||
Cpp.directive.accept = FALSE;
|
||||
c = skipToEndOfString(TRUE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
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: */
|
||||
50
third_party/ctags/get.h
vendored
50
third_party/ctags/get.h
vendored
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* $Id: get.h 525 2007-05-28 01:50:41Z elliotth $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h" /* must always come first */
|
||||
|
||||
#include "third_party/ctags/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, const boolean hasAtLiteralStrings);
|
||||
extern void cppTerminate (void);
|
||||
extern void cppBeginStatement (void);
|
||||
extern void cppEndStatement (void);
|
||||
extern void cppUngetc (const int c);
|
||||
extern int cppGetc (void);
|
||||
extern int skipOverCComment (void);
|
||||
|
||||
#endif /* _GET_H */
|
||||
|
||||
/* vi:set tabstop=4 shiftwidth=4: */
|
||||
596
third_party/ctags/go.c
vendored
596
third_party/ctags/go.c
vendored
@@ -1,596 +0,0 @@
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/ctags/debug.h"
|
||||
#include "third_party/ctags/entry.h"
|
||||
#include "third_party/ctags/keyword.h"
|
||||
#include "third_party/ctags/main.h"
|
||||
#include "third_party/ctags/options.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/routines.h"
|
||||
#include "third_party/ctags/vstring.h"
|
||||
|
||||
/*
|
||||
* MACROS
|
||||
*/
|
||||
#define isType(token, t) (boolean)((token)->type == (t))
|
||||
#define isKeyword(token, k) (boolean)((token)->keyword == (k))
|
||||
|
||||
/*
|
||||
* DATA DECLARATIONS
|
||||
*/
|
||||
|
||||
typedef enum eException { ExceptionNone, ExceptionEOF } exception_t;
|
||||
|
||||
typedef enum eKeywordId {
|
||||
KEYWORD_NONE = -1,
|
||||
KEYWORD_package,
|
||||
KEYWORD_import,
|
||||
KEYWORD_const,
|
||||
KEYWORD_type,
|
||||
KEYWORD_var,
|
||||
KEYWORD_func,
|
||||
KEYWORD_struct,
|
||||
KEYWORD_interface,
|
||||
KEYWORD_map,
|
||||
KEYWORD_chan
|
||||
} keywordId;
|
||||
|
||||
/* Used to determine whether keyword is valid for the current language and
|
||||
* what its ID is.
|
||||
*/
|
||||
typedef struct sKeywordDesc {
|
||||
const char *name;
|
||||
keywordId id;
|
||||
} keywordDesc;
|
||||
|
||||
typedef enum eTokenType {
|
||||
TOKEN_NONE = -1,
|
||||
TOKEN_CHARACTER,
|
||||
// Don't need TOKEN_FORWARD_SLASH
|
||||
TOKEN_FORWARD_SLASH,
|
||||
TOKEN_KEYWORD,
|
||||
TOKEN_IDENTIFIER,
|
||||
TOKEN_STRING,
|
||||
TOKEN_OPEN_PAREN,
|
||||
TOKEN_CLOSE_PAREN,
|
||||
TOKEN_OPEN_CURLY,
|
||||
TOKEN_CLOSE_CURLY,
|
||||
TOKEN_OPEN_SQUARE,
|
||||
TOKEN_CLOSE_SQUARE,
|
||||
TOKEN_SEMICOLON,
|
||||
TOKEN_STAR,
|
||||
TOKEN_LEFT_ARROW,
|
||||
TOKEN_DOT,
|
||||
TOKEN_COMMA
|
||||
} tokenType;
|
||||
|
||||
typedef struct sTokenInfo {
|
||||
tokenType type;
|
||||
keywordId keyword;
|
||||
vString *string; /* the name of the token */
|
||||
unsigned long lineNumber; /* line number of tag */
|
||||
fpos_t filePosition; /* file position of line containing name */
|
||||
} tokenInfo;
|
||||
|
||||
/*
|
||||
* DATA DEFINITIONS
|
||||
*/
|
||||
|
||||
static int Lang_go;
|
||||
static jmp_buf Exception;
|
||||
static vString *scope;
|
||||
|
||||
typedef enum {
|
||||
GOTAG_UNDEFINED = -1,
|
||||
GOTAG_PACKAGE,
|
||||
GOTAG_FUNCTION,
|
||||
GOTAG_CONST,
|
||||
GOTAG_TYPE,
|
||||
GOTAG_VAR,
|
||||
} goKind;
|
||||
|
||||
static kindOption GoKinds[] = {{TRUE, 'p', "package", "packages"},
|
||||
{TRUE, 'f', "func", "functions"},
|
||||
{TRUE, 'c', "const", "constants"},
|
||||
{TRUE, 't', "type", "types"},
|
||||
{TRUE, 'v', "var", "variables"}};
|
||||
|
||||
static keywordDesc GoKeywordTable[] = {
|
||||
{"package", KEYWORD_package}, {"import", KEYWORD_import},
|
||||
{"const", KEYWORD_const}, {"type", KEYWORD_type},
|
||||
{"var", KEYWORD_var}, {"func", KEYWORD_func},
|
||||
{"struct", KEYWORD_struct}, {"interface", KEYWORD_interface},
|
||||
{"map", KEYWORD_map}, {"chan", KEYWORD_chan}};
|
||||
|
||||
/*
|
||||
* FUNCTION DEFINITIONS
|
||||
*/
|
||||
|
||||
// XXX UTF-8
|
||||
static boolean isIdentChar(const int c) {
|
||||
return (boolean)(isalpha(c) || isdigit(c) || c == '$' || c == '@' ||
|
||||
c == '_' || c == '#' || c > 128);
|
||||
}
|
||||
|
||||
static void initialize(const langType language) {
|
||||
size_t i;
|
||||
const size_t count = sizeof(GoKeywordTable) / sizeof(GoKeywordTable[0]);
|
||||
Lang_go = language;
|
||||
for (i = 0; i < count; ++i) {
|
||||
const keywordDesc *const p = &GoKeywordTable[i];
|
||||
addKeyword(p->name, language, (int)p->id);
|
||||
}
|
||||
}
|
||||
|
||||
static tokenInfo *newToken(void) {
|
||||
tokenInfo *const token = xMalloc(1, tokenInfo);
|
||||
token->type = TOKEN_NONE;
|
||||
token->keyword = KEYWORD_NONE;
|
||||
token->string = vStringNew();
|
||||
token->lineNumber = getSourceLineNumber();
|
||||
token->filePosition = getInputFilePosition();
|
||||
return token;
|
||||
}
|
||||
|
||||
static void deleteToken(tokenInfo *const token) {
|
||||
if (token != NULL) {
|
||||
vStringDelete(token->string);
|
||||
eFree(token);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parsing functions
|
||||
*/
|
||||
|
||||
static void parseString(vString *const string, const int delimiter) {
|
||||
boolean end = FALSE;
|
||||
while (!end) {
|
||||
int c = fileGetc();
|
||||
if (c == EOF)
|
||||
end = TRUE;
|
||||
else if (c == '\\' && delimiter != '`') {
|
||||
c = fileGetc(); /* This maybe a ' or ". */
|
||||
vStringPut(string, c);
|
||||
} else if (c == delimiter)
|
||||
end = TRUE;
|
||||
else
|
||||
vStringPut(string, c);
|
||||
}
|
||||
vStringTerminate(string);
|
||||
}
|
||||
|
||||
static void parseIdentifier(vString *const string, const int firstChar) {
|
||||
int c = firstChar;
|
||||
// Assert (isIdentChar (c));
|
||||
do {
|
||||
vStringPut(string, c);
|
||||
c = fileGetc();
|
||||
} while (isIdentChar(c));
|
||||
vStringTerminate(string);
|
||||
fileUngetc(c); /* always unget, LF might add a semicolon */
|
||||
}
|
||||
|
||||
static void readToken(tokenInfo *const token) {
|
||||
int c;
|
||||
static tokenType lastTokenType = TOKEN_NONE;
|
||||
|
||||
token->type = TOKEN_NONE;
|
||||
token->keyword = KEYWORD_NONE;
|
||||
vStringClear(token->string);
|
||||
|
||||
getNextChar:
|
||||
do {
|
||||
c = fileGetc();
|
||||
token->lineNumber = getSourceLineNumber();
|
||||
token->filePosition = getInputFilePosition();
|
||||
if (c == '\n' &&
|
||||
(lastTokenType == TOKEN_IDENTIFIER || lastTokenType == TOKEN_STRING ||
|
||||
lastTokenType == TOKEN_CLOSE_PAREN ||
|
||||
lastTokenType == TOKEN_CLOSE_CURLY ||
|
||||
lastTokenType == TOKEN_CLOSE_SQUARE)) {
|
||||
token->type = TOKEN_SEMICOLON;
|
||||
goto done;
|
||||
}
|
||||
} while (c == '\t' || c == ' ' || c == '\r' || c == '\n');
|
||||
|
||||
switch (c) {
|
||||
case EOF:
|
||||
longjmp(Exception, (int)ExceptionEOF);
|
||||
break;
|
||||
|
||||
case '/': {
|
||||
boolean hasNewline = FALSE;
|
||||
int d = fileGetc();
|
||||
switch (d) {
|
||||
case '/':
|
||||
fileSkipToCharacter('\n');
|
||||
/* Line comments start with the
|
||||
* character sequence // and
|
||||
* continue through the next
|
||||
* newline. A line comment acts
|
||||
* like a newline. */
|
||||
fileUngetc('\n');
|
||||
goto getNextChar;
|
||||
case '*':
|
||||
do {
|
||||
int d;
|
||||
do {
|
||||
d = fileGetc();
|
||||
if (d == '\n') {
|
||||
hasNewline = TRUE;
|
||||
}
|
||||
} while (d != EOF && d != '*');
|
||||
|
||||
c = fileGetc();
|
||||
if (c == '/')
|
||||
break;
|
||||
else
|
||||
fileUngetc(c);
|
||||
} while (c != EOF && c != '\0');
|
||||
|
||||
fileUngetc(hasNewline ? '\n' : ' ');
|
||||
goto getNextChar;
|
||||
default:
|
||||
token->type = TOKEN_FORWARD_SLASH;
|
||||
fileUngetc(d);
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case '"':
|
||||
case '\'':
|
||||
case '`':
|
||||
token->type = TOKEN_STRING;
|
||||
parseString(token->string, c);
|
||||
token->lineNumber = getSourceLineNumber();
|
||||
token->filePosition = getInputFilePosition();
|
||||
break;
|
||||
|
||||
case '<': {
|
||||
int d = fileGetc();
|
||||
if (d == '-') {
|
||||
token->type = TOKEN_LEFT_ARROW;
|
||||
break;
|
||||
} else
|
||||
goto getNextChar;
|
||||
}
|
||||
|
||||
case '(':
|
||||
token->type = TOKEN_OPEN_PAREN;
|
||||
break;
|
||||
|
||||
case ')':
|
||||
token->type = TOKEN_CLOSE_PAREN;
|
||||
break;
|
||||
|
||||
case '{':
|
||||
token->type = TOKEN_OPEN_CURLY;
|
||||
break;
|
||||
|
||||
case '}':
|
||||
token->type = TOKEN_CLOSE_CURLY;
|
||||
break;
|
||||
|
||||
case '[':
|
||||
token->type = TOKEN_OPEN_SQUARE;
|
||||
break;
|
||||
|
||||
case ']':
|
||||
token->type = TOKEN_CLOSE_SQUARE;
|
||||
break;
|
||||
|
||||
case '*':
|
||||
token->type = TOKEN_STAR;
|
||||
break;
|
||||
|
||||
case '.':
|
||||
token->type = TOKEN_DOT;
|
||||
break;
|
||||
|
||||
case ',':
|
||||
token->type = TOKEN_COMMA;
|
||||
break;
|
||||
|
||||
default:
|
||||
parseIdentifier(token->string, c);
|
||||
token->lineNumber = getSourceLineNumber();
|
||||
token->filePosition = getInputFilePosition();
|
||||
token->keyword = lookupKeyword(vStringValue(token->string), Lang_go);
|
||||
if (isKeyword(token, KEYWORD_NONE))
|
||||
token->type = TOKEN_IDENTIFIER;
|
||||
else
|
||||
token->type = TOKEN_KEYWORD;
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
lastTokenType = token->type;
|
||||
}
|
||||
|
||||
static void skipToMatched(tokenInfo *const token) {
|
||||
int nest_level = 0;
|
||||
tokenType open_token;
|
||||
tokenType close_token;
|
||||
|
||||
switch (token->type) {
|
||||
case TOKEN_OPEN_PAREN:
|
||||
open_token = TOKEN_OPEN_PAREN;
|
||||
close_token = TOKEN_CLOSE_PAREN;
|
||||
break;
|
||||
case TOKEN_OPEN_CURLY:
|
||||
open_token = TOKEN_OPEN_CURLY;
|
||||
close_token = TOKEN_CLOSE_CURLY;
|
||||
break;
|
||||
case TOKEN_OPEN_SQUARE:
|
||||
open_token = TOKEN_OPEN_SQUARE;
|
||||
close_token = TOKEN_CLOSE_SQUARE;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine will skip to a matching closing token.
|
||||
* It will also handle nested tokens like the (, ) below.
|
||||
* ( name varchar(30), text binary(10) )
|
||||
*/
|
||||
if (isType(token, open_token)) {
|
||||
nest_level++;
|
||||
while (!(isType(token, close_token) && (nest_level == 0))) {
|
||||
readToken(token);
|
||||
if (isType(token, open_token)) {
|
||||
nest_level++;
|
||||
}
|
||||
if (isType(token, close_token)) {
|
||||
if (nest_level > 0) {
|
||||
nest_level--;
|
||||
}
|
||||
}
|
||||
}
|
||||
readToken(token);
|
||||
}
|
||||
}
|
||||
|
||||
static void skipType(tokenInfo *const token) {
|
||||
again:
|
||||
// Type = TypeName | TypeLit | "(" Type ")" .
|
||||
if (isType(token, TOKEN_OPEN_PAREN)) {
|
||||
skipToMatched(token);
|
||||
return;
|
||||
}
|
||||
|
||||
// TypeName = QualifiedIdent.
|
||||
// QualifiedIdent = [ PackageName "." ] identifier .
|
||||
// PackageName = identifier .
|
||||
if (isType(token, TOKEN_IDENTIFIER)) {
|
||||
readToken(token);
|
||||
if (isType(token, TOKEN_DOT)) {
|
||||
readToken(token);
|
||||
Assert(isType(token, TOKEN_IDENTIFIER));
|
||||
readToken(token);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// StructType = "struct" "{" { FieldDecl ";" } "}"
|
||||
// InterfaceType = "interface" "{" { MethodSpec ";" } "}" .
|
||||
if (isKeyword(token, KEYWORD_struct) || isKeyword(token, KEYWORD_interface)) {
|
||||
readToken(token);
|
||||
Assert(isType(token, TOKEN_OPEN_CURLY));
|
||||
skipToMatched(token);
|
||||
return;
|
||||
}
|
||||
|
||||
// ArrayType = "[" ArrayLength "]" ElementType .
|
||||
// SliceType = "[" "]" ElementType .
|
||||
// ElementType = Type .
|
||||
if (isType(token, TOKEN_OPEN_SQUARE)) {
|
||||
skipToMatched(token);
|
||||
goto again;
|
||||
}
|
||||
|
||||
// PointerType = "*" BaseType .
|
||||
// BaseType = Type .
|
||||
// ChannelType = ( "chan" [ "<-" ] | "<-" "chan" ) ElementType .
|
||||
if (isType(token, TOKEN_STAR) || isKeyword(token, KEYWORD_chan) ||
|
||||
isType(token, TOKEN_LEFT_ARROW)) {
|
||||
readToken(token);
|
||||
goto again;
|
||||
}
|
||||
|
||||
// MapType = "map" "[" KeyType "]" ElementType .
|
||||
// KeyType = Type .
|
||||
if (isKeyword(token, KEYWORD_map)) {
|
||||
readToken(token);
|
||||
Assert(isType(token, TOKEN_OPEN_SQUARE));
|
||||
skipToMatched(token);
|
||||
goto again;
|
||||
}
|
||||
|
||||
// FunctionType = "func" Signature .
|
||||
// Signature = Parameters [ Result ] .
|
||||
// Result = Parameters | Type .
|
||||
// Parameters = "(" [ ParameterList [ "," ] ] ")" .
|
||||
if (isKeyword(token, KEYWORD_func)) {
|
||||
readToken(token);
|
||||
Assert(isType(token, TOKEN_OPEN_PAREN));
|
||||
// Parameters
|
||||
skipToMatched(token);
|
||||
// Result is parameters or type or nothing. skipType treats anything
|
||||
// surrounded by parentheses as a type, and does nothing if what
|
||||
// follows is not a type.
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip to the next semicolon, skipping over matching brackets.
|
||||
static void skipToTopLevelSemicolon(tokenInfo *const token) {
|
||||
while (!isType(token, TOKEN_SEMICOLON)) {
|
||||
readToken(token);
|
||||
skipToMatched(token);
|
||||
}
|
||||
}
|
||||
|
||||
static void makeTag(tokenInfo *const token, const goKind kind) {
|
||||
const char *const name = vStringValue(token->string);
|
||||
|
||||
tagEntryInfo e;
|
||||
initTagEntry(&e, name);
|
||||
|
||||
if (!GoKinds[kind].enabled) return;
|
||||
|
||||
e.lineNumber = token->lineNumber;
|
||||
e.filePosition = token->filePosition;
|
||||
e.kindName = GoKinds[kind].name;
|
||||
e.kind = GoKinds[kind].letter;
|
||||
|
||||
makeTagEntry(&e);
|
||||
|
||||
if (scope && Option.include.qualifiedTags) {
|
||||
vString *qualifiedName = vStringNew();
|
||||
vStringCopy(qualifiedName, scope);
|
||||
vStringCatS(qualifiedName, ".");
|
||||
vStringCat(qualifiedName, token->string);
|
||||
e.name = vStringValue(qualifiedName);
|
||||
makeTagEntry(&e);
|
||||
vStringDelete(qualifiedName);
|
||||
}
|
||||
}
|
||||
|
||||
static void parsePackage(tokenInfo *const token) {
|
||||
tokenInfo *const name = newToken();
|
||||
|
||||
readToken(name);
|
||||
Assert(isType(name, TOKEN_IDENTIFIER));
|
||||
makeTag(name, GOTAG_PACKAGE);
|
||||
if (!scope && Option.include.qualifiedTags) {
|
||||
scope = vStringNew();
|
||||
vStringCopy(scope, name->string);
|
||||
}
|
||||
|
||||
deleteToken(name);
|
||||
}
|
||||
|
||||
static void parseFunctionOrMethod(tokenInfo *const token) {
|
||||
// FunctionDecl = "func" identifier Signature [ Body ] .
|
||||
// Body = Block.
|
||||
//
|
||||
// MethodDecl = "func" Receiver MethodName Signature [ Body ] .
|
||||
// Receiver = "(" [ identifier ] [ "*" ] BaseTypeName ")" .
|
||||
// BaseTypeName = identifier .
|
||||
tokenInfo *const name = newToken();
|
||||
|
||||
// Skip over receiver.
|
||||
readToken(name);
|
||||
if (isType(name, TOKEN_OPEN_PAREN)) skipToMatched(name);
|
||||
|
||||
Assert(isType(name, TOKEN_IDENTIFIER));
|
||||
|
||||
// Skip over parameters.
|
||||
readToken(token);
|
||||
skipToMatched(token);
|
||||
|
||||
// Skip over result.
|
||||
skipType(token);
|
||||
|
||||
// Skip over function body.
|
||||
if (isType(token, TOKEN_OPEN_CURLY)) skipToMatched(token);
|
||||
|
||||
makeTag(name, GOTAG_FUNCTION);
|
||||
|
||||
deleteToken(name);
|
||||
}
|
||||
|
||||
static void parseConstTypeVar(tokenInfo *const token, goKind kind) {
|
||||
// ConstDecl = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) .
|
||||
// ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] .
|
||||
// IdentifierList = identifier { "," identifier } .
|
||||
// ExpressionList = Expression { "," Expression } .
|
||||
// TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) .
|
||||
// TypeSpec = identifier Type .
|
||||
// VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
|
||||
// VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "="
|
||||
// ExpressionList ) .
|
||||
tokenInfo *const name = newToken();
|
||||
boolean usesParens = FALSE;
|
||||
|
||||
readToken(name);
|
||||
|
||||
if (isType(name, TOKEN_OPEN_PAREN)) {
|
||||
usesParens = TRUE;
|
||||
readToken(name);
|
||||
}
|
||||
|
||||
again:
|
||||
while (1) {
|
||||
makeTag(name, kind);
|
||||
readToken(token);
|
||||
if (!isType(token, TOKEN_COMMA) && !isType(token, TOKEN_CLOSE_PAREN)) break;
|
||||
readToken(name);
|
||||
}
|
||||
|
||||
skipType(token);
|
||||
skipToTopLevelSemicolon(token);
|
||||
|
||||
if (usesParens) {
|
||||
readToken(name);
|
||||
if (!isType(name, TOKEN_CLOSE_PAREN)) goto again;
|
||||
}
|
||||
|
||||
deleteToken(name);
|
||||
}
|
||||
|
||||
static void parseGoFile(tokenInfo *const token) {
|
||||
do {
|
||||
readToken(token);
|
||||
|
||||
if (isType(token, TOKEN_KEYWORD)) {
|
||||
switch (token->keyword) {
|
||||
case KEYWORD_package:
|
||||
parsePackage(token);
|
||||
break;
|
||||
case KEYWORD_func:
|
||||
parseFunctionOrMethod(token);
|
||||
break;
|
||||
case KEYWORD_const:
|
||||
parseConstTypeVar(token, GOTAG_CONST);
|
||||
break;
|
||||
case KEYWORD_type:
|
||||
parseConstTypeVar(token, GOTAG_TYPE);
|
||||
break;
|
||||
case KEYWORD_var:
|
||||
parseConstTypeVar(token, GOTAG_VAR);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (TRUE);
|
||||
}
|
||||
|
||||
static void findGoTags(void) {
|
||||
tokenInfo *const token = newToken();
|
||||
exception_t exception;
|
||||
|
||||
exception = (exception_t)(setjmp(Exception));
|
||||
while (exception == ExceptionNone) parseGoFile(token);
|
||||
|
||||
deleteToken(token);
|
||||
vStringDelete(scope);
|
||||
scope = NULL;
|
||||
}
|
||||
|
||||
extern parserDefinition *GoParser(void) {
|
||||
static const char *const extensions[] = {"go", NULL};
|
||||
parserDefinition *def = parserNew("Go");
|
||||
def->kinds = GoKinds;
|
||||
def->kindCount = KIND_COUNT(GoKinds);
|
||||
def->extensions = extensions;
|
||||
def->parser = findGoTags;
|
||||
def->initialize = initialize;
|
||||
return def;
|
||||
}
|
||||
41
third_party/ctags/html.c
vendored
41
third_party/ctags/html.c
vendored
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* $Id: html.c 443 2006-05-30 04:37:13Z darren $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/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: */
|
||||
1496
third_party/ctags/jscript.c
vendored
1496
third_party/ctags/jscript.c
vendored
File diff suppressed because it is too large
Load Diff
222
third_party/ctags/keyword.c
vendored
222
third_party/ctags/keyword.c
vendored
@@ -1,222 +0,0 @@
|
||||
/*
|
||||
* $Id: keyword.c 715 2009-07-06 03:31:00Z dhiebert $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/debug.h"
|
||||
#include "third_party/ctags/keyword.h"
|
||||
#include "third_party/ctags/options.h"
|
||||
#include "third_party/ctags/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 *entry = getHashTableEntry(hashedValue);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
extern int analyzeToken(vString *const name, langType language) {
|
||||
vString *keyword = vStringNew();
|
||||
int result;
|
||||
vStringCopyToLower(keyword, name);
|
||||
result = lookupKeyword(vStringValue(keyword), language);
|
||||
vStringDelete(keyword);
|
||||
return result;
|
||||
}
|
||||
|
||||
#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: */
|
||||
18
third_party/ctags/keyword.h
vendored
18
third_party/ctags/keyword.h
vendored
@@ -1,18 +0,0 @@
|
||||
#ifndef _KEYWORD_H
|
||||
#define _KEYWORD_H
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/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
|
||||
extern int analyzeToken(vString *const name, langType language);
|
||||
|
||||
#endif /* _KEYWORD_H */
|
||||
110
third_party/ctags/lisp.c
vendored
110
third_party/ctags/lisp.c
vendored
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* $Id: lisp.c 717 2009-07-07 03:40:50Z dhiebert $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/parse.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/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", 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: */
|
||||
616
third_party/ctags/lregex.c
vendored
616
third_party/ctags/lregex.c
vendored
@@ -1,616 +0,0 @@
|
||||
/*
|
||||
* $Id: lregex.c 747 2009-11-06 02:33:37Z dhiebert $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/debug.h"
|
||||
#include "third_party/ctags/entry.h"
|
||||
#include "third_party/ctags/parse.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/routines.h"
|
||||
#include "third_party/regex/regex.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) {
|
||||
regexPattern* p = &set->patterns[i];
|
||||
#if defined(POSIX_REGEX)
|
||||
regfree(p->pattern);
|
||||
#endif
|
||||
eFree(p->pattern);
|
||||
p->pattern = NULL;
|
||||
|
||||
if (p->type == PTRN_TAG) {
|
||||
eFree(p->u.tag.name_pattern);
|
||||
p->u.tag.name_pattern = NULL;
|
||||
eFree(p->u.tag.kind.name);
|
||||
p->u.tag.kind.name = NULL;
|
||||
if (p->u.tag.kind.description != NULL) {
|
||||
eFree(p->u.tag.kind.description);
|
||||
p->u.tag.kind.description = 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, "regcomp %s: %s", regexp, 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, "%s", 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 \"%s\" in --%s option", (dash + 1),
|
||||
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 __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)
|
||||
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: */
|
||||
108
third_party/ctags/lua.c
vendored
108
third_party/ctags/lua.c
vendored
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* $Id: lua.c 443 2006-05-30 04:37:13Z darren $
|
||||
*
|
||||
* Copyright (c) 2000-2001, Max Ischenko <mfi@ukr.net>.
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/options.h"
|
||||
#include "third_party/ctags/parse.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/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: */
|
||||
478
third_party/ctags/main.c
vendored
478
third_party/ctags/main.c
vendored
@@ -1,478 +0,0 @@
|
||||
/*
|
||||
* $Id: main.c 536 2007-06-02 06:09:00Z elliotth $
|
||||
*
|
||||
* Copyright (c) 1996-2003, Darren Hiebert
|
||||
*
|
||||
* Author: Darren Hiebert <dhiebert@users.sourceforge.net>
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "libc/calls/struct/dirent.h"
|
||||
#include "libc/calls/weirdtypes.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "third_party/ctags/debug.h"
|
||||
#include "third_party/ctags/keyword.h"
|
||||
#include "third_party/ctags/main.h"
|
||||
#include "third_party/ctags/options.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/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 "third_party/ctags/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);
|
||||
|
||||
eStatFree(status);
|
||||
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: */
|
||||
15
third_party/ctags/main.h
vendored
15
third_party/ctags/main.h
vendored
@@ -1,15 +0,0 @@
|
||||
#ifndef _MAIN_H
|
||||
#define _MAIN_H
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/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 */
|
||||
175
third_party/ctags/make.c
vendored
175
third_party/ctags/make.c
vendored
@@ -1,175 +0,0 @@
|
||||
/*
|
||||
* $Id: make.c 751 2010-02-27 17:41:57Z elliotth $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/options.h"
|
||||
#include "third_party/ctags/parse.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/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' || c == EOF)
|
||||
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 {
|
||||
if (strcmp(vStringValue(name), "export") == 0 && isIdentifier(c)) {
|
||||
c = skipToNonWhite();
|
||||
readIdentifier(c, name);
|
||||
}
|
||||
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", "GNUmakefile", 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: */
|
||||
42
third_party/ctags/matlab.c
vendored
42
third_party/ctags/matlab.c
vendored
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2008, David Fishburn
|
||||
*
|
||||
* 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 MATLAB
|
||||
* language files.
|
||||
*/
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/parse.h"
|
||||
|
||||
/*
|
||||
* FUNCTION DEFINITIONS
|
||||
*/
|
||||
|
||||
static void installMatLabRegex(const langType language) {
|
||||
/* function [x,y,z] = asdf */
|
||||
addTagRegex(language, "^function[ \t]*\\[.*\\][ \t]*=[ \t]*([a-zA-Z0-9_]+)",
|
||||
"\\1", "f,function", NULL);
|
||||
/* function x = asdf */
|
||||
addTagRegex(language,
|
||||
"^function[ \t]*[a-zA-Z0-9_]+[ \t]*=[ \t]*([a-zA-Z0-9_]+)", "\\1",
|
||||
"f,function", NULL);
|
||||
/* function asdf */
|
||||
addTagRegex(language, "^function[ \t]*([a-zA-Z0-9_]+)[^=]*$", "\\1",
|
||||
"f,function", NULL);
|
||||
}
|
||||
|
||||
extern parserDefinition* MatLabParser() {
|
||||
static const char* const extensions[] = {"m", NULL};
|
||||
parserDefinition* const def = parserNew("MatLab");
|
||||
def->extensions = extensions;
|
||||
def->initialize = installMatLabRegex;
|
||||
def->regex = TRUE;
|
||||
return def;
|
||||
}
|
||||
|
||||
/* vi:set tabstop=4 shiftwidth=4: */
|
||||
1027
third_party/ctags/objc.c
vendored
1027
third_party/ctags/objc.c
vendored
File diff suppressed because it is too large
Load Diff
1713
third_party/ctags/ocaml.c
vendored
1713
third_party/ctags/ocaml.c
vendored
File diff suppressed because it is too large
Load Diff
1669
third_party/ctags/options.c
vendored
1669
third_party/ctags/options.c
vendored
File diff suppressed because it is too large
Load Diff
134
third_party/ctags/options.h
vendored
134
third_party/ctags/options.h
vendored
@@ -1,134 +0,0 @@
|
||||
#ifndef _OPTIONS_H
|
||||
#define _OPTIONS_H
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/args.h"
|
||||
#include "third_party/ctags/parse.h"
|
||||
#include "third_party/ctags/strlist.h"
|
||||
#include "third_party/ctags/vstring.h"
|
||||
|
||||
#if defined(OPTION_WRITE) || defined(VAXC)
|
||||
#define CONST_OPTION
|
||||
#else
|
||||
#define CONST_OPTION const
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
574
third_party/ctags/parse.c
vendored
574
third_party/ctags/parse.c
vendored
@@ -1,574 +0,0 @@
|
||||
/*
|
||||
* $Id: parse.c 597 2007-07-31 05:35:30Z dhiebert $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/debug.h"
|
||||
#include "third_party/ctags/entry.h"
|
||||
#include "third_party/ctags/main.h"
|
||||
#define OPTION_WRITE
|
||||
#include "third_party/ctags/options.h"
|
||||
#include "third_party/ctags/parsers.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/routines.h"
|
||||
#include "third_party/ctags/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));
|
||||
if (result == LANG_IGNORE)
|
||||
result = getNamedLanguage(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 \"%s\" in \"%s\" option",
|
||||
vStringValue(langName), 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: */
|
||||
125
third_party/ctags/parse.h
vendored
125
third_party/ctags/parse.h
vendored
@@ -1,125 +0,0 @@
|
||||
#ifndef _PARSE_H
|
||||
#define _PARSE_H
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/parsers.h"
|
||||
#include "third_party/ctags/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 */
|
||||
15
third_party/ctags/parsers.h
vendored
15
third_party/ctags/parsers.h
vendored
@@ -1,15 +0,0 @@
|
||||
#ifndef _PARSERS_H
|
||||
#define _PARSERS_H
|
||||
|
||||
/* Add the name of any new parser definition function here */
|
||||
#define PARSER_LIST \
|
||||
AntParser, AsmParser, AspParser, AwkParser, BasicParser, BetaParser, \
|
||||
CParser, CppParser, CsharpParser, CobolParser, DosBatchParser, \
|
||||
EiffelParser, ErlangParser, FlexParser, FortranParser, GoParser, \
|
||||
HtmlParser, JavaParser, JavaScriptParser, LispParser, LuaParser, \
|
||||
MakefileParser, MatLabParser, ObjcParser, OcamlParser, PascalParser, \
|
||||
PerlParser, PhpParser, PythonParser, RexxParser, RubyParser, \
|
||||
SchemeParser, ShParser, SlangParser, SmlParser, SqlParser, TclParser, \
|
||||
TexParser, VeraParser, VerilogParser, VhdlParser, VimParser, YaccParser
|
||||
|
||||
#endif /* _PARSERS_H */
|
||||
222
third_party/ctags/pascal.c
vendored
222
third_party/ctags/pascal.c
vendored
@@ -1,222 +0,0 @@
|
||||
/*
|
||||
* $Id: pascal.c 536 2007-06-02 06:09:00Z elliotth $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/entry.h"
|
||||
#include "third_party/ctags/parse.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/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 */
|
||||
}
|
||||
vStringDelete(name);
|
||||
}
|
||||
|
||||
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: */
|
||||
327
third_party/ctags/perl.c
vendored
327
third_party/ctags/perl.c
vendored
@@ -1,327 +0,0 @@
|
||||
/*
|
||||
* $Id: perl.c 601 2007-08-02 04:45:16Z perlguy0 $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/entry.h"
|
||||
#include "third_party/ctags/options.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/routines.h"
|
||||
#include "third_party/ctags/vstring.h"
|
||||
|
||||
#define TRACE_PERL_C 0
|
||||
#define TRACE \
|
||||
if (TRACE_PERL_C) printf("perl.c:%d: ", __LINE__), printf
|
||||
|
||||
/*
|
||||
* DATA DEFINITIONS
|
||||
*/
|
||||
typedef enum {
|
||||
K_NONE = -1,
|
||||
K_CONSTANT,
|
||||
K_FORMAT,
|
||||
K_LABEL,
|
||||
K_PACKAGE,
|
||||
K_SUBROUTINE,
|
||||
K_SUBROUTINE_DECLARATION
|
||||
} perlKind;
|
||||
|
||||
static kindOption PerlKinds[] = {
|
||||
{TRUE, 'c', "constant", "constants"},
|
||||
{TRUE, 'f', "format", "formats"},
|
||||
{TRUE, 'l', "label", "labels"},
|
||||
{TRUE, 'p', "package", "packages"},
|
||||
{TRUE, 's', "subroutine", "subroutines"},
|
||||
{FALSE, 'd', "subroutine declaration", "subroutine declarations"},
|
||||
};
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perl subroutine declaration may look like one of the following:
|
||||
*
|
||||
* sub abc;
|
||||
* sub abc :attr;
|
||||
* sub abc (proto);
|
||||
* sub abc (proto) :attr;
|
||||
*
|
||||
* Note that there may be more than one attribute. Attributes may
|
||||
* have things in parentheses (they look like arguments). Anything
|
||||
* inside of those parentheses goes. Prototypes may contain semi-colons.
|
||||
* The matching end when we encounter (outside of any parentheses) either
|
||||
* a semi-colon (that'd be a declaration) or an left curly brace
|
||||
* (definition).
|
||||
*
|
||||
* This is pretty complicated parsing (plus we all know that only perl can
|
||||
* parse Perl), so we are only promising best effort here.
|
||||
*
|
||||
* If we can't determine what this is (due to a file ending, for example),
|
||||
* we will return FALSE.
|
||||
*/
|
||||
static boolean isSubroutineDeclaration(const unsigned char *cp) {
|
||||
boolean attr = FALSE;
|
||||
int nparens = 0;
|
||||
|
||||
do {
|
||||
for (; *cp; ++cp) {
|
||||
SUB_DECL_SWITCH:
|
||||
switch (*cp) {
|
||||
case ':':
|
||||
if (nparens)
|
||||
break;
|
||||
else if (TRUE == attr)
|
||||
return FALSE; /* Invalid attribute name */
|
||||
else
|
||||
attr = TRUE;
|
||||
break;
|
||||
case '(':
|
||||
++nparens;
|
||||
break;
|
||||
case ')':
|
||||
--nparens;
|
||||
break;
|
||||
case ' ':
|
||||
case '\t':
|
||||
break;
|
||||
case ';':
|
||||
if (!nparens) return TRUE;
|
||||
case '{':
|
||||
if (!nparens) return FALSE;
|
||||
default:
|
||||
if (attr) {
|
||||
if (isIdentifier1(*cp)) {
|
||||
cp++;
|
||||
while (isIdentifier(*cp)) cp++;
|
||||
attr = FALSE;
|
||||
goto SUB_DECL_SWITCH; /* Instead of --cp; */
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
} else if (nparens) {
|
||||
break;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (NULL != (cp = fileReadLine()));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
tagEntryInfo e;
|
||||
|
||||
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) {
|
||||
TRACE("this looks like a sub\n");
|
||||
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) {
|
||||
/* This will point to space after 'package' so that a tag
|
||||
can be made */
|
||||
const unsigned char *space = 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, "::");
|
||||
|
||||
cp = space; /* Rewind */
|
||||
kind = K_PACKAGE;
|
||||
spaceRequired = TRUE;
|
||||
qualified = TRUE;
|
||||
} else if (strncmp((const char *)cp, "format", (size_t)6) == 0) {
|
||||
cp += 6;
|
||||
kind = K_FORMAT;
|
||||
spaceRequired = TRUE;
|
||||
qualified = TRUE;
|
||||
} else {
|
||||
if (isIdentifier1(*cp)) {
|
||||
const unsigned char *p = cp;
|
||||
while (isIdentifier(*p)) ++p;
|
||||
while (isspace(*p)) ++p;
|
||||
if ((int)*p == ':' && (int)*(p + 1) != ':') kind = K_LABEL;
|
||||
}
|
||||
}
|
||||
if (kind != K_NONE) {
|
||||
TRACE("cp0: %s\n", (const char *)cp);
|
||||
if (spaceRequired && *cp && !isspace(*cp)) continue;
|
||||
|
||||
TRACE("cp1: %s\n", (const char *)cp);
|
||||
while (isspace(*cp)) cp++;
|
||||
|
||||
while (!*cp || '#' == *cp) { /* Gobble up empty lines
|
||||
and comments */
|
||||
cp = fileReadLine();
|
||||
if (!cp) goto END_MAIN_WHILE;
|
||||
while (isspace(*cp)) cp++;
|
||||
}
|
||||
|
||||
while (isIdentifier(*cp) || (K_PACKAGE == kind && ':' == *cp)) {
|
||||
vStringPut(name, (int)*cp);
|
||||
cp++;
|
||||
}
|
||||
|
||||
if (K_FORMAT == kind &&
|
||||
vStringLength(name) == 0 && /* cp did not advance */
|
||||
'=' == *cp) {
|
||||
/* format's name is optional. If it's omitted, 'STDOUT'
|
||||
is assumed. */
|
||||
vStringCatS(name, "STDOUT");
|
||||
}
|
||||
|
||||
vStringTerminate(name);
|
||||
TRACE("name: %s\n", name->buffer);
|
||||
|
||||
if (0 == vStringLength(name)) {
|
||||
vStringClear(name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (K_SUBROUTINE == kind) {
|
||||
/*
|
||||
* isSubroutineDeclaration() may consume several lines. So
|
||||
* we record line positions.
|
||||
*/
|
||||
initTagEntry(&e, vStringValue(name));
|
||||
|
||||
if (TRUE == isSubroutineDeclaration(cp)) {
|
||||
if (TRUE == PerlKinds[K_SUBROUTINE_DECLARATION].enabled) {
|
||||
kind = K_SUBROUTINE_DECLARATION;
|
||||
} else {
|
||||
vStringClear(name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
e.kind = PerlKinds[kind].letter;
|
||||
e.kindName = PerlKinds[kind].name;
|
||||
|
||||
makeTagEntry(&e);
|
||||
|
||||
if (Option.include.qualifiedTags && qualified && package != NULL &&
|
||||
vStringLength(package) > 0) {
|
||||
vString *const qualifiedName = vStringNew();
|
||||
vStringCopy(qualifiedName, package);
|
||||
vStringCat(qualifiedName, name);
|
||||
e.name = vStringValue(qualifiedName);
|
||||
makeTagEntry(&e);
|
||||
vStringDelete(qualifiedName);
|
||||
}
|
||||
} else if (vStringLength(name) > 0) {
|
||||
makeSimpleTag(name, PerlKinds, kind);
|
||||
if (Option.include.qualifiedTags && qualified && K_PACKAGE != kind &&
|
||||
package != NULL && vStringLength(package) > 0) {
|
||||
vString *const qualifiedName = vStringNew();
|
||||
vStringCopy(qualifiedName, package);
|
||||
vStringCat(qualifiedName, name);
|
||||
makeSimpleTag(qualifiedName, PerlKinds, kind);
|
||||
vStringDelete(qualifiedName);
|
||||
}
|
||||
}
|
||||
vStringClear(name);
|
||||
}
|
||||
}
|
||||
|
||||
END_MAIN_WHILE:
|
||||
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 noexpandtab: */
|
||||
240
third_party/ctags/php.c
vendored
240
third_party/ctags/php.c
vendored
@@ -1,240 +0,0 @@
|
||||
/*
|
||||
* $Id: php.c 734 2009-08-20 23:33:54Z jafl $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/parse.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/vstring.h"
|
||||
|
||||
/*
|
||||
* DATA DEFINITIONS
|
||||
*/
|
||||
typedef enum { K_CLASS, K_DEFINE, K_FUNCTION, K_VARIABLE } phpKind;
|
||||
|
||||
#if 0
|
||||
static kindOption PhpKinds [] = {
|
||||
{ TRUE, 'c', "class", "classes" },
|
||||
{ TRUE, 'd', "define", "constant definitions" },
|
||||
{ TRUE, 'f', "function", "functions" },
|
||||
{ TRUE, 'v', "variable", "variables" }
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* FUNCTION DEFINITIONS
|
||||
*/
|
||||
|
||||
/* JavaScript patterns are duplicated in jscript.c */
|
||||
|
||||
/*
|
||||
* Cygwin doesn't support non-ASCII characters in character classes.
|
||||
* This isn't a good solution to the underlying problem, because we're still
|
||||
* making assumptions about the character encoding.
|
||||
* Really, these regular expressions need to concentrate on what marks the
|
||||
* end of an identifier, and we need something like iconv to take into
|
||||
* account the user's locale (or an override on the command-line.)
|
||||
*/
|
||||
#ifdef __CYGWIN__
|
||||
#define ALPHA "[:alpha:]"
|
||||
#define ALNUM "[:alnum:]"
|
||||
#else
|
||||
#define ALPHA "A-Za-z\x7f-\uffff"
|
||||
#define ALNUM "0-9A-Za-z\x7f-\uffff"
|
||||
#endif
|
||||
|
||||
static void installPHPRegex(const langType language) {
|
||||
addTagRegex(language,
|
||||
"^[ \t]*((final|abstract)[ \t]+)*class[ \t]+([" ALPHA "_][" ALNUM
|
||||
"_]*)",
|
||||
"\\3", "c,class,classes", NULL);
|
||||
addTagRegex(language, "^[ \t]*interface[ \t]+([" ALPHA "_][" ALNUM "_]*)",
|
||||
"\\1", "i,interface,interfaces", NULL);
|
||||
addTagRegex(language,
|
||||
"^[ \t]*define[ \t]*\\([ \t]*['\"]?([" ALPHA "_][" ALNUM "_]*)",
|
||||
"\\1", "d,define,constant definitions", NULL);
|
||||
addTagRegex(language,
|
||||
"^[ \t]*((static|public|protected|private)[ \t]+)*function[ "
|
||||
"\t]+&?[ \t]*([" ALPHA "_][" ALNUM "_]*)",
|
||||
"\\3", "f,function,functions", NULL);
|
||||
addTagRegex(language,
|
||||
"^[ \t]*(\\$|::\\$|\\$this->)([" ALPHA "_][" ALNUM "_]*)[ \t]*=",
|
||||
"\\2", "v,variable,variables", NULL);
|
||||
addTagRegex(language,
|
||||
"^[ \t]*((var|public|protected|private|static)[ \t]+)+\\$([" ALPHA
|
||||
"_][" ALNUM "_]*)[ \t]*[=;]",
|
||||
"\\3", "v,variable,variables", NULL);
|
||||
|
||||
/* function regex is covered by PHP regex */
|
||||
addTagRegex(language,
|
||||
"(^|[ \t])([A-Za-z0-9_]+)[ \t]*[=:][ \t]*function[ \t]*\\(",
|
||||
"\\2", "j,jsfunction,javascript functions", NULL);
|
||||
addTagRegex(language,
|
||||
"(^|[ \t])([A-Za-z0-9_.]+)\\.([A-Za-z0-9_]+)[ \t]*=[ "
|
||||
"\t]*function[ \t]*\\(",
|
||||
"\\2.\\3", "j,jsfunction,javascript functions", NULL);
|
||||
addTagRegex(language,
|
||||
"(^|[ \t])([A-Za-z0-9_.]+)\\.([A-Za-z0-9_]+)[ \t]*=[ "
|
||||
"\t]*function[ \t]*\\(",
|
||||
"\\3", "j,jsfunction,javascript functions", NULL);
|
||||
}
|
||||
|
||||
/* Create parser definition structure */
|
||||
extern parserDefinition* PhpParser(void) {
|
||||
static const char* const extensions[] = {"php", "php3", "phtml", NULL};
|
||||
parserDefinition* def = parserNew("PHP");
|
||||
def->extensions = extensions;
|
||||
def->initialize = installPHPRegex;
|
||||
def->regex = TRUE;
|
||||
return def;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
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;
|
||||
const char* f;
|
||||
|
||||
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 ((f = strstr ((const char*) cp, "function")) != NULL &&
|
||||
(f == (const char*) cp || isspace ((int) f [-1])) &&
|
||||
isspace ((int) f [8]))
|
||||
{
|
||||
cp = ((const unsigned char *) f) + 8;
|
||||
|
||||
while (isspace ((int) *cp))
|
||||
++cp;
|
||||
|
||||
if (*cp == '&') /* skip reference character and following whitespace */
|
||||
{
|
||||
cp++;
|
||||
|
||||
while (isspace ((int) *cp))
|
||||
++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;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* vi:set tabstop=4 shiftwidth=4: */
|
||||
668
third_party/ctags/python.c
vendored
668
third_party/ctags/python.c
vendored
@@ -1,668 +0,0 @@
|
||||
/*
|
||||
* $Id: python.c 752 2010-02-27 17:52:46Z elliotth $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "libc/mem/mem.h"
|
||||
#include "third_party/ctags/debug.h"
|
||||
#include "third_party/ctags/entry.h"
|
||||
#include "third_party/ctags/main.h"
|
||||
#include "third_party/ctags/options.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/routines.h"
|
||||
#include "third_party/ctags/vstring.h"
|
||||
|
||||
/*
|
||||
* DATA DECLARATIONS
|
||||
*/
|
||||
typedef struct NestingLevel NestingLevel;
|
||||
typedef struct NestingLevels NestingLevels;
|
||||
|
||||
struct NestingLevel {
|
||||
int indentation;
|
||||
vString *name;
|
||||
int type;
|
||||
};
|
||||
|
||||
struct NestingLevels {
|
||||
NestingLevel *levels;
|
||||
int n; /* number of levels in use */
|
||||
int allocated;
|
||||
};
|
||||
|
||||
typedef enum { K_CLASS, K_FUNCTION, K_MEMBER, K_VARIABLE, K_IMPORT } pythonKind;
|
||||
|
||||
/*
|
||||
* DATA DEFINITIONS
|
||||
*/
|
||||
static kindOption PythonKinds[] = {{TRUE, 'c', "class", "classes"},
|
||||
{TRUE, 'f', "function", "functions"},
|
||||
{TRUE, 'm', "member", "class members"},
|
||||
{TRUE, 'v', "variable", "variables"},
|
||||
{FALSE, 'i', "namespace", "imports"}};
|
||||
|
||||
static char const *const singletriple = "'''";
|
||||
static char const *const doubletriple = "\"\"\"";
|
||||
|
||||
/*
|
||||
* FUNCTION DEFINITIONS
|
||||
*/
|
||||
|
||||
static NestingLevels *nestingLevelsNew(void) {
|
||||
NestingLevels *nls = xCalloc(1, NestingLevels);
|
||||
return nls;
|
||||
}
|
||||
|
||||
static void nestingLevelsFree(NestingLevels *nls) {
|
||||
int i;
|
||||
for (i = 0; i < nls->allocated; i++) vStringDelete(nls->levels[i].name);
|
||||
if (nls->levels) eFree(nls->levels);
|
||||
eFree(nls);
|
||||
}
|
||||
|
||||
static void nestingLevelsPush(NestingLevels *nls, const vString *name,
|
||||
int type) {
|
||||
NestingLevel *nl = NULL;
|
||||
|
||||
if (nls->n >= nls->allocated) {
|
||||
nls->allocated++;
|
||||
nls->levels = xRealloc(nls->levels, nls->allocated, NestingLevel);
|
||||
nls->levels[nls->n].name = vStringNew();
|
||||
}
|
||||
nl = &nls->levels[nls->n];
|
||||
nls->n++;
|
||||
|
||||
vStringCopy(nl->name, name);
|
||||
nl->type = type;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static NestingLevel *nestingLevelsGetCurrent (NestingLevels *nls)
|
||||
{
|
||||
Assert (nls != NULL);
|
||||
|
||||
if (nls->n < 1)
|
||||
return NULL;
|
||||
|
||||
return &nls->levels[nls->n - 1];
|
||||
}
|
||||
|
||||
static void nestingLevelsPop (NestingLevels *nls)
|
||||
{
|
||||
const NestingLevel *nl = nestingLevelsGetCurrent(nls);
|
||||
|
||||
Assert (nl != NULL);
|
||||
vStringClear(nl->name);
|
||||
nls->n--;
|
||||
}
|
||||
#endif
|
||||
|
||||
static boolean isIdentifierFirstCharacter(int c) {
|
||||
return (boolean)(isalpha(c) || c == '_');
|
||||
}
|
||||
|
||||
static boolean isIdentifierCharacter(int c) {
|
||||
return (boolean)(isalnum(c) || c == '_');
|
||||
}
|
||||
|
||||
/* Given a string with the contents of a line directly after the "def" keyword,
|
||||
* extract all relevant information and create a tag.
|
||||
*/
|
||||
static void makeFunctionTag(vString *const function, vString *const parent,
|
||||
int is_class_parent,
|
||||
const char *arglist __unused__) {
|
||||
tagEntryInfo tag;
|
||||
initTagEntry(&tag, vStringValue(function));
|
||||
|
||||
tag.kindName = "function";
|
||||
tag.kind = 'f';
|
||||
/* tag.extensionFields.arglist = arglist; */
|
||||
|
||||
if (vStringLength(parent) > 0) {
|
||||
if (is_class_parent) {
|
||||
tag.kindName = "member";
|
||||
tag.kind = 'm';
|
||||
tag.extensionFields.scope[0] = "class";
|
||||
tag.extensionFields.scope[1] = vStringValue(parent);
|
||||
} else {
|
||||
tag.extensionFields.scope[0] = "function";
|
||||
tag.extensionFields.scope[1] = vStringValue(parent);
|
||||
}
|
||||
}
|
||||
|
||||
/* If a function starts with __, we mark it as file scope.
|
||||
* FIXME: What is the proper way to signal such attributes?
|
||||
* TODO: What does functions/classes starting with _ and __ mean in python?
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/* Given a string with the contents of the line directly after the "class"
|
||||
* keyword, extract all necessary information and create a tag.
|
||||
*/
|
||||
static void makeClassTag(vString *const class, vString *const inheritance,
|
||||
vString *const parent, int is_class_parent) {
|
||||
tagEntryInfo tag;
|
||||
initTagEntry(&tag, vStringValue(class));
|
||||
tag.kindName = "class";
|
||||
tag.kind = 'c';
|
||||
if (vStringLength(parent) > 0) {
|
||||
if (is_class_parent) {
|
||||
tag.extensionFields.scope[0] = "class";
|
||||
tag.extensionFields.scope[1] = vStringValue(parent);
|
||||
} else {
|
||||
tag.extensionFields.scope[0] = "function";
|
||||
tag.extensionFields.scope[1] = vStringValue(parent);
|
||||
}
|
||||
}
|
||||
tag.extensionFields.inheritance = vStringValue(inheritance);
|
||||
makeTagEntry(&tag);
|
||||
}
|
||||
|
||||
static void makeVariableTag(vString *const var, vString *const parent) {
|
||||
tagEntryInfo tag;
|
||||
initTagEntry(&tag, vStringValue(var));
|
||||
tag.kindName = "variable";
|
||||
tag.kind = 'v';
|
||||
if (vStringLength(parent) > 0) {
|
||||
tag.extensionFields.scope[0] = "class";
|
||||
tag.extensionFields.scope[1] = vStringValue(parent);
|
||||
}
|
||||
makeTagEntry(&tag);
|
||||
}
|
||||
|
||||
/* Skip a single or double quoted string. */
|
||||
static const char *skipString(const char *cp) {
|
||||
const char *start = cp;
|
||||
int escaped = 0;
|
||||
for (cp++; *cp; cp++) {
|
||||
if (escaped)
|
||||
escaped--;
|
||||
else if (*cp == '\\')
|
||||
escaped++;
|
||||
else if (*cp == *start)
|
||||
return cp + 1;
|
||||
}
|
||||
return cp;
|
||||
}
|
||||
|
||||
/* Skip everything up to an identifier start. */
|
||||
static const char *skipEverything(const char *cp) {
|
||||
for (; *cp; cp++) {
|
||||
if (*cp == '"' || *cp == '\'' || *cp == '#') {
|
||||
cp = skipString(cp);
|
||||
if (!*cp) break;
|
||||
}
|
||||
if (isIdentifierFirstCharacter((int)*cp)) return cp;
|
||||
}
|
||||
return cp;
|
||||
}
|
||||
|
||||
/* Skip an identifier. */
|
||||
static const char *skipIdentifier(const char *cp) {
|
||||
while (isIdentifierCharacter((int)*cp)) cp++;
|
||||
return cp;
|
||||
}
|
||||
|
||||
static const char *findDefinitionOrClass(const char *cp) {
|
||||
while (*cp) {
|
||||
cp = skipEverything(cp);
|
||||
if (!strncmp(cp, "def", 3) || !strncmp(cp, "class", 5) ||
|
||||
!strncmp(cp, "cdef", 4) || !strncmp(cp, "cpdef", 5)) {
|
||||
return cp;
|
||||
}
|
||||
cp = skipIdentifier(cp);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *skipSpace(const char *cp) {
|
||||
while (isspace((int)*cp)) ++cp;
|
||||
return cp;
|
||||
}
|
||||
|
||||
/* Starting at ''cp'', parse an identifier into ''identifier''. */
|
||||
static const char *parseIdentifier(const char *cp, vString *const identifier) {
|
||||
vStringClear(identifier);
|
||||
while (isIdentifierCharacter((int)*cp)) {
|
||||
vStringPut(identifier, (int)*cp);
|
||||
++cp;
|
||||
}
|
||||
vStringTerminate(identifier);
|
||||
return cp;
|
||||
}
|
||||
|
||||
static void parseClass(const char *cp, vString *const class,
|
||||
vString *const parent, int is_class_parent) {
|
||||
vString *const inheritance = vStringNew();
|
||||
vStringClear(inheritance);
|
||||
cp = parseIdentifier(cp, class);
|
||||
cp = skipSpace(cp);
|
||||
if (*cp == '(') {
|
||||
++cp;
|
||||
while (*cp != ')') {
|
||||
if (*cp == '\0') {
|
||||
/* Closing parenthesis can be in follow up line. */
|
||||
cp = (const char *)fileReadLine();
|
||||
if (!cp) break;
|
||||
vStringPut(inheritance, ' ');
|
||||
continue;
|
||||
}
|
||||
vStringPut(inheritance, *cp);
|
||||
++cp;
|
||||
}
|
||||
vStringTerminate(inheritance);
|
||||
}
|
||||
makeClassTag(class, inheritance, parent, is_class_parent);
|
||||
vStringDelete(inheritance);
|
||||
}
|
||||
|
||||
static void parseImports(const char *cp) {
|
||||
const char *pos;
|
||||
vString *name, *name_next;
|
||||
|
||||
cp = skipEverything(cp);
|
||||
|
||||
if ((pos = strstr(cp, "import")) == NULL) return;
|
||||
|
||||
cp = pos + 6;
|
||||
|
||||
/* continue only if there is some space between the keyword and the identifier
|
||||
*/
|
||||
if (!isspace(*cp)) return;
|
||||
|
||||
cp++;
|
||||
cp = skipSpace(cp);
|
||||
|
||||
name = vStringNew();
|
||||
name_next = vStringNew();
|
||||
|
||||
cp = skipEverything(cp);
|
||||
while (*cp) {
|
||||
cp = parseIdentifier(cp, name);
|
||||
|
||||
cp = skipEverything(cp);
|
||||
/* we parse the next possible import statement as well to be able to ignore
|
||||
* 'foo' in 'import foo as bar' */
|
||||
parseIdentifier(cp, name_next);
|
||||
|
||||
/* take the current tag only if the next one is not "as" */
|
||||
if (strcmp(vStringValue(name_next), "as") != 0 &&
|
||||
strcmp(vStringValue(name), "as") != 0) {
|
||||
makeSimpleTag(name, PythonKinds, K_IMPORT);
|
||||
}
|
||||
}
|
||||
vStringDelete(name);
|
||||
vStringDelete(name_next);
|
||||
}
|
||||
|
||||
/* modified from get.c getArglistFromStr().
|
||||
* warning: terminates rest of string past arglist!
|
||||
* note: does not ignore brackets inside strings! */
|
||||
static char *parseArglist(const char *buf) {
|
||||
char *start, *end;
|
||||
int level;
|
||||
if (NULL == buf) return NULL;
|
||||
if (NULL == (start = strchr(buf, '('))) return NULL;
|
||||
for (level = 1, end = start + 1; level > 0; ++end) {
|
||||
if ('\0' == *end)
|
||||
break;
|
||||
else if ('(' == *end)
|
||||
++level;
|
||||
else if (')' == *end)
|
||||
--level;
|
||||
}
|
||||
*end = '\0';
|
||||
return strdup(start);
|
||||
}
|
||||
|
||||
static void parseFunction(const char *cp, vString *const def,
|
||||
vString *const parent, int is_class_parent) {
|
||||
char *arglist;
|
||||
|
||||
cp = parseIdentifier(cp, def);
|
||||
arglist = parseArglist(cp);
|
||||
makeFunctionTag(def, parent, is_class_parent, arglist);
|
||||
if (arglist != NULL) {
|
||||
eFree(arglist);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the combined name of a nested symbol. Classes are separated with ".",
|
||||
* functions with "/". For example this code:
|
||||
* class MyClass:
|
||||
* def myFunction:
|
||||
* def SubFunction:
|
||||
* class SubClass:
|
||||
* def Method:
|
||||
* pass
|
||||
* Would produce this string:
|
||||
* MyClass.MyFunction/SubFunction/SubClass.Method
|
||||
*/
|
||||
static boolean constructParentString(NestingLevels *nls, int indent,
|
||||
vString *result) {
|
||||
int i;
|
||||
NestingLevel *prev = NULL;
|
||||
int is_class = FALSE;
|
||||
vStringClear(result);
|
||||
for (i = 0; i < nls->n; i++) {
|
||||
NestingLevel *nl = nls->levels + i;
|
||||
if (indent <= nl->indentation) break;
|
||||
if (prev) {
|
||||
vStringCatS(result,
|
||||
"."); /* make Geany symbol list grouping work properly */
|
||||
/*
|
||||
if (prev->type == K_CLASS)
|
||||
vStringCatS(result, ".");
|
||||
else
|
||||
vStringCatS(result, "/");
|
||||
*/
|
||||
}
|
||||
vStringCat(result, nl->name);
|
||||
is_class = (nl->type == K_CLASS);
|
||||
prev = nl;
|
||||
}
|
||||
return is_class;
|
||||
}
|
||||
|
||||
/* Check whether parent's indentation level is higher than the current level and
|
||||
* if so, remove it.
|
||||
*/
|
||||
static void checkParent(NestingLevels *nls, int indent, vString *parent) {
|
||||
int i;
|
||||
NestingLevel *n;
|
||||
|
||||
for (i = 0; i < nls->n; i++) {
|
||||
n = nls->levels + i;
|
||||
/* is there a better way to compare two vStrings? */
|
||||
if (strcmp(vStringValue(parent), vStringValue(n->name)) == 0) {
|
||||
if (n && indent <= n->indentation) {
|
||||
/* remove this level by clearing its name */
|
||||
vStringClear(n->name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void addNestingLevel(NestingLevels *nls, int indentation,
|
||||
const vString *name, boolean is_class) {
|
||||
int i;
|
||||
NestingLevel *nl = NULL;
|
||||
|
||||
for (i = 0; i < nls->n; i++) {
|
||||
nl = nls->levels + i;
|
||||
if (indentation <= nl->indentation) break;
|
||||
}
|
||||
if (i == nls->n) {
|
||||
nestingLevelsPush(nls, name, 0);
|
||||
nl = nls->levels + i;
|
||||
} else { /* reuse existing slot */
|
||||
nls->n = i + 1;
|
||||
vStringCopy(nl->name, name);
|
||||
}
|
||||
nl->indentation = indentation;
|
||||
nl->type = is_class ? K_CLASS : !K_CLASS;
|
||||
}
|
||||
|
||||
/* Return a pointer to the start of the next triple string, or NULL. Store
|
||||
* the kind of triple string in "which" if the return is not NULL.
|
||||
*/
|
||||
static char const *find_triple_start(char const *string, char const **which) {
|
||||
char const *cp = string;
|
||||
|
||||
for (; *cp; cp++) {
|
||||
if (*cp == '"' || *cp == '\'') {
|
||||
if (strncmp(cp, doubletriple, 3) == 0) {
|
||||
*which = doubletriple;
|
||||
return cp;
|
||||
}
|
||||
if (strncmp(cp, singletriple, 3) == 0) {
|
||||
*which = singletriple;
|
||||
return cp;
|
||||
}
|
||||
cp = skipString(cp);
|
||||
if (!*cp) break;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find the end of a triple string as pointed to by "which", and update "which"
|
||||
* with any other triple strings following in the given string.
|
||||
*/
|
||||
static void find_triple_end(char const *string, char const **which) {
|
||||
char const *s = string;
|
||||
while (1) {
|
||||
/* Check if the string ends in the same line. */
|
||||
s = strstr(s, *which);
|
||||
if (!s) break;
|
||||
s += 3;
|
||||
*which = NULL;
|
||||
/* If yes, check if another one starts in the same line. */
|
||||
s = find_triple_start(s, which);
|
||||
if (!s) break;
|
||||
s += 3;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *findVariable(const char *line) {
|
||||
/* Parse global and class variable names (C.x) from assignment statements.
|
||||
* Object attributes (obj.x) are ignored.
|
||||
* Assignment to a tuple 'x, y = 2, 3' not supported.
|
||||
* TODO: ignore duplicate tags from reassignment statements. */
|
||||
const char *cp, *sp, *eq, *start;
|
||||
|
||||
cp = strstr(line, "=");
|
||||
if (!cp) return NULL;
|
||||
eq = cp + 1;
|
||||
while (*eq) {
|
||||
if (*eq == '=')
|
||||
return NULL; /* ignore '==' operator and 'x=5,y=6)' function lines */
|
||||
if (*eq == '(' || *eq == '#')
|
||||
break; /* allow 'x = func(b=2,y=2,' lines and comments at the end of line
|
||||
*/
|
||||
eq++;
|
||||
}
|
||||
|
||||
/* go backwards to the start of the line, checking we have valid chars */
|
||||
start = cp - 1;
|
||||
while (start >= line && isspace((int)*start)) --start;
|
||||
while (start >= line && isIdentifierCharacter((int)*start)) --start;
|
||||
if (!isIdentifierFirstCharacter(*(start + 1))) return NULL;
|
||||
sp = start;
|
||||
while (sp >= line && isspace((int)*sp)) --sp;
|
||||
if ((sp + 1) != line) /* the line isn't a simple variable assignment */
|
||||
return NULL;
|
||||
/* the line is valid, parse the variable name */
|
||||
++start;
|
||||
return start;
|
||||
}
|
||||
|
||||
/* Skip type declaration that optionally follows a cdef/cpdef */
|
||||
static const char *skipTypeDecl(const char *cp, boolean *is_class) {
|
||||
const char *lastStart = cp, *ptr = cp;
|
||||
int loopCount = 0;
|
||||
ptr = skipSpace(cp);
|
||||
if (!strncmp("extern", ptr, 6)) {
|
||||
ptr += 6;
|
||||
ptr = skipSpace(ptr);
|
||||
if (!strncmp("from", ptr, 4)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (!strncmp("class", ptr, 5)) {
|
||||
ptr += 5;
|
||||
*is_class = TRUE;
|
||||
ptr = skipSpace(ptr);
|
||||
return ptr;
|
||||
}
|
||||
/* limit so that we don't pick off "int item=obj()" */
|
||||
while (*ptr && loopCount++ < 2) {
|
||||
while (*ptr && *ptr != '=' && *ptr != '(' && !isspace(*ptr)) ptr++;
|
||||
if (!*ptr || *ptr == '=') return NULL;
|
||||
if (*ptr == '(') {
|
||||
return lastStart; /* if we stopped on a '(' we are done */
|
||||
}
|
||||
ptr = skipSpace(ptr);
|
||||
lastStart = ptr;
|
||||
while (*lastStart == '*') lastStart++; /* cdef int *identifier */
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void findPythonTags(void) {
|
||||
vString *const continuation = vStringNew();
|
||||
vString *const name = vStringNew();
|
||||
vString *const parent = vStringNew();
|
||||
|
||||
NestingLevels *const nesting_levels = nestingLevelsNew();
|
||||
|
||||
const char *line;
|
||||
int line_skip = 0;
|
||||
char const *longStringLiteral = NULL;
|
||||
|
||||
while ((line = (const char *)fileReadLine()) != NULL) {
|
||||
const char *cp = line, *candidate;
|
||||
char const *longstring;
|
||||
char const *keyword, *variable;
|
||||
int indent;
|
||||
|
||||
cp = skipSpace(cp);
|
||||
|
||||
if (*cp == '\0') /* skip blank line */
|
||||
continue;
|
||||
|
||||
/* Skip comment if we are not inside a multi-line string. */
|
||||
if (*cp == '#' && !longStringLiteral) continue;
|
||||
|
||||
/* Deal with line continuation. */
|
||||
if (!line_skip) vStringClear(continuation);
|
||||
vStringCatS(continuation, line);
|
||||
vStringStripTrailing(continuation);
|
||||
if (vStringLast(continuation) == '\\') {
|
||||
vStringChop(continuation);
|
||||
vStringCatS(continuation, " ");
|
||||
line_skip = 1;
|
||||
continue;
|
||||
}
|
||||
cp = line = vStringValue(continuation);
|
||||
cp = skipSpace(cp);
|
||||
indent = cp - line;
|
||||
line_skip = 0;
|
||||
|
||||
checkParent(nesting_levels, indent, parent);
|
||||
|
||||
/* Deal with multiline string ending. */
|
||||
if (longStringLiteral) {
|
||||
find_triple_end(cp, &longStringLiteral);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Deal with multiline string start. */
|
||||
longstring = find_triple_start(cp, &longStringLiteral);
|
||||
if (longstring) {
|
||||
longstring += 3;
|
||||
find_triple_end(longstring, &longStringLiteral);
|
||||
/* We don't parse for any tags in the rest of the line. */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Deal with def and class keywords. */
|
||||
keyword = findDefinitionOrClass(cp);
|
||||
if (keyword) {
|
||||
boolean found = FALSE;
|
||||
boolean is_class = FALSE;
|
||||
if (!strncmp(keyword, "def ", 4)) {
|
||||
cp = skipSpace(keyword + 3);
|
||||
found = TRUE;
|
||||
} else if (!strncmp(keyword, "class ", 6)) {
|
||||
cp = skipSpace(keyword + 5);
|
||||
found = TRUE;
|
||||
is_class = TRUE;
|
||||
} else if (!strncmp(keyword, "cdef ", 5)) {
|
||||
cp = skipSpace(keyword + 4);
|
||||
candidate = skipTypeDecl(cp, &is_class);
|
||||
if (candidate) {
|
||||
found = TRUE;
|
||||
cp = candidate;
|
||||
}
|
||||
|
||||
} else if (!strncmp(keyword, "cpdef ", 6)) {
|
||||
cp = skipSpace(keyword + 5);
|
||||
candidate = skipTypeDecl(cp, &is_class);
|
||||
if (candidate) {
|
||||
found = TRUE;
|
||||
cp = candidate;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
boolean is_parent_class;
|
||||
|
||||
is_parent_class = constructParentString(nesting_levels, indent, parent);
|
||||
|
||||
if (is_class)
|
||||
parseClass(cp, name, parent, is_parent_class);
|
||||
else
|
||||
parseFunction(cp, name, parent, is_parent_class);
|
||||
|
||||
addNestingLevel(nesting_levels, indent, name, is_class);
|
||||
}
|
||||
}
|
||||
/* Find global and class variables */
|
||||
variable = findVariable(line);
|
||||
if (variable) {
|
||||
const char *start = variable;
|
||||
boolean parent_is_class;
|
||||
|
||||
vStringClear(name);
|
||||
while (isIdentifierCharacter((int)*start)) {
|
||||
vStringPut(name, (int)*start);
|
||||
++start;
|
||||
}
|
||||
vStringTerminate(name);
|
||||
|
||||
parent_is_class = constructParentString(nesting_levels, indent, parent);
|
||||
/* skip variables in methods */
|
||||
if (!parent_is_class && vStringLength(parent) > 0) continue;
|
||||
|
||||
makeVariableTag(name, parent);
|
||||
}
|
||||
/* Find and parse imports */
|
||||
parseImports(line);
|
||||
}
|
||||
/* Clean up all memory we allocated. */
|
||||
vStringDelete(parent);
|
||||
vStringDelete(name);
|
||||
vStringDelete(continuation);
|
||||
nestingLevelsFree(nesting_levels);
|
||||
}
|
||||
|
||||
extern parserDefinition *PythonParser(void) {
|
||||
static const char *const extensions[] = {"py", "pyx", "pxd",
|
||||
"pxi", "scons", 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: */
|
||||
473
third_party/ctags/read.c
vendored
473
third_party/ctags/read.c
vendored
@@ -1,473 +0,0 @@
|
||||
/*
|
||||
* $Id: read.c 769 2010-09-11 21:00:16Z dhiebert $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#define FILE_WRITE
|
||||
#include "third_party/ctags/debug.h"
|
||||
#include "third_party/ctags/entry.h"
|
||||
#include "third_party/ctags/main.h"
|
||||
#include "third_party/ctags/options.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/routines.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) {
|
||||
if (File.name != NULL) vStringDelete(File.name);
|
||||
if (File.path != NULL) vStringDelete(File.path);
|
||||
if (File.source.name != NULL) vStringDelete(File.source.name);
|
||||
if (File.source.tagPath != NULL) eFree(File.source.tagPath);
|
||||
if (File.line != NULL) 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.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/Mac OS X), CR (Mac OS 9),
|
||||
* and CR-LF (MS-DOS) are converted into a generic newline.
|
||||
*/
|
||||
#ifndef macintosh
|
||||
const int next = getc(File.fp); /* is CR followed by LF? */
|
||||
if (next != NEWLINE)
|
||||
ungetc(next, File.fp);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
extern int fileSkipToCharacter(int c) {
|
||||
int d;
|
||||
do {
|
||||
d = fileGetc();
|
||||
} while (d != EOF && d != c);
|
||||
return d;
|
||||
}
|
||||
|
||||
/* 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: */
|
||||
98
third_party/ctags/read.h
vendored
98
third_party/ctags/read.h
vendored
@@ -1,98 +0,0 @@
|
||||
#ifndef _READ_H
|
||||
#define _READ_H
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "third_party/ctags/parse.h"
|
||||
#include "third_party/ctags/vstring.h"
|
||||
|
||||
#if defined(FILE_WRITE) || defined(VAXC)
|
||||
#define CONST_FILE
|
||||
#else
|
||||
#define CONST_FILE const
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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? */
|
||||
|
||||
/* 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 int fileSkipToCharacter(int c);
|
||||
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 */
|
||||
805
third_party/ctags/readtags.c
vendored
805
third_party/ctags/readtags.c
vendored
@@ -1,805 +0,0 @@
|
||||
/*
|
||||
* $Id: readtags.c 592 2007-07-31 03:30:41Z dhiebert $
|
||||
*
|
||||
* Copyright (c) 1996-2003, Darren Hiebert
|
||||
*
|
||||
* This source code is released into the public domain.
|
||||
*
|
||||
* This module contains functions for reading tag files.
|
||||
*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/weirdtypes.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/ctags/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 */
|
||||
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 = (unsigned short)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);
|
||||
|
||||
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) {
|
||||
int fieldsPresent;
|
||||
*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 = strdup(str);
|
||||
if (result == NULL) perror(NULL);
|
||||
}
|
||||
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 = (short)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 *)calloc((size_t)1, sizeof(tagFile));
|
||||
if (result != NULL) {
|
||||
growString(&result->line);
|
||||
growString(&result->name);
|
||||
result->fields.max = 20;
|
||||
result->fields.list = (tagExtensionField *)calloc(
|
||||
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);
|
||||
if (file->search.name != NULL) free(file->search.name);
|
||||
|
||||
memset(file, 0, sizeof(tagFile));
|
||||
|
||||
free(file);
|
||||
}
|
||||
|
||||
static tagResult readNext(tagFile *const file, tagEntry *const entry) {
|
||||
tagResult result;
|
||||
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;
|
||||
if (file->search.name != NULL) free(file->search.name);
|
||||
file->search.name = duplicate(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;
|
||||
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: */
|
||||
224
third_party/ctags/readtags.h
vendored
224
third_party/ctags/readtags.h
vendored
@@ -1,224 +0,0 @@
|
||||
#ifndef COSMOPOLITAN_THIRD_PARTY_CTAGS_READTAGS_H_
|
||||
#define COSMOPOLITAN_THIRD_PARTY_CTAGS_READTAGS_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_THIRD_PARTY_CTAGS_READTAGS_H_ */
|
||||
34
third_party/ctags/rexx.c
vendored
34
third_party/ctags/rexx.c
vendored
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* $Id: rexx.c 443 2006-05-30 04:37:13Z darren $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* always include first */
|
||||
#include "third_party/ctags/parse.h"
|
||||
|
||||
/*
|
||||
* 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: */
|
||||
756
third_party/ctags/routines.c
vendored
756
third_party/ctags/routines.c
vendored
@@ -1,756 +0,0 @@
|
||||
/*
|
||||
* $Id: routines.c 536 2007-06-02 06:09:00Z elliotth $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/temp.h"
|
||||
#include "third_party/ctags/debug.h"
|
||||
#include "third_party/ctags/routines.h"
|
||||
|
||||
/*
|
||||
* 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 const char *getExecutablePath(void) {
|
||||
return ExecutableProgram;
|
||||
}
|
||||
|
||||
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) {
|
||||
eStatFree(&file);
|
||||
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 void eStatFree(fileStatus *status) {
|
||||
if (status->name != NULL) {
|
||||
eFree(status->name);
|
||||
status->name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
memmove(cp, slashp + 3, strlen(slashp + 3) + 1);
|
||||
slashp = cp;
|
||||
continue;
|
||||
} else if (slashp[2] == PATH_SEPARATOR || slashp[2] == '\0') {
|
||||
memmove(slashp, slashp + 2, strlen(slashp + 2) + 1);
|
||||
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);
|
||||
eStatFree(file);
|
||||
#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: */
|
||||
125
third_party/ctags/routines.h
vendored
125
third_party/ctags/routines.h
vendored
@@ -1,125 +0,0 @@
|
||||
#ifndef _ROUTINES_H
|
||||
#define _ROUTINES_H
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "third_party/ctags/vstring.h"
|
||||
|
||||
/*
|
||||
* 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 const char *getExecutablePath(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 void eStatFree(fileStatus *status);
|
||||
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: */
|
||||
344
third_party/ctags/ruby.c
vendored
344
third_party/ctags/ruby.c
vendored
@@ -1,344 +0,0 @@
|
||||
/*
|
||||
* $Id: ruby.c 571 2007-06-24 23:32:14Z elliotth $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/entry.h"
|
||||
#include "third_party/ctags/parse.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/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 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 == '"') {
|
||||
/* Skip string literals.
|
||||
* FIXME: should cope with escapes and interpolation.
|
||||
*/
|
||||
do {
|
||||
++cp;
|
||||
} while (*cp != 0 && *cp != '"');
|
||||
} 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: */
|
||||
90
third_party/ctags/scheme.c
vendored
90
third_party/ctags/scheme.c
vendored
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* $Id: scheme.c 443 2006-05-30 04:37:13Z darren $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/parse.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/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: */
|
||||
87
third_party/ctags/sh.c
vendored
87
third_party/ctags/sh.c
vendored
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* $Id: sh.c 443 2006-05-30 04:37:13Z darren $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/parse.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/routines.h"
|
||||
#include "third_party/ctags/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
third_party/ctags/slang.c
vendored
41
third_party/ctags/slang.c
vendored
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* $Id: slang.c 443 2006-05-30 04:37:13Z darren $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h" /* must always come first */
|
||||
#include "third_party/ctags/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;
|
||||
}
|
||||
175
third_party/ctags/sml.c
vendored
175
third_party/ctags/sml.c
vendored
@@ -1,175 +0,0 @@
|
||||
/*
|
||||
* $Id: sml.c 536 2007-06-02 06:09:00Z elliotth $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/entry.h"
|
||||
#include "third_party/ctags/parse.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/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;
|
||||
}
|
||||
vStringDelete(identifier);
|
||||
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: */
|
||||
196
third_party/ctags/sort.c
vendored
196
third_party/ctags/sort.c
vendored
@@ -1,196 +0,0 @@
|
||||
/*
|
||||
* $Id: sort.c 747 2009-11-06 02:33:37Z dhiebert $
|
||||
*
|
||||
* 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 "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "third_party/ctags/debug.h"
|
||||
#include "third_party/ctags/entry.h"
|
||||
#include "third_party/ctags/options.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/routines.h"
|
||||
#include "third_party/ctags/sort.h"
|
||||
|
||||
/*
|
||||
* 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, "%s", 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
third_party/ctags/sort.h
vendored
32
third_party/ctags/sort.h
vendored
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* $Id: sort.h 443 2006-05-30 04:37:13Z darren $
|
||||
*
|
||||
* 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 "third_party/ctags/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: */
|
||||
2174
third_party/ctags/sql.c
vendored
2174
third_party/ctags/sql.c
vendored
File diff suppressed because it is too large
Load Diff
237
third_party/ctags/strlist.c
vendored
237
third_party/ctags/strlist.c
vendored
@@ -1,237 +0,0 @@
|
||||
/*
|
||||
* $Id: strlist.c 443 2006-05-30 04:37:13Z darren $
|
||||
*
|
||||
* 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 managing resizable string lists.
|
||||
*/
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/debug.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/routines.h"
|
||||
#include "third_party/ctags/strlist.h"
|
||||
#include "third_party/musl/fnmatch.h"
|
||||
|
||||
/*
|
||||
* FUNCTION DEFINITIONS
|
||||
*/
|
||||
|
||||
extern stringList *stringListNew(void) {
|
||||
stringList *const result = xMalloc(1, stringList);
|
||||
result->max = 0;
|
||||
result->count = 0;
|
||||
result->list = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
extern void stringListAdd(stringList *const current, vString *string) {
|
||||
enum { incrementalIncrease = 10 };
|
||||
Assert(current != NULL);
|
||||
if (current->list == NULL) {
|
||||
Assert(current->max == 0);
|
||||
current->count = 0;
|
||||
current->max = incrementalIncrease;
|
||||
current->list = xMalloc(current->max, vString *);
|
||||
} else if (current->count == current->max) {
|
||||
current->max += incrementalIncrease;
|
||||
current->list = xRealloc(current->list, current->max, vString *);
|
||||
}
|
||||
current->list[current->count++] = string;
|
||||
}
|
||||
|
||||
extern void stringListRemoveLast(stringList *const current) {
|
||||
Assert(current != NULL);
|
||||
Assert(current->count > 0);
|
||||
--current->count;
|
||||
current->list[current->count] = NULL;
|
||||
}
|
||||
|
||||
/* Combine list `from' into `current', deleting `from' */
|
||||
extern void stringListCombine(stringList *const current,
|
||||
stringList *const from) {
|
||||
unsigned int i;
|
||||
Assert(current != NULL);
|
||||
Assert(from != NULL);
|
||||
for (i = 0; i < from->count; ++i) {
|
||||
stringListAdd(current, from->list[i]);
|
||||
from->list[i] = NULL;
|
||||
}
|
||||
stringListDelete(from);
|
||||
}
|
||||
|
||||
extern stringList *stringListNewFromArgv(const char *const *const argv) {
|
||||
stringList *const result = stringListNew();
|
||||
const char *const *p;
|
||||
Assert(argv != NULL);
|
||||
for (p = argv; *p != NULL; ++p) stringListAdd(result, vStringNewInit(*p));
|
||||
return result;
|
||||
}
|
||||
|
||||
extern stringList *stringListNewFromFile(const char *const fileName) {
|
||||
stringList *result = NULL;
|
||||
FILE *const fp = fopen(fileName, "r");
|
||||
if (fp != NULL) {
|
||||
result = stringListNew();
|
||||
while (!feof(fp)) {
|
||||
vString *const str = vStringNew();
|
||||
readLine(str, fp);
|
||||
vStringStripTrailing(str);
|
||||
if (vStringLength(str) > 0)
|
||||
stringListAdd(result, str);
|
||||
else
|
||||
vStringDelete(str);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern unsigned int stringListCount(const stringList *const current) {
|
||||
Assert(current != NULL);
|
||||
return current->count;
|
||||
}
|
||||
|
||||
extern vString *stringListItem(const stringList *const current,
|
||||
const unsigned int indx) {
|
||||
Assert(current != NULL);
|
||||
return current->list[indx];
|
||||
}
|
||||
|
||||
extern vString *stringListLast(const stringList *const current) {
|
||||
Assert(current != NULL);
|
||||
Assert(current->count > 0);
|
||||
return current->list[current->count - 1];
|
||||
}
|
||||
|
||||
extern void stringListClear(stringList *const current) {
|
||||
unsigned int i;
|
||||
Assert(current != NULL);
|
||||
for (i = 0; i < current->count; ++i) {
|
||||
vStringDelete(current->list[i]);
|
||||
current->list[i] = NULL;
|
||||
}
|
||||
current->count = 0;
|
||||
}
|
||||
|
||||
extern void stringListDelete(stringList *const current) {
|
||||
if (current != NULL) {
|
||||
if (current->list != NULL) {
|
||||
stringListClear(current);
|
||||
eFree(current->list);
|
||||
current->list = NULL;
|
||||
}
|
||||
current->max = 0;
|
||||
current->count = 0;
|
||||
eFree(current);
|
||||
}
|
||||
}
|
||||
|
||||
static boolean compareString(const char *const string, vString *const itm) {
|
||||
return (boolean)(strcmp(string, vStringValue(itm)) == 0);
|
||||
}
|
||||
|
||||
static boolean compareStringInsensitive(const char *const string,
|
||||
vString *const itm) {
|
||||
return (boolean)(strcasecmp(string, vStringValue(itm)) == 0);
|
||||
}
|
||||
|
||||
static int stringListIndex(const stringList *const current,
|
||||
const char *const string,
|
||||
boolean (*test)(const char *s, vString *const vs)) {
|
||||
int result = -1;
|
||||
unsigned int i;
|
||||
Assert(current != NULL);
|
||||
Assert(string != NULL);
|
||||
Assert(test != NULL);
|
||||
for (i = 0; result == -1 && i < current->count; ++i)
|
||||
if ((*test)(string, current->list[i])) result = i;
|
||||
return result;
|
||||
}
|
||||
|
||||
extern boolean stringListHas(const stringList *const current,
|
||||
const char *const string) {
|
||||
boolean result = FALSE;
|
||||
Assert(current != NULL);
|
||||
result = stringListIndex(current, string, compareString) != -1;
|
||||
return result;
|
||||
}
|
||||
|
||||
extern boolean stringListHasInsensitive(const stringList *const current,
|
||||
const char *const string) {
|
||||
boolean result = FALSE;
|
||||
Assert(current != NULL);
|
||||
Assert(string != NULL);
|
||||
result = stringListIndex(current, string, compareStringInsensitive) != -1;
|
||||
return result;
|
||||
}
|
||||
|
||||
extern boolean stringListHasTest(const stringList *const current,
|
||||
boolean (*test)(const char *s)) {
|
||||
boolean result = FALSE;
|
||||
unsigned int i;
|
||||
Assert(current != NULL);
|
||||
for (i = 0; !result && i < current->count; ++i)
|
||||
result = (*test)(vStringValue(current->list[i]));
|
||||
return result;
|
||||
}
|
||||
|
||||
extern boolean stringListRemoveExtension(stringList *const current,
|
||||
const char *const extension) {
|
||||
boolean result = FALSE;
|
||||
int where;
|
||||
#ifdef CASE_INSENSITIVE_FILENAMES
|
||||
where = stringListIndex(current, extension, compareStringInsensitive);
|
||||
#else
|
||||
where = stringListIndex(current, extension, compareString);
|
||||
#endif
|
||||
if (where != -1) {
|
||||
memmove(current->list + where, current->list + where + 1,
|
||||
(current->count - where) * sizeof(*current->list));
|
||||
current->list[current->count - 1] = NULL;
|
||||
--current->count;
|
||||
result = TRUE;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern boolean stringListExtensionMatched(const stringList *const current,
|
||||
const char *const extension) {
|
||||
#ifdef CASE_INSENSITIVE_FILENAMES
|
||||
return stringListHasInsensitive(current, extension);
|
||||
#else
|
||||
return stringListHas(current, extension);
|
||||
#endif
|
||||
}
|
||||
|
||||
static boolean fileNameMatched(const vString *const vpattern,
|
||||
const char *const fileName) {
|
||||
const char *const pattern = vStringValue(vpattern);
|
||||
#if defined(HAVE_FNMATCH)
|
||||
return (boolean)(fnmatch(pattern, fileName, 0) == 0);
|
||||
#elif defined(CASE_INSENSITIVE_FILENAMES)
|
||||
return (boolean)(strcasecmp(pattern, fileName) == 0);
|
||||
#else
|
||||
return (boolean)(strcmp(pattern, fileName) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
extern boolean stringListFileMatched(const stringList *const current,
|
||||
const char *const fileName) {
|
||||
boolean result = FALSE;
|
||||
unsigned int i;
|
||||
for (i = 0; !result && i < stringListCount(current); ++i)
|
||||
result = fileNameMatched(stringListItem(current, i), fileName);
|
||||
return result;
|
||||
}
|
||||
|
||||
extern void stringListPrint(const stringList *const current) {
|
||||
unsigned int i;
|
||||
Assert(current != NULL);
|
||||
for (i = 0; i < current->count; ++i)
|
||||
printf("%s%s", (i > 0) ? ", " : "", vStringValue(current->list[i]));
|
||||
}
|
||||
|
||||
/* vi:set tabstop=4 shiftwidth=4: */
|
||||
54
third_party/ctags/strlist.h
vendored
54
third_party/ctags/strlist.h
vendored
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* $Id: strlist.h 443 2006-05-30 04:37:13Z darren $
|
||||
*
|
||||
* 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 resizable string lists.
|
||||
*/
|
||||
#ifndef _STRLIST_H
|
||||
#define _STRLIST_H
|
||||
|
||||
/*
|
||||
* INCLUDE FILES
|
||||
*/
|
||||
#include "third_party/ctags/general.h" /* must always come first */
|
||||
|
||||
#include "third_party/ctags/vstring.h"
|
||||
|
||||
/*
|
||||
* DATA DECLARATIONS
|
||||
*/
|
||||
typedef struct sStringList {
|
||||
unsigned int max;
|
||||
unsigned int count;
|
||||
vString **list;
|
||||
} stringList;
|
||||
|
||||
/*
|
||||
* FUNCTION PROTOTYPES
|
||||
*/
|
||||
extern stringList *stringListNew (void);
|
||||
extern void stringListAdd (stringList *const current, vString *string);
|
||||
extern void stringListRemoveLast (stringList *const current);
|
||||
extern void stringListCombine (stringList *const current, stringList *const from);
|
||||
extern stringList* stringListNewFromArgv (const char* const* const list);
|
||||
extern stringList* stringListNewFromFile (const char* const fileName);
|
||||
extern void stringListClear (stringList *const current);
|
||||
extern unsigned int stringListCount (const stringList *const current);
|
||||
extern vString* stringListItem (const stringList *const current, const unsigned int indx);
|
||||
extern vString* stringListLast (const stringList *const current);
|
||||
extern void stringListDelete (stringList *const current);
|
||||
extern boolean stringListHasInsensitive (const stringList *const current, const char *const string);
|
||||
extern boolean stringListHas (const stringList *const current, const char *const string);
|
||||
extern boolean stringListHasTest (const stringList *const current, boolean (*test)(const char *s));
|
||||
extern boolean stringListRemoveExtension (stringList* const current, const char* const extension);
|
||||
extern boolean stringListExtensionMatched (const stringList* const list, const char* const extension);
|
||||
extern boolean stringListFileMatched (const stringList* const list, const char* const str);
|
||||
extern void stringListPrint (const stringList *const current);
|
||||
|
||||
#endif /* _STRLIST_H */
|
||||
|
||||
/* vi:set tabstop=4 shiftwidth=4: */
|
||||
91
third_party/ctags/tcl.c
vendored
91
third_party/ctags/tcl.c
vendored
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* $Id: tcl.c 443 2006-05-30 04:37:13Z darren $
|
||||
*
|
||||
* 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 TCL scripts.
|
||||
*/
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/parse.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/vstring.h"
|
||||
|
||||
/*
|
||||
* DATA DEFINITIONS
|
||||
*/
|
||||
typedef enum { K_CLASS, K_METHOD, K_PROCEDURE } tclKind;
|
||||
|
||||
static kindOption TclKinds[] = {{TRUE, 'c', "class", "classes"},
|
||||
{TRUE, 'm', "method", "methods"},
|
||||
{TRUE, 'p', "procedure", "procedures"}};
|
||||
|
||||
/*
|
||||
* FUNCTION DEFINITIONS
|
||||
*/
|
||||
|
||||
static const unsigned char *makeTclTag(const unsigned char *cp,
|
||||
vString *const name,
|
||||
const tclKind kind) {
|
||||
vStringClear(name);
|
||||
while ((int)*cp != '\0' && !isspace((int)*cp)) {
|
||||
vStringPut(name, (int)*cp);
|
||||
++cp;
|
||||
}
|
||||
vStringTerminate(name);
|
||||
makeSimpleTag(name, TclKinds, kind);
|
||||
return cp;
|
||||
}
|
||||
|
||||
static boolean match(const unsigned char *line, const char *word) {
|
||||
return (boolean)(strncmp((const char *)line, word, strlen(word)) == 0);
|
||||
}
|
||||
|
||||
static void findTclTags(void) {
|
||||
vString *name = vStringNew();
|
||||
const unsigned char *line;
|
||||
|
||||
while ((line = fileReadLine()) != NULL) {
|
||||
const unsigned char *cp;
|
||||
|
||||
while (isspace(line[0])) ++line;
|
||||
|
||||
if (line[0] == '\0' || line[0] == '#') continue;
|
||||
|
||||
/* read first word */
|
||||
for (cp = line; *cp != '\0' && !isspace((int)*cp); ++cp)
|
||||
;
|
||||
if (!isspace((int)*cp)) continue;
|
||||
while (isspace((int)*cp)) ++cp;
|
||||
/* Now `line' points at first word and `cp' points at next word */
|
||||
|
||||
if (match(line, "proc"))
|
||||
cp = makeTclTag(cp, name, K_PROCEDURE);
|
||||
else if (match(line, "class") || match(line, "itcl::class"))
|
||||
cp = makeTclTag(cp, name, K_CLASS);
|
||||
else if (match(line, "public") || match(line, "protected") ||
|
||||
match(line, "private")) {
|
||||
if (match(cp, "method")) {
|
||||
cp += 6;
|
||||
while (isspace((int)*cp)) ++cp;
|
||||
cp = makeTclTag(cp, name, K_METHOD);
|
||||
}
|
||||
}
|
||||
}
|
||||
vStringDelete(name);
|
||||
}
|
||||
|
||||
extern parserDefinition *TclParser(void) {
|
||||
static const char *const extensions[] = {"tcl", "tk", "wish", "itcl", NULL};
|
||||
parserDefinition *def = parserNew("Tcl");
|
||||
def->kinds = TclKinds;
|
||||
def->kindCount = KIND_COUNT(TclKinds);
|
||||
def->extensions = extensions;
|
||||
def->parser = findTclTags;
|
||||
return def;
|
||||
}
|
||||
|
||||
/* vi:set tabstop=4 shiftwidth=4: */
|
||||
476
third_party/ctags/tex.c
vendored
476
third_party/ctags/tex.c
vendored
@@ -1,476 +0,0 @@
|
||||
/*
|
||||
* $Id: tex.c 666 2008-05-15 17:47:31Z dfishburn $
|
||||
*
|
||||
* Copyright (c) 2008, David Fishburn
|
||||
*
|
||||
* 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 TeX
|
||||
* language files.
|
||||
*
|
||||
* Tex language reference:
|
||||
* http://en.wikibooks.org/wiki/TeX#The_Structure_of_TeX
|
||||
*/
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/debug.h"
|
||||
#include "third_party/ctags/entry.h"
|
||||
#include "third_party/ctags/keyword.h"
|
||||
#include "third_party/ctags/parse.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/routines.h"
|
||||
#include "third_party/ctags/vstring.h"
|
||||
|
||||
/*
|
||||
* MACROS
|
||||
*/
|
||||
#define isType(token, t) (boolean)((token)->type == (t))
|
||||
#define isKeyword(token, k) (boolean)((token)->keyword == (k))
|
||||
|
||||
/*
|
||||
* DATA DECLARATIONS
|
||||
*/
|
||||
|
||||
typedef enum eException { ExceptionNone, ExceptionEOF } exception_t;
|
||||
|
||||
/*
|
||||
* Used to specify type of keyword.
|
||||
*/
|
||||
typedef enum eKeywordId {
|
||||
KEYWORD_NONE = -1,
|
||||
KEYWORD_chapter,
|
||||
KEYWORD_section,
|
||||
KEYWORD_subsection,
|
||||
KEYWORD_subsubsection,
|
||||
KEYWORD_part,
|
||||
KEYWORD_paragraph,
|
||||
KEYWORD_subparagraph,
|
||||
KEYWORD_include
|
||||
} keywordId;
|
||||
|
||||
/* Used to determine whether keyword is valid for the token language and
|
||||
* what its ID is.
|
||||
*/
|
||||
typedef struct sKeywordDesc {
|
||||
const char *name;
|
||||
keywordId id;
|
||||
} keywordDesc;
|
||||
|
||||
typedef enum eTokenType {
|
||||
TOKEN_UNDEFINED,
|
||||
TOKEN_CHARACTER,
|
||||
TOKEN_CLOSE_PAREN,
|
||||
TOKEN_COMMA,
|
||||
TOKEN_KEYWORD,
|
||||
TOKEN_OPEN_PAREN,
|
||||
TOKEN_IDENTIFIER,
|
||||
TOKEN_STRING,
|
||||
TOKEN_OPEN_CURLY,
|
||||
TOKEN_CLOSE_CURLY,
|
||||
TOKEN_OPEN_SQUARE,
|
||||
TOKEN_CLOSE_SQUARE,
|
||||
TOKEN_QUESTION_MARK,
|
||||
TOKEN_STAR
|
||||
} tokenType;
|
||||
|
||||
typedef struct sTokenInfo {
|
||||
tokenType type;
|
||||
keywordId keyword;
|
||||
vString *string;
|
||||
vString *scope;
|
||||
unsigned long lineNumber;
|
||||
fpos_t filePosition;
|
||||
} tokenInfo;
|
||||
|
||||
/*
|
||||
* DATA DEFINITIONS
|
||||
*/
|
||||
|
||||
static langType Lang_js;
|
||||
|
||||
static jmp_buf Exception;
|
||||
|
||||
typedef enum {
|
||||
TEXTAG_CHAPTER,
|
||||
TEXTAG_SECTION,
|
||||
TEXTAG_SUBSECTION,
|
||||
TEXTAG_SUBSUBSECTION,
|
||||
TEXTAG_PART,
|
||||
TEXTAG_PARAGRAPH,
|
||||
TEXTAG_SUBPARAGRAPH,
|
||||
TEXTAG_INCLUDE,
|
||||
TEXTAG_COUNT
|
||||
} texKind;
|
||||
|
||||
static kindOption TexKinds[] = {{TRUE, 'c', "chapter", "chapters"},
|
||||
{TRUE, 's', "section", "sections"},
|
||||
{TRUE, 'u', "subsection", "subsections"},
|
||||
{TRUE, 'b', "subsubsection", "subsubsections"},
|
||||
{TRUE, 'p', "part", "parts"},
|
||||
{TRUE, 'P', "paragraph", "paragraphs"},
|
||||
{TRUE, 'G', "subparagraph", "subparagraphs"},
|
||||
{TRUE, 'i', "include", "includes"}};
|
||||
|
||||
static const keywordDesc TexKeywordTable[] = {
|
||||
/* keyword keyword ID */
|
||||
{"chapter", KEYWORD_chapter},
|
||||
{"section", KEYWORD_section},
|
||||
{"subsection", KEYWORD_subsection},
|
||||
{"subsubsection", KEYWORD_subsubsection},
|
||||
{"part", KEYWORD_part},
|
||||
{"paragraph", KEYWORD_paragraph},
|
||||
{"subparagraph", KEYWORD_subparagraph},
|
||||
{"include", KEYWORD_include}};
|
||||
|
||||
/*
|
||||
* FUNCTION DEFINITIONS
|
||||
*/
|
||||
|
||||
static boolean isIdentChar(const int c) {
|
||||
return (boolean)(isalpha(c) || isdigit(c) || c == '$' || c == '_' ||
|
||||
c == '#' || c == '-' || c == '.');
|
||||
}
|
||||
|
||||
static void buildTexKeywordHash(void) {
|
||||
const size_t count = sizeof(TexKeywordTable) / sizeof(TexKeywordTable[0]);
|
||||
size_t i;
|
||||
for (i = 0; i < count; ++i) {
|
||||
const keywordDesc *const p = &TexKeywordTable[i];
|
||||
addKeyword(p->name, Lang_js, (int)p->id);
|
||||
}
|
||||
}
|
||||
|
||||
static tokenInfo *newToken(void) {
|
||||
tokenInfo *const token = xMalloc(1, tokenInfo);
|
||||
|
||||
token->type = TOKEN_UNDEFINED;
|
||||
token->keyword = KEYWORD_NONE;
|
||||
token->string = vStringNew();
|
||||
token->scope = vStringNew();
|
||||
token->lineNumber = getSourceLineNumber();
|
||||
token->filePosition = getInputFilePosition();
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
static void deleteToken(tokenInfo *const token) {
|
||||
vStringDelete(token->string);
|
||||
vStringDelete(token->scope);
|
||||
eFree(token);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tag generation functions
|
||||
*/
|
||||
|
||||
static void makeConstTag(tokenInfo *const token, const texKind kind) {
|
||||
if (TexKinds[kind].enabled) {
|
||||
const char *const name = vStringValue(token->string);
|
||||
tagEntryInfo e;
|
||||
initTagEntry(&e, name);
|
||||
|
||||
e.lineNumber = token->lineNumber;
|
||||
e.filePosition = token->filePosition;
|
||||
e.kindName = TexKinds[kind].name;
|
||||
e.kind = TexKinds[kind].letter;
|
||||
|
||||
makeTagEntry(&e);
|
||||
}
|
||||
}
|
||||
|
||||
static void makeTexTag(tokenInfo *const token, texKind kind) {
|
||||
vString *fulltag;
|
||||
|
||||
if (TexKinds[kind].enabled) {
|
||||
/*
|
||||
* If a scope has been added to the token, change the token
|
||||
* string to include the scope when making the tag.
|
||||
*/
|
||||
if (vStringLength(token->scope) > 0) {
|
||||
fulltag = vStringNew();
|
||||
vStringCopy(fulltag, token->scope);
|
||||
vStringCatS(fulltag, ".");
|
||||
vStringCatS(fulltag, vStringValue(token->string));
|
||||
vStringTerminate(fulltag);
|
||||
vStringCopy(token->string, fulltag);
|
||||
vStringDelete(fulltag);
|
||||
}
|
||||
makeConstTag(token, kind);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parsing functions
|
||||
*/
|
||||
|
||||
static void parseString(vString *const string, const int delimiter) {
|
||||
boolean end = FALSE;
|
||||
while (!end) {
|
||||
int c = fileGetc();
|
||||
if (c == EOF)
|
||||
end = TRUE;
|
||||
else if (c == '\\') {
|
||||
c = fileGetc(); /* This maybe a ' or ". */
|
||||
vStringPut(string, c);
|
||||
} else if (c == delimiter)
|
||||
end = TRUE;
|
||||
else
|
||||
vStringPut(string, c);
|
||||
}
|
||||
vStringTerminate(string);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a C identifier beginning with "firstChar" and places it into
|
||||
* "name".
|
||||
*/
|
||||
static void parseIdentifier(vString *const string, const int firstChar) {
|
||||
int c = firstChar;
|
||||
Assert(isIdentChar(c));
|
||||
do {
|
||||
vStringPut(string, c);
|
||||
c = fileGetc();
|
||||
} while (isIdentChar(c));
|
||||
|
||||
vStringTerminate(string);
|
||||
if (!isspace(c)) fileUngetc(c); /* unget non-identifier character */
|
||||
}
|
||||
|
||||
static void readToken(tokenInfo *const token) {
|
||||
int c;
|
||||
|
||||
token->type = TOKEN_UNDEFINED;
|
||||
token->keyword = KEYWORD_NONE;
|
||||
vStringClear(token->string);
|
||||
|
||||
getNextChar:
|
||||
do {
|
||||
c = fileGetc();
|
||||
token->lineNumber = getSourceLineNumber();
|
||||
token->filePosition = getInputFilePosition();
|
||||
} while (c == '\t' || c == ' ' || c == '\n');
|
||||
|
||||
switch (c) {
|
||||
case EOF:
|
||||
longjmp(Exception, (int)ExceptionEOF);
|
||||
break;
|
||||
case '(':
|
||||
token->type = TOKEN_OPEN_PAREN;
|
||||
break;
|
||||
case ')':
|
||||
token->type = TOKEN_CLOSE_PAREN;
|
||||
break;
|
||||
case ',':
|
||||
token->type = TOKEN_COMMA;
|
||||
break;
|
||||
case '{':
|
||||
token->type = TOKEN_OPEN_CURLY;
|
||||
break;
|
||||
case '}':
|
||||
token->type = TOKEN_CLOSE_CURLY;
|
||||
break;
|
||||
case '[':
|
||||
token->type = TOKEN_OPEN_SQUARE;
|
||||
break;
|
||||
case ']':
|
||||
token->type = TOKEN_CLOSE_SQUARE;
|
||||
break;
|
||||
case '*':
|
||||
token->type = TOKEN_STAR;
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
case '"':
|
||||
token->type = TOKEN_STRING;
|
||||
parseString(token->string, c);
|
||||
token->lineNumber = getSourceLineNumber();
|
||||
token->filePosition = getInputFilePosition();
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
/*
|
||||
* All Tex tags start with a backslash.
|
||||
* Check if the next character is an alpha character
|
||||
* else it is not a potential tex tag.
|
||||
*/
|
||||
c = fileGetc();
|
||||
if (!isalpha(c))
|
||||
fileUngetc(c);
|
||||
else {
|
||||
parseIdentifier(token->string, c);
|
||||
token->lineNumber = getSourceLineNumber();
|
||||
token->filePosition = getInputFilePosition();
|
||||
token->keyword = analyzeToken(token->string, Lang_js);
|
||||
if (isKeyword(token, KEYWORD_NONE))
|
||||
token->type = TOKEN_IDENTIFIER;
|
||||
else
|
||||
token->type = TOKEN_KEYWORD;
|
||||
}
|
||||
break;
|
||||
|
||||
case '%':
|
||||
fileSkipToCharacter('\n'); /* % are single line comments */
|
||||
goto getNextChar;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!isIdentChar(c))
|
||||
token->type = TOKEN_UNDEFINED;
|
||||
else {
|
||||
parseIdentifier(token->string, c);
|
||||
token->lineNumber = getSourceLineNumber();
|
||||
token->filePosition = getInputFilePosition();
|
||||
token->type = TOKEN_IDENTIFIER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void copyToken(tokenInfo *const dest, tokenInfo *const src) {
|
||||
dest->lineNumber = src->lineNumber;
|
||||
dest->filePosition = src->filePosition;
|
||||
dest->type = src->type;
|
||||
dest->keyword = src->keyword;
|
||||
vStringCopy(dest->string, src->string);
|
||||
vStringCopy(dest->scope, src->scope);
|
||||
}
|
||||
|
||||
/*
|
||||
* Scanning functions
|
||||
*/
|
||||
|
||||
static boolean parseTag(tokenInfo *const token, texKind kind) {
|
||||
tokenInfo *const name = newToken();
|
||||
vString *fullname;
|
||||
boolean useLongName = TRUE;
|
||||
|
||||
fullname = vStringNew();
|
||||
vStringClear(fullname);
|
||||
|
||||
/*
|
||||
* Tex tags are of these formats:
|
||||
* \keyword{any number of words}
|
||||
* \keyword[short desc]{any number of words}
|
||||
* \keyword*[short desc]{any number of words}
|
||||
*
|
||||
* When a keyword is found, loop through all words within
|
||||
* the curly braces for the tag name.
|
||||
*/
|
||||
|
||||
if (isType(token, TOKEN_KEYWORD)) {
|
||||
copyToken(name, token);
|
||||
readToken(token);
|
||||
}
|
||||
|
||||
if (isType(token, TOKEN_OPEN_SQUARE)) {
|
||||
useLongName = FALSE;
|
||||
|
||||
readToken(token);
|
||||
while (!isType(token, TOKEN_CLOSE_SQUARE)) {
|
||||
if (isType(token, TOKEN_IDENTIFIER)) {
|
||||
if (fullname->length > 0) vStringCatS(fullname, " ");
|
||||
vStringCatS(fullname, vStringValue(token->string));
|
||||
}
|
||||
readToken(token);
|
||||
}
|
||||
vStringTerminate(fullname);
|
||||
vStringCopy(name->string, fullname);
|
||||
makeTexTag(name, kind);
|
||||
}
|
||||
|
||||
if (isType(token, TOKEN_STAR)) {
|
||||
readToken(token);
|
||||
}
|
||||
|
||||
if (isType(token, TOKEN_OPEN_CURLY)) {
|
||||
readToken(token);
|
||||
while (!isType(token, TOKEN_CLOSE_CURLY)) {
|
||||
/* if (isType (token, TOKEN_IDENTIFIER) && useLongName) */
|
||||
if (useLongName) {
|
||||
if (fullname->length > 0) vStringCatS(fullname, " ");
|
||||
vStringCatS(fullname, vStringValue(token->string));
|
||||
}
|
||||
readToken(token);
|
||||
}
|
||||
if (useLongName) {
|
||||
vStringTerminate(fullname);
|
||||
vStringCopy(name->string, fullname);
|
||||
makeTexTag(name, kind);
|
||||
}
|
||||
}
|
||||
|
||||
deleteToken(name);
|
||||
vStringDelete(fullname);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void parseTexFile(tokenInfo *const token) {
|
||||
do {
|
||||
readToken(token);
|
||||
|
||||
if (isType(token, TOKEN_KEYWORD)) {
|
||||
switch (token->keyword) {
|
||||
case KEYWORD_chapter:
|
||||
parseTag(token, TEXTAG_CHAPTER);
|
||||
break;
|
||||
case KEYWORD_section:
|
||||
parseTag(token, TEXTAG_SECTION);
|
||||
break;
|
||||
case KEYWORD_subsection:
|
||||
parseTag(token, TEXTAG_SUBSECTION);
|
||||
break;
|
||||
case KEYWORD_subsubsection:
|
||||
parseTag(token, TEXTAG_SUBSUBSECTION);
|
||||
break;
|
||||
case KEYWORD_part:
|
||||
parseTag(token, TEXTAG_PART);
|
||||
break;
|
||||
case KEYWORD_paragraph:
|
||||
parseTag(token, TEXTAG_PARAGRAPH);
|
||||
break;
|
||||
case KEYWORD_subparagraph:
|
||||
parseTag(token, TEXTAG_SUBPARAGRAPH);
|
||||
break;
|
||||
case KEYWORD_include:
|
||||
parseTag(token, TEXTAG_INCLUDE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (TRUE);
|
||||
}
|
||||
|
||||
static void initialize(const langType language) {
|
||||
Assert(sizeof(TexKinds) / sizeof(TexKinds[0]) == TEXTAG_COUNT);
|
||||
Lang_js = language;
|
||||
buildTexKeywordHash();
|
||||
}
|
||||
|
||||
static void findTexTags(void) {
|
||||
tokenInfo *const token = newToken();
|
||||
exception_t exception;
|
||||
|
||||
exception = (exception_t)(setjmp(Exception));
|
||||
while (exception == ExceptionNone) parseTexFile(token);
|
||||
|
||||
deleteToken(token);
|
||||
}
|
||||
|
||||
/* Create parser definition stucture */
|
||||
extern parserDefinition *TexParser(void) {
|
||||
static const char *const extensions[] = {"tex", NULL};
|
||||
parserDefinition *const def = parserNew("Tex");
|
||||
def->extensions = extensions;
|
||||
/*
|
||||
* New definitions for parsing instead of regex
|
||||
*/
|
||||
def->kinds = TexKinds;
|
||||
def->kindCount = KIND_COUNT(TexKinds);
|
||||
def->parser = findTexTags;
|
||||
def->initialize = initialize;
|
||||
|
||||
return def;
|
||||
}
|
||||
/* vi:set tabstop=4 shiftwidth=4 noexpandtab: */
|
||||
293
third_party/ctags/verilog.c
vendored
293
third_party/ctags/verilog.c
vendored
@@ -1,293 +0,0 @@
|
||||
/*
|
||||
* $Id: verilog.c 753 2010-02-27 17:53:32Z elliotth $
|
||||
*
|
||||
* 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 the Verilog HDL
|
||||
* (Hardware Description Language).
|
||||
*
|
||||
* Language definition documents:
|
||||
* http://www.eg.bucknell.edu/~cs320/verilog/verilog-manual.html
|
||||
* http://www.sutherland-hdl.com/on-line_ref_guide/vlog_ref_top.html
|
||||
* http://www.verilog.com/VerilogBNF.html
|
||||
* http://eesun.free.fr/DOC/VERILOG/verilog_manual1.html
|
||||
*/
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/debug.h"
|
||||
#include "third_party/ctags/get.h"
|
||||
#include "third_party/ctags/keyword.h"
|
||||
#include "third_party/ctags/parse.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/vstring.h"
|
||||
|
||||
/*
|
||||
* DATA DECLARATIONS
|
||||
*/
|
||||
typedef enum eException { ExceptionNone, ExceptionEOF } exception_t;
|
||||
|
||||
typedef enum {
|
||||
K_UNDEFINED = -1,
|
||||
K_CONSTANT,
|
||||
K_EVENT,
|
||||
K_FUNCTION,
|
||||
K_MODULE,
|
||||
K_NET,
|
||||
K_PORT,
|
||||
K_REGISTER,
|
||||
K_TASK
|
||||
} verilogKind;
|
||||
|
||||
typedef struct {
|
||||
const char *keyword;
|
||||
verilogKind kind;
|
||||
} keywordAssoc;
|
||||
|
||||
/*
|
||||
* DATA DEFINITIONS
|
||||
*/
|
||||
static int Ungetc;
|
||||
static int Lang_verilog;
|
||||
static jmp_buf Exception;
|
||||
|
||||
static kindOption VerilogKinds[] = {
|
||||
{TRUE, 'c', "constant", "constants (define, parameter, specparam)"},
|
||||
{TRUE, 'e', "event", "events"},
|
||||
{TRUE, 'f', "function", "functions"},
|
||||
{TRUE, 'm', "module", "modules"},
|
||||
{TRUE, 'n', "net", "net data types"},
|
||||
{TRUE, 'p', "port", "ports"},
|
||||
{TRUE, 'r', "register", "register data types"},
|
||||
{TRUE, 't', "task", "tasks"},
|
||||
};
|
||||
|
||||
static keywordAssoc VerilogKeywordTable[] = {
|
||||
{"`define", K_CONSTANT},
|
||||
{"event", K_EVENT},
|
||||
{"function", K_FUNCTION},
|
||||
{"inout", K_PORT},
|
||||
{"input", K_PORT},
|
||||
{"integer", K_REGISTER},
|
||||
{"module", K_MODULE},
|
||||
{"output", K_PORT},
|
||||
{"parameter", K_CONSTANT},
|
||||
{"real", K_REGISTER},
|
||||
{"realtime", K_REGISTER},
|
||||
{"reg", K_REGISTER},
|
||||
{"specparam", K_CONSTANT},
|
||||
{"supply0", K_NET},
|
||||
{"supply1", K_NET},
|
||||
{"task", K_TASK},
|
||||
{"time", K_REGISTER},
|
||||
{"tri0", K_NET},
|
||||
{"tri1", K_NET},
|
||||
{"triand", K_NET},
|
||||
{"tri", K_NET},
|
||||
{"trior", K_NET},
|
||||
{"trireg", K_NET},
|
||||
{"wand", K_NET},
|
||||
{"wire", K_NET},
|
||||
{"wor", K_NET},
|
||||
};
|
||||
|
||||
/*
|
||||
* FUNCTION DEFINITIONS
|
||||
*/
|
||||
|
||||
static void initialize(const langType language) {
|
||||
size_t i;
|
||||
const size_t count =
|
||||
sizeof(VerilogKeywordTable) / sizeof(VerilogKeywordTable[0]);
|
||||
Lang_verilog = language;
|
||||
for (i = 0; i < count; ++i) {
|
||||
const keywordAssoc *const p = &VerilogKeywordTable[i];
|
||||
addKeyword(p->keyword, language, (int)p->kind);
|
||||
}
|
||||
}
|
||||
|
||||
static void vUngetc(int c) {
|
||||
Assert(Ungetc == '\0');
|
||||
Ungetc = c;
|
||||
}
|
||||
|
||||
static int vGetc(void) {
|
||||
int c;
|
||||
if (Ungetc == '\0')
|
||||
c = fileGetc();
|
||||
else {
|
||||
c = Ungetc;
|
||||
Ungetc = '\0';
|
||||
}
|
||||
if (c == '/') {
|
||||
int c2 = fileGetc();
|
||||
if (c2 == EOF)
|
||||
longjmp(Exception, (int)ExceptionEOF);
|
||||
else if (c2 == '/') /* strip comment until end-of-line */
|
||||
{
|
||||
do
|
||||
c = fileGetc();
|
||||
while (c != '\n' && c != EOF);
|
||||
} else if (c2 == '*') /* strip block comment */
|
||||
{
|
||||
c = skipOverCComment();
|
||||
} else {
|
||||
fileUngetc(c2);
|
||||
}
|
||||
} else if (c == '"') /* strip string contents */
|
||||
{
|
||||
int c2;
|
||||
do
|
||||
c2 = fileGetc();
|
||||
while (c2 != '"' && c2 != EOF);
|
||||
c = '@';
|
||||
}
|
||||
if (c == EOF) longjmp(Exception, (int)ExceptionEOF);
|
||||
return c;
|
||||
}
|
||||
|
||||
static boolean isIdentifierCharacter(const int c) {
|
||||
return (boolean)(isalnum(c) || c == '_' || c == '`');
|
||||
}
|
||||
|
||||
static int skipWhite(int c) {
|
||||
while (isspace(c)) c = vGetc();
|
||||
return c;
|
||||
}
|
||||
|
||||
static int skipPastMatch(const char *const pair) {
|
||||
const int begin = pair[0], end = pair[1];
|
||||
int matchLevel = 1;
|
||||
int c;
|
||||
do {
|
||||
c = vGetc();
|
||||
if (c == begin)
|
||||
++matchLevel;
|
||||
else if (c == end)
|
||||
--matchLevel;
|
||||
} while (matchLevel > 0);
|
||||
return vGetc();
|
||||
}
|
||||
|
||||
static boolean readIdentifier(vString *const name, int c) {
|
||||
vStringClear(name);
|
||||
if (isIdentifierCharacter(c)) {
|
||||
while (isIdentifierCharacter(c)) {
|
||||
vStringPut(name, c);
|
||||
c = vGetc();
|
||||
}
|
||||
vUngetc(c);
|
||||
vStringTerminate(name);
|
||||
}
|
||||
return (boolean)(name->length > 0);
|
||||
}
|
||||
|
||||
static void tagNameList(const verilogKind kind, int c) {
|
||||
vString *name = vStringNew();
|
||||
boolean repeat;
|
||||
Assert(isIdentifierCharacter(c));
|
||||
do {
|
||||
repeat = FALSE;
|
||||
if (isIdentifierCharacter(c)) {
|
||||
readIdentifier(name, c);
|
||||
makeSimpleTag(name, VerilogKinds, kind);
|
||||
} else
|
||||
break;
|
||||
c = skipWhite(vGetc());
|
||||
if (c == '[') c = skipPastMatch("[]");
|
||||
c = skipWhite(c);
|
||||
if (c == '=') {
|
||||
c = skipWhite(vGetc());
|
||||
if (c == '{')
|
||||
skipPastMatch("{}");
|
||||
else {
|
||||
do
|
||||
c = vGetc();
|
||||
while (c != ',' && c != ';');
|
||||
}
|
||||
}
|
||||
if (c == ',') {
|
||||
c = skipWhite(vGetc());
|
||||
repeat = TRUE;
|
||||
} else
|
||||
repeat = FALSE;
|
||||
} while (repeat);
|
||||
vStringDelete(name);
|
||||
vUngetc(c);
|
||||
}
|
||||
|
||||
static void findTag(vString *const name) {
|
||||
const verilogKind kind =
|
||||
(verilogKind)lookupKeyword(vStringValue(name), Lang_verilog);
|
||||
if (kind == K_CONSTANT && vStringItem(name, 0) == '`') {
|
||||
/* Bug #961001: Verilog compiler directives are line-based. */
|
||||
int c = skipWhite(vGetc());
|
||||
readIdentifier(name, c);
|
||||
makeSimpleTag(name, VerilogKinds, kind);
|
||||
/* Skip the rest of the line. */
|
||||
do {
|
||||
c = vGetc();
|
||||
} while (c != '\n');
|
||||
vUngetc(c);
|
||||
} else if (kind != K_UNDEFINED) {
|
||||
int c = skipWhite(vGetc());
|
||||
|
||||
/* Many keywords can have bit width.
|
||||
* reg [3:0] net_name;
|
||||
* inout [(`DBUSWIDTH-1):0] databus;
|
||||
*/
|
||||
if (c == '(') c = skipPastMatch("()");
|
||||
c = skipWhite(c);
|
||||
if (c == '[') c = skipPastMatch("[]");
|
||||
c = skipWhite(c);
|
||||
if (c == '#') {
|
||||
c = vGetc();
|
||||
if (c == '(') c = skipPastMatch("()");
|
||||
}
|
||||
c = skipWhite(c);
|
||||
if (isIdentifierCharacter(c)) tagNameList(kind, c);
|
||||
}
|
||||
}
|
||||
|
||||
static void findVerilogTags(void) {
|
||||
vString *const name = vStringNew();
|
||||
volatile boolean newStatement = TRUE;
|
||||
volatile int c = '\0';
|
||||
exception_t exception = (exception_t)setjmp(Exception);
|
||||
|
||||
if (exception == ExceptionNone)
|
||||
while (c != EOF) {
|
||||
c = vGetc();
|
||||
switch (c) {
|
||||
case ';':
|
||||
case '\n':
|
||||
newStatement = TRUE;
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
case '\t':
|
||||
break;
|
||||
|
||||
default:
|
||||
if (newStatement && readIdentifier(name, c)) findTag(name);
|
||||
newStatement = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
vStringDelete(name);
|
||||
}
|
||||
|
||||
extern parserDefinition *VerilogParser(void) {
|
||||
static const char *const extensions[] = {"v", NULL};
|
||||
parserDefinition *def = parserNew("Verilog");
|
||||
def->kinds = VerilogKinds;
|
||||
def->kindCount = KIND_COUNT(VerilogKinds);
|
||||
def->extensions = extensions;
|
||||
def->parser = findVerilogTags;
|
||||
def->initialize = initialize;
|
||||
return def;
|
||||
}
|
||||
|
||||
/* vi:set tabstop=4 shiftwidth=4: */
|
||||
737
third_party/ctags/vhdl.c
vendored
737
third_party/ctags/vhdl.c
vendored
@@ -1,737 +0,0 @@
|
||||
/*
|
||||
* $Id: vhdl.c 652 2008-04-18 03:51:47Z elliotth $
|
||||
*
|
||||
* Copyright (c) 2008, Nicolas Vincent
|
||||
*
|
||||
* 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 VHDL files.
|
||||
*/
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/debug.h"
|
||||
#include "third_party/ctags/entry.h"
|
||||
#include "third_party/ctags/keyword.h"
|
||||
#include "third_party/ctags/parse.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/routines.h"
|
||||
#include "third_party/ctags/vstring.h"
|
||||
|
||||
/*
|
||||
* MACROS
|
||||
*/
|
||||
#define isType(token, t) (boolean)((token)->type == (t))
|
||||
#define isKeyword(token, k) (boolean)((token)->keyword == (k))
|
||||
|
||||
/*
|
||||
* DATA DECLARATIONS
|
||||
*/
|
||||
typedef enum eException { ExceptionNone, ExceptionEOF } exception_t;
|
||||
|
||||
/*
|
||||
* Used to specify type of keyword.
|
||||
*/
|
||||
typedef enum eKeywordId {
|
||||
KEYWORD_NONE = -1,
|
||||
KEYWORD_ABS,
|
||||
KEYWORD_ACCESS,
|
||||
KEYWORD_AFTER,
|
||||
KEYWORD_ALIAS,
|
||||
KEYWORD_ALL,
|
||||
KEYWORD_AND,
|
||||
KEYWORD_ARCHITECTURE,
|
||||
KEYWORD_ARRAY,
|
||||
KEYWORD_ASSERT,
|
||||
KEYWORD_ATTRIBUTE,
|
||||
KEYWORD_BEGIN,
|
||||
KEYWORD_BLOCK,
|
||||
KEYWORD_BODY,
|
||||
KEYWORD_BUFFER,
|
||||
KEYWORD_BUS,
|
||||
KEYWORD_CASE,
|
||||
KEYWORD_COMPONENT,
|
||||
KEYWORD_CONFIGURATION,
|
||||
KEYWORD_CONSTANT,
|
||||
KEYWORD_DISCONNECT,
|
||||
KEYWORD_DOWNTO,
|
||||
KEYWORD_ELSE,
|
||||
KEYWORD_ELSIF,
|
||||
KEYWORD_END,
|
||||
KEYWORD_ENTITY,
|
||||
KEYWORD_EXIT,
|
||||
KEYWORD_FILE,
|
||||
KEYWORD_FOR,
|
||||
KEYWORD_FUNCTION,
|
||||
KEYWORD_GENERATE,
|
||||
KEYWORD_GENERIC,
|
||||
KEYWORD_GROUP,
|
||||
KEYWORD_GUARDED,
|
||||
KEYWORD_IF,
|
||||
KEYWORD_IMPURE,
|
||||
KEYWORD_IN,
|
||||
KEYWORD_INERTIAL,
|
||||
KEYWORD_INOUT,
|
||||
KEYWORD_IS,
|
||||
KEYWORD_LABEL,
|
||||
KEYWORD_LIBRARY,
|
||||
KEYWORD_LINKAGE,
|
||||
KEYWORD_LITERAL,
|
||||
KEYWORD_LOOP,
|
||||
KEYWORD_MAP,
|
||||
KEYWORD_MOD,
|
||||
KEYWORD_NAND,
|
||||
KEYWORD_NEW,
|
||||
KEYWORD_NEXT,
|
||||
KEYWORD_NOR,
|
||||
KEYWORD_NOT,
|
||||
KEYWORD_NULL,
|
||||
KEYWORD_OF,
|
||||
KEYWORD_ON,
|
||||
KEYWORD_OPEN,
|
||||
KEYWORD_OR,
|
||||
KEYWORD_OTHERS,
|
||||
KEYWORD_OUT,
|
||||
KEYWORD_PACKAGE,
|
||||
KEYWORD_PORT,
|
||||
KEYWORD_POSTPONED,
|
||||
KEYWORD_PROCEDURE,
|
||||
KEYWORD_PROCESS,
|
||||
KEYWORD_PURE,
|
||||
KEYWORD_RANGE,
|
||||
KEYWORD_RECORD,
|
||||
KEYWORD_REGISTER,
|
||||
KEYWORD_REJECT,
|
||||
KEYWORD_RETURN,
|
||||
KEYWORD_ROL,
|
||||
KEYWORD_ROR,
|
||||
KEYWORD_SELECT,
|
||||
KEYWORD_SEVERITY,
|
||||
KEYWORD_SIGNAL,
|
||||
KEYWORD_SHARED,
|
||||
KEYWORD_SLA,
|
||||
KEYWORD_SLI,
|
||||
KEYWORD_SRA,
|
||||
KEYWORD_SRL,
|
||||
KEYWORD_SUBTYPE,
|
||||
KEYWORD_THEN,
|
||||
KEYWORD_TO,
|
||||
KEYWORD_TRANSPORT,
|
||||
KEYWORD_TYPE,
|
||||
KEYWORD_UNAFFECTED,
|
||||
KEYWORD_UNITS,
|
||||
KEYWORD_UNTIL,
|
||||
KEYWORD_USE,
|
||||
KEYWORD_VARIABLE,
|
||||
KEYWORD_WAIT,
|
||||
KEYWORD_WHEN,
|
||||
KEYWORD_WHILE,
|
||||
KEYWORD_WITH,
|
||||
KEYWORD_XNOR,
|
||||
KEYWORD_XOR
|
||||
} keywordId;
|
||||
|
||||
/* Used to determine whether keyword is valid for the current language and
|
||||
* what its ID is.
|
||||
*/
|
||||
typedef struct sKeywordDesc {
|
||||
const char *name;
|
||||
keywordId id;
|
||||
} keywordDesc;
|
||||
|
||||
typedef enum eTokenType {
|
||||
TOKEN_NONE, /* none */
|
||||
TOKEN_OPEN_PAREN, /* ( */
|
||||
TOKEN_CLOSE_PAREN, /* ) */
|
||||
TOKEN_COMMA, /* the comma character */
|
||||
TOKEN_IDENTIFIER,
|
||||
TOKEN_KEYWORD,
|
||||
TOKEN_PERIOD, /* . */
|
||||
TOKEN_OPERATOR,
|
||||
TOKEN_SEMICOLON, /* the semicolon character */
|
||||
TOKEN_STRING
|
||||
} tokenType;
|
||||
|
||||
typedef struct sTokenInfo {
|
||||
tokenType type;
|
||||
keywordId keyword;
|
||||
vString *string; /* the name of the token */
|
||||
vString *scope;
|
||||
unsigned long lineNumber; /* line number of tag */
|
||||
fpos_t filePosition; /* file position of line containing name */
|
||||
} tokenInfo;
|
||||
|
||||
/*
|
||||
* DATA DEFINITIONS
|
||||
*/
|
||||
static int Lang_vhdl;
|
||||
static jmp_buf Exception;
|
||||
|
||||
/* Used to index into the VhdlKinds table. */
|
||||
typedef enum {
|
||||
VHDLTAG_UNDEFINED = -1,
|
||||
VHDLTAG_CONSTANT,
|
||||
VHDLTAG_TYPE,
|
||||
VHDLTAG_SUBTYPE,
|
||||
VHDLTAG_RECORD,
|
||||
VHDLTAG_ENTITY,
|
||||
VHDLTAG_COMPONENT,
|
||||
VHDLTAG_PROTOTYPE,
|
||||
VHDLTAG_FUNCTION,
|
||||
VHDLTAG_PROCEDURE,
|
||||
VHDLTAG_PACKAGE,
|
||||
VHDLTAG_LOCAL
|
||||
} vhdlKind;
|
||||
|
||||
static kindOption VhdlKinds[] = {
|
||||
{TRUE, 'c', "constant", "constant declarations"},
|
||||
{TRUE, 't', "type", "type definitions"},
|
||||
{TRUE, 'T', "subtype", "subtype definitions"},
|
||||
{TRUE, 'r', "record", "record names"},
|
||||
{TRUE, 'e', "entity", "entity declarations"},
|
||||
{FALSE, 'C', "component", "component declarations"},
|
||||
{FALSE, 'd', "prototype", "prototypes"},
|
||||
{TRUE, 'f', "function", "function prototypes and declarations"},
|
||||
{TRUE, 'p', "procedure", "procedure prototypes and declarations"},
|
||||
{TRUE, 'P', "package", "package definitions"},
|
||||
{FALSE, 'l', "local", "local definitions"}};
|
||||
|
||||
static keywordDesc VhdlKeywordTable[] = {
|
||||
{"abs", KEYWORD_ABS},
|
||||
{"access", KEYWORD_ACCESS},
|
||||
{"after", KEYWORD_AFTER},
|
||||
{"alias", KEYWORD_ALIAS},
|
||||
{"all", KEYWORD_ALL},
|
||||
{"and", KEYWORD_AND},
|
||||
{"architecture", KEYWORD_ARCHITECTURE},
|
||||
{"array", KEYWORD_ARRAY},
|
||||
{"assert", KEYWORD_ASSERT},
|
||||
{"attribute", KEYWORD_ATTRIBUTE},
|
||||
{"begin", KEYWORD_BEGIN},
|
||||
{"block", KEYWORD_BLOCK},
|
||||
{"body", KEYWORD_BODY},
|
||||
{"buffer", KEYWORD_BUFFER},
|
||||
{"bus", KEYWORD_BUS},
|
||||
{"case", KEYWORD_CASE},
|
||||
{"component", KEYWORD_COMPONENT},
|
||||
{"configuration", KEYWORD_CONFIGURATION},
|
||||
{"constant", KEYWORD_CONSTANT},
|
||||
{"disconnect", KEYWORD_DISCONNECT},
|
||||
{"downto", KEYWORD_DOWNTO},
|
||||
{"else", KEYWORD_ELSE},
|
||||
{"elsif", KEYWORD_ELSIF},
|
||||
{"end", KEYWORD_END},
|
||||
{"entity", KEYWORD_ENTITY},
|
||||
{"exit", KEYWORD_EXIT},
|
||||
{"file", KEYWORD_FILE},
|
||||
{"for", KEYWORD_FOR},
|
||||
{"function", KEYWORD_FUNCTION},
|
||||
{"generate", KEYWORD_GENERATE},
|
||||
{"generic", KEYWORD_GENERIC},
|
||||
{"group", KEYWORD_GROUP},
|
||||
{"guarded", KEYWORD_GUARDED},
|
||||
{"if", KEYWORD_IF},
|
||||
{"impure", KEYWORD_IMPURE},
|
||||
{"in", KEYWORD_IN},
|
||||
{"inertial", KEYWORD_INERTIAL},
|
||||
{"inout", KEYWORD_INOUT},
|
||||
{"is", KEYWORD_IS},
|
||||
{"label", KEYWORD_LABEL},
|
||||
{"library", KEYWORD_LIBRARY},
|
||||
{"linkage", KEYWORD_LINKAGE},
|
||||
{"literal", KEYWORD_LITERAL},
|
||||
{"loop", KEYWORD_LOOP},
|
||||
{"map", KEYWORD_MAP},
|
||||
{"mod", KEYWORD_MOD},
|
||||
{"nand", KEYWORD_NAND},
|
||||
{"new", KEYWORD_NEW},
|
||||
{"next", KEYWORD_NEXT},
|
||||
{"nor", KEYWORD_NOR},
|
||||
{"not", KEYWORD_NOT},
|
||||
{"null", KEYWORD_NULL},
|
||||
{"of", KEYWORD_OF},
|
||||
{"on", KEYWORD_ON},
|
||||
{"open", KEYWORD_OPEN},
|
||||
{"or", KEYWORD_OR},
|
||||
{"others", KEYWORD_OTHERS},
|
||||
{"out", KEYWORD_OUT},
|
||||
{"package", KEYWORD_PACKAGE},
|
||||
{"port", KEYWORD_PORT},
|
||||
{"postponed", KEYWORD_POSTPONED},
|
||||
{"procedure", KEYWORD_PROCEDURE},
|
||||
{"process", KEYWORD_PROCESS},
|
||||
{"pure", KEYWORD_PURE},
|
||||
{"range", KEYWORD_RANGE},
|
||||
{"record", KEYWORD_RECORD},
|
||||
{"register", KEYWORD_REGISTER},
|
||||
{"reject", KEYWORD_REJECT},
|
||||
{"return", KEYWORD_RETURN},
|
||||
{"rol", KEYWORD_ROL},
|
||||
{"ror", KEYWORD_ROR},
|
||||
{"select", KEYWORD_SELECT},
|
||||
{"severity", KEYWORD_SEVERITY},
|
||||
{"signal", KEYWORD_SIGNAL},
|
||||
{"shared", KEYWORD_SHARED},
|
||||
{"sla", KEYWORD_SLA},
|
||||
{"sli", KEYWORD_SLI},
|
||||
{"sra", KEYWORD_SRA},
|
||||
{"srl", KEYWORD_SRL},
|
||||
{"subtype", KEYWORD_SUBTYPE},
|
||||
{"then", KEYWORD_THEN},
|
||||
{"to", KEYWORD_TO},
|
||||
{"transport", KEYWORD_TRANSPORT},
|
||||
{"type", KEYWORD_TYPE},
|
||||
{"unaffected", KEYWORD_UNAFFECTED},
|
||||
{"units", KEYWORD_UNITS},
|
||||
{"until", KEYWORD_UNTIL},
|
||||
{"use", KEYWORD_USE},
|
||||
{"variable", KEYWORD_VARIABLE},
|
||||
{"wait", KEYWORD_WAIT},
|
||||
{"when", KEYWORD_WHEN},
|
||||
{"while", KEYWORD_WHILE},
|
||||
{"with", KEYWORD_WITH},
|
||||
{"xnor", KEYWORD_XNOR},
|
||||
{"xor", KEYWORD_XOR}};
|
||||
|
||||
/*
|
||||
* FUNCTION DECLARATIONS
|
||||
*/
|
||||
static void parseKeywords(tokenInfo *const token, boolean local);
|
||||
|
||||
/*
|
||||
* FUNCTION DEFINITIONS
|
||||
*/
|
||||
|
||||
static boolean isIdentChar1(const int c) {
|
||||
return (boolean)(isalpha(c) || c == '_');
|
||||
}
|
||||
|
||||
static boolean isIdentChar(const int c) {
|
||||
return (boolean)(isalpha(c) || isdigit(c) || c == '_');
|
||||
}
|
||||
|
||||
static boolean isIdentifierMatch(const tokenInfo *const token,
|
||||
const vString *const name) {
|
||||
return (boolean)(
|
||||
isType(token, TOKEN_IDENTIFIER) &&
|
||||
strcasecmp(vStringValue(token->string), vStringValue(name)) == 0);
|
||||
/* XXX this is copy/paste from eiffel.c and slightly modified */
|
||||
/* shouldn't we use strNcasecmp ? */
|
||||
}
|
||||
|
||||
static boolean isKeywordOrIdent(const tokenInfo *const token,
|
||||
const keywordId keyword,
|
||||
const vString *const name) {
|
||||
return (boolean)(isKeyword(token, keyword) || isIdentifierMatch(token, name));
|
||||
}
|
||||
|
||||
static tokenInfo *newToken(void) {
|
||||
tokenInfo *const token = xMalloc(1, tokenInfo);
|
||||
token->type = TOKEN_NONE;
|
||||
token->keyword = KEYWORD_NONE;
|
||||
token->string = vStringNew();
|
||||
token->scope = vStringNew();
|
||||
token->lineNumber = getSourceLineNumber();
|
||||
token->filePosition = getInputFilePosition();
|
||||
return token;
|
||||
}
|
||||
|
||||
static void deleteToken(tokenInfo *const token) {
|
||||
if (token != NULL) {
|
||||
vStringDelete(token->string);
|
||||
vStringDelete(token->scope);
|
||||
eFree(token);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parsing functions
|
||||
*/
|
||||
|
||||
static void parseString(vString *const string, const int delimiter) {
|
||||
boolean end = FALSE;
|
||||
while (!end) {
|
||||
int c = fileGetc();
|
||||
if (c == EOF)
|
||||
end = TRUE;
|
||||
else if (c == '\\') {
|
||||
c = fileGetc(); /* This maybe a ' or ". */
|
||||
vStringPut(string, c);
|
||||
} else if (c == delimiter)
|
||||
end = TRUE;
|
||||
else
|
||||
vStringPut(string, c);
|
||||
}
|
||||
vStringTerminate(string);
|
||||
}
|
||||
|
||||
/* Read a VHDL identifier beginning with "firstChar" and place it into "name".
|
||||
*/
|
||||
static void parseIdentifier(vString *const string, const int firstChar) {
|
||||
int c = firstChar;
|
||||
Assert(isIdentChar1(c));
|
||||
do {
|
||||
vStringPut(string, c);
|
||||
c = fileGetc();
|
||||
} while (isIdentChar(c));
|
||||
vStringTerminate(string);
|
||||
if (!isspace(c)) fileUngetc(c); /* unget non-identifier character */
|
||||
}
|
||||
|
||||
static void readToken(tokenInfo *const token) {
|
||||
int c;
|
||||
|
||||
token->type = TOKEN_NONE;
|
||||
token->keyword = KEYWORD_NONE;
|
||||
vStringClear(token->string);
|
||||
|
||||
getNextChar:
|
||||
do {
|
||||
c = fileGetc();
|
||||
token->lineNumber = getSourceLineNumber();
|
||||
token->filePosition = getInputFilePosition();
|
||||
} while (c == '\t' || c == ' ' || c == '\n');
|
||||
|
||||
switch (c) {
|
||||
case EOF:
|
||||
longjmp(Exception, (int)ExceptionEOF);
|
||||
break;
|
||||
case '(':
|
||||
token->type = TOKEN_OPEN_PAREN;
|
||||
break;
|
||||
case ')':
|
||||
token->type = TOKEN_CLOSE_PAREN;
|
||||
break;
|
||||
case ';':
|
||||
token->type = TOKEN_SEMICOLON;
|
||||
break;
|
||||
case '.':
|
||||
token->type = TOKEN_PERIOD;
|
||||
break;
|
||||
case ',':
|
||||
token->type = TOKEN_COMMA;
|
||||
break;
|
||||
case '\'': /* only single char are inside simple quotes */
|
||||
break; /* or it is for attributes so we don't care */
|
||||
case '"':
|
||||
token->type = TOKEN_STRING;
|
||||
parseString(token->string, c);
|
||||
token->lineNumber = getSourceLineNumber();
|
||||
token->filePosition = getInputFilePosition();
|
||||
break;
|
||||
case '-':
|
||||
c = fileGetc();
|
||||
if (c == '-') /* start of a comment */
|
||||
{
|
||||
fileSkipToCharacter('\n');
|
||||
goto getNextChar;
|
||||
} else {
|
||||
if (!isspace(c)) fileUngetc(c);
|
||||
token->type = TOKEN_OPERATOR;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (!isIdentChar1(c))
|
||||
token->type = TOKEN_NONE;
|
||||
else {
|
||||
parseIdentifier(token->string, c);
|
||||
token->lineNumber = getSourceLineNumber();
|
||||
token->filePosition = getInputFilePosition();
|
||||
token->keyword = analyzeToken(token->string, Lang_vhdl);
|
||||
if (isKeyword(token, KEYWORD_NONE))
|
||||
token->type = TOKEN_IDENTIFIER;
|
||||
else
|
||||
token->type = TOKEN_KEYWORD;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void skipToKeyword(const keywordId keyword) {
|
||||
tokenInfo *const token = newToken();
|
||||
do {
|
||||
readToken(token);
|
||||
} while (!isKeyword(token, keyword));
|
||||
deleteToken(token);
|
||||
}
|
||||
|
||||
static void skipToMatched(tokenInfo *const token) {
|
||||
int nest_level = 0;
|
||||
tokenType open_token;
|
||||
tokenType close_token;
|
||||
|
||||
switch (token->type) {
|
||||
case TOKEN_OPEN_PAREN:
|
||||
open_token = TOKEN_OPEN_PAREN;
|
||||
close_token = TOKEN_CLOSE_PAREN;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine will skip to a matching closing token.
|
||||
* It will also handle nested tokens like the (, ) below.
|
||||
* ( name varchar(30), text binary(10) )
|
||||
*/
|
||||
if (isType(token, open_token)) {
|
||||
nest_level++;
|
||||
while (!(isType(token, close_token) && (nest_level == 0))) {
|
||||
readToken(token);
|
||||
if (isType(token, open_token)) {
|
||||
nest_level++;
|
||||
}
|
||||
if (isType(token, close_token)) {
|
||||
if (nest_level > 0) {
|
||||
nest_level--;
|
||||
}
|
||||
}
|
||||
}
|
||||
readToken(token);
|
||||
}
|
||||
}
|
||||
|
||||
static void makeConstTag(tokenInfo *const token, const vhdlKind kind) {
|
||||
if (VhdlKinds[kind].enabled) {
|
||||
const char *const name = vStringValue(token->string);
|
||||
tagEntryInfo e;
|
||||
initTagEntry(&e, name);
|
||||
e.lineNumber = token->lineNumber;
|
||||
e.filePosition = token->filePosition;
|
||||
e.kindName = VhdlKinds[kind].name;
|
||||
e.kind = VhdlKinds[kind].letter;
|
||||
makeTagEntry(&e);
|
||||
}
|
||||
}
|
||||
|
||||
static void makeVhdlTag(tokenInfo *const token, const vhdlKind kind) {
|
||||
if (VhdlKinds[kind].enabled) {
|
||||
/*
|
||||
* If a scope has been added to the token, change the token
|
||||
* string to include the scope when making the tag.
|
||||
*/
|
||||
if (vStringLength(token->scope) > 0) {
|
||||
vString *fulltag = vStringNew();
|
||||
vStringCopy(fulltag, token->scope);
|
||||
vStringCatS(fulltag, ".");
|
||||
vStringCatS(fulltag, vStringValue(token->string));
|
||||
vStringTerminate(fulltag);
|
||||
vStringCopy(token->string, fulltag);
|
||||
vStringDelete(fulltag);
|
||||
}
|
||||
makeConstTag(token, kind);
|
||||
}
|
||||
}
|
||||
|
||||
static void initialize(const langType language) {
|
||||
size_t i;
|
||||
const size_t count = sizeof(VhdlKeywordTable) / sizeof(VhdlKeywordTable[0]);
|
||||
Lang_vhdl = language;
|
||||
for (i = 0; i < count; ++i) {
|
||||
const keywordDesc *const p = &VhdlKeywordTable[i];
|
||||
addKeyword(p->name, language, (int)p->id);
|
||||
}
|
||||
}
|
||||
|
||||
static void parsePackage(tokenInfo *const token) {
|
||||
tokenInfo *const name = newToken();
|
||||
Assert(isKeyword(token, KEYWORD_PACKAGE));
|
||||
readToken(token);
|
||||
if (isKeyword(token, KEYWORD_BODY)) {
|
||||
readToken(name);
|
||||
makeVhdlTag(name, VHDLTAG_PACKAGE);
|
||||
} else if (isType(token, TOKEN_IDENTIFIER)) {
|
||||
makeVhdlTag(token, VHDLTAG_PACKAGE);
|
||||
}
|
||||
deleteToken(name);
|
||||
}
|
||||
|
||||
static void parseModule(tokenInfo *const token) {
|
||||
tokenInfo *const name = newToken();
|
||||
const vhdlKind kind =
|
||||
isKeyword(token, KEYWORD_ENTITY) ? VHDLTAG_ENTITY : VHDLTAG_COMPONENT;
|
||||
Assert(isKeyword(token, KEYWORD_ENTITY) ||
|
||||
isKeyword(token, KEYWORD_COMPONENT));
|
||||
readToken(name);
|
||||
if (kind == VHDLTAG_COMPONENT) {
|
||||
makeVhdlTag(name, VHDLTAG_COMPONENT);
|
||||
skipToKeyword(KEYWORD_END);
|
||||
fileSkipToCharacter(';');
|
||||
} else {
|
||||
readToken(token);
|
||||
if (isKeyword(token, KEYWORD_IS)) {
|
||||
makeVhdlTag(name, VHDLTAG_ENTITY);
|
||||
skipToKeyword(KEYWORD_END);
|
||||
fileSkipToCharacter(';');
|
||||
}
|
||||
}
|
||||
deleteToken(name);
|
||||
}
|
||||
|
||||
static void parseRecord(tokenInfo *const token) {
|
||||
tokenInfo *const name = newToken();
|
||||
Assert(isKeyword(token, KEYWORD_RECORD));
|
||||
readToken(name);
|
||||
do {
|
||||
readToken(token); /* should be a colon */
|
||||
fileSkipToCharacter(';');
|
||||
makeVhdlTag(name, VHDLTAG_RECORD);
|
||||
readToken(name);
|
||||
} while (!isKeyword(name, KEYWORD_END));
|
||||
fileSkipToCharacter(';');
|
||||
deleteToken(name);
|
||||
}
|
||||
|
||||
static void parseTypes(tokenInfo *const token) {
|
||||
tokenInfo *const name = newToken();
|
||||
const vhdlKind kind =
|
||||
isKeyword(token, KEYWORD_TYPE) ? VHDLTAG_TYPE : VHDLTAG_SUBTYPE;
|
||||
Assert(isKeyword(token, KEYWORD_TYPE) || isKeyword(token, KEYWORD_SUBTYPE));
|
||||
readToken(name);
|
||||
readToken(token);
|
||||
if (isKeyword(token, KEYWORD_IS)) {
|
||||
readToken(token); /* type */
|
||||
if (isKeyword(token, KEYWORD_RECORD)) {
|
||||
makeVhdlTag(name, kind);
|
||||
/*TODO: make tags of the record's names */
|
||||
parseRecord(token);
|
||||
} else {
|
||||
makeVhdlTag(name, kind);
|
||||
}
|
||||
}
|
||||
deleteToken(name);
|
||||
}
|
||||
|
||||
static void parseConstant(boolean local) {
|
||||
tokenInfo *const name = newToken();
|
||||
readToken(name);
|
||||
if (local) {
|
||||
makeVhdlTag(name, VHDLTAG_LOCAL);
|
||||
} else {
|
||||
makeVhdlTag(name, VHDLTAG_CONSTANT);
|
||||
}
|
||||
fileSkipToCharacter(';');
|
||||
deleteToken(name);
|
||||
}
|
||||
|
||||
static void parseSubProgram(tokenInfo *const token) {
|
||||
tokenInfo *const name = newToken();
|
||||
boolean endSubProgram = FALSE;
|
||||
const vhdlKind kind =
|
||||
isKeyword(token, KEYWORD_FUNCTION) ? VHDLTAG_FUNCTION : VHDLTAG_PROCEDURE;
|
||||
Assert(isKeyword(token, KEYWORD_FUNCTION) ||
|
||||
isKeyword(token, KEYWORD_PROCEDURE));
|
||||
readToken(name); /* the name of the function or procedure */
|
||||
readToken(token);
|
||||
if (isType(token, TOKEN_OPEN_PAREN)) {
|
||||
skipToMatched(token);
|
||||
}
|
||||
|
||||
if (kind == VHDLTAG_FUNCTION) {
|
||||
if (isKeyword(token, KEYWORD_RETURN)) {
|
||||
/* Read datatype */
|
||||
readToken(token);
|
||||
while (!isKeyword(token, KEYWORD_IS) && !isType(token, TOKEN_SEMICOLON)) {
|
||||
readToken(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isType(token, TOKEN_SEMICOLON)) {
|
||||
makeVhdlTag(name, VHDLTAG_PROTOTYPE);
|
||||
} else if (isKeyword(token, KEYWORD_IS)) {
|
||||
if (kind == VHDLTAG_FUNCTION) {
|
||||
makeVhdlTag(name, VHDLTAG_FUNCTION);
|
||||
do {
|
||||
readToken(token);
|
||||
if (isKeyword(token, KEYWORD_END)) {
|
||||
readToken(token);
|
||||
endSubProgram =
|
||||
isKeywordOrIdent(token, KEYWORD_FUNCTION, name->string);
|
||||
fileSkipToCharacter(';');
|
||||
} else {
|
||||
parseKeywords(token, TRUE);
|
||||
}
|
||||
} while (!endSubProgram);
|
||||
} else {
|
||||
makeVhdlTag(name, VHDLTAG_PROCEDURE);
|
||||
do {
|
||||
readToken(token);
|
||||
if (isKeyword(token, KEYWORD_END)) {
|
||||
readToken(token);
|
||||
endSubProgram =
|
||||
isKeywordOrIdent(token, KEYWORD_PROCEDURE, name->string);
|
||||
fileSkipToCharacter(';');
|
||||
} else {
|
||||
parseKeywords(token, TRUE);
|
||||
}
|
||||
} while (!endSubProgram);
|
||||
}
|
||||
}
|
||||
deleteToken(name);
|
||||
}
|
||||
|
||||
/* TODO */
|
||||
/* records */
|
||||
static void parseKeywords(tokenInfo *const token, boolean local) {
|
||||
switch (token->keyword) {
|
||||
case KEYWORD_END:
|
||||
fileSkipToCharacter(';');
|
||||
break;
|
||||
case KEYWORD_CONSTANT:
|
||||
parseConstant(local);
|
||||
break;
|
||||
case KEYWORD_TYPE:
|
||||
parseTypes(token);
|
||||
break;
|
||||
case KEYWORD_SUBTYPE:
|
||||
parseTypes(token);
|
||||
break;
|
||||
case KEYWORD_ENTITY:
|
||||
parseModule(token);
|
||||
break;
|
||||
case KEYWORD_COMPONENT:
|
||||
parseModule(token);
|
||||
break;
|
||||
case KEYWORD_FUNCTION:
|
||||
parseSubProgram(token);
|
||||
break;
|
||||
case KEYWORD_PROCEDURE:
|
||||
parseSubProgram(token);
|
||||
break;
|
||||
case KEYWORD_PACKAGE:
|
||||
parsePackage(token);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void parseVhdlFile(tokenInfo *const token) {
|
||||
do {
|
||||
readToken(token);
|
||||
parseKeywords(token, FALSE);
|
||||
} while (!isKeyword(token, KEYWORD_END));
|
||||
}
|
||||
|
||||
static void findVhdlTags(void) {
|
||||
tokenInfo *const token = newToken();
|
||||
exception_t exception = (exception_t)(setjmp(Exception));
|
||||
|
||||
while (exception == ExceptionNone) parseVhdlFile(token);
|
||||
|
||||
deleteToken(token);
|
||||
}
|
||||
|
||||
extern parserDefinition *VhdlParser(void) {
|
||||
static const char *const extensions[] = {"vhdl", "vhd", NULL};
|
||||
parserDefinition *def = parserNew("VHDL");
|
||||
def->kinds = VhdlKinds;
|
||||
def->kindCount = KIND_COUNT(VhdlKinds);
|
||||
def->extensions = extensions;
|
||||
def->parser = findVhdlTags;
|
||||
def->initialize = initialize;
|
||||
return def;
|
||||
}
|
||||
|
||||
/* vi:set tabstop=4 shiftwidth=4 noet: */
|
||||
547
third_party/ctags/vim.c
vendored
547
third_party/ctags/vim.c
vendored
@@ -1,547 +0,0 @@
|
||||
/*
|
||||
* $Id: vim.c 762 2010-07-28 11:38:19Z dfishburn $
|
||||
*
|
||||
* Copyright (c) 2000-2003, Darren Hiebert
|
||||
*
|
||||
* This source code is released for free distribution under the
|
||||
* terms of the GNU General Public License.
|
||||
*
|
||||
* Thanks are due to Jay Glanville for significant improvements.
|
||||
*
|
||||
* This module contains functions for generating tags for user-defined
|
||||
* functions for the Vim editor.
|
||||
*/
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/parse.h"
|
||||
#include "third_party/ctags/read.h"
|
||||
#include "third_party/ctags/vstring.h"
|
||||
|
||||
#if 0
|
||||
typedef struct sLineInfo {
|
||||
tokenType type;
|
||||
keywordId keyword;
|
||||
vString * string;
|
||||
vString * scope;
|
||||
unsigned long lineNumber;
|
||||
fpos_t filePosition;
|
||||
} lineInfo;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* DATA DEFINITIONS
|
||||
*/
|
||||
typedef enum { K_AUGROUP, K_COMMAND, K_FUNCTION, K_MAP, K_VARIABLE } vimKind;
|
||||
|
||||
static kindOption VimKinds[] = {
|
||||
{TRUE, 'a', "augroup", "autocommand groups"},
|
||||
{TRUE, 'c', "command", "user-defined commands"},
|
||||
{TRUE, 'f', "function", "function definitions"},
|
||||
{TRUE, 'm', "map", "maps"},
|
||||
{TRUE, 'v', "variable", "variable definitions"},
|
||||
};
|
||||
|
||||
/*
|
||||
* DATA DECLARATIONS
|
||||
*/
|
||||
|
||||
#if 0
|
||||
typedef enum eException {
|
||||
ExceptionNone, ExceptionEOF
|
||||
} exception_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* DATA DEFINITIONS
|
||||
*/
|
||||
|
||||
#if 0
|
||||
static jmp_buf Exception;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* FUNCTION DEFINITIONS
|
||||
*/
|
||||
|
||||
/* This function takes a char pointer, tries to find a scope separator in the
|
||||
* string, and if it does, returns a pointer to the character after the colon,
|
||||
* and the character defining the scope.
|
||||
* If a colon is not found, it returns the original pointer.
|
||||
*/
|
||||
static const unsigned char *skipPrefix(const unsigned char *name, int *scope) {
|
||||
const unsigned char *result = name;
|
||||
int counter;
|
||||
size_t length;
|
||||
length = strlen((const char *)name);
|
||||
if (scope != NULL) *scope = '\0';
|
||||
if (length > 3 && name[1] == ':') {
|
||||
if (scope != NULL) *scope = *name;
|
||||
result = name + 2;
|
||||
} else if (length > 5 &&
|
||||
strncasecmp((const char *)name, "<SID>", (size_t)5) == 0) {
|
||||
if (scope != NULL) *scope = *name;
|
||||
result = name + 5;
|
||||
} else {
|
||||
/*
|
||||
* Vim7 check for dictionaries or autoload function names
|
||||
*/
|
||||
counter = 0;
|
||||
do {
|
||||
switch (name[counter]) {
|
||||
case '.':
|
||||
/* Set the scope to d - Dictionary */
|
||||
*scope = 'd';
|
||||
break;
|
||||
case '#':
|
||||
/* Set the scope to a - autoload */
|
||||
*scope = 'a';
|
||||
break;
|
||||
}
|
||||
++counter;
|
||||
} while (isalnum((int)name[counter]) || name[counter] == '_' ||
|
||||
name[counter] == '.' || name[counter] == '#');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static boolean isMap(const unsigned char *line) {
|
||||
/*
|
||||
* There are many different short cuts for specifying a map.
|
||||
* This routine should capture all the permutations.
|
||||
*/
|
||||
if (strncmp((const char *)line, "map", (size_t)3) == 0 ||
|
||||
strncmp((const char *)line, "nm", (size_t)2) == 0 ||
|
||||
strncmp((const char *)line, "nma", (size_t)3) == 0 ||
|
||||
strncmp((const char *)line, "nmap", (size_t)4) == 0 ||
|
||||
strncmp((const char *)line, "vm", (size_t)2) == 0 ||
|
||||
strncmp((const char *)line, "vma", (size_t)3) == 0 ||
|
||||
strncmp((const char *)line, "vmap", (size_t)4) == 0 ||
|
||||
strncmp((const char *)line, "om", (size_t)2) == 0 ||
|
||||
strncmp((const char *)line, "oma", (size_t)3) == 0 ||
|
||||
strncmp((const char *)line, "omap", (size_t)4) == 0 ||
|
||||
strncmp((const char *)line, "im", (size_t)2) == 0 ||
|
||||
strncmp((const char *)line, "ima", (size_t)3) == 0 ||
|
||||
strncmp((const char *)line, "imap", (size_t)4) == 0 ||
|
||||
strncmp((const char *)line, "lm", (size_t)2) == 0 ||
|
||||
strncmp((const char *)line, "lma", (size_t)3) == 0 ||
|
||||
strncmp((const char *)line, "lmap", (size_t)4) == 0 ||
|
||||
strncmp((const char *)line, "cm", (size_t)2) == 0 ||
|
||||
strncmp((const char *)line, "cma", (size_t)3) == 0 ||
|
||||
strncmp((const char *)line, "cmap", (size_t)4) == 0 ||
|
||||
strncmp((const char *)line, "no", (size_t)2) == 0 ||
|
||||
strncmp((const char *)line, "nor", (size_t)3) == 0 ||
|
||||
strncmp((const char *)line, "nore", (size_t)4) == 0 ||
|
||||
strncmp((const char *)line, "norem", (size_t)5) == 0 ||
|
||||
strncmp((const char *)line, "norema", (size_t)6) == 0 ||
|
||||
strncmp((const char *)line, "noremap", (size_t)7) == 0 ||
|
||||
strncmp((const char *)line, "nno", (size_t)3) == 0 ||
|
||||
strncmp((const char *)line, "nnor", (size_t)4) == 0 ||
|
||||
strncmp((const char *)line, "nnore", (size_t)5) == 0 ||
|
||||
strncmp((const char *)line, "nnorem", (size_t)6) == 0 ||
|
||||
strncmp((const char *)line, "nnorema", (size_t)7) == 0 ||
|
||||
strncmp((const char *)line, "nnoremap", (size_t)8) == 0 ||
|
||||
strncmp((const char *)line, "vno", (size_t)3) == 0 ||
|
||||
strncmp((const char *)line, "vnor", (size_t)4) == 0 ||
|
||||
strncmp((const char *)line, "vnore", (size_t)5) == 0 ||
|
||||
strncmp((const char *)line, "vnorem", (size_t)6) == 0 ||
|
||||
strncmp((const char *)line, "vnorema", (size_t)7) == 0 ||
|
||||
strncmp((const char *)line, "vnoremap", (size_t)8) == 0 ||
|
||||
strncmp((const char *)line, "ono", (size_t)3) == 0 ||
|
||||
strncmp((const char *)line, "onor", (size_t)4) == 0 ||
|
||||
strncmp((const char *)line, "onore", (size_t)5) == 0 ||
|
||||
strncmp((const char *)line, "onorem", (size_t)6) == 0 ||
|
||||
strncmp((const char *)line, "onorema", (size_t)7) == 0 ||
|
||||
strncmp((const char *)line, "onoremap", (size_t)8) == 0 ||
|
||||
strncmp((const char *)line, "ino", (size_t)3) == 0 ||
|
||||
strncmp((const char *)line, "inor", (size_t)4) == 0 ||
|
||||
strncmp((const char *)line, "inore", (size_t)5) == 0 ||
|
||||
strncmp((const char *)line, "inorem", (size_t)6) == 0 ||
|
||||
strncmp((const char *)line, "inorema", (size_t)7) == 0 ||
|
||||
strncmp((const char *)line, "inoremap", (size_t)8) == 0 ||
|
||||
strncmp((const char *)line, "lno", (size_t)3) == 0 ||
|
||||
strncmp((const char *)line, "lnor", (size_t)4) == 0 ||
|
||||
strncmp((const char *)line, "lnore", (size_t)5) == 0 ||
|
||||
strncmp((const char *)line, "lnorem", (size_t)6) == 0 ||
|
||||
strncmp((const char *)line, "lnorema", (size_t)7) == 0 ||
|
||||
strncmp((const char *)line, "lnoremap", (size_t)8) == 0 ||
|
||||
strncmp((const char *)line, "cno", (size_t)3) == 0 ||
|
||||
strncmp((const char *)line, "cnor", (size_t)4) == 0 ||
|
||||
strncmp((const char *)line, "cnore", (size_t)5) == 0 ||
|
||||
strncmp((const char *)line, "cnorem", (size_t)6) == 0 ||
|
||||
strncmp((const char *)line, "cnorema", (size_t)7) == 0 ||
|
||||
strncmp((const char *)line, "cnoremap", (size_t)8) == 0)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static const unsigned char *readVimLine(void) {
|
||||
const unsigned char *line;
|
||||
|
||||
while ((line = fileReadLine()) != NULL) {
|
||||
while (isspace((int)*line)) ++line;
|
||||
|
||||
if ((int)*line == '"') continue; /* skip comment */
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
static void parseFunction(const unsigned char *line) {
|
||||
vString *name = vStringNew();
|
||||
/* boolean inFunction = FALSE; */
|
||||
int scope;
|
||||
|
||||
const unsigned char *cp = line + 1;
|
||||
|
||||
if ((int)*++cp == 'n' && (int)*++cp == 'c' && (int)*++cp == 't' &&
|
||||
(int)*++cp == 'i' && (int)*++cp == 'o' && (int)*++cp == 'n')
|
||||
++cp;
|
||||
if ((int)*cp == '!') ++cp;
|
||||
if (isspace((int)*cp)) {
|
||||
while (*cp && isspace((int)*cp)) ++cp;
|
||||
|
||||
if (*cp) {
|
||||
cp = skipPrefix(cp, &scope);
|
||||
if (isupper((int)*cp) || scope == 's' || /* script scope */
|
||||
scope == '<' || /* script scope */
|
||||
scope == 'd' || /* dictionary */
|
||||
scope == 'a') /* autoload */
|
||||
{
|
||||
do {
|
||||
vStringPut(name, (int)*cp);
|
||||
++cp;
|
||||
} while (isalnum((int)*cp) || *cp == '_' || *cp == '.' || *cp == '#');
|
||||
vStringTerminate(name);
|
||||
makeSimpleTag(name, VimKinds, K_FUNCTION);
|
||||
vStringClear(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO - update struct to indicate inside function */
|
||||
while ((line = readVimLine()) != NULL) {
|
||||
/*
|
||||
* Vim7 added the for/endfo[r] construct, so we must first
|
||||
* check for an "endfo", before a "endf"
|
||||
*/
|
||||
if ((!strncmp((const char *)line, "endfo", (size_t)5) == 0) &&
|
||||
(strncmp((const char *)line, "endf", (size_t)4) == 0))
|
||||
break;
|
||||
/* TODO - call parseVimLine */
|
||||
}
|
||||
vStringDelete(name);
|
||||
}
|
||||
|
||||
static void parseAutogroup(const unsigned char *line) {
|
||||
vString *name = vStringNew();
|
||||
|
||||
/* Found Autocommand Group (augroup) */
|
||||
const unsigned char *cp = line + 2;
|
||||
if ((int)*++cp == 'r' && (int)*++cp == 'o' && (int)*++cp == 'u' &&
|
||||
(int)*++cp == 'p')
|
||||
++cp;
|
||||
if (isspace((int)*cp)) {
|
||||
while (*cp && isspace((int)*cp)) ++cp;
|
||||
|
||||
if (*cp) {
|
||||
if (strncasecmp((const char *)cp, "end", (size_t)3) != 0) {
|
||||
do {
|
||||
vStringPut(name, (int)*cp);
|
||||
++cp;
|
||||
} while (isalnum((int)*cp) || *cp == '_');
|
||||
vStringTerminate(name);
|
||||
makeSimpleTag(name, VimKinds, K_AUGROUP);
|
||||
vStringClear(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
vStringDelete(name);
|
||||
}
|
||||
|
||||
static boolean parseCommand(const unsigned char *line) {
|
||||
vString *name = vStringNew();
|
||||
boolean cmdProcessed = TRUE;
|
||||
|
||||
/*
|
||||
* Found a user-defined command
|
||||
*
|
||||
* They can have many options preceeded by a dash
|
||||
* command! -nargs=+ -complete Select :call s:DB_execSql("select " .
|
||||
* <q-args>) The name of the command should be the first word not preceeded by
|
||||
* a dash
|
||||
*
|
||||
*/
|
||||
const unsigned char *cp = line;
|
||||
|
||||
if ((int)*cp == '\\') {
|
||||
/*
|
||||
* We are recursively calling this function is the command
|
||||
* has been continued on to the next line
|
||||
*
|
||||
* Vim statements can be continued onto a newline using a \
|
||||
* to indicate the previous line is continuing.
|
||||
*
|
||||
* com -nargs=1 -bang -complete=customlist,EditFileComplete
|
||||
* \ EditFile edit<bang> <args>
|
||||
*
|
||||
* If the following lines do not have a line continuation
|
||||
* the command must not be spanning multiple lines and should
|
||||
* be synatically incorrect.
|
||||
*/
|
||||
if ((int)*cp == '\\') ++cp;
|
||||
|
||||
while (*cp && isspace((int)*cp)) ++cp;
|
||||
} else if ((!strncmp((const char *)line, "comp", (size_t)4) == 0) &&
|
||||
(!strncmp((const char *)line, "comc", (size_t)4) == 0) &&
|
||||
(strncmp((const char *)line, "com", (size_t)3) == 0)) {
|
||||
cp += 2;
|
||||
if ((int)*++cp == 'm' && (int)*++cp == 'a' && (int)*++cp == 'n' &&
|
||||
(int)*++cp == 'd')
|
||||
++cp;
|
||||
|
||||
if ((int)*cp == '!') ++cp;
|
||||
|
||||
if ((int)*cp != ' ') {
|
||||
/*
|
||||
* :command must be followed by a space. If it is not, it is
|
||||
* not a valid command.
|
||||
* Treat the line as processed and continue.
|
||||
*/
|
||||
cmdProcessed = TRUE;
|
||||
goto cleanUp;
|
||||
}
|
||||
|
||||
while (*cp && isspace((int)*cp)) ++cp;
|
||||
} else {
|
||||
/*
|
||||
* We are recursively calling this function. If it does not start
|
||||
* with "com" or a line continuation character, we have moved off
|
||||
* the command line and should let the other routines parse this file.
|
||||
*/
|
||||
cmdProcessed = FALSE;
|
||||
goto cleanUp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Strip off any spaces and options which are part of the command.
|
||||
* These should preceed the command name.
|
||||
*/
|
||||
do {
|
||||
if (isspace((int)*cp)) {
|
||||
++cp;
|
||||
} else if (*cp == '-') {
|
||||
/*
|
||||
* Read until the next space which separates options or the name
|
||||
*/
|
||||
while (*cp && !isspace((int)*cp)) ++cp;
|
||||
} else
|
||||
break;
|
||||
} while (*cp);
|
||||
|
||||
if (!*cp) {
|
||||
/*
|
||||
* We have reached the end of the line without finding the command name.
|
||||
* Read the next line and continue processing it as a command.
|
||||
*/
|
||||
line = readVimLine();
|
||||
parseCommand(line);
|
||||
goto cleanUp;
|
||||
}
|
||||
|
||||
do {
|
||||
vStringPut(name, (int)*cp);
|
||||
++cp;
|
||||
} while (isalnum((int)*cp) || *cp == '_');
|
||||
|
||||
vStringTerminate(name);
|
||||
makeSimpleTag(name, VimKinds, K_COMMAND);
|
||||
vStringClear(name);
|
||||
|
||||
cleanUp:
|
||||
vStringDelete(name);
|
||||
|
||||
return cmdProcessed;
|
||||
}
|
||||
|
||||
static void parseLet(const unsigned char *line) {
|
||||
vString *name = vStringNew();
|
||||
|
||||
/* we've found a variable declared outside of a function!! */
|
||||
const unsigned char *cp = line + 3;
|
||||
const unsigned char *np = line;
|
||||
/* get the name */
|
||||
if (isspace((int)*cp)) {
|
||||
while (*cp && isspace((int)*cp)) ++cp;
|
||||
|
||||
/*
|
||||
* Ignore lets which set:
|
||||
* & - local buffer vim settings
|
||||
* @ - registers
|
||||
* [ - Lists or Dictionaries
|
||||
*/
|
||||
if (!*cp || *cp == '&' || *cp == '@' || *cp == '[') goto cleanUp;
|
||||
|
||||
/*
|
||||
* Ignore vim variables which are read only
|
||||
* v: - Vim variables.
|
||||
*/
|
||||
np = cp;
|
||||
++np;
|
||||
if ((int)*cp == 'v' && (int)*np == ':') goto cleanUp;
|
||||
|
||||
/* deal with spaces, $, @ and & */
|
||||
while (*cp && *cp != '$' && !isalnum((int)*cp)) ++cp;
|
||||
|
||||
if (!*cp) goto cleanUp;
|
||||
|
||||
/* cp = skipPrefix (cp, &scope); */
|
||||
do {
|
||||
if (!*cp) break;
|
||||
|
||||
vStringPut(name, (int)*cp);
|
||||
++cp;
|
||||
} while (isalnum((int)*cp) || *cp == '_' || *cp == '#' || *cp == ':' ||
|
||||
*cp == '$');
|
||||
vStringTerminate(name);
|
||||
makeSimpleTag(name, VimKinds, K_VARIABLE);
|
||||
vStringClear(name);
|
||||
}
|
||||
|
||||
cleanUp:
|
||||
vStringDelete(name);
|
||||
}
|
||||
|
||||
static boolean parseMap(const unsigned char *line) {
|
||||
vString *name = vStringNew();
|
||||
|
||||
const unsigned char *cp = line;
|
||||
|
||||
/* Remove map */
|
||||
while (*cp && isalnum((int)*cp)) ++cp;
|
||||
|
||||
if ((int)*cp == '!') ++cp;
|
||||
|
||||
/*
|
||||
* Maps follow this basic format
|
||||
* map
|
||||
* nnoremap <silent> <F8> :Tlist<CR>
|
||||
* map <unique> <Leader>scdt <Plug>GetColumnDataType
|
||||
* inoremap ,,, <esc>diwi<<esc>pa><cr></<esc>pa><esc>kA
|
||||
* inoremap <buffer> ( <C-R>=PreviewFunctionSignature()<LF>
|
||||
*
|
||||
* The Vim help shows the various special arguments available to a map:
|
||||
* 1.2 SPECIAL ARGUMENTS *:map-arguments*
|
||||
* <buffer>
|
||||
* <silent>
|
||||
* <script>
|
||||
* <unique>
|
||||
* <special>
|
||||
* <expr>
|
||||
*
|
||||
* Strip the special arguments from the map command, this should leave
|
||||
* the map name which we will use as the "name".
|
||||
*/
|
||||
|
||||
do {
|
||||
while (*cp && isspace((int)*cp)) ++cp;
|
||||
|
||||
if (strncmp((const char *)cp, "<Leader>", (size_t)8) == 0) break;
|
||||
|
||||
if (strncmp((const char *)cp, "<buffer>", (size_t)8) == 0 ||
|
||||
strncmp((const char *)cp, "<silent>", (size_t)8) == 0 ||
|
||||
strncmp((const char *)cp, "<script>", (size_t)8) == 0 ||
|
||||
strncmp((const char *)cp, "<unique>", (size_t)8) == 0) {
|
||||
cp += 8;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp((const char *)cp, "<expr>", (size_t)6) == 0) {
|
||||
cp += 6;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp((const char *)cp, "<special>", (size_t)9) == 0) {
|
||||
cp += 9;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
} while (*cp);
|
||||
|
||||
do {
|
||||
vStringPut(name, (int)*cp);
|
||||
++cp;
|
||||
} while (*cp && *cp != ' ');
|
||||
|
||||
vStringTerminate(name);
|
||||
makeSimpleTag(name, VimKinds, K_MAP);
|
||||
vStringClear(name);
|
||||
|
||||
vStringDelete(name);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static boolean parseVimLine(const unsigned char *line) {
|
||||
boolean readNextLine = TRUE;
|
||||
|
||||
if ((!strncmp((const char *)line, "comp", (size_t)4) == 0) &&
|
||||
(!strncmp((const char *)line, "comc", (size_t)4) == 0) &&
|
||||
(strncmp((const char *)line, "com", (size_t)3) == 0)) {
|
||||
readNextLine = parseCommand(line);
|
||||
/* TODO - Handle parseCommand returning FALSE */
|
||||
}
|
||||
|
||||
if (isMap(line)) {
|
||||
parseMap(line);
|
||||
}
|
||||
|
||||
if (strncmp((const char *)line, "fu", (size_t)2) == 0) {
|
||||
parseFunction(line);
|
||||
}
|
||||
|
||||
if (strncmp((const char *)line, "aug", (size_t)3) == 0) {
|
||||
parseAutogroup(line);
|
||||
}
|
||||
|
||||
if (strncmp((const char *)line, "let", (size_t)3) == 0) {
|
||||
parseLet(line);
|
||||
}
|
||||
|
||||
return readNextLine;
|
||||
}
|
||||
|
||||
static void parseVimFile(const unsigned char *line) {
|
||||
boolean readNextLine = TRUE;
|
||||
line = readVimLine();
|
||||
|
||||
while (line != NULL) {
|
||||
readNextLine = parseVimLine(line);
|
||||
|
||||
if (readNextLine) line = readVimLine();
|
||||
}
|
||||
}
|
||||
|
||||
static void findVimTags(void) {
|
||||
const unsigned char *line;
|
||||
/* TODO - change this into a structure */
|
||||
|
||||
line = '\0';
|
||||
|
||||
parseVimFile(line);
|
||||
}
|
||||
|
||||
extern parserDefinition *VimParser(void) {
|
||||
static const char *const extensions[] = {"vim", NULL};
|
||||
parserDefinition *def = parserNew("Vim");
|
||||
def->kinds = VimKinds;
|
||||
def->kindCount = KIND_COUNT(VimKinds);
|
||||
def->extensions = extensions;
|
||||
def->parser = findVimTags;
|
||||
return def;
|
||||
}
|
||||
|
||||
/* vi:set tabstop=4 shiftwidth=4 noexpandtab: */
|
||||
197
third_party/ctags/vstring.c
vendored
197
third_party/ctags/vstring.c
vendored
@@ -1,197 +0,0 @@
|
||||
/*
|
||||
* $Id: vstring.c 558 2007-06-15 19:17:02Z elliotth $
|
||||
*
|
||||
* Copyright (c) 1998-2002, Darren Hiebert
|
||||
*
|
||||
* This source code is released for free distribution under the terms of the
|
||||
* GNU General Public License.
|
||||
*
|
||||
* This module contains functions supporting resizeable strings.
|
||||
*/
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "libc/limits.h"
|
||||
#include "third_party/ctags/debug.h"
|
||||
#include "third_party/ctags/routines.h"
|
||||
#include "third_party/ctags/vstring.h"
|
||||
|
||||
/*
|
||||
* DATA DEFINITIONS
|
||||
*/
|
||||
static const size_t vStringInitialSize = 32;
|
||||
|
||||
/*
|
||||
* FUNCTION DEFINITIONS
|
||||
*/
|
||||
|
||||
static void vStringResize(vString *const string, const size_t newSize) {
|
||||
char *const newBuffer = xRealloc(string->buffer, newSize, char);
|
||||
|
||||
string->size = newSize;
|
||||
string->buffer = newBuffer;
|
||||
}
|
||||
|
||||
/*
|
||||
* External interface
|
||||
*/
|
||||
|
||||
extern boolean vStringAutoResize(vString *const string) {
|
||||
boolean ok = TRUE;
|
||||
|
||||
if (string->size <= INT_MAX / 2) {
|
||||
const size_t newSize = string->size * 2;
|
||||
|
||||
vStringResize(string, newSize);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
extern void vStringClear(vString *const string) {
|
||||
string->length = 0;
|
||||
string->buffer[0] = '\0';
|
||||
DebugStatement(memset(string->buffer, 0, string->size);)
|
||||
}
|
||||
|
||||
extern void vStringDelete(vString *const string) {
|
||||
if (string != NULL) {
|
||||
if (string->buffer != NULL) eFree(string->buffer);
|
||||
eFree(string);
|
||||
}
|
||||
}
|
||||
|
||||
extern vString *vStringNew(void) {
|
||||
vString *const string = xMalloc(1, vString);
|
||||
|
||||
string->length = 0;
|
||||
string->size = vStringInitialSize;
|
||||
string->buffer = xMalloc(string->size, char);
|
||||
|
||||
vStringClear(string);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
#ifndef VSTRING_PUTC_MACRO
|
||||
extern void vStringPut(vString *const string, const int c) {
|
||||
if (string->length + 1 == string->size) /* check for buffer overflow */
|
||||
vStringAutoResize(string);
|
||||
|
||||
string->buffer[string->length] = c;
|
||||
if (c != '\0') string->buffer[++string->length] = '\0';
|
||||
}
|
||||
#endif
|
||||
|
||||
extern void vStringCatS(vString *const string, const char *const s) {
|
||||
#if 1
|
||||
const size_t len = strlen(s);
|
||||
while (string->length + len + 1 >=
|
||||
string->size) /* check for buffer overflow */
|
||||
vStringAutoResize(string);
|
||||
strcpy(string->buffer + string->length, s);
|
||||
string->length += len;
|
||||
#else
|
||||
const char *p = s;
|
||||
do
|
||||
vStringPut(string, *p);
|
||||
while (*p++ != '\0');
|
||||
#endif
|
||||
}
|
||||
|
||||
extern vString *vStringNewCopy(const vString *const string) {
|
||||
vString *vs = vStringNew();
|
||||
vStringCatS(vs, string->buffer);
|
||||
return vs;
|
||||
}
|
||||
|
||||
extern vString *vStringNewInit(const char *const s) {
|
||||
vString *vs = vStringNew();
|
||||
vStringCatS(vs, s);
|
||||
return vs;
|
||||
}
|
||||
|
||||
extern void vStringNCatS(vString *const string, const char *const s,
|
||||
const size_t length) {
|
||||
const char *p = s;
|
||||
size_t remain = length;
|
||||
|
||||
while (*p != '\0' && remain > 0) {
|
||||
vStringPut(string, *p);
|
||||
--remain;
|
||||
++p;
|
||||
}
|
||||
vStringTerminate(string);
|
||||
}
|
||||
|
||||
/* Strip trailing newline from string.
|
||||
*/
|
||||
extern void vStringStripNewline(vString *const string) {
|
||||
const size_t final = string->length - 1;
|
||||
if (string->buffer[final] == '\n') {
|
||||
string->buffer[final] = '\0';
|
||||
string->length--;
|
||||
}
|
||||
}
|
||||
|
||||
/* Strip leading white space from string.
|
||||
*/
|
||||
extern void vStringStripLeading(vString *const string) {
|
||||
while (isspace((int)string->buffer[0]) && string->length > 0) {
|
||||
size_t i;
|
||||
for (i = 1; i < string->length; ++i)
|
||||
string->buffer[i - 1] = string->buffer[i];
|
||||
--string->length;
|
||||
string->buffer[string->length] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* Strip trailing white space from string.
|
||||
*/
|
||||
extern void vStringStripTrailing(vString *const string) {
|
||||
while (isspace((int)string->buffer[string->length - 1]) &&
|
||||
string->length > 0) {
|
||||
string->length--;
|
||||
string->buffer[string->length] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* Chop last character from string.
|
||||
*/
|
||||
extern void vStringChop(vString *const string) {
|
||||
if (string->length > 0) {
|
||||
--string->length;
|
||||
string->buffer[string->length] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
extern void vStringCopyS(vString *const string, const char *const s) {
|
||||
vStringClear(string);
|
||||
vStringCatS(string, s);
|
||||
}
|
||||
|
||||
extern void vStringNCopyS(vString *const string, const char *const s,
|
||||
const size_t length) {
|
||||
vStringClear(string);
|
||||
vStringNCatS(string, s, length);
|
||||
}
|
||||
|
||||
extern void vStringCopyToLower(vString *const dest, const vString *const src) {
|
||||
const size_t length = src->length;
|
||||
const char *s = src->buffer;
|
||||
char *d;
|
||||
size_t i;
|
||||
|
||||
if (dest->size < src->size) vStringResize(dest, src->size);
|
||||
d = dest->buffer;
|
||||
for (i = 0; i < length; ++i) {
|
||||
int c = s[i];
|
||||
|
||||
d[i] = tolower(c);
|
||||
}
|
||||
d[i] = '\0';
|
||||
}
|
||||
|
||||
extern void vStringSetLength(vString *const string) {
|
||||
string->length = strlen(string->buffer);
|
||||
}
|
||||
|
||||
/* vi:set tabstop=4 shiftwidth=4: */
|
||||
68
third_party/ctags/vstring.h
vendored
68
third_party/ctags/vstring.h
vendored
@@ -1,68 +0,0 @@
|
||||
#ifndef _VSTRING_H
|
||||
#define _VSTRING_H
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
|
||||
/*
|
||||
* MACROS
|
||||
*/
|
||||
#ifndef DEBUG
|
||||
#define VSTRING_PUTC_MACRO 1
|
||||
#endif
|
||||
#ifdef VSTRING_PUTC_MACRO
|
||||
#define vStringPut(s, c) \
|
||||
(void)(((s)->length + 1 == (s)->size ? vStringAutoResize(s) : 0), \
|
||||
((s)->buffer[(s)->length] = (c)), \
|
||||
((c) == '\0' ? 0 : ((s)->buffer[++(s)->length] = '\0')))
|
||||
#endif
|
||||
|
||||
#define vStringValue(vs) ((vs)->buffer)
|
||||
#define vStringItem(vs, i) ((vs)->buffer[i])
|
||||
#define vStringLast(vs) ((vs)->buffer[(vs)->length - 1])
|
||||
#define vStringLength(vs) ((vs)->length)
|
||||
#define vStringSize(vs) ((vs)->size)
|
||||
#define vStringCat(vs, s) vStringCatS((vs), vStringValue((s)))
|
||||
#define vStringNCat(vs, s, l) vStringNCatS((vs), vStringValue((s)), (l))
|
||||
#define vStringCopy(vs, s) vStringCopyS((vs), vStringValue((s)))
|
||||
#define vStringNCopy(vs, s, l) vStringNCopyS((vs), vStringValue((s)), (l))
|
||||
#define vStringChar(vs, i) ((vs)->buffer[i])
|
||||
#define vStringTerminate(vs) vStringPut(vs, '\0')
|
||||
#define vStringLower(vs) toLowerString((vs)->buffer)
|
||||
#define vStringUpper(vs) toUpperString((vs)->buffer)
|
||||
|
||||
/*
|
||||
* DATA DECLARATIONS
|
||||
*/
|
||||
|
||||
typedef struct sVString {
|
||||
size_t length; /* size of buffer used */
|
||||
size_t size; /* allocated size of buffer */
|
||||
char *buffer; /* location of buffer */
|
||||
} vString;
|
||||
|
||||
/*
|
||||
* FUNCTION PROTOTYPES
|
||||
*/
|
||||
extern boolean vStringAutoResize(vString *const string);
|
||||
extern void vStringClear(vString *const string);
|
||||
extern vString *vStringNew(void);
|
||||
extern void vStringDelete(vString *const string);
|
||||
#ifndef VSTRING_PUTC_MACRO
|
||||
extern void vStringPut(vString *const string, const int c);
|
||||
#endif
|
||||
extern void vStringStripNewline(vString *const string);
|
||||
extern void vStringStripLeading(vString *const string);
|
||||
extern void vStringChop(vString *const string);
|
||||
extern void vStringStripTrailing(vString *const string);
|
||||
extern void vStringCatS(vString *const string, const char *const s);
|
||||
extern void vStringNCatS(vString *const string, const char *const s,
|
||||
const size_t length);
|
||||
extern vString *vStringNewCopy(const vString *const string);
|
||||
extern vString *vStringNewInit(const char *const s);
|
||||
extern void vStringCopyS(vString *const string, const char *const s);
|
||||
extern void vStringNCopyS(vString *const string, const char *const s,
|
||||
const size_t length);
|
||||
extern void vStringCopyToLower(vString *const dest, const vString *const src);
|
||||
extern void vStringSetLength(vString *const string);
|
||||
|
||||
#endif /* _VSTRING_H */
|
||||
33
third_party/ctags/yacc.c
vendored
33
third_party/ctags/yacc.c
vendored
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* $Id: yacc.c 443 2006-05-30 04:37:13Z darren $
|
||||
*
|
||||
* Copyright (c) 2001-2002, Nick Hibma <n_hibma@van-laarhoven.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 YACC language files.
|
||||
*/
|
||||
#include "third_party/ctags/general.h"
|
||||
/* must always come first */
|
||||
#include "third_party/ctags/parse.h"
|
||||
|
||||
/*
|
||||
* FUNCTION DEFINITIONS
|
||||
*/
|
||||
|
||||
static void installYaccRegex(const langType language) {
|
||||
addTagRegex(language, "^([A-Za-z][A-Za-z_0-9]+)[ \t]*:", "\\1",
|
||||
"l,label,labels", NULL);
|
||||
}
|
||||
|
||||
extern parserDefinition* YaccParser() {
|
||||
static const char* const extensions[] = {"y", NULL};
|
||||
parserDefinition* const def = parserNew("YACC");
|
||||
def->extensions = extensions;
|
||||
def->initialize = installYaccRegex;
|
||||
def->regex = TRUE;
|
||||
return def;
|
||||
}
|
||||
|
||||
/* vi:set tabstop=4 shiftwidth=4: */
|
||||
23
third_party/dlmalloc/initdlmalloc.S
vendored
23
third_party/dlmalloc/initdlmalloc.S
vendored
@@ -3,19 +3,18 @@
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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; version 2 of the License. │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ 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., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.h"
|
||||
.source __FILE__
|
||||
|
||||
23
third_party/dlmalloc/mtrace.c
vendored
23
third_party/dlmalloc/mtrace.c
vendored
@@ -3,19 +3,18 @@
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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; version 2 of the License. │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ 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., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
23
third_party/duktape/dukhexdectab.S
vendored
23
third_party/duktape/dukhexdectab.S
vendored
@@ -3,19 +3,18 @@
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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; version 2 of the License. │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ 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., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.h"
|
||||
|
||||
|
||||
23
third_party/f2c/i_len.c
vendored
23
third_party/f2c/i_len.c
vendored
@@ -3,19 +3,18 @@
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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; version 2 of the License. │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ 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., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "third_party/f2c/f2c.h"
|
||||
|
||||
|
||||
23
third_party/getopt/initgetopt.S
vendored
23
third_party/getopt/initgetopt.S
vendored
@@ -3,19 +3,18 @@
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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; version 2 of the License. │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ 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., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.h"
|
||||
.source __FILE__
|
||||
|
||||
23
third_party/regex/regerror.c
vendored
23
third_party/regex/regerror.c
vendored
@@ -3,19 +3,18 @@
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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; version 2 of the License. │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ 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., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
|
||||
23
third_party/stb/idct-sse.S
vendored
23
third_party/stb/idct-sse.S
vendored
@@ -3,19 +3,18 @@
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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; version 2 of the License. │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ 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., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.h"
|
||||
|
||||
|
||||
23
third_party/stb/stb_image.c
vendored
23
third_party/stb/stb_image.c
vendored
@@ -3,19 +3,18 @@
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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; version 2 of the License. │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ 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., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
|
||||
23
third_party/stb/stb_image_resize.c
vendored
23
third_party/stb/stb_image_resize.c
vendored
@@ -3,19 +3,18 @@
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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; version 2 of the License. │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ 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., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/macros.h"
|
||||
|
||||
23
third_party/stb/ycbcr-sse2.S
vendored
23
third_party/stb/ycbcr-sse2.S
vendored
@@ -3,19 +3,18 @@
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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; version 2 of the License. │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ 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., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.h"
|
||||
|
||||
|
||||
23
third_party/stb/ycbcr.c
vendored
23
third_party/stb/ycbcr.c
vendored
@@ -3,19 +3,18 @@
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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; version 2 of the License. │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ 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., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
|
||||
1
third_party/third_party.mk
vendored
1
third_party/third_party.mk
vendored
@@ -6,7 +6,6 @@ o/$(MODE)/third_party: \
|
||||
o/$(MODE)/third_party/blas \
|
||||
o/$(MODE)/third_party/chibicc \
|
||||
o/$(MODE)/third_party/compiler_rt \
|
||||
o/$(MODE)/third_party/ctags \
|
||||
o/$(MODE)/third_party/dlmalloc \
|
||||
o/$(MODE)/third_party/gdtoa \
|
||||
o/$(MODE)/third_party/duktape \
|
||||
|
||||
23
third_party/xed/xederror.c
vendored
23
third_party/xed/xederror.c
vendored
@@ -3,19 +3,18 @@
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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; version 2 of the License. │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ 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., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "third_party/xed/x86.h"
|
||||
|
||||
|
||||
23
third_party/zlib/deflateinit.S
vendored
23
third_party/zlib/deflateinit.S
vendored
@@ -3,19 +3,18 @@
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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; version 2 of the License. │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ 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., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "third_party/zlib/zlib.h"
|
||||
#include "libc/macros.h"
|
||||
|
||||
23
third_party/zlib/inflateinit.S
vendored
23
third_party/zlib/inflateinit.S
vendored
@@ -3,19 +3,18 @@
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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; version 2 of the License. │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ 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., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "third_party/zlib/zutil.h"
|
||||
#include "libc/macros.h"
|
||||
|
||||
23
third_party/zlib/kdistcode.S
vendored
23
third_party/zlib/kdistcode.S
vendored
@@ -3,19 +3,18 @@
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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; version 2 of the License. │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ 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., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "third_party/zlib/deflate.h"
|
||||
#include "libc/macros.h"
|
||||
|
||||
23
third_party/zlib/klengthcode.S
vendored
23
third_party/zlib/klengthcode.S
vendored
@@ -3,19 +3,18 @@
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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; version 2 of the License. │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ 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., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "third_party/zlib/zutil.h"
|
||||
#include "libc/macros.h"
|
||||
|
||||
23
third_party/zlib/zalloc.c
vendored
23
third_party/zlib/zalloc.c
vendored
@@ -3,19 +3,18 @@
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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; version 2 of the License. │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ 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., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
||||
Reference in New Issue
Block a user