Rename MIO variables from fp to mio
[geany-mirror.git] / ctags / main / entry.c
blobd0706ccba1041ac179f633faf61dbf5bff2d2daa
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"
47 #include "routines.h"
50 * MACROS
52 #define PSEUDO_TAG_PREFIX "!_"
54 #define includeExtensionFlags() (Option.tagFileFormat > 1)
57 * Portability defines
59 #if !defined(HAVE_TRUNCATE) && !defined(HAVE_FTRUNCATE) && !defined(HAVE_CHSIZE)
60 # define USE_REPLACEMENT_TRUNCATE
61 #endif
63 /* Hack for ridiculous practice of Microsoft Visual C++.
65 #if defined (WIN32) && defined (_MSC_VER)
66 # define chsize _chsize
67 # define open _open
68 # define close _close
69 # define O_RDWR _O_RDWR
70 #endif
73 * DATA DEFINITIONS
76 tagFile TagFile = {
77 NULL, /* tag file name */
78 NULL, /* tag file directory (absolute) */
79 NULL, /* file pointer */
80 { 0, 0 }, /* numTags */
81 { 0, 0, 0 }, /* max */
82 { NULL, NULL, 0 }, /* etags */
83 NULL /* vLine */
86 static boolean TagsToStdout = FALSE;
89 * FUNCTION PROTOTYPES
91 #ifdef NEED_PROTO_TRUNCATE
92 extern int truncate (const char *path, off_t length);
93 #endif
95 #ifdef NEED_PROTO_FTRUNCATE
96 extern int ftruncate (int fd, off_t length);
97 #endif
100 * FUNCTION DEFINITIONS
103 extern void freeTagFileResources (void)
105 eFree (TagFile.directory);
106 vStringDelete (TagFile.vLine);
109 extern const char *tagFileName (void)
111 return TagFile.name;
115 * Pseudo tag support
118 static void rememberMaxLengths (const size_t nameLength, const size_t lineLength)
120 if (nameLength > TagFile.max.tag)
121 TagFile.max.tag = nameLength;
123 if (lineLength > TagFile.max.line)
124 TagFile.max.line = lineLength;
127 static void writePseudoTag (const char *const tagName,
128 const char *const fileName,
129 const char *const pattern)
131 const int length = mio_printf (TagFile.mio, "%s%s\t%s\t/%s/\n",
132 PSEUDO_TAG_PREFIX, tagName, fileName, pattern);
133 ++TagFile.numTags.added;
134 rememberMaxLengths (strlen (tagName), (size_t) length);
137 static void addPseudoTags (void)
139 if (! Option.xref)
141 char format [11];
142 const char *formatComment = "unknown format";
144 sprintf (format, "%u", Option.tagFileFormat);
146 if (Option.tagFileFormat == 1)
147 formatComment = "original ctags format";
148 else if (Option.tagFileFormat == 2)
149 formatComment =
150 "extended format; --format=1 will not append ;\" to lines";
152 writePseudoTag ("TAG_FILE_FORMAT", format, formatComment);
153 writePseudoTag ("TAG_FILE_SORTED", Option.sorted ? "1":"0",
154 "0=unsorted, 1=sorted");
155 writePseudoTag ("TAG_PROGRAM_AUTHOR", AUTHOR_NAME, AUTHOR_EMAIL);
156 writePseudoTag ("TAG_PROGRAM_NAME", PROGRAM_NAME, "");
157 writePseudoTag ("TAG_PROGRAM_URL", PROGRAM_URL, "official site");
158 writePseudoTag ("TAG_PROGRAM_VERSION", PROGRAM_VERSION, "");
162 static void updateSortedFlag (const char *const line,
163 MIO *const mio, MIOPos startOfLine)
165 const char *const tab = strchr (line, '\t');
167 if (tab != NULL)
169 const long boolOffset = tab - line + 1; /* where it should be */
171 if (line [boolOffset] == '0' || line [boolOffset] == '1')
173 MIOPos nextLine;
175 if (mio_getpos (mio, &nextLine) == -1 || mio_setpos (mio, &startOfLine) == -1)
176 error (WARNING, "Failed to update 'sorted' pseudo-tag");
177 else
179 MIOPos flagLocation;
180 int c, d;
183 c = mio_getc (mio);
184 while (c != '\t' && c != '\n');
185 mio_getpos (mio, &flagLocation);
186 d = mio_getc (mio);
187 if (c == '\t' && (d == '0' || d == '1') &&
188 d != (int) Option.sorted)
190 mio_setpos (mio, &flagLocation);
191 mio_putc (mio, Option.sorted ? '1' : '0');
193 mio_setpos (mio, &nextLine);
199 /* Look through all line beginning with "!_TAG_FILE", and update those which
200 * require it.
202 static long unsigned int updatePseudoTags (MIO *const mio)
204 enum { maxClassLength = 20 };
205 char class [maxClassLength + 1];
206 unsigned long linesRead = 0;
207 MIOPos startOfLine;
208 size_t classLength;
209 const char *line;
211 sprintf (class, "%sTAG_FILE", PSEUDO_TAG_PREFIX);
212 classLength = strlen (class);
213 Assert (classLength < maxClassLength);
215 mio_getpos (mio, &startOfLine);
216 line = readLineRaw (TagFile.vLine, mio);
217 while (line != NULL && line [0] == class [0])
219 ++linesRead;
220 if (strncmp (line, class, classLength) == 0)
222 char tab, classType [16];
224 if (sscanf (line + classLength, "%15s%c", classType, &tab) == 2 &&
225 tab == '\t')
227 if (strcmp (classType, "_SORTED") == 0)
228 updateSortedFlag (line, mio, startOfLine);
230 mio_getpos (mio, &startOfLine);
232 line = readLineRaw (TagFile.vLine, mio);
234 while (line != NULL) /* skip to end of file */
236 ++linesRead;
237 line = readLineRaw (TagFile.vLine, mio);
239 return linesRead;
243 * Tag file management
248 static boolean isTagFile (const char *const filename)
250 boolean ok = FALSE; /* we assume not unless confirmed */
251 MIO *const mio = mio_new_file_full (filename, "rb", g_fopen, fclose);
253 if (mio == NULL && errno == ENOENT)
254 ok = TRUE;
255 else if (mio != NULL)
257 const char *line = readLineRaw (TagFile.vLine, mio);
259 if (line == NULL)
260 ok = TRUE;
261 mio_free (mio);
263 return ok;
266 extern void copyBytes (MIO* const fromMio, MIO* const toMio, const long size)
268 enum { BufferSize = 1000 };
269 long toRead, numRead;
270 char* buffer = xMalloc (BufferSize, char);
271 long remaining = size;
274 toRead = (0 < remaining && remaining < BufferSize) ?
275 remaining : BufferSize;
276 numRead = mio_read (fromMio, buffer, (size_t) 1, (size_t) toRead);
277 if (mio_write (toMio, buffer, (size_t)1, (size_t)numRead) < (size_t)numRead)
278 error (FATAL | PERROR, "cannot complete write");
279 if (remaining > 0)
280 remaining -= numRead;
281 } while (numRead == toRead && remaining != 0);
282 eFree (buffer);
285 extern void copyFile (const char *const from, const char *const to, const long size)
287 MIO* const fromMio = mio_new_file_full (from, "rb", g_fopen, fclose);
288 if (fromMio == NULL)
289 error (FATAL | PERROR, "cannot open file to copy");
290 else
292 MIO* const toMio = mio_new_file_full (to, "wb", g_fopen, fclose);
293 if (toMio == NULL)
294 error (FATAL | PERROR, "cannot open copy destination");
295 else
297 copyBytes (fromMio, toMio, size);
298 mio_free (toMio);
300 mio_free (fromMio);
304 extern void openTagFile (void)
306 setDefaultTagFileName ();
307 TagsToStdout = isDestinationStdout ();
309 if (TagFile.vLine == NULL)
310 TagFile.vLine = vStringNew ();
312 /* Open the tags file.
314 if (TagsToStdout)
316 FILE *fp;
318 fp = tempFile ("w", &TagFile.name);
319 TagFile.mio = mio_new_fp (fp, fclose);
321 else
323 boolean fileExists;
325 setDefaultTagFileName ();
326 TagFile.name = eStrdup (Option.tagFileName);
327 fileExists = doesFileExist (TagFile.name);
328 if (fileExists && ! isTagFile (TagFile.name))
329 error (FATAL,
330 "\"%s\" doesn't look like a tag file; I refuse to overwrite it.",
331 TagFile.name);
333 if (Option.append && fileExists)
335 TagFile.mio = mio_new_file_full (TagFile.name, "r+", g_fopen, fclose);
336 if (TagFile.mio != NULL)
338 TagFile.numTags.prev = updatePseudoTags (TagFile.mio);
339 mio_free (TagFile.mio);
340 TagFile.mio = mio_new_file_full (TagFile.name, "a+", g_fopen, fclose);
343 else
345 TagFile.mio = mio_new_file_full (TagFile.name, "w", g_fopen, fclose);
346 if (TagFile.mio != NULL)
347 addPseudoTags ();
350 if (TagFile.mio == NULL)
352 error (FATAL | PERROR, "cannot open tag file");
353 exit (1);
356 if (TagsToStdout)
357 TagFile.directory = eStrdup (CurrentDirectory);
358 else
359 TagFile.directory = absoluteDirname (TagFile.name);
362 #ifdef USE_REPLACEMENT_TRUNCATE
364 /* Replacement for missing library function.
366 static int replacementTruncate (const char *const name, const long size)
368 char *tempName = NULL;
369 MIO *mio = tempFile ("w", &tempName);
370 fclose (mio);
371 copyFile (name, tempName, size);
372 copyFile (tempName, name, WHOLE_FILE);
373 remove (tempName);
374 eFree (tempName);
376 return 0;
379 #endif
383 * Tag entry management
387 extern void makeTagEntry (const tagEntryInfo *const tag)
389 Assert (tag->name != NULL);
390 if (tag->name [0] == '\0')
391 error (WARNING, "ignoring null tag in %s", getInputFileName ());
392 else
394 int length = 0;
396 if (NULL != TagEntryFunction)
397 length = TagEntryFunction(tag, TagEntryUserData);
399 ++TagFile.numTags.added;
400 rememberMaxLengths (strlen (tag->name), (size_t) length);
404 extern void initTagEntry (tagEntryInfo *const e, const char *const name, const kindOption *kind)
406 Assert (File.source.name != NULL);
407 memset (e, 0, sizeof (tagEntryInfo));
408 e->lineNumberEntry = (boolean) (Option.locate == EX_LINENUM);
409 e->lineNumber = getSourceLineNumber ();
410 e->language = getSourceLanguageName ();
411 e->filePosition = getInputFilePosition ();
412 e->sourceFileName = getSourceFileTagPath ();
413 e->name = name;
414 e->kind = kind;
417 /* vi:set tabstop=4 shiftwidth=4: */