Fix building with makefile.win32 from Windows command prompt, not MSYS
[geany-mirror.git] / tagmanager / entry.c
blob8dfd312aecb0333f8901ec5a5ee9f0f222347407
1 /*
3 * Copyright (c) 1996-2001, Darren Hiebert
5 * This source code is released for free distribution under the terms of the
6 * GNU General Public License.
8 * This module contains functions for creating tag entries.
9 */
12 * INCLUDE FILES
14 #include "general.h" /* must always come first */
16 #include <string.h>
17 #include <ctype.h> /* to define isspace () */
18 #include <errno.h>
19 #include <glib.h>
20 #include <glib/gstdio.h>
22 #if defined (HAVE_SYS_TYPES_H)
23 # include <sys/types.h> /* to declare off_t on some hosts */
24 #endif
25 #if defined (HAVE_TYPES_H)
26 # include <types.h> /* to declare off_t on some hosts */
27 #endif
30 /* These header files provide for the functions necessary to do file
31 * truncation.
33 #ifdef HAVE_FCNTL_H
34 # include <fcntl.h>
35 #endif
36 #ifdef HAVE_IO_H
37 # include <io.h>
38 #endif
40 #include "ctags.h"
41 #include "entry.h"
42 #include "main.h"
43 #include "options.h"
44 #include "read.h"
45 #include "sort.h"
46 #include "strlist.h"
49 * MACROS
51 #define PSEUDO_TAG_PREFIX "!_"
53 #define includeExtensionFlags() (Option.tagFileFormat > 1)
56 * Portability defines
58 #if !defined(HAVE_TRUNCATE) && !defined(HAVE_FTRUNCATE) && !defined(HAVE_CHSIZE)
59 # define USE_REPLACEMENT_TRUNCATE
60 #endif
62 /* Hack for rediculous practice of Microsoft Visual C++.
64 #if defined (WIN32) && defined (_MSC_VER)
65 # define chsize _chsize
66 # define open _open
67 # define close _close
68 # define O_RDWR _O_RDWR
69 #endif
72 * DATA DEFINITIONS
75 tagFile TagFile = {
76 NULL, /* tag file name */
77 NULL, /* tag file directory (absolute) */
78 NULL, /* file pointer */
79 { 0, 0 }, /* numTags */
80 { 0, 0, 0 }, /* max */
81 { NULL, NULL, 0 }, /* etags */
82 NULL /* vLine */
85 static boolean TagsToStdout = FALSE;
88 * FUNCTION PROTOTYPES
90 #ifdef NEED_PROTO_TRUNCATE
91 extern int truncate (const char *path, off_t length);
92 #endif
94 #ifdef NEED_PROTO_FTRUNCATE
95 extern int ftruncate (int fd, off_t length);
96 #endif
99 * FUNCTION DEFINITIONS
102 extern void freeTagFileResources (void)
104 eFree (TagFile.directory);
105 vStringDelete (TagFile.vLine);
108 extern const char *tagFileName (void)
110 return TagFile.name;
114 * Pseudo tag support
117 static void rememberMaxLengths (const size_t nameLength, const size_t lineLength)
119 if (nameLength > TagFile.max.tag)
120 TagFile.max.tag = nameLength;
122 if (lineLength > TagFile.max.line)
123 TagFile.max.line = lineLength;
126 static void writePseudoTag (const char *const tagName,
127 const char *const fileName,
128 const char *const pattern)
130 const int length = mio_printf (TagFile.mio, "%s%s\t%s\t/%s/\n",
131 PSEUDO_TAG_PREFIX, tagName, fileName, pattern);
132 ++TagFile.numTags.added;
133 rememberMaxLengths (strlen (tagName), (size_t) length);
136 static void addPseudoTags (void)
138 if (! Option.xref)
140 char format [11];
141 const char *formatComment = "unknown format";
143 sprintf (format, "%u", Option.tagFileFormat);
145 if (Option.tagFileFormat == 1)
146 formatComment = "original ctags format";
147 else if (Option.tagFileFormat == 2)
148 formatComment =
149 "extended format; --format=1 will not append ;\" to lines";
151 writePseudoTag ("TAG_FILE_FORMAT", format, formatComment);
152 writePseudoTag ("TAG_FILE_SORTED", Option.sorted ? "1":"0",
153 "0=unsorted, 1=sorted");
154 writePseudoTag ("TAG_PROGRAM_AUTHOR", AUTHOR_NAME, AUTHOR_EMAIL);
155 writePseudoTag ("TAG_PROGRAM_NAME", PROGRAM_NAME, "");
156 writePseudoTag ("TAG_PROGRAM_URL", PROGRAM_URL, "official site");
157 writePseudoTag ("TAG_PROGRAM_VERSION", PROGRAM_VERSION, "");
161 static void updateSortedFlag (const char *const line,
162 MIO *const mio, MIOPos startOfLine)
164 const char *const tab = strchr (line, '\t');
166 if (tab != NULL)
168 const long boolOffset = tab - line + 1; /* where it should be */
170 if (line [boolOffset] == '0' || line [boolOffset] == '1')
172 MIOPos nextLine;
174 if (mio_getpos (mio, &nextLine) == -1 || mio_setpos (mio, &startOfLine) == -1)
175 error (WARNING, "Failed to update 'sorted' pseudo-tag");
176 else
178 MIOPos flagLocation;
179 int c, d;
182 c = mio_getc (mio);
183 while (c != '\t' && c != '\n');
184 mio_getpos (mio, &flagLocation);
185 d = mio_getc (mio);
186 if (c == '\t' && (d == '0' || d == '1') &&
187 d != (int) Option.sorted)
189 mio_setpos (mio, &flagLocation);
190 mio_putc (mio, Option.sorted ? '1' : '0');
192 mio_setpos (mio, &nextLine);
198 /* Look through all line beginning with "!_TAG_FILE", and update those which
199 * require it.
201 static long unsigned int updatePseudoTags (MIO *const mio)
203 enum { maxClassLength = 20 };
204 char class [maxClassLength + 1];
205 unsigned long linesRead = 0;
206 MIOPos startOfLine;
207 size_t classLength;
208 const char *line;
210 sprintf (class, "%sTAG_FILE", PSEUDO_TAG_PREFIX);
211 classLength = strlen (class);
212 Assert (classLength < maxClassLength);
214 mio_getpos (mio, &startOfLine);
215 line = readLine (TagFile.vLine, mio);
216 while (line != NULL && line [0] == class [0])
218 ++linesRead;
219 if (strncmp (line, class, classLength) == 0)
221 char tab, classType [16];
223 if (sscanf (line + classLength, "%15s%c", classType, &tab) == 2 &&
224 tab == '\t')
226 if (strcmp (classType, "_SORTED") == 0)
227 updateSortedFlag (line, mio, startOfLine);
229 mio_getpos (mio, &startOfLine);
231 line = readLine (TagFile.vLine, mio);
233 while (line != NULL) /* skip to end of file */
235 ++linesRead;
236 line = readLine (TagFile.vLine, mio);
238 return linesRead;
242 * Tag file management
247 static boolean isTagFile (const char *const filename)
249 boolean ok = FALSE; /* we assume not unless confirmed */
250 MIO *const mio = mio_new_file_full (filename, "rb", g_fopen, fclose);
252 if (mio == NULL && errno == ENOENT)
253 ok = TRUE;
254 else if (mio != NULL)
256 const char *line = readLine (TagFile.vLine, mio);
258 if (line == NULL)
259 ok = TRUE;
260 mio_free (mio);
262 return ok;
265 extern void copyBytes (MIO* const fromMio, MIO* const toMio, const long size)
267 enum { BufferSize = 1000 };
268 long toRead, numRead;
269 char* buffer = xMalloc (BufferSize, char);
270 long remaining = size;
273 toRead = (0 < remaining && remaining < BufferSize) ?
274 remaining : BufferSize;
275 numRead = mio_read (fromMio, buffer, (size_t) 1, (size_t) toRead);
276 if (mio_write (toMio, buffer, (size_t)1, (size_t)numRead) < (size_t)numRead)
277 error (FATAL | PERROR, "cannot complete write");
278 if (remaining > 0)
279 remaining -= numRead;
280 } while (numRead == toRead && remaining != 0);
281 eFree (buffer);
284 extern void copyFile (const char *const from, const char *const to, const long size)
286 MIO* const fromMio = mio_new_file_full (from, "rb", g_fopen, fclose);
287 if (fromMio == NULL)
288 error (FATAL | PERROR, "cannot open file to copy");
289 else
291 MIO* const toMio = mio_new_file_full (to, "wb", g_fopen, fclose);
292 if (toMio == NULL)
293 error (FATAL | PERROR, "cannot open copy destination");
294 else
296 copyBytes (fromMio, toMio, size);
297 mio_free (toMio);
299 mio_free (fromMio);
303 extern void openTagFile (void)
305 setDefaultTagFileName ();
306 TagsToStdout = isDestinationStdout ();
308 if (TagFile.vLine == NULL)
309 TagFile.vLine = vStringNew ();
311 /* Open the tags file.
313 if (TagsToStdout)
315 FILE *fp;
317 fp = tempFile ("w", &TagFile.name);
318 TagFile.mio = mio_new_fp (fp, fclose);
320 else
322 boolean fileExists;
324 setDefaultTagFileName ();
325 TagFile.name = eStrdup (Option.tagFileName);
326 fileExists = doesFileExist (TagFile.name);
327 if (fileExists && ! isTagFile (TagFile.name))
328 error (FATAL,
329 "\"%s\" doesn't look like a tag file; I refuse to overwrite it.",
330 TagFile.name);
332 if (Option.append && fileExists)
334 TagFile.mio = mio_new_file_full (TagFile.name, "r+", g_fopen, fclose);
335 if (TagFile.mio != NULL)
337 TagFile.numTags.prev = updatePseudoTags (TagFile.mio);
338 mio_free (TagFile.mio);
339 TagFile.mio = mio_new_file_full (TagFile.name, "a+", g_fopen, fclose);
342 else
344 TagFile.mio = mio_new_file_full (TagFile.name, "w", g_fopen, fclose);
345 if (TagFile.mio != NULL)
346 addPseudoTags ();
349 if (TagFile.mio == NULL)
351 error (FATAL | PERROR, "cannot open tag file");
352 exit (1);
355 if (TagsToStdout)
356 TagFile.directory = eStrdup (CurrentDirectory);
357 else
358 TagFile.directory = absoluteDirname (TagFile.name);
361 #ifdef USE_REPLACEMENT_TRUNCATE
363 /* Replacement for missing library function.
365 static int replacementTruncate (const char *const name, const long size)
367 char *tempName = NULL;
368 FILE *fp = tempFile ("w", &tempName);
369 fclose (fp);
370 copyFile (name, tempName, size);
371 copyFile (tempName, name, WHOLE_FILE);
372 remove (tempName);
373 eFree (tempName);
375 return 0;
378 #endif
382 * Tag entry management
386 extern void makeTagEntry (const tagEntryInfo *const tag)
388 Assert (tag->name != NULL);
389 if (tag->name [0] == '\0')
390 error (WARNING, "ignoring null tag in %s", vStringValue (File.name));
391 else
393 int length = 0;
395 if (NULL != TagEntryFunction)
396 length = TagEntryFunction(tag);
398 ++TagFile.numTags.added;
399 rememberMaxLengths (strlen (tag->name), (size_t) length);
403 extern void setTagArglistByName (const char *tag_name, const char *arglist)
405 if (NULL != TagEntrySetArglistFunction)
406 TagEntrySetArglistFunction(tag_name, arglist);
409 extern void initTagEntry (tagEntryInfo *const e, const char *const name)
411 Assert (File.source.name != NULL);
412 memset (e, 0, sizeof (tagEntryInfo));
413 e->lineNumberEntry = (boolean) (Option.locate == EX_LINENUM);
414 e->lineNumber = getSourceLineNumber ();
415 e->language = getSourceLanguageName ();
416 e->filePosition = getInputFilePosition ();
417 e->sourceFileName = getSourceFileTagPath ();
418 e->name = name;
421 /* vi:set tabstop=8 shiftwidth=4: */