3 * Copyright (c) 2001-2002, Biswapesh Chattopadhyay
5 * This source code is released for free distribution under the terms of the
6 * GNU General Public License.
11 * @file tm_source_file.h
12 The TMSourceFile structure and associated functions are used to maintain
13 tags for individual files.
23 #include <glib/gstdio.h>
26 # define WIN32_LEAN_AND_MEAN
27 # include <windows.h> /* for GetFullPathName */
30 #include "tm_source_file.h"
32 #include "tm_parser.h"
33 #include "tm_ctags_wrappers.h"
43 TM_FILE_FORMAT_TAGMANAGER
,
48 /* Note: To preserve binary compatibility, it is very important
49 that you only *append* to this list ! */
55 TA_POS
, /* Obsolete */
65 TA_INACTIVE
, /* Obsolete */
70 #define SOURCE_FILE_NEW(S) ((S) = g_slice_new(TMSourceFilePriv))
71 #define SOURCE_FILE_FREE(S) g_slice_free(TMSourceFilePriv, (TMSourceFilePriv *) S)
73 static int get_path_max(const char *path
)
78 int path_max
= pathconf(path
, _PC_PATH_MAX
);
87 /* realpath implementation for Windows found at http://bugzilla.gnome.org/show_bug.cgi?id=342926
88 * this one is better than e.g. liberty's lrealpath because this one uses Win32 API and works
89 * with special chars within the filename */
90 static char *realpath (const char *pathname
, char *resolved_path
)
94 if (resolved_path
!= NULL
)
96 int path_max
= get_path_max(pathname
);
97 size
= GetFullPathNameA (pathname
, path_max
, resolved_path
, NULL
);
101 return resolved_path
;
105 size
= GetFullPathNameA (pathname
, 0, NULL
, NULL
);
106 resolved_path
= g_new0 (char, size
);
107 GetFullPathNameA (pathname
, size
, resolved_path
, NULL
);
108 return resolved_path
;
114 Given a file name, returns a newly allocated string containing the realpath()
116 @param file_name The original file_name
117 @return A newly allocated string containing the real path to the file. NULL if none is available.
120 gchar
*tm_get_real_path(const gchar
*file_name
)
124 gsize len
= get_path_max(file_name
) + 1;
125 gchar
*path
= g_malloc0(len
);
127 if (realpath(file_name
, path
))
135 static char get_tag_impl(const char *impl
)
137 if ((0 == strcmp("virtual", impl
))
138 || (0 == strcmp("pure virtual", impl
)))
139 return TAG_IMPL_VIRTUAL
;
142 g_warning("Unknown implementation %s", impl
);
144 return TAG_IMPL_UNKNOWN
;
147 static char get_tag_access(const char *access
)
149 if (0 == strcmp("public", access
))
150 return TAG_ACCESS_PUBLIC
;
151 else if (0 == strcmp("protected", access
))
152 return TAG_ACCESS_PROTECTED
;
153 else if (0 == strcmp("private", access
))
154 return TAG_ACCESS_PRIVATE
;
155 else if (0 == strcmp("friend", access
))
156 return TAG_ACCESS_FRIEND
;
157 else if (0 == strcmp("default", access
))
158 return TAG_ACCESS_DEFAULT
;
161 g_warning("Unknown access type %s", access
);
163 return TAG_ACCESS_UNKNOWN
;
167 Initializes a TMTag structure with information from a tagEntryInfo struct
168 used by the ctags parsers. Note that the TMTag structure must be malloc()ed
169 before calling this function.
170 @param tag The TMTag structure to initialize
171 @param file Pointer to a TMSourceFile struct (it is assigned to the file member)
172 @param tag_entry Tag information gathered by the ctags parser
173 @return TRUE on success, FALSE on failure
175 static gboolean
init_tag(TMTag
*tag
, TMSourceFile
*file
, const tagEntryInfo
*tag_entry
)
182 type
= tm_parser_get_tag_type(tag_entry
->kind
, file
->lang
);
183 if (!tag_entry
->name
|| type
== tm_tag_undef_t
)
186 tag
->name
= g_strdup(tag_entry
->name
);
188 tag
->local
= tag_entry
->isFileScope
;
189 tag
->pointerOrder
= 0; /* backward compatibility (use var_type instead) */
190 tag
->line
= tag_entry
->lineNumber
;
191 if (NULL
!= tag_entry
->extensionFields
.signature
)
192 tag
->arglist
= g_strdup(tag_entry
->extensionFields
.signature
);
193 if ((NULL
!= tag_entry
->extensionFields
.scope
[1]) &&
194 (0 != tag_entry
->extensionFields
.scope
[1][0]))
195 tag
->scope
= g_strdup(tag_entry
->extensionFields
.scope
[1]);
196 if (tag_entry
->extensionFields
.inheritance
!= NULL
)
197 tag
->inheritance
= g_strdup(tag_entry
->extensionFields
.inheritance
);
198 if (tag_entry
->extensionFields
.varType
!= NULL
)
199 tag
->var_type
= g_strdup(tag_entry
->extensionFields
.varType
);
200 if (tag_entry
->extensionFields
.access
!= NULL
)
201 tag
->access
= get_tag_access(tag_entry
->extensionFields
.access
);
202 if (tag_entry
->extensionFields
.implementation
!= NULL
)
203 tag
->impl
= get_tag_impl(tag_entry
->extensionFields
.implementation
);
204 if ((tm_tag_macro_t
== tag
->type
) && (NULL
!= tag
->arglist
))
205 tag
->type
= tm_tag_macro_with_arg_t
;
207 tag
->lang
= file
->lang
;
212 Initializes an already malloc()ed TMTag structure by reading a tag entry
213 line from a file. The structure should be allocated beforehand.
214 @param tag The TMTag structure to populate
215 @param file The TMSourceFile struct (assigned to the file member)
216 @param fp FILE pointer from where the tag line is read
217 @return TRUE on success, FALSE on FAILURE
219 static gboolean
init_tag_from_file(TMTag
*tag
, TMSourceFile
*file
, FILE *fp
)
224 guchar changed_char
= TA_NAME
;
227 if ((NULL
== fgets((gchar
*)buf
, BUFSIZ
, fp
)) || ('\0' == *buf
))
229 for (start
= end
= buf
, status
= TRUE
; (TRUE
== status
); start
= end
, ++ end
)
231 while ((*end
< TA_NAME
) && (*end
!= '\0') && (*end
!= '\n'))
233 if (('\0' == *end
) || ('\n' == *end
))
237 if (NULL
== tag
->name
)
239 if (!isprint(*start
))
242 tag
->name
= g_strdup((gchar
*)start
);
249 tag
->line
= atol((gchar
*)start
+ 1);
252 tag
->local
= atoi((gchar
*)start
+ 1);
255 tag
->type
= (TMTagType
) atoi((gchar
*)start
+ 1);
258 tag
->arglist
= g_strdup((gchar
*)start
+ 1);
261 tag
->scope
= g_strdup((gchar
*)start
+ 1);
264 tag
->pointerOrder
= atoi((gchar
*)start
+ 1);
267 tag
->var_type
= g_strdup((gchar
*)start
+ 1);
270 tag
->inheritance
= g_strdup((gchar
*)start
+ 1);
272 case TA_TIME
: /* Obsolete */
274 case TA_LANG
: /* Obsolete */
276 case TA_INACTIVE
: /* Obsolete */
279 tag
->access
= (char) *(start
+ 1);
282 tag
->impl
= (char) *(start
+ 1);
286 g_warning("Unknown attribute %s", start
+ 1);
293 if (NULL
== tag
->name
)
299 /* alternative parser for Pascal and LaTeX global tags files with the following format
300 * tagname|return value|arglist|description\n */
301 static gboolean
init_tag_from_file_alt(TMTag
*tag
, TMSourceFile
*file
, FILE *fp
)
306 /*guchar changed_char = TA_NAME;*/
309 if ((NULL
== fgets((gchar
*)buf
, BUFSIZ
, fp
)) || ('\0' == *buf
))
314 for (start
= end
= buf
, status
= TRUE
; (TRUE
== status
); start
= end
, ++ end
)
316 while ((*end
< TA_NAME
) && (*end
!= '\0') && (*end
!= '\n'))
318 if (('\0' == *end
) || ('\n' == *end
))
320 /*changed_char = *end;*/
322 if (NULL
== tag
->name
&& !isprint(*start
))
325 fields
= g_strsplit((gchar
*)start
, "|", -1);
326 field_len
= g_strv_length(fields
);
328 if (field_len
>= 1) tag
->name
= g_strdup(fields
[0]);
329 else tag
->name
= NULL
;
330 if (field_len
>= 2 && fields
[1] != NULL
) tag
->var_type
= g_strdup(fields
[1]);
331 if (field_len
>= 3 && fields
[2] != NULL
) tag
->arglist
= g_strdup(fields
[2]);
332 tag
->type
= tm_tag_prototype_t
;
337 if (NULL
== tag
->name
)
344 CTags tag file format (http://ctags.sourceforge.net/FORMAT)
346 static gboolean
init_tag_from_file_ctags(TMTag
*tag
, TMSourceFile
*file
, FILE *fp
, TMParserType lang
)
352 tag
->type
= tm_tag_function_t
; /* default type is function if no kind is specified */
355 if ((NULL
== fgets(buf
, BUFSIZ
, fp
)) || ('\0' == *buf
))
358 while (strncmp(buf
, "!_TAG_", 6) == 0); /* skip !_TAG_ lines */
363 if (! (tab
= strchr(p
, '\t')) || p
== tab
)
365 tag
->name
= g_strndup(p
, (gsize
)(tab
- p
));
368 /* tagfile, unused */
369 if (! (tab
= strchr(p
, '\t')))
376 /* Ex command, unused */
377 if (*p
== '/' || *p
== '?')
380 for (++p
; *p
&& *p
!= c
; p
++)
382 if (*p
== '\\' && p
[1])
386 else /* assume a line */
388 tab
= strstr(p
, ";\"");
389 /* read extension fields */
393 while (*p
&& *p
!= '\n' && *p
!= '\r')
396 const gchar
*key
, *value
= NULL
;
398 /* skip leading tabulations */
399 while (*p
&& *p
== '\t') p
++;
400 /* find the separator (:) and end (\t) */
402 while (*end
&& *end
!= '\t' && *end
!= '\n' && *end
!= '\r')
404 if (*end
== ':' && ! value
)
406 *end
= 0; /* terminate the key */
411 /* move p paste the so we won't stop parsing by setting *end=0 below */
412 p
= *end
? end
+ 1 : end
;
413 *end
= 0; /* terminate the value (or key if no value) */
415 if (! value
|| 0 == strcmp(key
, "kind")) /* tag kind */
417 const gchar
*kind
= value
? value
: key
;
419 if (kind
[0] && kind
[1])
420 tag
->type
= tm_parser_get_tag_type(tm_ctags_get_kind_from_name(kind
, lang
), lang
);
422 tag
->type
= tm_parser_get_tag_type(*kind
, lang
);
424 else if (0 == strcmp(key
, "inherits")) /* comma-separated list of classes this class inherits from */
426 g_free(tag
->inheritance
);
427 tag
->inheritance
= g_strdup(value
);
429 else if (0 == strcmp(key
, "implementation")) /* implementation limit */
430 tag
->impl
= get_tag_impl(value
);
431 else if (0 == strcmp(key
, "line")) /* line */
432 tag
->line
= atol(value
);
433 else if (0 == strcmp(key
, "access")) /* access */
434 tag
->access
= get_tag_access(value
);
435 else if (0 == strcmp(key
, "class") ||
436 0 == strcmp(key
, "enum") ||
437 0 == strcmp(key
, "function") ||
438 0 == strcmp(key
, "struct") ||
439 0 == strcmp(key
, "union")) /* Name of the class/enum/function/struct/union in which this tag is a member */
442 tag
->scope
= g_strdup(value
);
444 else if (0 == strcmp(key
, "file")) /* static (local) tag */
446 else if (0 == strcmp(key
, "signature")) /* arglist */
448 g_free(tag
->arglist
);
449 tag
->arglist
= g_strdup(value
);
458 static TMTag
*new_tag_from_tags_file(TMSourceFile
*file
, FILE *fp
, TMParserType mode
, TMFileFormat format
)
460 TMTag
*tag
= tm_tag_new();
461 gboolean result
= FALSE
;
465 case TM_FILE_FORMAT_TAGMANAGER
:
466 result
= init_tag_from_file(tag
, file
, fp
);
468 case TM_FILE_FORMAT_PIPE
:
469 result
= init_tag_from_file_alt(tag
, file
, fp
);
471 case TM_FILE_FORMAT_CTAGS
:
472 result
= init_tag_from_file_ctags(tag
, file
, fp
, mode
);
486 Writes tag information to the given FILE *.
487 @param tag The tag information to write.
488 @param file FILE pointer to which the tag information is written.
489 @param attrs Attributes to be written (bitmask).
490 @return TRUE on success, FALSE on failure.
492 static gboolean
write_tag(TMTag
*tag
, FILE *fp
, TMTagAttrType attrs
)
494 fprintf(fp
, "%s", tag
->name
);
495 if (attrs
& tm_tag_attr_type_t
)
496 fprintf(fp
, "%c%d", TA_TYPE
, tag
->type
);
497 if ((attrs
& tm_tag_attr_arglist_t
) && (NULL
!= tag
->arglist
))
498 fprintf(fp
, "%c%s", TA_ARGLIST
, tag
->arglist
);
499 if (attrs
& tm_tag_attr_line_t
)
500 fprintf(fp
, "%c%ld", TA_LINE
, tag
->line
);
501 if (attrs
& tm_tag_attr_local_t
)
502 fprintf(fp
, "%c%d", TA_LOCAL
, tag
->local
);
503 if ((attrs
& tm_tag_attr_scope_t
) && (NULL
!= tag
->scope
))
504 fprintf(fp
, "%c%s", TA_SCOPE
, tag
->scope
);
505 if ((attrs
& tm_tag_attr_inheritance_t
) && (NULL
!= tag
->inheritance
))
506 fprintf(fp
, "%c%s", TA_INHERITS
, tag
->inheritance
);
507 if (attrs
& tm_tag_attr_pointer_t
)
508 fprintf(fp
, "%c%d", TA_POINTER
, tag
->pointerOrder
);
509 if ((attrs
& tm_tag_attr_vartype_t
) && (NULL
!= tag
->var_type
))
510 fprintf(fp
, "%c%s", TA_VARTYPE
, tag
->var_type
);
511 if ((attrs
& tm_tag_attr_access_t
) && (TAG_ACCESS_UNKNOWN
!= tag
->access
))
512 fprintf(fp
, "%c%c", TA_ACCESS
, tag
->access
);
513 if ((attrs
& tm_tag_attr_impl_t
) && (TAG_IMPL_UNKNOWN
!= tag
->impl
))
514 fprintf(fp
, "%c%c", TA_IMPL
, tag
->impl
);
516 if (fprintf(fp
, "\n"))
522 GPtrArray
*tm_source_file_read_tags_file(const gchar
*tags_file
, TMParserType mode
)
526 GPtrArray
*file_tags
;
528 TMFileFormat format
= TM_FILE_FORMAT_TAGMANAGER
;
530 if (NULL
== (fp
= g_fopen(tags_file
, "r")))
532 if ((NULL
== fgets((gchar
*) buf
, BUFSIZ
, fp
)) || ('\0' == *buf
))
535 return NULL
; /* early out on error */
538 { /* We read the first line for the format specification. */
539 if (buf
[0] == '#' && strstr((gchar
*) buf
, "format=pipe") != NULL
)
540 format
= TM_FILE_FORMAT_PIPE
;
541 else if (buf
[0] == '#' && strstr((gchar
*) buf
, "format=tagmanager") != NULL
)
542 format
= TM_FILE_FORMAT_TAGMANAGER
;
543 else if (buf
[0] == '#' && strstr((gchar
*) buf
, "format=ctags") != NULL
)
544 format
= TM_FILE_FORMAT_CTAGS
;
545 else if (strncmp((gchar
*) buf
, "!_TAG_", 6) == 0)
546 format
= TM_FILE_FORMAT_CTAGS
;
548 { /* We didn't find a valid format specification, so we try to auto-detect the format
549 * by counting the pipe characters on the first line and asumme pipe format when
550 * we find more than one pipe on the line. */
551 guint i
, pipe_cnt
= 0, tab_cnt
= 0;
552 for (i
= 0; i
< BUFSIZ
&& buf
[i
] != '\0' && pipe_cnt
< 2; i
++)
556 else if (buf
[i
] == '\t')
560 format
= TM_FILE_FORMAT_PIPE
;
561 else if (tab_cnt
> 1)
562 format
= TM_FILE_FORMAT_CTAGS
;
564 rewind(fp
); /* reset the file pointer, to start reading again from the beginning */
567 file_tags
= g_ptr_array_new();
568 while (NULL
!= (tag
= new_tag_from_tags_file(NULL
, fp
, mode
, format
)))
569 g_ptr_array_add(file_tags
, tag
);
575 gboolean
tm_source_file_write_tags_file(const gchar
*tags_file
, GPtrArray
*tags_array
)
581 g_return_val_if_fail(tags_array
&& tags_file
, FALSE
);
583 fp
= g_fopen(tags_file
, "w");
587 fprintf(fp
, "# format=tagmanager\n");
588 for (i
= 0; i
< tags_array
->len
; i
++)
590 TMTag
*tag
= TM_TAG(tags_array
->pdata
[i
]);
592 ret
= write_tag(tag
, fp
, tm_tag_attr_type_t
593 | tm_tag_attr_scope_t
| tm_tag_attr_arglist_t
| tm_tag_attr_vartype_t
594 | tm_tag_attr_pointer_t
);
604 /* add argument list of __init__() Python methods to the class tag */
605 static void update_python_arglist(const TMTag
*tag
, TMSourceFile
*current_source_file
)
608 const char *parent_tag_name
;
610 if (tag
->type
!= tm_tag_method_t
|| tag
->scope
== NULL
||
611 g_strcmp0(tag
->name
, "__init__") != 0)
614 parent_tag_name
= strrchr(tag
->scope
, '.');
618 parent_tag_name
= tag
->scope
;
620 /* going in reverse order because the tag was added recently */
621 for (i
= current_source_file
->tags_array
->len
; i
> 0; i
--)
623 TMTag
*prev_tag
= (TMTag
*) current_source_file
->tags_array
->pdata
[i
- 1];
624 if (g_strcmp0(prev_tag
->name
, parent_tag_name
) == 0)
626 g_free(prev_tag
->arglist
);
627 prev_tag
->arglist
= g_strdup(tag
->arglist
);
633 /* new parsing pass ctags callback function */
634 static gboolean
ctags_pass_start(void *user_data
)
636 TMSourceFile
*current_source_file
= user_data
;
638 tm_tags_array_free(current_source_file
->tags_array
, FALSE
);
642 /* new tag ctags callback function */
643 static gboolean
ctags_new_tag(const tagEntryInfo
*const tag
,
646 TMSourceFile
*current_source_file
= user_data
;
647 TMTag
*tm_tag
= tm_tag_new();
649 if (!init_tag(tm_tag
, current_source_file
, tag
))
651 tm_tag_unref(tm_tag
);
655 if (tm_tag
->lang
== TM_PARSER_PYTHON
)
656 update_python_arglist(tm_tag
, current_source_file
);
658 g_ptr_array_add(current_source_file
->tags_array
, tm_tag
);
663 /* Initializes a TMSourceFile structure from a file name. */
664 static gboolean
tm_source_file_init(TMSourceFile
*source_file
, const char *file_name
,
671 g_message("Source File init: %s", file_name
);
674 if (file_name
!= NULL
)
676 status
= g_stat(file_name
, &s
);
679 /* g_warning("Unable to stat %s", file_name);*/
682 if (!S_ISREG(s
.st_mode
))
684 g_warning("%s: Not a regular file", file_name
);
687 source_file
->file_name
= tm_get_real_path(file_name
);
688 source_file
->short_name
= strrchr(source_file
->file_name
, '/');
689 if (source_file
->short_name
)
690 ++ source_file
->short_name
;
692 source_file
->short_name
= source_file
->file_name
;
695 source_file
->tags_array
= g_ptr_array_new();
698 source_file
->lang
= TM_PARSER_NONE
;
700 source_file
->lang
= tm_ctags_get_named_lang(name
);
705 /** Initializes a TMSourceFile structure and returns a pointer to it. The
706 * TMSourceFile has to be added to TMWorkspace to start its parsing.
707 * @param file_name The file name.
708 * @param name Name of the used programming language, NULL to disable parsing.
709 * @return The created unparsed TMSourceFile object.
712 TMSourceFile
*tm_source_file_new(const char *file_name
, const char *name
)
714 TMSourceFilePriv
*priv
;
716 SOURCE_FILE_NEW(priv
);
717 if (TRUE
!= tm_source_file_init(&priv
->public, file_name
, name
))
719 SOURCE_FILE_FREE(priv
);
723 return &priv
->public;
727 static TMSourceFile
*tm_source_file_dup(TMSourceFile
*source_file
)
729 TMSourceFilePriv
*priv
= (TMSourceFilePriv
*) source_file
;
731 g_return_val_if_fail(NULL
!= source_file
, NULL
);
733 g_atomic_int_inc(&priv
->refcount
);
737 /* Destroys the contents of the source file. Note that the tags are owned by the
738 source file and are also destroyed when the source file is destroyed. If pointers
739 to these tags are used elsewhere, then those tag arrays should be rebuilt.
741 static void tm_source_file_destroy(TMSourceFile
*source_file
)
744 g_message("Destroying source file: %s", source_file
->file_name
);
747 g_free(source_file
->file_name
);
748 tm_tags_array_free(source_file
->tags_array
, TRUE
);
749 source_file
->tags_array
= NULL
;
752 /** Decrements the reference count of @a source_file
754 * If the reference count drops to 0, then @a source_file is freed, including all contents.
755 * Make sure the @a source_file is already removed from any TMWorkSpace before the
757 * @param source_file The source file to free.
758 * @see tm_workspace_remove_source_file()
761 void tm_source_file_free(TMSourceFile
*source_file
)
763 TMSourceFilePriv
*priv
= (TMSourceFilePriv
*) source_file
;
765 if (NULL
!= priv
&& g_atomic_int_dec_and_test(&priv
->refcount
))
767 tm_source_file_destroy(source_file
);
768 SOURCE_FILE_FREE(priv
);
772 /** Gets the GBoxed-derived GType for TMSourceFile
774 * @return TMSourceFile type . */
776 GType
tm_source_file_get_type(void);
778 G_DEFINE_BOXED_TYPE(TMSourceFile
, tm_source_file
, tm_source_file_dup
, tm_source_file_free
);
780 /* Parses the text-buffer or source file and regenarates the tags.
781 @param source_file The source file to parse
782 @param text_buf The text buffer to parse
783 @param buf_size The size of text_buf.
784 @param use_buffer Set FALSE to ignore the buffer and parse the file directly or
785 TRUE to parse the buffer and ignore the file content.
786 @return TRUE on success, FALSE on failure
788 gboolean
tm_source_file_parse(TMSourceFile
*source_file
, guchar
* text_buf
, gsize buf_size
,
791 const char *file_name
;
792 gboolean retry
= TRUE
;
793 gboolean parse_file
= FALSE
;
794 gboolean free_buf
= FALSE
;
796 if ((NULL
== source_file
) || (NULL
== source_file
->file_name
))
798 g_warning("Attempt to parse NULL file");
802 if (source_file
->lang
== TM_PARSER_NONE
)
804 tm_tags_array_free(source_file
->tags_array
, FALSE
);
808 file_name
= source_file
->file_name
;
814 /* load file to memory and parse it from memory unless the file is too big */
815 if (g_stat(file_name
, &s
) != 0 || s
.st_size
> 10*1024*1024)
819 if (!g_file_get_contents(file_name
, (gchar
**)&text_buf
, (gsize
*)&buf_size
, NULL
))
821 g_warning("Unable to open %s", file_name
);
828 if (!parse_file
&& (NULL
== text_buf
|| 0 == buf_size
))
830 /* Empty buffer, "parse" by setting empty tag array */
831 tm_tags_array_free(source_file
->tags_array
, FALSE
);
837 tm_tags_array_free(source_file
->tags_array
, FALSE
);
839 tm_ctags_parse(parse_file
? NULL
: text_buf
, buf_size
, file_name
,
840 source_file
->lang
, ctags_new_tag
, ctags_pass_start
, source_file
);
847 /* Gets the name associated with the language index.
848 @param lang The language index.
849 @return The language name, or NULL.
851 const gchar
*tm_source_file_get_lang_name(TMParserType lang
)
853 return tm_ctags_get_lang_name(lang
);
856 /* Gets the language index for \a name.
857 @param name The language name.
858 @return The language index, or TM_PARSER_NONE.
860 TMParserType
tm_source_file_get_named_lang(const gchar
*name
)
862 return tm_ctags_get_named_lang(name
);