Use consistent shadows across Geany
[geany-mirror.git] / tagmanager / src / tm_source_file.c
blob40118a9bdf575b2756f48f18f18ed02268dab14b
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. 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.
197 * */
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))
203 g_free(source_file);
204 return NULL;
206 return source_file;
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)
215 #ifdef TM_DEBUG
216 g_message("Destroying source file: %s", source_file->file_name);
217 #endif
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);
233 g_free(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,
246 gboolean use_buffer)
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");
256 return FALSE;
259 if (source_file->lang == LANG_IGNORE)
261 tm_tags_array_free(source_file->tags_array, FALSE);
262 return FALSE;
265 file_name = source_file->file_name;
267 if (!use_buffer)
269 struct stat s;
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)
273 parse_file = TRUE;
274 else
276 if (!g_file_get_contents(file_name, (gchar**)&text_buf, (gsize*)&buf_size, NULL))
278 g_warning("Unable to open %s", file_name);
279 return FALSE;
281 free_buf = TRUE;
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);
289 if (free_buf)
290 g_free(text_buf);
291 return TRUE;
294 if (NULL == LanguageTable)
296 initializeParsing();
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)
308 #ifdef TM_DEBUG
309 g_warning("ignoring %s (unknown language)\n", file_name);
310 #endif
312 else if (! LanguageTable [source_file->lang]->enabled)
314 #ifdef TM_DEBUG
315 g_warning("ignoring %s (language disabled)\n", file_name);
316 #endif
318 else
320 guint passCount = 0;
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 ();
329 fileClose ();
330 retry = FALSE;
331 break;
333 else if (LanguageTable [source_file->lang]->parser2 != NULL)
334 retry = LanguageTable [source_file->lang]->parser2 (passCount);
335 fileClose ();
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 ();
342 bufferClose ();
343 retry = FALSE;
344 break;
346 else if (LanguageTable [source_file->lang]->parser2 != NULL)
347 retry = LanguageTable [source_file->lang]->parser2 (passCount);
348 bufferClose ();
350 else
352 g_warning("Unable to open %s", file_name);
353 return FALSE;
355 ++ passCount;
359 if (free_buf)
360 g_free(text_buf);
361 return !retry;
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)
372 initializeParsing();
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)
390 initializeParsing();
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);
400 #if 0
402 Writes all tags of a source file (including the file tag itself) to the passed
403 file pointer.
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)
411 TMTag *tag;
412 guint i;
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);
419 tm_tag_unref(tag);
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))
426 return FALSE;
431 return TRUE;
433 #endif