Return an unisgned tag count in tm_tags_find()
[geany-mirror.git] / tagmanager / src / tm_source_file.c
bloba700da3efa00becb32a8d08dba48d209e05dfba1
1 /*
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.
8 */
10 /**
11 * @file tm_source_file.h
12 The TMSourceFile structure and associated functions are used to maintain
13 tags for individual files.
17 #include <stdio.h>
18 #include <limits.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <sys/stat.h>
22 #include <glib/gstdio.h>
23 #ifdef G_OS_WIN32
24 # define VC_EXTRALEAN
25 # define WIN32_LEAN_AND_MEAN
26 # include <windows.h> /* for GetFullPathName */
27 #endif
29 #include "general.h"
30 #include "entry.h"
31 #include "parse.h"
32 #include "read.h"
34 #define LIBCTAGS_DEFINED
35 #include "tm_source_file.h"
36 #include "tm_tag.h"
39 static TMSourceFile *current_source_file = NULL;
41 static int get_path_max(const char *path)
43 #ifdef PATH_MAX
44 return PATH_MAX;
45 #else
46 int path_max = pathconf(path, _PC_PATH_MAX);
47 if (path_max <= 0)
48 path_max = 4096;
49 return path_max;
50 #endif
54 #ifdef G_OS_WIN32
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)
60 int size;
62 if (resolved_path != NULL)
64 int path_max = get_path_max(pathname);
65 size = GetFullPathNameA (pathname, path_max, resolved_path, NULL);
66 if (size > path_max)
67 return NULL;
68 else
69 return resolved_path;
71 else
73 size = GetFullPathNameA (pathname, 0, NULL, NULL);
74 resolved_path = g_new0 (char, size);
75 GetFullPathNameA (pathname, size, resolved_path, NULL);
76 return resolved_path;
79 #endif
81 /**
82 Given a file name, returns a newly allocated string containing the realpath()
83 of the file.
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)
89 if (file_name)
91 gsize len = get_path_max(file_name) + 1;
92 gchar *path = g_malloc0(len);
94 if (realpath(file_name, path))
95 return path;
96 else
97 g_free(path);
99 return NULL;
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)
111 return 0;
112 g_ptr_array_add(current_source_file->tags_array,
113 tm_tag_new(current_source_file, tag));
114 return TRUE;
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)
120 guint count;
121 TMTag **tags, *tag;
123 if (NULL == arglist ||
124 NULL == tag_name ||
125 NULL == current_source_file)
127 return;
130 tags = tm_tags_find(current_source_file->tags_array, tag_name, FALSE, FALSE,
131 &count);
132 if (tags != NULL && count == 1)
134 tag = tags[0];
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,
142 const char* name)
144 struct stat s;
145 int status;
147 #ifdef TM_DEBUG
148 g_message("Source File init: %s", file_name);
149 #endif
151 if (file_name != NULL)
153 status = g_stat(file_name, &s);
154 if (0 != status)
156 /* g_warning("Unable to stat %s", file_name);*/
157 return FALSE;
159 if (!S_ISREG(s.st_mode))
161 g_warning("%s: Not a regular file", file_name);
162 return FALSE;
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;
168 else
169 source_file->short_name = source_file->file_name;
172 source_file->tags_array = g_ptr_array_new();
174 if (NULL == LanguageTable)
176 initializeParsing();
177 installLanguageMapDefaults();
178 if (NULL == TagEntryFunction)
179 TagEntryFunction = tm_source_file_tags;
180 if (NULL == TagEntrySetArglistFunction)
181 TagEntrySetArglistFunction = tm_source_file_set_tag_arglist;
184 if (name == NULL)
185 source_file->lang = LANG_AUTO;
186 else
187 source_file->lang = getNamedLanguage(name);
189 return TRUE;
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.
196 * */
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))
202 g_free(source_file);
203 return NULL;
205 return source_file;
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)
214 #ifdef TM_DEBUG
215 g_message("Destroying source file: %s", source_file->file_name);
216 #endif
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);
229 g_free(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;
241 int passCount = 0;
243 if ((NULL == source_file) || (NULL == source_file->file_name))
245 g_warning("Attempt to parse NULL file");
246 return FALSE;
249 file_name = source_file->file_name;
250 if (NULL == LanguageTable)
252 initializeParsing();
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)
265 return status;
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 ();
275 fileClose ();
276 break;
278 else if (LanguageTable [source_file->lang]->parser2 != NULL)
279 status = LanguageTable [source_file->lang]->parser2 (passCount);
280 fileClose ();
282 else
284 g_warning("%s: Unable to open %s", G_STRFUNC, file_name);
285 return FALSE;
287 ++ passCount;
289 return status;
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");
306 return FALSE;
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)
317 initializeParsing();
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)
329 #ifdef TM_DEBUG
330 g_warning("ignoring %s (unknown language)\n", file_name);
331 #endif
333 else if (! LanguageTable [source_file->lang]->enabled)
335 #ifdef TM_DEBUG
336 g_warning("ignoring %s (language disabled)\n", file_name);
337 #endif
339 else
341 int passCount = 0;
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 ();
350 bufferClose ();
351 break;
353 else if (LanguageTable [source_file->lang]->parser2 != NULL)
354 status = LanguageTable [source_file->lang]->parser2 (passCount);
355 bufferClose ();
357 else
359 g_warning("Unable to open %s", file_name);
360 return FALSE;
362 ++ passCount;
364 return TRUE;
366 return status;
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)
378 initializeParsing();
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)
396 initializeParsing();
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);
406 #if 0
408 Writes all tags of a source file (including the file tag itself) to the passed
409 file pointer.
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)
417 TMTag *tag;
418 guint i;
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);
425 tm_tag_unref(tag);
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))
432 return FALSE;
437 return TRUE;
439 #endif