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. This function is called by tm_tag_new() - you
170 should not need to call this directly.
171 @param tag The TMTag structure to initialize
172 @param file Pointer to a TMSourceFile struct (it is assigned to the file member)
173 @param tag_entry Tag information gathered by the ctags parser
174 @return TRUE on success, FALSE on failure
176 static gboolean
init_tag(TMTag
*tag
, TMSourceFile
*file
, const tagEntryInfo
*tag_entry
)
183 type
= tm_parser_get_tag_type(tag_entry
->kind
, file
->lang
);
184 if (!tag_entry
->name
|| type
== tm_tag_undef_t
)
187 tag
->name
= g_strdup(tag_entry
->name
);
189 tag
->local
= tag_entry
->isFileScope
;
190 tag
->pointerOrder
= 0; /* backward compatibility (use var_type instead) */
191 tag
->line
= tag_entry
->lineNumber
;
192 if (NULL
!= tag_entry
->extensionFields
.arglist
)
193 tag
->arglist
= g_strdup(tag_entry
->extensionFields
.arglist
);
194 if ((NULL
!= tag_entry
->extensionFields
.scope
[1]) &&
195 (0 != tag_entry
->extensionFields
.scope
[1][0]))
196 tag
->scope
= g_strdup(tag_entry
->extensionFields
.scope
[1]);
197 if (tag_entry
->extensionFields
.inheritance
!= NULL
)
198 tag
->inheritance
= g_strdup(tag_entry
->extensionFields
.inheritance
);
199 if (tag_entry
->extensionFields
.varType
!= NULL
)
200 tag
->var_type
= g_strdup(tag_entry
->extensionFields
.varType
);
201 if (tag_entry
->extensionFields
.access
!= NULL
)
202 tag
->access
= get_tag_access(tag_entry
->extensionFields
.access
);
203 if (tag_entry
->extensionFields
.implementation
!= NULL
)
204 tag
->impl
= get_tag_impl(tag_entry
->extensionFields
.implementation
);
205 if ((tm_tag_macro_t
== tag
->type
) && (NULL
!= tag
->arglist
))
206 tag
->type
= tm_tag_macro_with_arg_t
;
208 tag
->lang
= file
->lang
;
213 Initializes an already malloc()ed TMTag structure by reading a tag entry
214 line from a file. The structure should be allocated beforehand.
215 @param tag The TMTag structure to populate
216 @param file The TMSourceFile struct (assigned to the file member)
217 @param fp FILE pointer from where the tag line is read
218 @return TRUE on success, FALSE on FAILURE
220 static gboolean
init_tag_from_file(TMTag
*tag
, TMSourceFile
*file
, FILE *fp
)
225 guchar changed_char
= TA_NAME
;
228 if ((NULL
== fgets((gchar
*)buf
, BUFSIZ
, fp
)) || ('\0' == *buf
))
230 for (start
= end
= buf
, status
= TRUE
; (TRUE
== status
); start
= end
, ++ end
)
232 while ((*end
< TA_NAME
) && (*end
!= '\0') && (*end
!= '\n'))
234 if (('\0' == *end
) || ('\n' == *end
))
238 if (NULL
== tag
->name
)
240 if (!isprint(*start
))
243 tag
->name
= g_strdup((gchar
*)start
);
250 tag
->line
= atol((gchar
*)start
+ 1);
253 tag
->local
= atoi((gchar
*)start
+ 1);
256 tag
->type
= (TMTagType
) atoi((gchar
*)start
+ 1);
259 tag
->arglist
= g_strdup((gchar
*)start
+ 1);
262 tag
->scope
= g_strdup((gchar
*)start
+ 1);
265 tag
->pointerOrder
= atoi((gchar
*)start
+ 1);
268 tag
->var_type
= g_strdup((gchar
*)start
+ 1);
271 tag
->inheritance
= g_strdup((gchar
*)start
+ 1);
273 case TA_TIME
: /* Obsolete */
275 case TA_LANG
: /* Obsolete */
277 case TA_INACTIVE
: /* Obsolete */
280 tag
->access
= (char) *(start
+ 1);
283 tag
->impl
= (char) *(start
+ 1);
287 g_warning("Unknown attribute %s", start
+ 1);
294 if (NULL
== tag
->name
)
300 /* alternative parser for Pascal and LaTeX global tags files with the following format
301 * tagname|return value|arglist|description\n */
302 static gboolean
init_tag_from_file_alt(TMTag
*tag
, TMSourceFile
*file
, FILE *fp
)
307 /*guchar changed_char = TA_NAME;*/
310 if ((NULL
== fgets((gchar
*)buf
, BUFSIZ
, fp
)) || ('\0' == *buf
))
315 for (start
= end
= buf
, status
= TRUE
; (TRUE
== status
); start
= end
, ++ end
)
317 while ((*end
< TA_NAME
) && (*end
!= '\0') && (*end
!= '\n'))
319 if (('\0' == *end
) || ('\n' == *end
))
321 /*changed_char = *end;*/
323 if (NULL
== tag
->name
&& !isprint(*start
))
326 fields
= g_strsplit((gchar
*)start
, "|", -1);
327 field_len
= g_strv_length(fields
);
329 if (field_len
>= 1) tag
->name
= g_strdup(fields
[0]);
330 else tag
->name
= NULL
;
331 if (field_len
>= 2 && fields
[1] != NULL
) tag
->var_type
= g_strdup(fields
[1]);
332 if (field_len
>= 3 && fields
[2] != NULL
) tag
->arglist
= g_strdup(fields
[2]);
333 tag
->type
= tm_tag_prototype_t
;
338 if (NULL
== tag
->name
)
345 CTags tag file format (http://ctags.sourceforge.net/FORMAT)
347 static gboolean
init_tag_from_file_ctags(TMTag
*tag
, TMSourceFile
*file
, FILE *fp
, TMParserType lang
)
353 tag
->type
= tm_tag_function_t
; /* default type is function if no kind is specified */
356 if ((NULL
== fgets(buf
, BUFSIZ
, fp
)) || ('\0' == *buf
))
359 while (strncmp(buf
, "!_TAG_", 6) == 0); /* skip !_TAG_ lines */
364 if (! (tab
= strchr(p
, '\t')) || p
== tab
)
366 tag
->name
= g_strndup(p
, (gsize
)(tab
- p
));
369 /* tagfile, unused */
370 if (! (tab
= strchr(p
, '\t')))
377 /* Ex command, unused */
378 if (*p
== '/' || *p
== '?')
381 for (++p
; *p
&& *p
!= c
; p
++)
383 if (*p
== '\\' && p
[1])
387 else /* assume a line */
389 tab
= strstr(p
, ";\"");
390 /* read extension fields */
394 while (*p
&& *p
!= '\n' && *p
!= '\r')
397 const gchar
*key
, *value
= NULL
;
399 /* skip leading tabulations */
400 while (*p
&& *p
== '\t') p
++;
401 /* find the separator (:) and end (\t) */
403 while (*end
&& *end
!= '\t' && *end
!= '\n' && *end
!= '\r')
405 if (*end
== ':' && ! value
)
407 *end
= 0; /* terminate the key */
412 /* move p paste the so we won't stop parsing by setting *end=0 below */
413 p
= *end
? end
+ 1 : end
;
414 *end
= 0; /* terminate the value (or key if no value) */
416 if (! value
|| 0 == strcmp(key
, "kind")) /* tag kind */
418 const gchar
*kind
= value
? value
: key
;
420 if (kind
[0] && kind
[1])
421 tag
->type
= tm_parser_get_tag_type(tm_ctags_get_kind_from_name(kind
, lang
), lang
);
423 tag
->type
= tm_parser_get_tag_type(*kind
, lang
);
425 else if (0 == strcmp(key
, "inherits")) /* comma-separated list of classes this class inherits from */
427 g_free(tag
->inheritance
);
428 tag
->inheritance
= g_strdup(value
);
430 else if (0 == strcmp(key
, "implementation")) /* implementation limit */
431 tag
->impl
= get_tag_impl(value
);
432 else if (0 == strcmp(key
, "line")) /* line */
433 tag
->line
= atol(value
);
434 else if (0 == strcmp(key
, "access")) /* access */
435 tag
->access
= get_tag_access(value
);
436 else if (0 == strcmp(key
, "class") ||
437 0 == strcmp(key
, "enum") ||
438 0 == strcmp(key
, "function") ||
439 0 == strcmp(key
, "struct") ||
440 0 == strcmp(key
, "union")) /* Name of the class/enum/function/struct/union in which this tag is a member */
443 tag
->scope
= g_strdup(value
);
445 else if (0 == strcmp(key
, "file")) /* static (local) tag */
447 else if (0 == strcmp(key
, "signature")) /* arglist */
449 g_free(tag
->arglist
);
450 tag
->arglist
= g_strdup(value
);
459 static TMTag
*new_tag_from_tags_file(TMSourceFile
*file
, FILE *fp
, TMParserType mode
, TMFileFormat format
)
461 TMTag
*tag
= tm_tag_new();
462 gboolean result
= FALSE
;
466 case TM_FILE_FORMAT_TAGMANAGER
:
467 result
= init_tag_from_file(tag
, file
, fp
);
469 case TM_FILE_FORMAT_PIPE
:
470 result
= init_tag_from_file_alt(tag
, file
, fp
);
472 case TM_FILE_FORMAT_CTAGS
:
473 result
= init_tag_from_file_ctags(tag
, file
, fp
, mode
);
487 Writes tag information to the given FILE *.
488 @param tag The tag information to write.
489 @param file FILE pointer to which the tag information is written.
490 @param attrs Attributes to be written (bitmask).
491 @return TRUE on success, FALSE on failure.
493 static gboolean
write_tag(TMTag
*tag
, FILE *fp
, TMTagAttrType attrs
)
495 fprintf(fp
, "%s", tag
->name
);
496 if (attrs
& tm_tag_attr_type_t
)
497 fprintf(fp
, "%c%d", TA_TYPE
, tag
->type
);
498 if ((attrs
& tm_tag_attr_arglist_t
) && (NULL
!= tag
->arglist
))
499 fprintf(fp
, "%c%s", TA_ARGLIST
, tag
->arglist
);
500 if (attrs
& tm_tag_attr_line_t
)
501 fprintf(fp
, "%c%ld", TA_LINE
, tag
->line
);
502 if (attrs
& tm_tag_attr_local_t
)
503 fprintf(fp
, "%c%d", TA_LOCAL
, tag
->local
);
504 if ((attrs
& tm_tag_attr_scope_t
) && (NULL
!= tag
->scope
))
505 fprintf(fp
, "%c%s", TA_SCOPE
, tag
->scope
);
506 if ((attrs
& tm_tag_attr_inheritance_t
) && (NULL
!= tag
->inheritance
))
507 fprintf(fp
, "%c%s", TA_INHERITS
, tag
->inheritance
);
508 if (attrs
& tm_tag_attr_pointer_t
)
509 fprintf(fp
, "%c%d", TA_POINTER
, tag
->pointerOrder
);
510 if ((attrs
& tm_tag_attr_vartype_t
) && (NULL
!= tag
->var_type
))
511 fprintf(fp
, "%c%s", TA_VARTYPE
, tag
->var_type
);
512 if ((attrs
& tm_tag_attr_access_t
) && (TAG_ACCESS_UNKNOWN
!= tag
->access
))
513 fprintf(fp
, "%c%c", TA_ACCESS
, tag
->access
);
514 if ((attrs
& tm_tag_attr_impl_t
) && (TAG_IMPL_UNKNOWN
!= tag
->impl
))
515 fprintf(fp
, "%c%c", TA_IMPL
, tag
->impl
);
517 if (fprintf(fp
, "\n"))
523 GPtrArray
*tm_source_file_read_tags_file(const gchar
*tags_file
, TMParserType mode
)
527 GPtrArray
*file_tags
;
529 TMFileFormat format
= TM_FILE_FORMAT_TAGMANAGER
;
531 if (NULL
== (fp
= g_fopen(tags_file
, "r")))
533 if ((NULL
== fgets((gchar
*) buf
, BUFSIZ
, fp
)) || ('\0' == *buf
))
536 return NULL
; /* early out on error */
539 { /* We read the first line for the format specification. */
540 if (buf
[0] == '#' && strstr((gchar
*) buf
, "format=pipe") != NULL
)
541 format
= TM_FILE_FORMAT_PIPE
;
542 else if (buf
[0] == '#' && strstr((gchar
*) buf
, "format=tagmanager") != NULL
)
543 format
= TM_FILE_FORMAT_TAGMANAGER
;
544 else if (buf
[0] == '#' && strstr((gchar
*) buf
, "format=ctags") != NULL
)
545 format
= TM_FILE_FORMAT_CTAGS
;
546 else if (strncmp((gchar
*) buf
, "!_TAG_", 6) == 0)
547 format
= TM_FILE_FORMAT_CTAGS
;
549 { /* We didn't find a valid format specification, so we try to auto-detect the format
550 * by counting the pipe characters on the first line and asumme pipe format when
551 * we find more than one pipe on the line. */
552 guint i
, pipe_cnt
= 0, tab_cnt
= 0;
553 for (i
= 0; i
< BUFSIZ
&& buf
[i
] != '\0' && pipe_cnt
< 2; i
++)
557 else if (buf
[i
] == '\t')
561 format
= TM_FILE_FORMAT_PIPE
;
562 else if (tab_cnt
> 1)
563 format
= TM_FILE_FORMAT_CTAGS
;
565 rewind(fp
); /* reset the file pointer, to start reading again from the beginning */
568 file_tags
= g_ptr_array_new();
569 while (NULL
!= (tag
= new_tag_from_tags_file(NULL
, fp
, mode
, format
)))
570 g_ptr_array_add(file_tags
, tag
);
576 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 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
);
601 /* add argument list of __init__() Python methods to the class tag */
602 static void update_python_arglist(const TMTag
*tag
, TMSourceFile
*current_source_file
)
605 const char *parent_tag_name
;
607 if (tag
->type
!= tm_tag_method_t
|| tag
->scope
== NULL
||
608 g_strcmp0(tag
->name
, "__init__") != 0)
611 parent_tag_name
= strrchr(tag
->scope
, '.');
615 parent_tag_name
= tag
->scope
;
617 /* going in reverse order because the tag was added recently */
618 for (i
= current_source_file
->tags_array
->len
; i
> 0; i
--)
620 TMTag
*prev_tag
= (TMTag
*) current_source_file
->tags_array
->pdata
[i
- 1];
621 if (g_strcmp0(prev_tag
->name
, parent_tag_name
) == 0)
623 g_free(prev_tag
->arglist
);
624 prev_tag
->arglist
= g_strdup(tag
->arglist
);
631 This function is registered into the ctags parser when a file is parsed for
632 the first time. The function is then called by the ctags parser each time
633 it finds a new tag. You should not have to use this function.
634 @see tm_source_file_parse()
636 static gboolean
tm_source_file_tags(const tagEntryInfo
*const tag
,
637 gboolean invalidate
, void *user_data
)
639 TMSourceFile
*current_source_file
= user_data
;
644 tm_tags_array_free(current_source_file
->tags_array
, FALSE
);
648 tm_tag
= tm_tag_new();
650 if (!init_tag(tm_tag
, current_source_file
, tag
))
652 tm_tag_unref(tm_tag
);
656 if (tm_tag
->lang
== TM_PARSER_PYTHON
)
657 update_python_arglist(tm_tag
, current_source_file
);
659 g_ptr_array_add(current_source_file
->tags_array
, tm_tag
);
664 /* Initializes a TMSourceFile structure from a file name. */
665 static gboolean
tm_source_file_init(TMSourceFile
*source_file
, const char *file_name
,
672 g_message("Source File init: %s", file_name
);
675 if (file_name
!= NULL
)
677 status
= g_stat(file_name
, &s
);
680 /* g_warning("Unable to stat %s", file_name);*/
683 if (!S_ISREG(s
.st_mode
))
685 g_warning("%s: Not a regular file", file_name
);
688 source_file
->file_name
= tm_get_real_path(file_name
);
689 source_file
->short_name
= strrchr(source_file
->file_name
, '/');
690 if (source_file
->short_name
)
691 ++ source_file
->short_name
;
693 source_file
->short_name
= source_file
->file_name
;
696 source_file
->tags_array
= g_ptr_array_new();
699 source_file
->lang
= TM_PARSER_NONE
;
701 source_file
->lang
= tm_ctags_get_named_lang(name
);
706 /** Initializes a TMSourceFile structure and returns a pointer to it. The
707 * TMSourceFile has to be added to TMWorkspace to start its parsing.
708 * @param file_name The file name.
709 * @param name Name of the used programming language, NULL to disable parsing.
710 * @return The created unparsed TMSourceFile object.
713 TMSourceFile
*tm_source_file_new(const char *file_name
, const char *name
)
715 TMSourceFilePriv
*priv
;
717 SOURCE_FILE_NEW(priv
);
718 if (TRUE
!= tm_source_file_init(&priv
->public, file_name
, name
))
720 SOURCE_FILE_FREE(priv
);
724 return &priv
->public;
728 static TMSourceFile
*tm_source_file_dup(TMSourceFile
*source_file
)
730 TMSourceFilePriv
*priv
= (TMSourceFilePriv
*) source_file
;
732 g_return_val_if_fail(NULL
!= source_file
, NULL
);
734 g_atomic_int_inc(&priv
->refcount
);
738 /* Destroys the contents of the source file. Note that the tags are owned by the
739 source file and are also destroyed when the source file is destroyed. If pointers
740 to these tags are used elsewhere, then those tag arrays should be rebuilt.
742 static void tm_source_file_destroy(TMSourceFile
*source_file
)
745 g_message("Destroying source file: %s", source_file
->file_name
);
748 g_free(source_file
->file_name
);
749 tm_tags_array_free(source_file
->tags_array
, TRUE
);
750 source_file
->tags_array
= NULL
;
753 /** Decrements the reference count of @a source_file
755 * If the reference count drops to 0, then @a source_file is freed, including all contents.
756 * Make sure the @a source_file is already removed from any TMWorkSpace before the
758 * @param source_file The source file to free.
759 * @see tm_workspace_remove_source_file()
762 void tm_source_file_free(TMSourceFile
*source_file
)
764 TMSourceFilePriv
*priv
= (TMSourceFilePriv
*) source_file
;
766 if (NULL
!= priv
&& g_atomic_int_dec_and_test(&priv
->refcount
))
768 tm_source_file_destroy(source_file
);
769 SOURCE_FILE_FREE(priv
);
773 /** Gets the GBoxed-derived GType for TMSourceFile
775 * @return TMSourceFile type . */
777 GType
tm_source_file_get_type(void);
779 G_DEFINE_BOXED_TYPE(TMSourceFile
, tm_source_file
, tm_source_file_dup
, tm_source_file_free
);
781 /* Parses the text-buffer or source file and regenarates the tags.
782 @param source_file The source file to parse
783 @param text_buf The text buffer to parse
784 @param buf_size The size of text_buf.
785 @param use_buffer Set FALSE to ignore the buffer and parse the file directly or
786 TRUE to parse the buffer and ignore the file content.
787 @return TRUE on success, FALSE on failure
789 gboolean
tm_source_file_parse(TMSourceFile
*source_file
, guchar
* text_buf
, gsize buf_size
,
792 const char *file_name
;
793 gboolean retry
= TRUE
;
794 gboolean parse_file
= FALSE
;
795 gboolean free_buf
= FALSE
;
797 if ((NULL
== source_file
) || (NULL
== source_file
->file_name
))
799 g_warning("Attempt to parse NULL file");
803 if (source_file
->lang
== TM_PARSER_NONE
)
805 tm_tags_array_free(source_file
->tags_array
, FALSE
);
809 file_name
= source_file
->file_name
;
815 /* load file to memory and parse it from memory unless the file is too big */
816 if (g_stat(file_name
, &s
) != 0 || s
.st_size
> 10*1024*1024)
820 if (!g_file_get_contents(file_name
, (gchar
**)&text_buf
, (gsize
*)&buf_size
, NULL
))
822 g_warning("Unable to open %s", file_name
);
829 if (!parse_file
&& (NULL
== text_buf
|| 0 == buf_size
))
831 /* Empty buffer, "parse" by setting empty tag array */
832 tm_tags_array_free(source_file
->tags_array
, FALSE
);
838 tm_tags_array_free(source_file
->tags_array
, FALSE
);
840 tm_ctags_parse(parse_file
? NULL
: text_buf
, buf_size
, file_name
,
841 source_file
->lang
, tm_source_file_tags
, source_file
);
848 /* Gets the name associated with the language index.
849 @param lang The language index.
850 @return The language name, or NULL.
852 const gchar
*tm_source_file_get_lang_name(TMParserType lang
)
854 return tm_ctags_get_lang_name(lang
);
857 /* Gets the language index for \a name.
858 @param name The language name.
859 @return The language index, or TM_PARSER_NONE.
861 TMParserType
tm_source_file_get_named_lang(const gchar
*name
)
863 return tm_ctags_get_named_lang(name
);