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.
22 #include <glib/gstdio.h>
25 # define WIN32_LEAN_AND_MEAN
26 # include <windows.h> /* for GetFullPathName */
34 #define LIBCTAGS_DEFINED
35 #include "tm_source_file.h"
39 static TMSourceFile
*current_source_file
= NULL
;
41 static int get_path_max(const char *path
)
46 int path_max
= pathconf(path
, _PC_PATH_MAX
);
55 /* realpath implementation for Windows found at http://bugzilla.gnome.org/show_bug.cgi?id=342926
56 * this one is better than e.g. liberty's lrealpath because this one uses Win32 API and works
57 * with special chars within the filename */
58 static char *realpath (const char *pathname
, char *resolved_path
)
62 if (resolved_path
!= NULL
)
64 int path_max
= get_path_max(pathname
);
65 size
= GetFullPathNameA (pathname
, path_max
, resolved_path
, NULL
);
73 size
= GetFullPathNameA (pathname
, 0, NULL
, NULL
);
74 resolved_path
= g_new0 (char, size
);
75 GetFullPathNameA (pathname
, size
, resolved_path
, NULL
);
82 Given a file name, returns a newly allocated string containing the realpath()
84 @param file_name The original file_name
85 @return A newly allocated string containing the real path to the file. NULL if none is available.
87 gchar
*tm_get_real_path(const gchar
*file_name
)
91 gsize len
= get_path_max(file_name
) + 1;
92 gchar
*path
= g_malloc0(len
);
94 if (realpath(file_name
, path
))
103 This function is registered into the ctags parser when a file is parsed for
104 the first time. The function is then called by the ctags parser each time
105 it finds a new tag. You should not have to use this function.
106 @see tm_source_file_parse()
108 static int tm_source_file_tags(const tagEntryInfo
*tag
)
110 if (NULL
== current_source_file
)
112 g_ptr_array_add(current_source_file
->tags_array
,
113 tm_tag_new(current_source_file
, tag
));
117 /* Set the argument list of tag identified by its name */
118 static void tm_source_file_set_tag_arglist(const char *tag_name
, const char *arglist
)
123 if (NULL
== arglist
||
125 NULL
== current_source_file
)
130 tags
= tm_tags_find(current_source_file
->tags_array
, tag_name
, FALSE
, FALSE
,
132 if (tags
!= NULL
&& count
== 1)
135 g_free(tag
->arglist
);
136 tag
->arglist
= g_strdup(arglist
);
140 /* Initializes a TMSourceFile structure from a file name. */
141 static gboolean
tm_source_file_init(TMSourceFile
*source_file
, const char *file_name
,
148 g_message("Source File init: %s", file_name
);
151 if (file_name
!= NULL
)
153 status
= g_stat(file_name
, &s
);
156 /* g_warning("Unable to stat %s", file_name);*/
159 if (!S_ISREG(s
.st_mode
))
161 g_warning("%s: Not a regular file", file_name
);
164 source_file
->file_name
= tm_get_real_path(file_name
);
165 source_file
->short_name
= strrchr(source_file
->file_name
, '/');
166 if (source_file
->short_name
)
167 ++ source_file
->short_name
;
169 source_file
->short_name
= source_file
->file_name
;
172 source_file
->tags_array
= g_ptr_array_new();
174 if (NULL
== LanguageTable
)
177 installLanguageMapDefaults();
178 if (NULL
== TagEntryFunction
)
179 TagEntryFunction
= tm_source_file_tags
;
180 if (NULL
== TagEntrySetArglistFunction
)
181 TagEntrySetArglistFunction
= tm_source_file_set_tag_arglist
;
185 source_file
->lang
= LANG_AUTO
;
187 source_file
->lang
= getNamedLanguage(name
);
192 /** Initializes a TMSourceFile structure and returns a pointer to it. The
193 * TMSourceFile has to be added to TMWorkspace to start its parsing.
194 * @param file_name The file name.
195 * @param name Name of the used programming language, NULL for autodetection.
196 * @return The created unparsed TMSourceFile object.
198 TMSourceFile
*tm_source_file_new(const char *file_name
, const char *name
)
200 TMSourceFile
*source_file
= g_new(TMSourceFile
, 1);
201 if (TRUE
!= tm_source_file_init(source_file
, file_name
, name
))
209 /* Destroys the contents of the source file. Note that the tags are owned by the
210 source file and are also destroyed when the source file is destroyed. If pointers
211 to these tags are used elsewhere, then those tag arrays should be rebuilt.
213 static void tm_source_file_destroy(TMSourceFile
*source_file
)
216 g_message("Destroying source file: %s", source_file
->file_name
);
219 g_free(source_file
->file_name
);
220 tm_tags_array_free(source_file
->tags_array
, TRUE
);
221 source_file
->tags_array
= NULL
;
224 /** Frees a TMSourceFile structure, including all contents. Before calling this
225 function the TMSourceFile has to be removed from the TMWorkspace.
226 @param source_file The source file to free.
228 void tm_source_file_free(TMSourceFile
*source_file
)
230 if (NULL
!= source_file
)
232 tm_source_file_destroy(source_file
);
237 /* Parses the text-buffer or source file and regenarates the tags.
238 @param source_file The source file to parse
239 @param text_buf The text buffer to parse
240 @param buf_size The size of text_buf.
241 @param use_buffer Set FALSE to ignore the buffer and parse the file directly or
242 TRUE to parse the buffer and ignore the file content.
243 @return TRUE on success, FALSE on failure
245 gboolean
tm_source_file_parse(TMSourceFile
*source_file
, guchar
* text_buf
, gsize buf_size
,
248 const char *file_name
;
249 gboolean retry
= TRUE
;
250 gboolean parse_file
= FALSE
;
251 gboolean free_buf
= FALSE
;
253 if ((NULL
== source_file
) || (NULL
== source_file
->file_name
))
255 g_warning("Attempt to parse NULL file");
259 if (source_file
->lang
== LANG_IGNORE
)
261 tm_tags_array_free(source_file
->tags_array
, FALSE
);
265 file_name
= source_file
->file_name
;
271 /* load file to memory and parse it from memory unless the file is too big */
272 if (g_stat(file_name
, &s
) != 0 || s
.st_size
> 10*1024*1024)
276 if (!g_file_get_contents(file_name
, (gchar
**)&text_buf
, (gsize
*)&buf_size
, NULL
))
278 g_warning("Unable to open %s", file_name
);
285 if (!parse_file
&& (NULL
== text_buf
|| 0 == buf_size
))
287 /* Empty buffer, "parse" by setting empty tag array */
288 tm_tags_array_free(source_file
->tags_array
, FALSE
);
294 if (NULL
== LanguageTable
)
297 installLanguageMapDefaults();
298 if (NULL
== TagEntryFunction
)
299 TagEntryFunction
= tm_source_file_tags
;
300 if (NULL
== TagEntrySetArglistFunction
)
301 TagEntrySetArglistFunction
= tm_source_file_set_tag_arglist
;
303 current_source_file
= source_file
;
304 if (LANG_AUTO
== source_file
->lang
)
305 source_file
->lang
= getFileLanguage (file_name
);
306 if (source_file
->lang
== LANG_IGNORE
)
309 g_warning("ignoring %s (unknown language)\n", file_name
);
312 else if (! LanguageTable
[source_file
->lang
]->enabled
)
315 g_warning("ignoring %s (language disabled)\n", file_name
);
321 while (retry
&& passCount
< 3)
323 tm_tags_array_free(source_file
->tags_array
, FALSE
);
324 if (parse_file
&& fileOpen (file_name
, source_file
->lang
))
326 if (LanguageTable
[source_file
->lang
]->parser
!= NULL
)
328 LanguageTable
[source_file
->lang
]->parser ();
333 else if (LanguageTable
[source_file
->lang
]->parser2
!= NULL
)
334 retry
= LanguageTable
[source_file
->lang
]->parser2 (passCount
);
337 else if (!parse_file
&& bufferOpen (text_buf
, buf_size
, file_name
, source_file
->lang
))
339 if (LanguageTable
[source_file
->lang
]->parser
!= NULL
)
341 LanguageTable
[source_file
->lang
]->parser ();
346 else if (LanguageTable
[source_file
->lang
]->parser2
!= NULL
)
347 retry
= LanguageTable
[source_file
->lang
]->parser2 (passCount
);
352 g_warning("Unable to open %s", file_name
);
364 /* Gets the name associated with the language index.
365 @param lang The language index.
366 @return The language name, or NULL.
368 const gchar
*tm_source_file_get_lang_name(gint lang
)
370 if (NULL
== LanguageTable
)
373 installLanguageMapDefaults();
374 if (NULL
== TagEntryFunction
)
375 TagEntryFunction
= tm_source_file_tags
;
376 if (NULL
== TagEntrySetArglistFunction
)
377 TagEntrySetArglistFunction
= tm_source_file_set_tag_arglist
;
379 return getLanguageName(lang
);
382 /* Gets the language index for \a name.
383 @param name The language name.
384 @return The language index, or -2.
386 gint
tm_source_file_get_named_lang(const gchar
*name
)
388 if (NULL
== LanguageTable
)
391 installLanguageMapDefaults();
392 if (NULL
== TagEntryFunction
)
393 TagEntryFunction
= tm_source_file_tags
;
394 if (NULL
== TagEntrySetArglistFunction
)
395 TagEntrySetArglistFunction
= tm_source_file_set_tag_arglist
;
397 return getNamedLanguage(name
);
402 Writes all tags of a source file (including the file tag itself) to the passed
404 @param source_file The source file to write.
405 @param fp The file pointer to write to.
406 @param attrs The attributes to write.
407 @return TRUE on success, FALSE on failure.
409 static gboolean
tm_source_file_write(TMSourceFile
*source_file
, FILE *fp
, guint attrs
)
414 if (NULL
!= source_file
)
416 if (NULL
!= (tag
= tm_tag_new(source_file
, NULL
)))
418 tm_tag_write(tag
, fp
, tm_tag_attr_max_t
);
420 if (NULL
!= source_file
->tags_array
)
422 for (i
=0; i
< source_file
->tags_array
->len
; ++i
)
424 tag
= TM_TAG(source_file
->tags_array
->pdata
[i
]);
425 if (TRUE
!= tm_tag_write(tag
, fp
, attrs
))