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 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 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
#ifdef WINDOWSNT
# include <direct.h>
-# define MAXPATHLEN _MAX_PATH
# undef HAVE_NTGUI
# undef DOS_NT
# define DOS_NT
static const char Objc_help [] =
"In Objective C code, tags include Objective C definitions for classes,\n\
class categories, methods and protocols. Tags for variables and\n\
-functions in classes are named 'CLASS::VARIABLE' and 'CLASS::FUNCTION'.\n\
-(Use --help --lang=c --lang=objc --lang=java for full help.)";
+functions in classes are named 'CLASS::VARIABLE' and 'CLASS::FUNCTION'.\
+\n(Use --help --lang=c --lang=objc --lang=java for full help.)";
static const char *Pascal_suffixes [] =
{ "p", "pas", NULL };
generate a tag.";
static const char *Ruby_suffixes [] =
- { "rb", "ruby", NULL };
+ { "rb", "ru", "rbw", NULL };
+static const char *Ruby_filenames [] =
+ { "Rakefile", "Thorfile", NULL };
static const char Ruby_help [] =
"In Ruby code, 'def' or 'class' or 'module' at the beginning of\n\
a line generate a tag. Constants also generate a tag.";
{ "proc", no_lang_help, plain_C_entries, plain_C_suffixes },
{ "prolog", Prolog_help, Prolog_functions, Prolog_suffixes },
{ "python", Python_help, Python_functions, Python_suffixes },
- { "ruby", Ruby_help, Ruby_functions, Ruby_suffixes },
+ { "ruby", Ruby_help,Ruby_functions,Ruby_suffixes,Ruby_filenames },
{ "scheme", Scheme_help, Scheme_functions, Scheme_suffixes },
{ "tex", TeX_help, TeX_commands, TeX_suffixes },
{ "texinfo", Texinfo_help, Texinfo_nodes, Texinfo_suffixes },
Do not create tag entries for global variables in some\n\
languages. This makes the tags file smaller.");
- if (PRINT_UNDOCUMENTED_OPTIONS_HELP)
- puts ("--no-line-directive\n\
+ puts ("--no-line-directive\n\
Ignore #line preprocessor directives in C and derived languages.");
if (CTAGS)
in some languages.");
puts ("-Q, --class-qualify\n\
- Qualify tag names with their class name in C++, ObjC, and Java.\n\
+ Qualify tag names with their class name in C++, ObjC, Java, and Perl.\n\
This produces tag names of the form \"class::member\" for C++,\n\
\"class(category)\" for Objective C, and \"class.member\" for Java.\n\
For Objective C, this also produces class methods qualified with\n\
- their arguments, as in \"foo:bar:baz:more\".");
+ their arguments, as in \"foo:bar:baz:more\".\n\
+ For Perl, this produces \"package::member\".");
puts ("-r REGEXP, --regex=REGEXP or --regex=@regexfile\n\
Make a tag for each line matching a regular expression pattern\n\
in the following files. {LANGUAGE}REGEXP uses REGEXP for LANGUAGE\n\
{
char *cmd =
xmalloc (strlen (tagfile) + whatlen_max +
- sizeof "mv..OTAGS;fgrep -v '\t\t' OTAGS >;rm OTAGS");
+ sizeof "mv..OTAGS;grep -Fv '\t\t' OTAGS >;rm OTAGS");
for (i = 0; i < current_arg; ++i)
{
switch (argbuffer[i].arg_type)
}
char *z = stpcpy (cmd, "mv ");
z = stpcpy (z, tagfile);
- z = stpcpy (z, " OTAGS;fgrep -v '\t");
+ z = stpcpy (z, " OTAGS;grep -Fv '\t");
z = stpcpy (z, argbuffer[i].what);
z = stpcpy (z, "\t' OTAGS >");
z = stpcpy (z, tagfile);
{
language *lang;
const char **name, **ext, *suffix;
+ char *slash;
/* Try whole file name first. */
+ slash = strrchr (file, '/');
+ if (slash != NULL)
+ file = slash + 1;
+#ifdef DOS_NT
+ else if (file[0] && file[1] == ':')
+ file += 2;
+#endif
for (lang = lang_names; lang->name != NULL; lang++)
if (lang->filenames != NULL)
for (name = lang->filenames; *name != NULL; name++)
((assert ("" kw), true) /* syntax error if not a literal string */ \
&& strneq ((cp), kw, sizeof (kw)-1) /* cp points at kw */ \
&& notinname ((cp)[sizeof (kw)-1]) /* end of kw */ \
- && ((cp) = skip_spaces ((cp)+sizeof (kw)-1))) /* skip spaces */
+ && ((cp) = skip_spaces ((cp) + sizeof (kw) - 1), true)) /* skip spaces */
/* Similar to LOOKING_AT but does not use notinname, does not skip */
#define LOOKING_AT_NOCASE(cp, kw) /* the keyword is a literal string */ \
((assert ("" kw), true) /* syntax error if not a literal string */ \
&& strncaseeq ((cp), kw, sizeof (kw)-1) /* cp points at kw */ \
- && ((cp) += sizeof (kw)-1)) /* skip spaces */
+ && ((cp) += sizeof (kw) - 1, true)) /* skip spaces */
/*
* Read a file, but do no processing. This is used to do regexp
continue; /* nothing found */
pos = strchr (sp, ':');
if (pos && pos < cp && pos[1] == ':')
- /* The name is already qualified. */
- make_tag (sp, cp - sp, true,
- lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
- else
+ {
+ /* The name is already qualified. */
+ if (!class_qualify)
+ {
+ char *q = pos + 2, *qpos;
+ while ((qpos = strchr (q, ':')) != NULL
+ && qpos < cp
+ && qpos[1] == ':')
+ q = qpos + 2;
+ sp = q;
+ }
+ make_tag (sp, cp - sp, true,
+ lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
+ }
+ else if (class_qualify)
/* Qualify it. */
{
char savechar, *name;
lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
free (name);
}
+ else
+ make_tag (sp, cp - sp, true,
+ lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
}
else if (LOOKING_AT (cp, "use constant")
|| LOOKING_AT (cp, "use constant::defer"))
Ruby_functions (FILE *inf)
{
char *cp = NULL;
+ bool reader = false, writer = false, alias = false, continuation = false;
LOOP_ON_INPUT_LINES (inf, lb, cp)
{
char *name;
cp = skip_spaces (cp);
- if (c_isalpha (*cp) && c_isupper (*cp)) /* constants */
+ if (!continuation
+ /* Constants. */
+ && c_isalpha (*cp) && c_isupper (*cp))
{
char *bp, *colon = NULL;
if (cp > name + 1)
{
bp = skip_spaces (cp);
- if (*bp == '=' && c_isspace (bp[1]))
+ if (*bp == '=' && !(bp[1] == '=' || bp[1] == '>'))
{
if (colon && !c_isspace (colon[1]))
name = colon + 1;
}
}
}
- else if ((is_method = LOOKING_AT (cp, "def")) /* module/class/method */
- || (is_class = LOOKING_AT (cp, "class"))
- || LOOKING_AT (cp, "module"))
+ else if (!continuation
+ /* Modules, classes, methods. */
+ && ((is_method = LOOKING_AT (cp, "def"))
+ || (is_class = LOOKING_AT (cp, "class"))
+ || LOOKING_AT (cp, "module")))
{
const char self_name[] = "self.";
- const size_t self_size1 = sizeof ("self.") - 1;
+ const size_t self_size1 = sizeof (self_name) - 1;
name = cp;
make_tag (name, cp - name, true,
lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
}
+ else
+ {
+ /* Tag accessors and aliases. */
+
+ if (!continuation)
+ reader = writer = alias = false;
+
+ while (*cp && *cp != '#')
+ {
+ if (!continuation)
+ {
+ reader = writer = alias = false;
+ if (LOOKING_AT (cp, "attr_reader"))
+ reader = true;
+ else if (LOOKING_AT (cp, "attr_writer"))
+ writer = true;
+ else if (LOOKING_AT (cp, "attr_accessor"))
+ {
+ reader = true;
+ writer = true;
+ }
+ else if (LOOKING_AT (cp, "alias_method"))
+ alias = true;
+ }
+ if (reader || writer || alias)
+ {
+ do {
+ char *np;
+
+ cp = skip_spaces (cp);
+ if (*cp == '(')
+ cp = skip_spaces (cp + 1);
+ np = cp;
+ cp = skip_name (cp);
+ if (*np != ':')
+ continue;
+ np++;
+ if (reader)
+ {
+ make_tag (np, cp - np, true,
+ lb.buffer, cp - lb.buffer + 1,
+ lineno, linecharno);
+ continuation = false;
+ }
+ if (writer)
+ {
+ size_t name_len = cp - np + 1;
+ char *wr_name = xnew (name_len + 1, char);
+
+ memcpy (wr_name, np, name_len - 1);
+ memcpy (wr_name + name_len - 1, "=", 2);
+ pfnote (wr_name, true, lb.buffer, cp - lb.buffer + 1,
+ lineno, linecharno);
+ continuation = false;
+ }
+ if (alias)
+ {
+ if (!continuation)
+ make_tag (np, cp - np, true,
+ lb.buffer, cp - lb.buffer + 1,
+ lineno, linecharno);
+ continuation = false;
+ while (*cp && *cp != '#' && *cp != ';')
+ {
+ if (*cp == ',')
+ continuation = true;
+ else if (!c_isspace (*cp))
+ continuation = false;
+ cp++;
+ }
+ if (*cp == ';')
+ continuation = false;
+ }
+ cp = skip_spaces (cp);
+ } while ((alias
+ ? (*cp == ',')
+ : (continuation = (*cp == ',')))
+ && (cp = skip_spaces (cp + 1), *cp && *cp != '#'));
+ }
+ if (*cp != '#')
+ cp = skip_name (cp);
+ while (*cp && *cp != '#' && notinname (*cp))
+ cp++;
+ }
+ }
}
}