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.
14 #include "general.h" /* must always come first */
17 #include <ctype.h> /* to define isspace () */
20 #include <glib/gstdio.h>
22 #if defined (HAVE_SYS_TYPES_H)
23 # include <sys/types.h> /* to declare off_t on some hosts */
25 #if defined (HAVE_TYPES_H)
26 # include <types.h> /* to declare off_t on some hosts */
30 /* These header files provide for the functions necessary to do file
52 #define PSEUDO_TAG_PREFIX "!_"
54 #define includeExtensionFlags() (Option.tagFileFormat > 1)
59 #if !defined(HAVE_TRUNCATE) && !defined(HAVE_FTRUNCATE) && !defined(HAVE_CHSIZE)
60 # define USE_REPLACEMENT_TRUNCATE
63 /* Hack for ridiculous practice of Microsoft Visual C++.
65 #if defined (WIN32) && defined (_MSC_VER)
66 # define chsize _chsize
69 # define O_RDWR _O_RDWR
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 */
86 static boolean TagsToStdout
= FALSE
;
91 #ifdef NEED_PROTO_TRUNCATE
92 extern int truncate (const char *path
, off_t length
);
95 #ifdef NEED_PROTO_FTRUNCATE
96 extern int ftruncate (int fd
, off_t length
);
100 * FUNCTION DEFINITIONS
103 extern void freeTagFileResources (void)
105 eFree (TagFile
.directory
);
106 vStringDelete (TagFile
.vLine
);
109 extern const char *tagFileName (void)
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)
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)
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');
169 const long boolOffset
= tab
- line
+ 1; /* where it should be */
171 if (line
[boolOffset
] == '0' || line
[boolOffset
] == '1')
175 if (mio_getpos (mio
, &nextLine
) == -1 || mio_setpos (mio
, &startOfLine
) == -1)
176 error (WARNING
, "Failed to update 'sorted' pseudo-tag");
184 while (c
!= '\t' && c
!= '\n');
185 mio_getpos (mio
, &flagLocation
);
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
202 static long unsigned int updatePseudoTags (MIO
*const mio
)
204 enum { maxClassLength
= 20 };
205 char class [maxClassLength
+ 1];
206 unsigned long linesRead
= 0;
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])
220 if (strncmp (line
, class, classLength
) == 0)
222 char tab
, classType
[16];
224 if (sscanf (line
+ classLength
, "%15s%c", classType
, &tab
) == 2 &&
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 */
237 line
= readLineRaw (TagFile
.vLine
, mio
);
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
)
255 else if (mio
!= NULL
)
257 const char *line
= readLineRaw (TagFile
.vLine
, mio
);
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");
280 remaining
-= numRead
;
281 } while (numRead
== toRead
&& remaining
!= 0);
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
);
289 error (FATAL
| PERROR
, "cannot open file to copy");
292 MIO
* const toMio
= mio_new_file_full (to
, "wb", g_fopen
, fclose
);
294 error (FATAL
| PERROR
, "cannot open copy destination");
297 copyBytes (fromMio
, toMio
, size
);
304 extern void openTagFile (void)
306 setDefaultTagFileName ();
307 TagsToStdout
= isDestinationStdout ();
309 if (TagFile
.vLine
== NULL
)
310 TagFile
.vLine
= vStringNew ();
312 /* Open the tags file.
318 fp
= tempFile ("w", &TagFile
.name
);
319 TagFile
.mio
= mio_new_fp (fp
, fclose
);
325 setDefaultTagFileName ();
326 TagFile
.name
= eStrdup (Option
.tagFileName
);
327 fileExists
= doesFileExist (TagFile
.name
);
328 if (fileExists
&& ! isTagFile (TagFile
.name
))
330 "\"%s\" doesn't look like a tag file; I refuse to overwrite it.",
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
);
345 TagFile
.mio
= mio_new_file_full (TagFile
.name
, "w", g_fopen
, fclose
);
346 if (TagFile
.mio
!= NULL
)
350 if (TagFile
.mio
== NULL
)
352 error (FATAL
| PERROR
, "cannot open tag file");
357 TagFile
.directory
= eStrdup (CurrentDirectory
);
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
);
371 copyFile (name
, tempName
, size
);
372 copyFile (tempName
, name
, WHOLE_FILE
);
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 ());
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 ();
417 /* vi:set tabstop=4 shiftwidth=4: */