ctags.rb 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. data/Gemfile +2 -0
  2. data/Rakefile +23 -0
  3. data/ctags.rb.gemspec +23 -0
  4. data/ext/.gitignore +3 -0
  5. data/ext/extconf.rb +15 -0
  6. data/ext/vendor/exuberant-ctags/.gitignore +6 -0
  7. data/ext/vendor/exuberant-ctags/.indent.pro +31 -0
  8. data/ext/vendor/exuberant-ctags/COPYING +340 -0
  9. data/ext/vendor/exuberant-ctags/EXTENDING.html +386 -0
  10. data/ext/vendor/exuberant-ctags/FAQ +371 -0
  11. data/ext/vendor/exuberant-ctags/INSTALL +215 -0
  12. data/ext/vendor/exuberant-ctags/INSTALL.oth +73 -0
  13. data/ext/vendor/exuberant-ctags/MAINTAINERS +88 -0
  14. data/ext/vendor/exuberant-ctags/Makefile.in +222 -0
  15. data/ext/vendor/exuberant-ctags/NEWS +871 -0
  16. data/ext/vendor/exuberant-ctags/README +73 -0
  17. data/ext/vendor/exuberant-ctags/ant.c +42 -0
  18. data/ext/vendor/exuberant-ctags/argproc.c +505 -0
  19. data/ext/vendor/exuberant-ctags/args.c +274 -0
  20. data/ext/vendor/exuberant-ctags/args.h +63 -0
  21. data/ext/vendor/exuberant-ctags/asm.c +387 -0
  22. data/ext/vendor/exuberant-ctags/asp.c +328 -0
  23. data/ext/vendor/exuberant-ctags/awk.c +81 -0
  24. data/ext/vendor/exuberant-ctags/basic.c +203 -0
  25. data/ext/vendor/exuberant-ctags/beta.c +321 -0
  26. data/ext/vendor/exuberant-ctags/c.c +2932 -0
  27. data/ext/vendor/exuberant-ctags/cobol.c +50 -0
  28. data/ext/vendor/exuberant-ctags/config.h.in +277 -0
  29. data/ext/vendor/exuberant-ctags/configure +7704 -0
  30. data/ext/vendor/exuberant-ctags/configure.ac +532 -0
  31. data/ext/vendor/exuberant-ctags/ctags.1 +1186 -0
  32. data/ext/vendor/exuberant-ctags/ctags.h +28 -0
  33. data/ext/vendor/exuberant-ctags/ctags.html +2087 -0
  34. data/ext/vendor/exuberant-ctags/ctags.spec +40 -0
  35. data/ext/vendor/exuberant-ctags/debug.c +113 -0
  36. data/ext/vendor/exuberant-ctags/debug.h +70 -0
  37. data/ext/vendor/exuberant-ctags/descrip.mms +68 -0
  38. data/ext/vendor/exuberant-ctags/dosbatch.c +42 -0
  39. data/ext/vendor/exuberant-ctags/e_amiga.h +24 -0
  40. data/ext/vendor/exuberant-ctags/e_djgpp.h +47 -0
  41. data/ext/vendor/exuberant-ctags/e_mac.h +143 -0
  42. data/ext/vendor/exuberant-ctags/e_msoft.h +76 -0
  43. data/ext/vendor/exuberant-ctags/e_os2.h +37 -0
  44. data/ext/vendor/exuberant-ctags/e_qdos.h +34 -0
  45. data/ext/vendor/exuberant-ctags/e_riscos.h +58 -0
  46. data/ext/vendor/exuberant-ctags/e_vms.h +31 -0
  47. data/ext/vendor/exuberant-ctags/eiffel.c +1352 -0
  48. data/ext/vendor/exuberant-ctags/entry.c +847 -0
  49. data/ext/vendor/exuberant-ctags/entry.h +103 -0
  50. data/ext/vendor/exuberant-ctags/erlang.c +189 -0
  51. data/ext/vendor/exuberant-ctags/flex.c +2243 -0
  52. data/ext/vendor/exuberant-ctags/fortran.c +2197 -0
  53. data/ext/vendor/exuberant-ctags/general.h +127 -0
  54. data/ext/vendor/exuberant-ctags/get.c +669 -0
  55. data/ext/vendor/exuberant-ctags/get.h +50 -0
  56. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/all-wcprops +47 -0
  57. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/entries +112 -0
  58. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/README.txt.svn-base +5 -0
  59. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regcomp.c.svn-base +3818 -0
  60. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex.c.svn-base +74 -0
  61. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex.h.svn-base +575 -0
  62. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex_internal.c.svn-base +1713 -0
  63. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex_internal.h.svn-base +773 -0
  64. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regexec.c.svn-base +4338 -0
  65. data/ext/vendor/exuberant-ctags/gnu_regex/README.txt +5 -0
  66. data/ext/vendor/exuberant-ctags/gnu_regex/regcomp.c +3818 -0
  67. data/ext/vendor/exuberant-ctags/gnu_regex/regex.c +74 -0
  68. data/ext/vendor/exuberant-ctags/gnu_regex/regex.h +575 -0
  69. data/ext/vendor/exuberant-ctags/gnu_regex/regex_internal.c +1713 -0
  70. data/ext/vendor/exuberant-ctags/gnu_regex/regex_internal.h +773 -0
  71. data/ext/vendor/exuberant-ctags/gnu_regex/regexec.c +4338 -0
  72. data/ext/vendor/exuberant-ctags/html.c +49 -0
  73. data/ext/vendor/exuberant-ctags/jscript.c +1572 -0
  74. data/ext/vendor/exuberant-ctags/keyword.c +258 -0
  75. data/ext/vendor/exuberant-ctags/keyword.h +34 -0
  76. data/ext/vendor/exuberant-ctags/lisp.c +139 -0
  77. data/ext/vendor/exuberant-ctags/lregex.c +704 -0
  78. data/ext/vendor/exuberant-ctags/lua.c +133 -0
  79. data/ext/vendor/exuberant-ctags/mac.c +273 -0
  80. data/ext/vendor/exuberant-ctags/magic.diff +21 -0
  81. data/ext/vendor/exuberant-ctags/main.c +584 -0
  82. data/ext/vendor/exuberant-ctags/main.h +32 -0
  83. data/ext/vendor/exuberant-ctags/maintainer.mak +476 -0
  84. data/ext/vendor/exuberant-ctags/make.c +217 -0
  85. data/ext/vendor/exuberant-ctags/matlab.c +44 -0
  86. data/ext/vendor/exuberant-ctags/mk_bc3.mak +46 -0
  87. data/ext/vendor/exuberant-ctags/mk_bc5.mak +49 -0
  88. data/ext/vendor/exuberant-ctags/mk_djg.mak +18 -0
  89. data/ext/vendor/exuberant-ctags/mk_manx.mak +65 -0
  90. data/ext/vendor/exuberant-ctags/mk_mingw.mak +31 -0
  91. data/ext/vendor/exuberant-ctags/mk_mpw.mak +130 -0
  92. data/ext/vendor/exuberant-ctags/mk_mvc.mak +40 -0
  93. data/ext/vendor/exuberant-ctags/mk_os2.mak +104 -0
  94. data/ext/vendor/exuberant-ctags/mk_qdos.mak +100 -0
  95. data/ext/vendor/exuberant-ctags/mk_sas.mak +63 -0
  96. data/ext/vendor/exuberant-ctags/mkinstalldirs +40 -0
  97. data/ext/vendor/exuberant-ctags/ocaml.c +1842 -0
  98. data/ext/vendor/exuberant-ctags/options.c +1842 -0
  99. data/ext/vendor/exuberant-ctags/options.h +155 -0
  100. data/ext/vendor/exuberant-ctags/parse.c +677 -0
  101. data/ext/vendor/exuberant-ctags/parse.h +129 -0
  102. data/ext/vendor/exuberant-ctags/parsers.h +63 -0
  103. data/ext/vendor/exuberant-ctags/pascal.c +267 -0
  104. data/ext/vendor/exuberant-ctags/perl.c +382 -0
  105. data/ext/vendor/exuberant-ctags/php.c +237 -0
  106. data/ext/vendor/exuberant-ctags/python.c +771 -0
  107. data/ext/vendor/exuberant-ctags/qdos.c +106 -0
  108. data/ext/vendor/exuberant-ctags/read.c +569 -0
  109. data/ext/vendor/exuberant-ctags/read.h +116 -0
  110. data/ext/vendor/exuberant-ctags/readtags.c +959 -0
  111. data/ext/vendor/exuberant-ctags/readtags.h +252 -0
  112. data/ext/vendor/exuberant-ctags/rexx.c +39 -0
  113. data/ext/vendor/exuberant-ctags/routines.c +891 -0
  114. data/ext/vendor/exuberant-ctags/routines.h +134 -0
  115. data/ext/vendor/exuberant-ctags/ruby.c +408 -0
  116. data/ext/vendor/exuberant-ctags/scheme.c +111 -0
  117. data/ext/vendor/exuberant-ctags/sh.c +115 -0
  118. data/ext/vendor/exuberant-ctags/slang.c +41 -0
  119. data/ext/vendor/exuberant-ctags/sml.c +212 -0
  120. data/ext/vendor/exuberant-ctags/sort.c +230 -0
  121. data/ext/vendor/exuberant-ctags/sort.h +32 -0
  122. data/ext/vendor/exuberant-ctags/source.mak +122 -0
  123. data/ext/vendor/exuberant-ctags/sql.c +2112 -0
  124. data/ext/vendor/exuberant-ctags/strlist.c +281 -0
  125. data/ext/vendor/exuberant-ctags/strlist.h +54 -0
  126. data/ext/vendor/exuberant-ctags/tcl.c +116 -0
  127. data/ext/vendor/exuberant-ctags/tex.c +524 -0
  128. data/ext/vendor/exuberant-ctags/verilog.c +340 -0
  129. data/ext/vendor/exuberant-ctags/vhdl.c +835 -0
  130. data/ext/vendor/exuberant-ctags/vim.c +636 -0
  131. data/ext/vendor/exuberant-ctags/vstring.c +232 -0
  132. data/ext/vendor/exuberant-ctags/vstring.h +85 -0
  133. data/ext/vendor/exuberant-ctags/yacc.c +40 -0
  134. data/lib/ctags/exuberant.rb +45 -0
  135. data/lib/ctags/version.rb +3 -0
  136. data/lib/ctags.rb +6 -0
  137. data/test/test_ctags.rb +24 -0
  138. metadata +233 -0
@@ -0,0 +1,134 @@
1
+ /*
2
+ * $Id: routines.h 536 2007-06-02 06:09:00Z elliotth $
3
+ *
4
+ * Copyright (c) 2002, Darren Hiebert
5
+ *
6
+ * This source code is released for free distribution under the terms of the
7
+ * GNU General Public License.
8
+ *
9
+ * External interface to routines.c
10
+ */
11
+ #ifndef _ROUTINES_H
12
+ #define _ROUTINES_H
13
+
14
+ /*
15
+ * INCLUDE FILES
16
+ */
17
+ #include "general.h" /* must always come first */
18
+
19
+ /*
20
+ * MACROS
21
+ */
22
+ #define xMalloc(n,Type) (Type *)eMalloc((size_t)(n) * sizeof (Type))
23
+ #define xCalloc(n,Type) (Type *)eCalloc((size_t)(n), sizeof (Type))
24
+ #define xRealloc(p,n,Type) (Type *)eRealloc((p), (n) * sizeof (Type))
25
+
26
+ /*
27
+ * Portability macros
28
+ */
29
+ #ifndef PATH_SEPARATOR
30
+ # if defined (MSDOS_STYLE_PATH)
31
+ # define PATH_SEPARATOR '\\'
32
+ # elif defined (QDOS)
33
+ # define PATH_SEPARATOR '_'
34
+ # else
35
+ # define PATH_SEPARATOR '/'
36
+ # endif
37
+ #endif
38
+
39
+ #if defined (MSDOS_STYLE_PATH) && defined (UNIX_PATH_SEPARATOR)
40
+ # define OUTPUT_PATH_SEPARATOR '/'
41
+ #else
42
+ # define OUTPUT_PATH_SEPARATOR PATH_SEPARATOR
43
+ #endif
44
+
45
+ /*
46
+ * DATA DECLARATIONS
47
+ */
48
+ #if defined (MSDOS_STYLE_PATH) || defined (VMS)
49
+ extern const char *const PathDelimiters;
50
+ #endif
51
+ extern char *CurrentDirectory;
52
+ typedef int errorSelection;
53
+ enum eErrorTypes { FATAL = 1, WARNING = 2, PERROR = 4 };
54
+
55
+ typedef struct {
56
+ /* Name of file for which status is valid */
57
+ char* name;
58
+
59
+ /* Does file exist? If not, members below do not contain valid data. */
60
+ boolean exists;
61
+
62
+ /* is file path a symbolic link to another file? */
63
+ boolean isSymbolicLink;
64
+
65
+ /* Is file (pointed to) a directory? */
66
+ boolean isDirectory;
67
+
68
+ /* Is file (pointed to) a normal file? */
69
+ boolean isNormalFile;
70
+
71
+ /* Is file (pointed to) executable? */
72
+ boolean isExecutable;
73
+
74
+ /* Is file (pointed to) setuid? */
75
+ boolean isSetuid;
76
+
77
+ /* Size of file (pointed to) */
78
+ unsigned long size;
79
+ } fileStatus;
80
+
81
+ /*
82
+ * FUNCTION PROTOTYPES
83
+ */
84
+ extern void freeRoutineResources (void);
85
+ extern void setExecutableName (const char *const path);
86
+ extern const char *getExecutableName (void);
87
+ extern const char *getExecutablePath (void);
88
+ extern void error (const errorSelection selection, const char *const format, ...) __printf__ (2, 3);
89
+
90
+ /* Memory allocation functions */
91
+ #ifdef NEED_PROTO_MALLOC
92
+ extern void *malloc (size_t);
93
+ extern void *realloc (void *ptr, size_t);
94
+ #endif
95
+ extern void *eMalloc (const size_t size);
96
+ extern void *eCalloc (const size_t count, const size_t size);
97
+ extern void *eRealloc (void *const ptr, const size_t size);
98
+ extern void eFree (void *const ptr);
99
+
100
+ /* String manipulation functions */
101
+ extern int struppercmp (const char *s1, const char *s2);
102
+ extern int strnuppercmp (const char *s1, const char *s2, size_t n);
103
+ #ifndef HAVE_STRSTR
104
+ extern char* strstr (const char *str, const char *substr);
105
+ #endif
106
+ extern char* eStrdup (const char* str);
107
+ extern void toLowerString (char* str);
108
+ extern void toUpperString (char* str);
109
+ extern char* newLowerString (const char* str);
110
+ extern char* newUpperString (const char* str);
111
+
112
+ /* File system functions */
113
+ extern void setCurrentDirectory (void);
114
+ extern fileStatus *eStat (const char *const fileName);
115
+ extern void eStatFree (fileStatus *status);
116
+ extern boolean doesFileExist (const char *const fileName);
117
+ extern boolean isRecursiveLink (const char* const dirName);
118
+ extern boolean isSameFile (const char *const name1, const char *const name2);
119
+ #if defined(NEED_PROTO_FGETPOS)
120
+ extern int fgetpos (FILE *stream, fpos_t *pos);
121
+ extern int fsetpos (FILE *stream, fpos_t *pos);
122
+ #endif
123
+ extern const char *baseFilename (const char *const filePath);
124
+ extern const char *fileExtension (const char *const fileName);
125
+ extern boolean isAbsolutePath (const char *const path);
126
+ extern vString *combinePathAndFile (const char *const path, const char *const file);
127
+ extern char* absoluteFilename (const char *file);
128
+ extern char* absoluteDirname (char *file);
129
+ extern char* relativeFilename (const char *file, const char *dir);
130
+ extern FILE *tempFile (const char *const mode, char **const pName);
131
+
132
+ #endif /* _ROUTINES_H */
133
+
134
+ /* vi:set tabstop=4 shiftwidth=4: */
@@ -0,0 +1,408 @@
1
+ /*
2
+ * $Id: ruby.c 571 2007-06-24 23:32:14Z elliotth $
3
+ *
4
+ * Copyright (c) 2000-2001, Thaddeus Covert <sahuagin@mediaone.net>
5
+ * Copyright (c) 2002 Matthias Veit <matthias_veit@yahoo.de>
6
+ * Copyright (c) 2004 Elliott Hughes <enh@acm.org>
7
+ *
8
+ * This source code is released for free distribution under the terms of the
9
+ * GNU General Public License.
10
+ *
11
+ * This module contains functions for generating tags for Ruby language
12
+ * files.
13
+ */
14
+
15
+ /*
16
+ * INCLUDE FILES
17
+ */
18
+ #include "general.h" /* must always come first */
19
+
20
+ #include <string.h>
21
+
22
+ #include "entry.h"
23
+ #include "parse.h"
24
+ #include "read.h"
25
+ #include "vstring.h"
26
+
27
+ /*
28
+ * DATA DECLARATIONS
29
+ */
30
+ typedef enum {
31
+ K_UNDEFINED = -1, K_CLASS, K_METHOD, K_MODULE, K_SINGLETON
32
+ } rubyKind;
33
+
34
+ /*
35
+ * DATA DEFINITIONS
36
+ */
37
+ static kindOption RubyKinds [] = {
38
+ { TRUE, 'c', "class", "classes" },
39
+ { TRUE, 'f', "method", "methods" },
40
+ { TRUE, 'm', "module", "modules" },
41
+ { TRUE, 'F', "singleton method", "singleton methods" }
42
+ };
43
+
44
+ static stringList* nesting = 0;
45
+
46
+ /*
47
+ * FUNCTION DEFINITIONS
48
+ */
49
+
50
+ /*
51
+ * Returns a string describing the scope in 'list'.
52
+ * We record the current scope as a list of entered scopes.
53
+ * Scopes corresponding to 'if' statements and the like are
54
+ * represented by empty strings. Scopes corresponding to
55
+ * modules and classes are represented by the name of the
56
+ * module or class.
57
+ */
58
+ static vString* stringListToScope (const stringList* list)
59
+ {
60
+ unsigned int i;
61
+ unsigned int chunks_output = 0;
62
+ vString* result = vStringNew ();
63
+ const unsigned int max = stringListCount (list);
64
+ for (i = 0; i < max; ++i)
65
+ {
66
+ vString* chunk = stringListItem (list, i);
67
+ if (vStringLength (chunk) > 0)
68
+ {
69
+ vStringCatS (result, (chunks_output++ > 0) ? "." : "");
70
+ vStringCatS (result, vStringValue (chunk));
71
+ }
72
+ }
73
+ return result;
74
+ }
75
+
76
+ /*
77
+ * Attempts to advance 's' past 'literal'.
78
+ * Returns TRUE if it did, FALSE (and leaves 's' where
79
+ * it was) otherwise.
80
+ */
81
+ static boolean canMatch (const unsigned char** s, const char* literal)
82
+ {
83
+ const int literal_length = strlen (literal);
84
+ const unsigned char next_char = *(*s + literal_length);
85
+ if (strncmp ((const char*) *s, literal, literal_length) != 0)
86
+ {
87
+ return FALSE;
88
+ }
89
+ /* Additionally check that we're at the end of a token. */
90
+ if ( ! (next_char == 0 || isspace (next_char) || next_char == '('))
91
+ {
92
+ return FALSE;
93
+ }
94
+ *s += literal_length;
95
+ return TRUE;
96
+ }
97
+
98
+ /*
99
+ * Attempts to advance 'cp' past a Ruby operator method name. Returns
100
+ * TRUE if successful (and copies the name into 'name'), FALSE otherwise.
101
+ */
102
+ static boolean parseRubyOperator (vString* name, const unsigned char** cp)
103
+ {
104
+ static const char* RUBY_OPERATORS[] = {
105
+ "[]", "[]=",
106
+ "**",
107
+ "!", "~", "+@", "-@",
108
+ "*", "/", "%",
109
+ "+", "-",
110
+ ">>", "<<",
111
+ "&",
112
+ "^", "|",
113
+ "<=", "<", ">", ">=",
114
+ "<=>", "==", "===", "!=", "=~", "!~",
115
+ "`",
116
+ 0
117
+ };
118
+ int i;
119
+ for (i = 0; RUBY_OPERATORS[i] != 0; ++i)
120
+ {
121
+ if (canMatch (cp, RUBY_OPERATORS[i]))
122
+ {
123
+ vStringCatS (name, RUBY_OPERATORS[i]);
124
+ return TRUE;
125
+ }
126
+ }
127
+ return FALSE;
128
+ }
129
+
130
+ /*
131
+ * Emits a tag for the given 'name' of kind 'kind' at the current nesting.
132
+ */
133
+ static void emitRubyTag (vString* name, rubyKind kind)
134
+ {
135
+ tagEntryInfo tag;
136
+ vString* scope;
137
+
138
+ vStringTerminate (name);
139
+ scope = stringListToScope (nesting);
140
+
141
+ initTagEntry (&tag, vStringValue (name));
142
+ if (vStringLength (scope) > 0) {
143
+ tag.extensionFields.scope [0] = "class";
144
+ tag.extensionFields.scope [1] = vStringValue (scope);
145
+ }
146
+ tag.kindName = RubyKinds [kind].name;
147
+ tag.kind = RubyKinds [kind].letter;
148
+ makeTagEntry (&tag);
149
+
150
+ stringListAdd (nesting, vStringNewCopy (name));
151
+
152
+ vStringClear (name);
153
+ vStringDelete (scope);
154
+ }
155
+
156
+ /* Tests whether 'ch' is a character in 'list'. */
157
+ static boolean charIsIn (char ch, const char* list)
158
+ {
159
+ return (strchr (list, ch) != 0);
160
+ }
161
+
162
+ /* Advances 'cp' over leading whitespace. */
163
+ static void skipWhitespace (const unsigned char** cp)
164
+ {
165
+ while (isspace (**cp))
166
+ {
167
+ ++*cp;
168
+ }
169
+ }
170
+
171
+ /*
172
+ * Copies the characters forming an identifier from *cp into
173
+ * name, leaving *cp pointing to the character after the identifier.
174
+ */
175
+ static rubyKind parseIdentifier (
176
+ const unsigned char** cp, vString* name, rubyKind kind)
177
+ {
178
+ /* Method names are slightly different to class and variable names.
179
+ * A method name may optionally end with a question mark, exclamation
180
+ * point or equals sign. These are all part of the name.
181
+ * A method name may also contain a period if it's a singleton method.
182
+ */
183
+ const char* also_ok = (kind == K_METHOD) ? "_.?!=" : "_";
184
+
185
+ skipWhitespace (cp);
186
+
187
+ /* Check for an anonymous (singleton) class such as "class << HTTP". */
188
+ if (kind == K_CLASS && **cp == '<' && *(*cp + 1) == '<')
189
+ {
190
+ return K_UNDEFINED;
191
+ }
192
+
193
+ /* Check for operators such as "def []=(key, val)". */
194
+ if (kind == K_METHOD || kind == K_SINGLETON)
195
+ {
196
+ if (parseRubyOperator (name, cp))
197
+ {
198
+ return kind;
199
+ }
200
+ }
201
+
202
+ /* Copy the identifier into 'name'. */
203
+ while (**cp != 0 && (isalnum (**cp) || charIsIn (**cp, also_ok)))
204
+ {
205
+ char last_char = **cp;
206
+
207
+ vStringPut (name, last_char);
208
+ ++*cp;
209
+
210
+ if (kind == K_METHOD)
211
+ {
212
+ /* Recognize singleton methods. */
213
+ if (last_char == '.')
214
+ {
215
+ vStringTerminate (name);
216
+ vStringClear (name);
217
+ return parseIdentifier (cp, name, K_SINGLETON);
218
+ }
219
+
220
+ /* Recognize characters which mark the end of a method name. */
221
+ if (charIsIn (last_char, "?!="))
222
+ {
223
+ break;
224
+ }
225
+ }
226
+ }
227
+ return kind;
228
+ }
229
+
230
+ static void readAndEmitTag (const unsigned char** cp, rubyKind expected_kind)
231
+ {
232
+ if (isspace (**cp))
233
+ {
234
+ vString *name = vStringNew ();
235
+ rubyKind actual_kind = parseIdentifier (cp, name, expected_kind);
236
+
237
+ if (actual_kind == K_UNDEFINED || vStringLength (name) == 0)
238
+ {
239
+ /*
240
+ * What kind of tags should we create for code like this?
241
+ *
242
+ * %w(self.clfloor clfloor).each do |name|
243
+ * module_eval <<-"end;"
244
+ * def #{name}(x, y=1)
245
+ * q, r = x.divmod(y)
246
+ * q = q.to_i
247
+ * return q, r
248
+ * end
249
+ * end;
250
+ * end
251
+ *
252
+ * Or this?
253
+ *
254
+ * class << HTTP
255
+ *
256
+ * For now, we don't create any.
257
+ */
258
+ }
259
+ else
260
+ {
261
+ emitRubyTag (name, actual_kind);
262
+ }
263
+ vStringDelete (name);
264
+ }
265
+ }
266
+
267
+ static void enterUnnamedScope (void)
268
+ {
269
+ stringListAdd (nesting, vStringNewInit (""));
270
+ }
271
+
272
+ static void findRubyTags (void)
273
+ {
274
+ const unsigned char *line;
275
+ boolean inMultiLineComment = FALSE;
276
+
277
+ nesting = stringListNew ();
278
+
279
+ /* FIXME: this whole scheme is wrong, because Ruby isn't line-based.
280
+ * You could perfectly well write:
281
+ *
282
+ * def
283
+ * method
284
+ * puts("hello")
285
+ * end
286
+ *
287
+ * if you wished, and this function would fail to recognize anything.
288
+ */
289
+ while ((line = fileReadLine ()) != NULL)
290
+ {
291
+ const unsigned char *cp = line;
292
+
293
+ if (canMatch (&cp, "=begin"))
294
+ {
295
+ inMultiLineComment = TRUE;
296
+ continue;
297
+ }
298
+ if (canMatch (&cp, "=end"))
299
+ {
300
+ inMultiLineComment = FALSE;
301
+ continue;
302
+ }
303
+
304
+ skipWhitespace (&cp);
305
+
306
+ /* Avoid mistakenly starting a scope for modifiers such as
307
+ *
308
+ * return if <exp>
309
+ *
310
+ * FIXME: this is fooled by code such as
311
+ *
312
+ * result = if <exp>
313
+ * <a>
314
+ * else
315
+ * <b>
316
+ * end
317
+ *
318
+ * FIXME: we're also fooled if someone does something heinous such as
319
+ *
320
+ * puts("hello") \
321
+ * unless <exp>
322
+ */
323
+ if (canMatch (&cp, "case") || canMatch (&cp, "for") ||
324
+ canMatch (&cp, "if") || canMatch (&cp, "unless") ||
325
+ canMatch (&cp, "while"))
326
+ {
327
+ enterUnnamedScope ();
328
+ }
329
+
330
+ /*
331
+ * "module M", "class C" and "def m" should only be at the beginning
332
+ * of a line.
333
+ */
334
+ if (canMatch (&cp, "module"))
335
+ {
336
+ readAndEmitTag (&cp, K_MODULE);
337
+ }
338
+ else if (canMatch (&cp, "class"))
339
+ {
340
+ readAndEmitTag (&cp, K_CLASS);
341
+ }
342
+ else if (canMatch (&cp, "def"))
343
+ {
344
+ readAndEmitTag (&cp, K_METHOD);
345
+ }
346
+
347
+ while (*cp != '\0')
348
+ {
349
+ /* FIXME: we don't cope with here documents,
350
+ * or regular expression literals, or ... you get the idea.
351
+ * Hopefully, the restriction above that insists on seeing
352
+ * definitions at the starts of lines should keep us out of
353
+ * mischief.
354
+ */
355
+ if (inMultiLineComment || isspace (*cp))
356
+ {
357
+ ++cp;
358
+ }
359
+ else if (*cp == '#')
360
+ {
361
+ /* FIXME: this is wrong, but there *probably* won't be a
362
+ * definition after an interpolated string (where # doesn't
363
+ * mean 'comment').
364
+ */
365
+ break;
366
+ }
367
+ else if (canMatch (&cp, "begin") || canMatch (&cp, "do"))
368
+ {
369
+ enterUnnamedScope ();
370
+ }
371
+ else if (canMatch (&cp, "end") && stringListCount (nesting) > 0)
372
+ {
373
+ /* Leave the most recent scope. */
374
+ vStringDelete (stringListLast (nesting));
375
+ stringListRemoveLast (nesting);
376
+ }
377
+ else if (*cp == '"')
378
+ {
379
+ /* Skip string literals.
380
+ * FIXME: should cope with escapes and interpolation.
381
+ */
382
+ do {
383
+ ++cp;
384
+ } while (*cp != 0 && *cp != '"');
385
+ }
386
+ else if (*cp != '\0')
387
+ {
388
+ do
389
+ ++cp;
390
+ while (isalnum (*cp) || *cp == '_');
391
+ }
392
+ }
393
+ }
394
+ stringListDelete (nesting);
395
+ }
396
+
397
+ extern parserDefinition* RubyParser (void)
398
+ {
399
+ static const char *const extensions [] = { "rb", "ruby", NULL };
400
+ parserDefinition* def = parserNew ("Ruby");
401
+ def->kinds = RubyKinds;
402
+ def->kindCount = KIND_COUNT (RubyKinds);
403
+ def->extensions = extensions;
404
+ def->parser = findRubyTags;
405
+ return def;
406
+ }
407
+
408
+ /* vi:set tabstop=4 shiftwidth=4: */
@@ -0,0 +1,111 @@
1
+ /*
2
+ * $Id: scheme.c 443 2006-05-30 04:37:13Z darren $
3
+ *
4
+ * Copyright (c) 2000-2002, Darren Hiebert
5
+ *
6
+ * This source code is released for free distribution under the terms of the
7
+ * GNU General Public License.
8
+ *
9
+ * This module contains functions for generating tags for Scheme language
10
+ * files.
11
+ */
12
+
13
+ /*
14
+ * INCLUDE FILES
15
+ */
16
+ #include "general.h" /* must always come first */
17
+
18
+ #include <string.h>
19
+
20
+ #include "parse.h"
21
+ #include "read.h"
22
+ #include "vstring.h"
23
+
24
+ /*
25
+ * DATA DEFINITIONS
26
+ */
27
+ typedef enum {
28
+ K_FUNCTION, K_SET
29
+ } schemeKind;
30
+
31
+ static kindOption SchemeKinds [] = {
32
+ { TRUE, 'f', "function", "functions" },
33
+ { TRUE, 's', "set", "sets" }
34
+ };
35
+
36
+ /*
37
+ * FUNCTION DEFINITIONS
38
+ */
39
+
40
+ /* Algorithm adapted from from GNU etags.
41
+ * Scheme tag functions
42
+ * look for (def... xyzzy
43
+ * look for (def... (xyzzy
44
+ * look for (def ... ((... (xyzzy ....
45
+ * look for (set! xyzzy
46
+ */
47
+ static void readIdentifier (vString *const name, const unsigned char *cp)
48
+ {
49
+ const unsigned char *p;
50
+ vStringClear (name);
51
+ /* Go till you get to white space or a syntactic break */
52
+ for (p = cp; *p != '\0' && *p != '(' && *p != ')' && !isspace (*p); p++)
53
+ vStringPut (name, (int) *p);
54
+ vStringTerminate (name);
55
+ }
56
+
57
+ static void findSchemeTags (void)
58
+ {
59
+ vString *name = vStringNew ();
60
+ const unsigned char *line;
61
+
62
+ while ((line = fileReadLine ()) != NULL)
63
+ {
64
+ const unsigned char *cp = line;
65
+
66
+ if (cp [0] == '(' &&
67
+ (cp [1] == 'D' || cp [1] == 'd') &&
68
+ (cp [2] == 'E' || cp [2] == 'e') &&
69
+ (cp [3] == 'F' || cp [3] == 'f'))
70
+ {
71
+ while (!isspace (*cp))
72
+ cp++;
73
+ /* Skip over open parens and white space */
74
+ while (*cp != '\0' && (isspace (*cp) || *cp == '('))
75
+ cp++;
76
+ readIdentifier (name, cp);
77
+ makeSimpleTag (name, SchemeKinds, K_FUNCTION);
78
+ }
79
+ if (cp [0] == '(' &&
80
+ (cp [1] == 'S' || cp [1] == 's') &&
81
+ (cp [2] == 'E' || cp [2] == 'e') &&
82
+ (cp [3] == 'T' || cp [3] == 't') &&
83
+ (cp [4] == '!' || cp [4] == '!') &&
84
+ (isspace (cp [5])))
85
+ {
86
+ while (*cp != '\0' && !isspace (*cp))
87
+ cp++;
88
+ /* Skip over white space */
89
+ while (isspace (*cp))
90
+ cp++;
91
+ readIdentifier (name, cp);
92
+ makeSimpleTag (name, SchemeKinds, K_SET);
93
+ }
94
+ }
95
+ vStringDelete (name);
96
+ }
97
+
98
+ extern parserDefinition* SchemeParser (void)
99
+ {
100
+ static const char *const extensions [] = {
101
+ "SCM", "SM", "sch", "scheme", "scm", "sm", NULL
102
+ };
103
+ parserDefinition* def = parserNew ("Scheme");
104
+ def->kinds = SchemeKinds;
105
+ def->kindCount = KIND_COUNT (SchemeKinds);
106
+ def->extensions = extensions;
107
+ def->parser = findSchemeTags;
108
+ return def;
109
+ }
110
+
111
+ /* vi:set tabstop=4 shiftwidth=4: */