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.
193 * @param file_name The file name.
194 * @param name Name of the used programming language, NULL for autodetection.
195 * @return The created TMSourceFile object.
197 TMSourceFile
*tm_source_file_new(const char *file_name
, const char *name
)
199 TMSourceFile
*source_file
= g_new(TMSourceFile
, 1);
200 if (TRUE
!= tm_source_file_init(source_file
, file_name
, name
))
208 /* Destroys the contents of the source file. Note that the tags are owned by the
209 source file and are also destroyed when the source file is destroyed. If pointers
210 to these tags are used elsewhere, then those tag arrays should be rebuilt.
212 static void tm_source_file_destroy(TMSourceFile
*source_file
)
215 g_message("Destroying source file: %s", source_file
->file_name
);
218 g_free(source_file
->file_name
);
219 tm_tags_array_free(source_file
->tags_array
, TRUE
);
220 source_file
->tags_array
= NULL
;
223 /** Frees a TMSourceFile structure, including all contents */
224 void tm_source_file_free(TMSourceFile
*source_file
)
226 if (NULL
!= source_file
)
228 tm_source_file_destroy(source_file
);
233 /* Parses the source file and regenarates the tags.
234 @param source_file The source file to parse
235 @return TRUE on success, FALSE on failure
237 gboolean
tm_source_file_parse(TMSourceFile
*source_file
)
239 const char *file_name
;
240 gboolean status
= TRUE
;
243 if ((NULL
== source_file
) || (NULL
== source_file
->file_name
))
245 g_warning("Attempt to parse NULL file");
249 file_name
= source_file
->file_name
;
250 if (NULL
== LanguageTable
)
253 installLanguageMapDefaults();
254 if (NULL
== TagEntryFunction
)
255 TagEntryFunction
= tm_source_file_tags
;
256 if (NULL
== TagEntrySetArglistFunction
)
257 TagEntrySetArglistFunction
= tm_source_file_set_tag_arglist
;
259 current_source_file
= source_file
;
261 if (LANG_AUTO
== source_file
->lang
)
262 source_file
->lang
= getFileLanguage (file_name
);
264 if (source_file
->lang
< 0 || ! LanguageTable
[source_file
->lang
]->enabled
)
267 while ((TRUE
== status
) && (passCount
< 3))
269 tm_tags_array_free(source_file
->tags_array
, FALSE
);
270 if (fileOpen (file_name
, source_file
->lang
))
272 if (LanguageTable
[source_file
->lang
]->parser
!= NULL
)
274 LanguageTable
[source_file
->lang
]->parser ();
278 else if (LanguageTable
[source_file
->lang
]->parser2
!= NULL
)
279 status
= LanguageTable
[source_file
->lang
]->parser2 (passCount
);
284 g_warning("%s: Unable to open %s", G_STRFUNC
, file_name
);
292 /* Parses the text-buffer and regenarates the tags.
293 @param source_file The source file to parse
294 @param text_buf The text buffer to parse
295 @param buf_size The size of text_buf.
296 @return TRUE on success, FALSE on failure
298 gboolean
tm_source_file_buffer_parse(TMSourceFile
*source_file
, guchar
* text_buf
, gint buf_size
)
300 const char *file_name
;
301 gboolean status
= TRUE
;
303 if ((NULL
== source_file
) || (NULL
== source_file
->file_name
))
305 g_warning("Attempt to parse NULL file");
309 if ((NULL
== text_buf
) || (0 == buf_size
))
311 g_warning("Attempt to parse a NULL text buffer");
314 file_name
= source_file
->file_name
;
315 if (NULL
== LanguageTable
)
318 installLanguageMapDefaults();
319 if (NULL
== TagEntryFunction
)
320 TagEntryFunction
= tm_source_file_tags
;
321 if (NULL
== TagEntrySetArglistFunction
)
322 TagEntrySetArglistFunction
= tm_source_file_set_tag_arglist
;
324 current_source_file
= source_file
;
325 if (LANG_AUTO
== source_file
->lang
)
326 source_file
->lang
= getFileLanguage (file_name
);
327 if (source_file
->lang
== LANG_IGNORE
)
330 g_warning("ignoring %s (unknown language)\n", file_name
);
333 else if (! LanguageTable
[source_file
->lang
]->enabled
)
336 g_warning("ignoring %s (language disabled)\n", file_name
);
342 while ((TRUE
== status
) && (passCount
< 3))
344 tm_tags_array_free(source_file
->tags_array
, FALSE
);
345 if (bufferOpen (text_buf
, buf_size
, file_name
, source_file
->lang
))
347 if (LanguageTable
[source_file
->lang
]->parser
!= NULL
)
349 LanguageTable
[source_file
->lang
]->parser ();
353 else if (LanguageTable
[source_file
->lang
]->parser2
!= NULL
)
354 status
= LanguageTable
[source_file
->lang
]->parser2 (passCount
);
359 g_warning("Unable to open %s", file_name
);
370 /* Gets the name associated with the language index.
371 @param lang The language index.
372 @return The language name, or NULL.
374 const gchar
*tm_source_file_get_lang_name(gint lang
)
376 if (NULL
== LanguageTable
)
379 installLanguageMapDefaults();
380 if (NULL
== TagEntryFunction
)
381 TagEntryFunction
= tm_source_file_tags
;
382 if (NULL
== TagEntrySetArglistFunction
)
383 TagEntrySetArglistFunction
= tm_source_file_set_tag_arglist
;
385 return getLanguageName(lang
);
388 /* Gets the language index for \a name.
389 @param name The language name.
390 @return The language index, or -2.
392 gint
tm_source_file_get_named_lang(const gchar
*name
)
394 if (NULL
== LanguageTable
)
397 installLanguageMapDefaults();
398 if (NULL
== TagEntryFunction
)
399 TagEntryFunction
= tm_source_file_tags
;
400 if (NULL
== TagEntrySetArglistFunction
)
401 TagEntrySetArglistFunction
= tm_source_file_set_tag_arglist
;
403 return getNamedLanguage(name
);
408 Writes all tags of a source file (including the file tag itself) to the passed
410 @param source_file The source file to write.
411 @param fp The file pointer to write to.
412 @param attrs The attributes to write.
413 @return TRUE on success, FALSE on failure.
415 static gboolean
tm_source_file_write(TMSourceFile
*source_file
, FILE *fp
, guint attrs
)
420 if (NULL
!= source_file
)
422 if (NULL
!= (tag
= tm_tag_new(source_file
, NULL
)))
424 tm_tag_write(tag
, fp
, tm_tag_attr_max_t
);
426 if (NULL
!= source_file
->tags_array
)
428 for (i
=0; i
< source_file
->tags_array
->len
; ++i
)
430 tag
= TM_TAG(source_file
->tags_array
->pdata
[i
]);
431 if (TRUE
!= tm_tag_write(tag
, fp
, attrs
))