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
51 #define PSEUDO_TAG_PREFIX "!_"
53 #define includeExtensionFlags() (Option.tagFileFormat > 1)
58 #if !defined(HAVE_TRUNCATE) && !defined(HAVE_FTRUNCATE) && !defined(HAVE_CHSIZE)
59 # define USE_REPLACEMENT_TRUNCATE
62 /* Hack for rediculous practice of Microsoft Visual C++.
64 #if defined (WIN32) && defined (_MSC_VER)
65 # define chsize _chsize
68 # define O_RDWR _O_RDWR
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 */
85 static boolean TagsToStdout
= FALSE
;
90 #ifdef NEED_PROTO_TRUNCATE
91 extern int truncate (const char *path
, off_t length
);
94 #ifdef NEED_PROTO_FTRUNCATE
95 extern int ftruncate (int fd
, off_t length
);
99 * FUNCTION DEFINITIONS
102 extern void freeTagFileResources (void)
104 eFree (TagFile
.directory
);
105 vStringDelete (TagFile
.vLine
);
108 extern const char *tagFileName (void)
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)
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)
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');
168 const long boolOffset
= tab
- line
+ 1; /* where it should be */
170 if (line
[boolOffset
] == '0' || line
[boolOffset
] == '1')
174 if (mio_getpos (mio
, &nextLine
) == -1 || mio_setpos (mio
, &startOfLine
) == -1)
175 error (WARNING
, "Failed to update 'sorted' pseudo-tag");
183 while (c
!= '\t' && c
!= '\n');
184 mio_getpos (mio
, &flagLocation
);
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
201 static long unsigned int updatePseudoTags (MIO
*const mio
)
203 enum { maxClassLength
= 20 };
204 char class [maxClassLength
+ 1];
205 unsigned long linesRead
= 0;
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])
219 if (strncmp (line
, class, classLength
) == 0)
221 char tab
, classType
[16];
223 if (sscanf (line
+ classLength
, "%15s%c", classType
, &tab
) == 2 &&
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 */
236 line
= readLine (TagFile
.vLine
, mio
);
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
)
254 else if (mio
!= NULL
)
256 const char *line
= readLine (TagFile
.vLine
, mio
);
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");
279 remaining
-= numRead
;
280 } while (numRead
== toRead
&& remaining
!= 0);
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
);
288 error (FATAL
| PERROR
, "cannot open file to copy");
291 MIO
* const toMio
= mio_new_file_full (to
, "wb", g_fopen
, fclose
);
293 error (FATAL
| PERROR
, "cannot open copy destination");
296 copyBytes (fromMio
, toMio
, size
);
303 extern void openTagFile (void)
305 setDefaultTagFileName ();
306 TagsToStdout
= isDestinationStdout ();
308 if (TagFile
.vLine
== NULL
)
309 TagFile
.vLine
= vStringNew ();
311 /* Open the tags file.
317 fp
= tempFile ("w", &TagFile
.name
);
318 TagFile
.mio
= mio_new_fp (fp
, fclose
);
324 setDefaultTagFileName ();
325 TagFile
.name
= eStrdup (Option
.tagFileName
);
326 fileExists
= doesFileExist (TagFile
.name
);
327 if (fileExists
&& ! isTagFile (TagFile
.name
))
329 "\"%s\" doesn't look like a tag file; I refuse to overwrite it.",
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
);
344 TagFile
.mio
= mio_new_file_full (TagFile
.name
, "w", g_fopen
, fclose
);
345 if (TagFile
.mio
!= NULL
)
349 if (TagFile
.mio
== NULL
)
351 error (FATAL
| PERROR
, "cannot open tag file");
356 TagFile
.directory
= eStrdup (CurrentDirectory
);
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
);
370 copyFile (name
, tempName
, size
);
371 copyFile (tempName
, name
, WHOLE_FILE
);
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
));
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 ();
421 /* vi:set tabstop=8 shiftwidth=4: */