xref: /Universal-ctags/main/routines.c (revision d53559843c3c07240e7ea2eb5dce190aa0ab69d7)
1d4c6f1e6SMasatake YAMATO /*
2d4c6f1e6SMasatake YAMATO *   Copyright (c) 2002-2003, Darren Hiebert
3d4c6f1e6SMasatake YAMATO *
4d4c6f1e6SMasatake YAMATO *   This source code is released for free distribution under the terms of the
50ce38835Sviccuad *   GNU General Public License version 2 or (at your option) any later version.
6d4c6f1e6SMasatake YAMATO *
7d4c6f1e6SMasatake YAMATO *   This module contains a lose assortment of shared functions.
8d4c6f1e6SMasatake YAMATO */
9d4c6f1e6SMasatake YAMATO 
10d4c6f1e6SMasatake YAMATO /*
11d4c6f1e6SMasatake YAMATO *   INCLUDE FILES
12d4c6f1e6SMasatake YAMATO */
13d4c6f1e6SMasatake YAMATO #include "general.h"  /* must always come first */
14d4c6f1e6SMasatake YAMATO 
159243e4a9SMasatake YAMATO #include <stdlib.h>  /* to declare malloc (), realloc (), mbcs() */
16d4c6f1e6SMasatake YAMATO #include <ctype.h>
17d4c6f1e6SMasatake YAMATO #include <string.h>
18d4c6f1e6SMasatake YAMATO #include <stdio.h>  /* to declare tempnam(), and SEEK_SET (hopefully) */
19d4c6f1e6SMasatake YAMATO 
20d4c6f1e6SMasatake YAMATO #ifdef HAVE_FCNTL_H
215dbd2e67SK.Takata # include <fcntl.h>  /* to declare O_RDWR, O_CREAT, O_EXCL */
22d4c6f1e6SMasatake YAMATO #endif
23d4c6f1e6SMasatake YAMATO #ifdef HAVE_UNISTD_H
24d4c6f1e6SMasatake YAMATO # include <unistd.h>  /* to declare mkstemp () */
25d4c6f1e6SMasatake YAMATO #endif
26d4c6f1e6SMasatake YAMATO 
272acdcfa1SYasuhiro Matsumoto #include <limits.h>  /* to declare MB_LEN_MAX */
282acdcfa1SYasuhiro Matsumoto #ifndef MB_LEN_MAX
292acdcfa1SYasuhiro Matsumoto # define MB_LEN_MAX 6
302acdcfa1SYasuhiro Matsumoto #endif
312acdcfa1SYasuhiro Matsumoto 
32d4c6f1e6SMasatake YAMATO /*  To declare "struct stat" and stat ().
33d4c6f1e6SMasatake YAMATO  */
34d4c6f1e6SMasatake YAMATO #if defined (HAVE_SYS_TYPES_H)
35d4c6f1e6SMasatake YAMATO # include <sys/types.h>
36d4c6f1e6SMasatake YAMATO #else
37d4c6f1e6SMasatake YAMATO # if defined (HAVE_TYPES_H)
38d4c6f1e6SMasatake YAMATO #  include <types.h>
39d4c6f1e6SMasatake YAMATO # endif
40d4c6f1e6SMasatake YAMATO #endif
41d4c6f1e6SMasatake YAMATO #ifdef HAVE_SYS_STAT_H
42d4c6f1e6SMasatake YAMATO # include <sys/stat.h>
43d4c6f1e6SMasatake YAMATO #else
44d4c6f1e6SMasatake YAMATO # ifdef HAVE_STAT_H
45d4c6f1e6SMasatake YAMATO #  include <stat.h>
46d4c6f1e6SMasatake YAMATO # endif
47d4c6f1e6SMasatake YAMATO #endif
48d4c6f1e6SMasatake YAMATO 
49d4c6f1e6SMasatake YAMATO #ifdef HAVE_DIRECT_H
50d4c6f1e6SMasatake YAMATO # include <direct.h>  /* to _getcwd */
51d4c6f1e6SMasatake YAMATO #endif
52d4c6f1e6SMasatake YAMATO #ifdef HAVE_IO_H
53d4c6f1e6SMasatake YAMATO # include <io.h>  /* to declare open() */
54d4c6f1e6SMasatake YAMATO #endif
55d4c6f1e6SMasatake YAMATO #include "debug.h"
56d4c6f1e6SMasatake YAMATO #include "routines.h"
5729e40fb6SMasatake YAMATO #include "routines_p.h"
58583bdbcbSThomas Braun #include <errno.h>
59d4c6f1e6SMasatake YAMATO 
60d156a7aaSMasatake YAMATO #include "vstring.h"
61d156a7aaSMasatake YAMATO 
62d4c6f1e6SMasatake YAMATO /*
63d4c6f1e6SMasatake YAMATO *   MACROS
64d4c6f1e6SMasatake YAMATO */
65d4c6f1e6SMasatake YAMATO #ifndef TMPDIR
66d4c6f1e6SMasatake YAMATO # define TMPDIR "/tmp"
67d4c6f1e6SMasatake YAMATO #endif
68d4c6f1e6SMasatake YAMATO 
69d4c6f1e6SMasatake YAMATO /*  File type tests.
70d4c6f1e6SMasatake YAMATO  */
71d4c6f1e6SMasatake YAMATO #ifndef S_ISREG
72d4c6f1e6SMasatake YAMATO # if defined (S_IFREG)
73d4c6f1e6SMasatake YAMATO #  define S_ISREG(mode)		((mode) & S_IFREG)
74d4c6f1e6SMasatake YAMATO # endif
75d4c6f1e6SMasatake YAMATO #endif
76d4c6f1e6SMasatake YAMATO 
77d4c6f1e6SMasatake YAMATO #ifndef S_ISLNK
78d4c6f1e6SMasatake YAMATO # ifdef S_IFLNK
79d4c6f1e6SMasatake YAMATO #  define S_ISLNK(mode)		(((mode) & S_IFMT) == S_IFLNK)
80d4c6f1e6SMasatake YAMATO # else
81ce990805SThomas Braun #  define S_ISLNK(mode)		false  /* assume no soft links */
82d4c6f1e6SMasatake YAMATO # endif
83d4c6f1e6SMasatake YAMATO #endif
84d4c6f1e6SMasatake YAMATO 
85d4c6f1e6SMasatake YAMATO #ifndef S_ISDIR
86d4c6f1e6SMasatake YAMATO # ifdef S_IFDIR
87d4c6f1e6SMasatake YAMATO #  define S_ISDIR(mode)		(((mode) & S_IFMT) == S_IFDIR)
88d4c6f1e6SMasatake YAMATO # else
89ce990805SThomas Braun #  define S_ISDIR(mode)		false  /* assume no soft links */
90d4c6f1e6SMasatake YAMATO # endif
91d4c6f1e6SMasatake YAMATO #endif
92d4c6f1e6SMasatake YAMATO 
93d4c6f1e6SMasatake YAMATO #ifndef S_IFMT
94d4c6f1e6SMasatake YAMATO # define S_IFMT 0
95d4c6f1e6SMasatake YAMATO #endif
96d4c6f1e6SMasatake YAMATO 
97d4c6f1e6SMasatake YAMATO #ifndef S_IXUSR
98d4c6f1e6SMasatake YAMATO # define S_IXUSR 0
99d4c6f1e6SMasatake YAMATO #endif
100d4c6f1e6SMasatake YAMATO #ifndef S_IXGRP
101d4c6f1e6SMasatake YAMATO # define S_IXGRP 0
102d4c6f1e6SMasatake YAMATO #endif
103d4c6f1e6SMasatake YAMATO #ifndef S_IXOTH
104d4c6f1e6SMasatake YAMATO # define S_IXOTH 0
105d4c6f1e6SMasatake YAMATO #endif
106d4c6f1e6SMasatake YAMATO 
107d4c6f1e6SMasatake YAMATO #ifndef S_IRUSR
108d4c6f1e6SMasatake YAMATO # define S_IRUSR 0400
109d4c6f1e6SMasatake YAMATO #endif
110d4c6f1e6SMasatake YAMATO #ifndef S_IWUSR
111d4c6f1e6SMasatake YAMATO # define S_IWUSR 0200
112d4c6f1e6SMasatake YAMATO #endif
113d4c6f1e6SMasatake YAMATO 
114d4c6f1e6SMasatake YAMATO #ifndef S_ISUID
115d4c6f1e6SMasatake YAMATO # define S_ISUID 0
116d4c6f1e6SMasatake YAMATO #endif
117d4c6f1e6SMasatake YAMATO 
118994a326dSMasatake YAMATO #ifndef S_ISGID
119994a326dSMasatake YAMATO # define S_ISGID 0
120994a326dSMasatake YAMATO #endif
121994a326dSMasatake YAMATO 
1225dbd2e67SK.Takata /*  Hack for ridiculous practice of Microsoft Visual C++.
123d4c6f1e6SMasatake YAMATO  */
124d4c6f1e6SMasatake YAMATO #if defined (WIN32)
12567bdb82eSK.Takata # if defined (_MSC_VER) || defined (__MINGW32__)
12619d48665SK.Takata #  ifndef stat
127d4c6f1e6SMasatake YAMATO #   define stat    _stat
12819d48665SK.Takata #  endif
129d4c6f1e6SMasatake YAMATO #  define getcwd  _getcwd
130d4c6f1e6SMasatake YAMATO #  define currentdrive() (_getdrive() + 'A' - 1)
131d4c6f1e6SMasatake YAMATO # else
132d4c6f1e6SMasatake YAMATO #  define currentdrive() 'C'
133d4c6f1e6SMasatake YAMATO # endif
134d4c6f1e6SMasatake YAMATO #endif
135d4c6f1e6SMasatake YAMATO 
136d4c6f1e6SMasatake YAMATO #ifndef PATH_MAX
137d4c6f1e6SMasatake YAMATO # define PATH_MAX 256
138d4c6f1e6SMasatake YAMATO #endif
139d4c6f1e6SMasatake YAMATO 
140d4c6f1e6SMasatake YAMATO /*
141d4c6f1e6SMasatake YAMATO  *  Miscellaneous macros
142d4c6f1e6SMasatake YAMATO  */
143fc3ee6cbSMasatake YAMATO 
144d4c6f1e6SMasatake YAMATO 
145d4c6f1e6SMasatake YAMATO /*
146d4c6f1e6SMasatake YAMATO *   DATA DEFINITIONS
147d4c6f1e6SMasatake YAMATO */
148d4c6f1e6SMasatake YAMATO #if defined (MSDOS_STYLE_PATH)
149d4c6f1e6SMasatake YAMATO const char *const PathDelimiters = ":/\\";
150d4c6f1e6SMasatake YAMATO #endif
151d4c6f1e6SMasatake YAMATO 
152d4c6f1e6SMasatake YAMATO char *CurrentDirectory;
153d4c6f1e6SMasatake YAMATO 
154d4c6f1e6SMasatake YAMATO static const char *ExecutableProgram;
155d4c6f1e6SMasatake YAMATO static const char *ExecutableName;
156d4c6f1e6SMasatake YAMATO 
157d4c6f1e6SMasatake YAMATO /*
158d4c6f1e6SMasatake YAMATO *   FUNCTION PROTOTYPES
159d4c6f1e6SMasatake YAMATO */
160d4c6f1e6SMasatake YAMATO #ifdef NEED_PROTO_STAT
161d4c6f1e6SMasatake YAMATO extern int stat (const char *, struct stat *);
162d4c6f1e6SMasatake YAMATO #endif
163d4c6f1e6SMasatake YAMATO #ifdef NEED_PROTO_LSTAT
164d4c6f1e6SMasatake YAMATO extern int lstat (const char *, struct stat *);
165d4c6f1e6SMasatake YAMATO #endif
166d4c6f1e6SMasatake YAMATO #if defined (WIN32)
167d4c6f1e6SMasatake YAMATO # define lstat(fn,buf) stat(fn,buf)
168d4c6f1e6SMasatake YAMATO #endif
169d4c6f1e6SMasatake YAMATO 
17017e0aa54SMasatake YAMATO static bool isPathSeparator (const int c);
17117e0aa54SMasatake YAMATO static char *strSeparator (const char *s);
17217e0aa54SMasatake YAMATO static char *strRSeparator (const char *s);
173468ef944SMasatake YAMATO static void canonicalizePath (char *const path);
17417e0aa54SMasatake YAMATO 
17517e0aa54SMasatake YAMATO 
176d4c6f1e6SMasatake YAMATO /*
177d4c6f1e6SMasatake YAMATO *   FUNCTION DEFINITIONS
178d4c6f1e6SMasatake YAMATO */
179d4c6f1e6SMasatake YAMATO 
freeRoutineResources(void)180d4c6f1e6SMasatake YAMATO extern void freeRoutineResources (void)
181d4c6f1e6SMasatake YAMATO {
182d4c6f1e6SMasatake YAMATO 	if (CurrentDirectory != NULL)
183d4c6f1e6SMasatake YAMATO 		eFree (CurrentDirectory);
184d4c6f1e6SMasatake YAMATO }
185d4c6f1e6SMasatake YAMATO 
setExecutableName(const char * const path)186d4c6f1e6SMasatake YAMATO extern void setExecutableName (const char *const path)
187d4c6f1e6SMasatake YAMATO {
188d4c6f1e6SMasatake YAMATO 	ExecutableProgram = path;
189d4c6f1e6SMasatake YAMATO 	ExecutableName = baseFilename (path);
190d4c6f1e6SMasatake YAMATO }
191d4c6f1e6SMasatake YAMATO 
getExecutableName(void)192d4c6f1e6SMasatake YAMATO extern const char *getExecutableName (void)
193d4c6f1e6SMasatake YAMATO {
194d4c6f1e6SMasatake YAMATO 	return ExecutableName;
195d4c6f1e6SMasatake YAMATO }
196d4c6f1e6SMasatake YAMATO 
getExecutablePath(void)197d4c6f1e6SMasatake YAMATO extern const char *getExecutablePath (void)
198d4c6f1e6SMasatake YAMATO {
199d4c6f1e6SMasatake YAMATO 	return ExecutableProgram;
200d4c6f1e6SMasatake YAMATO }
201d4c6f1e6SMasatake YAMATO 
202d4c6f1e6SMasatake YAMATO /*
203004231d9SKevin Goodwin  *  compare file/dirname characters with platform-correct case sensitivity
204004231d9SKevin Goodwin  */
fnmChEq(int c1,int c2)205004231d9SKevin Goodwin static bool fnmChEq (int c1, int c2)
206004231d9SKevin Goodwin {
207004231d9SKevin Goodwin #ifdef WIN32
208004231d9SKevin Goodwin 	return tolower( c1 ) == tolower( c2 );  /* case-insensitive */
209004231d9SKevin Goodwin #else
210004231d9SKevin Goodwin 	return          c1   ==          c2  ;  /* case-  sensitive */
211004231d9SKevin Goodwin #endif
212004231d9SKevin Goodwin }
213004231d9SKevin Goodwin 
214004231d9SKevin Goodwin /*
215d4c6f1e6SMasatake YAMATO  *  Memory allocation functions
216d4c6f1e6SMasatake YAMATO  */
217d4c6f1e6SMasatake YAMATO 
eMalloc(const size_t size)218d4c6f1e6SMasatake YAMATO extern void *eMalloc (const size_t size)
219d4c6f1e6SMasatake YAMATO {
220d4c6f1e6SMasatake YAMATO 	void *buffer = malloc (size);
221d4c6f1e6SMasatake YAMATO 
222a055e2beSMasatake YAMATO 	if (buffer == NULL && size != 0)
223d4c6f1e6SMasatake YAMATO 		error (FATAL, "out of memory");
224d4c6f1e6SMasatake YAMATO 
225d4c6f1e6SMasatake YAMATO 	return buffer;
226d4c6f1e6SMasatake YAMATO }
227d4c6f1e6SMasatake YAMATO 
eCalloc(const size_t count,const size_t size)228d4c6f1e6SMasatake YAMATO extern void *eCalloc (const size_t count, const size_t size)
229d4c6f1e6SMasatake YAMATO {
230d4c6f1e6SMasatake YAMATO 	void *buffer = calloc (count, size);
231d4c6f1e6SMasatake YAMATO 
232a055e2beSMasatake YAMATO 	if (buffer == NULL && count != 0 && size != 0)
233d4c6f1e6SMasatake YAMATO 		error (FATAL, "out of memory");
234d4c6f1e6SMasatake YAMATO 
235d4c6f1e6SMasatake YAMATO 	return buffer;
236d4c6f1e6SMasatake YAMATO }
237d4c6f1e6SMasatake YAMATO 
eRealloc(void * const ptr,const size_t size)238d4c6f1e6SMasatake YAMATO extern void *eRealloc (void *const ptr, const size_t size)
239d4c6f1e6SMasatake YAMATO {
240d4c6f1e6SMasatake YAMATO 	void *buffer;
241d4c6f1e6SMasatake YAMATO 	if (ptr == NULL)
242d4c6f1e6SMasatake YAMATO 		buffer = eMalloc (size);
243d4c6f1e6SMasatake YAMATO 	else
244d4c6f1e6SMasatake YAMATO 	{
245d4c6f1e6SMasatake YAMATO 		buffer = realloc (ptr, size);
246a055e2beSMasatake YAMATO 		if (buffer == NULL && size != 0)
247d4c6f1e6SMasatake YAMATO 			error (FATAL, "out of memory");
248d4c6f1e6SMasatake YAMATO 	}
249d4c6f1e6SMasatake YAMATO 	return buffer;
250d4c6f1e6SMasatake YAMATO }
251d4c6f1e6SMasatake YAMATO 
eFree(void * const ptr)252d4c6f1e6SMasatake YAMATO extern void eFree (void *const ptr)
253d4c6f1e6SMasatake YAMATO {
254d4c6f1e6SMasatake YAMATO 	Assert (ptr != NULL);
255d4c6f1e6SMasatake YAMATO 	free (ptr);
256d4c6f1e6SMasatake YAMATO }
257d4c6f1e6SMasatake YAMATO 
eFreeNoNullCheck(void * const ptr)25883739ab9SMasatake YAMATO extern void eFreeNoNullCheck (void *const ptr)
25983739ab9SMasatake YAMATO {
26083739ab9SMasatake YAMATO 	free (ptr);
26183739ab9SMasatake YAMATO }
26283739ab9SMasatake YAMATO 
eFreeIndirect(void ** ptr)26356065e52SMasatake YAMATO extern void eFreeIndirect(void **ptr)
26456065e52SMasatake YAMATO {
26556065e52SMasatake YAMATO 	if (ptr && *ptr)
26656065e52SMasatake YAMATO 	{
26756065e52SMasatake YAMATO 		eFree (*ptr);
26856065e52SMasatake YAMATO 		*ptr = NULL;
26956065e52SMasatake YAMATO 	}
27056065e52SMasatake YAMATO }
27156065e52SMasatake YAMATO 
272d4c6f1e6SMasatake YAMATO /*
273d4c6f1e6SMasatake YAMATO  *  String manipulation functions
274d4c6f1e6SMasatake YAMATO  */
275d4c6f1e6SMasatake YAMATO 
276d4c6f1e6SMasatake YAMATO /*
277d4c6f1e6SMasatake YAMATO  * Compare two strings, ignoring case.
278d4c6f1e6SMasatake YAMATO  * Return 0 for match, < 0 for smaller, > 0 for bigger
279d4c6f1e6SMasatake YAMATO  * Make sure case is folded to uppercase in comparison (like for 'sort -f')
280d4c6f1e6SMasatake YAMATO  * This makes a difference when one of the chars lies between upper and lower
281d4c6f1e6SMasatake YAMATO  * ie. one of the chars [ \ ] ^ _ ` for ascii. (The '_' in particular !)
282d4c6f1e6SMasatake YAMATO  */
struppercmp(const char * s1,const char * s2)283d4c6f1e6SMasatake YAMATO extern int struppercmp (const char *s1, const char *s2)
284d4c6f1e6SMasatake YAMATO {
285d4c6f1e6SMasatake YAMATO 	int result;
286d4c6f1e6SMasatake YAMATO 	do
287d4c6f1e6SMasatake YAMATO 	{
288d4c6f1e6SMasatake YAMATO 		result = toupper ((int) *s1) - toupper ((int) *s2);
289d4c6f1e6SMasatake YAMATO 	} while (result == 0  &&  *s1++ != '\0'  &&  *s2++ != '\0');
290d4c6f1e6SMasatake YAMATO 	return result;
291d4c6f1e6SMasatake YAMATO }
292d4c6f1e6SMasatake YAMATO 
strnuppercmp(const char * s1,const char * s2,size_t n)293d4c6f1e6SMasatake YAMATO extern int strnuppercmp (const char *s1, const char *s2, size_t n)
294d4c6f1e6SMasatake YAMATO {
295d4c6f1e6SMasatake YAMATO 	int result;
296d4c6f1e6SMasatake YAMATO 	do
297d4c6f1e6SMasatake YAMATO 	{
298d4c6f1e6SMasatake YAMATO 		result = toupper ((int) *s1) - toupper ((int) *s2);
299d4c6f1e6SMasatake YAMATO 	} while (result == 0  &&  --n > 0  &&  *s1++ != '\0'  &&  *s2++ != '\0');
300d4c6f1e6SMasatake YAMATO 	return result;
301d4c6f1e6SMasatake YAMATO }
302d4c6f1e6SMasatake YAMATO 
303d4c6f1e6SMasatake YAMATO #ifndef HAVE_STRSTR
strstr(const char * str,const char * substr)304d4c6f1e6SMasatake YAMATO extern char* strstr (const char *str, const char *substr)
305d4c6f1e6SMasatake YAMATO {
306d4c6f1e6SMasatake YAMATO 	const size_t length = strlen (substr);
307d4c6f1e6SMasatake YAMATO 	const char *p;
308d4c6f1e6SMasatake YAMATO 
309d4c6f1e6SMasatake YAMATO 	for (p = str  ;  *p != '\0'  ;  ++p)
310d4c6f1e6SMasatake YAMATO 		if (strncmp (p, substr, length) == 0)
311d4c6f1e6SMasatake YAMATO 			return (char*) p;
312d4c6f1e6SMasatake YAMATO 	return NULL;
313d4c6f1e6SMasatake YAMATO }
314d4c6f1e6SMasatake YAMATO #endif
315d4c6f1e6SMasatake YAMATO 
strrstr(const char * str,const char * substr)316d4c6f1e6SMasatake YAMATO extern char* strrstr (const char *str, const char *substr)
317d4c6f1e6SMasatake YAMATO {
318d4c6f1e6SMasatake YAMATO 	const size_t length = strlen (substr);
319d4c6f1e6SMasatake YAMATO 	const char *p;
320d4c6f1e6SMasatake YAMATO 
321d4c6f1e6SMasatake YAMATO 	for (p = str + strlen(str) - length  ;  p >= str  ;  --p)
322d4c6f1e6SMasatake YAMATO 		if (strncmp (p, substr, length) == 0)
323d4c6f1e6SMasatake YAMATO 			return (char*) p;
324d4c6f1e6SMasatake YAMATO 	return NULL;
325d4c6f1e6SMasatake YAMATO }
326d4c6f1e6SMasatake YAMATO 
eStrdup(const char * str)327d4c6f1e6SMasatake YAMATO extern char* eStrdup (const char* str)
328d4c6f1e6SMasatake YAMATO {
329d4c6f1e6SMasatake YAMATO 	char* result = xMalloc (strlen (str) + 1, char);
330d4c6f1e6SMasatake YAMATO 	strcpy (result, str);
331d4c6f1e6SMasatake YAMATO 	return result;
332d4c6f1e6SMasatake YAMATO }
333d4c6f1e6SMasatake YAMATO 
eStrndup(const char * str,size_t len)334d4c6f1e6SMasatake YAMATO extern char* eStrndup (const char* str, size_t len)
335d4c6f1e6SMasatake YAMATO {
336d4c6f1e6SMasatake YAMATO 	char* result = xMalloc (len + 1, char);
337d4c6f1e6SMasatake YAMATO 	strncpy (result, str, len);
338dd57540dSMasatake YAMATO 	result [len] = '\0';
339d4c6f1e6SMasatake YAMATO 	return result;
340d4c6f1e6SMasatake YAMATO }
341d4c6f1e6SMasatake YAMATO 
toLowerString(char * str)342d4c6f1e6SMasatake YAMATO extern void toLowerString (char* str)
343d4c6f1e6SMasatake YAMATO {
344d4c6f1e6SMasatake YAMATO 	while (*str != '\0')
345d4c6f1e6SMasatake YAMATO 	{
346d4c6f1e6SMasatake YAMATO 		*str = tolower ((int) *str);
347d4c6f1e6SMasatake YAMATO 		++str;
348d4c6f1e6SMasatake YAMATO 	}
349d4c6f1e6SMasatake YAMATO }
350d4c6f1e6SMasatake YAMATO 
toUpperString(char * str)351d4c6f1e6SMasatake YAMATO extern void toUpperString (char* str)
352d4c6f1e6SMasatake YAMATO {
353d4c6f1e6SMasatake YAMATO 	while (*str != '\0')
354d4c6f1e6SMasatake YAMATO 	{
355d4c6f1e6SMasatake YAMATO 		*str = toupper ((int) *str);
356d4c6f1e6SMasatake YAMATO 		++str;
357d4c6f1e6SMasatake YAMATO 	}
358d4c6f1e6SMasatake YAMATO }
359d4c6f1e6SMasatake YAMATO 
360d4c6f1e6SMasatake YAMATO /*  Newly allocated string containing lower case conversion of a string.
361d4c6f1e6SMasatake YAMATO  */
newLowerString(const char * str)362d4c6f1e6SMasatake YAMATO extern char* newLowerString (const char* str)
363d4c6f1e6SMasatake YAMATO {
364d4c6f1e6SMasatake YAMATO 	char* const result = xMalloc (strlen (str) + 1, char);
365d4c6f1e6SMasatake YAMATO 	int i = 0;
366d4c6f1e6SMasatake YAMATO 	do
367d4c6f1e6SMasatake YAMATO 		result [i] = tolower ((int) str [i]);
368d4c6f1e6SMasatake YAMATO 	while (str [i++] != '\0');
369d4c6f1e6SMasatake YAMATO 	return result;
370d4c6f1e6SMasatake YAMATO }
371d4c6f1e6SMasatake YAMATO 
372d4c6f1e6SMasatake YAMATO /*  Newly allocated string containing upper case conversion of a string.
373d4c6f1e6SMasatake YAMATO  */
newUpperString(const char * str)374d4c6f1e6SMasatake YAMATO extern char* newUpperString (const char* str)
375d4c6f1e6SMasatake YAMATO {
376d4c6f1e6SMasatake YAMATO 	char* const result = xMalloc (strlen (str) + 1, char);
377d4c6f1e6SMasatake YAMATO 	int i = 0;
378d4c6f1e6SMasatake YAMATO 	do
379d4c6f1e6SMasatake YAMATO 		result [i] = toupper ((int) str [i]);
380d4c6f1e6SMasatake YAMATO 	while (str [i++] != '\0');
381d4c6f1e6SMasatake YAMATO 	return result;
382d4c6f1e6SMasatake YAMATO }
383d4c6f1e6SMasatake YAMATO 
384583bdbcbSThomas Braun /* Safe wrapper for strtoul
385583bdbcbSThomas Braun  *
386583bdbcbSThomas Braun  * The conversion result is placed in value and must only be used if the
387583bdbcbSThomas Braun  * function returned true.
388583bdbcbSThomas Braun  */
strToULong(const char * const str,int base,unsigned long * value)389ce990805SThomas Braun extern bool strToULong(const char *const str, int base, unsigned long *value)
390583bdbcbSThomas Braun {
391583bdbcbSThomas Braun 	char *endptr;
392583bdbcbSThomas Braun 
393583bdbcbSThomas Braun 	errno = 0;
394583bdbcbSThomas Braun 	*value = strtoul (str, &endptr, base);
395583bdbcbSThomas Braun 	return *endptr == '\0' && str != endptr && errno == 0;
396583bdbcbSThomas Braun }
397583bdbcbSThomas Braun 
398583bdbcbSThomas Braun /* Safe wrapper for strtol/atol
399583bdbcbSThomas Braun  *
400583bdbcbSThomas Braun  * The conversion result is placed in value and must only be used if the
401583bdbcbSThomas Braun  * function returned true.
402583bdbcbSThomas Braun  */
strToLong(const char * const str,int base,long * value)403ce990805SThomas Braun extern bool strToLong(const char *const str, int base, long *value)
404583bdbcbSThomas Braun {
405583bdbcbSThomas Braun 	char *endptr;
406583bdbcbSThomas Braun 
407583bdbcbSThomas Braun 	errno = 0;
408583bdbcbSThomas Braun 	*value = strtol (str, &endptr, base);
409583bdbcbSThomas Braun 	return *endptr == '\0' && str != endptr && errno == 0;
410583bdbcbSThomas Braun }
411583bdbcbSThomas Braun 
strToUInt(const char * const str,int base,unsigned int * value)412ce990805SThomas Braun extern bool strToUInt(const char *const str, int base, unsigned int *value)
413583bdbcbSThomas Braun {
414583bdbcbSThomas Braun 	unsigned long ulong_value;
415583bdbcbSThomas Braun 
416583bdbcbSThomas Braun 	if(!strToULong(str, base, &ulong_value) || ulong_value > UINT_MAX)
417ce990805SThomas Braun 		return false;
418583bdbcbSThomas Braun 
419583bdbcbSThomas Braun 	*value = (unsigned int) ulong_value;
420ce990805SThomas Braun 	return true;
421583bdbcbSThomas Braun }
422583bdbcbSThomas Braun 
strToInt(const char * const str,int base,int * value)423ce990805SThomas Braun extern bool strToInt(const char *const str, int base, int *value)
424583bdbcbSThomas Braun {
425583bdbcbSThomas Braun 	long long_value;
426583bdbcbSThomas Braun 
427583bdbcbSThomas Braun 	if(!strToLong(str, base, &long_value) || long_value > INT_MAX || long_value < INT_MIN)
428ce990805SThomas Braun 		return false;
429583bdbcbSThomas Braun 
430583bdbcbSThomas Braun 	*value = (int) long_value;
431ce990805SThomas Braun 	return true;
432583bdbcbSThomas Braun }
433583bdbcbSThomas Braun 
434d4c6f1e6SMasatake YAMATO /*
435d4c6f1e6SMasatake YAMATO  * File system functions
436d4c6f1e6SMasatake YAMATO  */
437d4c6f1e6SMasatake YAMATO 
setCurrentDirectory(void)438468ef944SMasatake YAMATO extern void setCurrentDirectory (void) /* TODO */
439d4c6f1e6SMasatake YAMATO {
440d4c6f1e6SMasatake YAMATO 	char* buf;
441d4c6f1e6SMasatake YAMATO 	if (CurrentDirectory == NULL)
442d4c6f1e6SMasatake YAMATO 		CurrentDirectory = xMalloc ((size_t) (PATH_MAX + 1), char);
443d4c6f1e6SMasatake YAMATO 	buf = getcwd (CurrentDirectory, PATH_MAX);
444d4c6f1e6SMasatake YAMATO 	if (buf == NULL)
445d4c6f1e6SMasatake YAMATO 		perror ("");
44617e0aa54SMasatake YAMATO 	if (! isPathSeparator (CurrentDirectory [strlen (CurrentDirectory) - (size_t) 1]))
447d4c6f1e6SMasatake YAMATO 	{
448d4c6f1e6SMasatake YAMATO 		sprintf (CurrentDirectory + strlen (CurrentDirectory), "%c",
449d4c6f1e6SMasatake YAMATO 				OUTPUT_PATH_SEPARATOR);
450d4c6f1e6SMasatake YAMATO 	}
451468ef944SMasatake YAMATO 	canonicalizePath (CurrentDirectory);
452d4c6f1e6SMasatake YAMATO }
453d4c6f1e6SMasatake YAMATO 
454d4c6f1e6SMasatake YAMATO /* For caching of stat() calls */
eStat(const char * const fileName)455d4c6f1e6SMasatake YAMATO extern fileStatus *eStat (const char *const fileName)
456d4c6f1e6SMasatake YAMATO {
457d4c6f1e6SMasatake YAMATO 	struct stat status;
458d4c6f1e6SMasatake YAMATO 	static fileStatus file;
459d4c6f1e6SMasatake YAMATO 	if (file.name == NULL  ||  strcmp (fileName, file.name) != 0)
460d4c6f1e6SMasatake YAMATO 	{
461d4c6f1e6SMasatake YAMATO 		eStatFree (&file);
462d4c6f1e6SMasatake YAMATO 		file.name = eStrdup (fileName);
463d4c6f1e6SMasatake YAMATO 		if (lstat (file.name, &status) != 0)
464ce990805SThomas Braun 			file.exists = false;
465d4c6f1e6SMasatake YAMATO 		else
466d4c6f1e6SMasatake YAMATO 		{
467ce990805SThomas Braun 			file.isSymbolicLink = (bool) S_ISLNK (status.st_mode);
468d4c6f1e6SMasatake YAMATO 			if (file.isSymbolicLink  &&  stat (file.name, &status) != 0)
469ce990805SThomas Braun 				file.exists = false;
470d4c6f1e6SMasatake YAMATO 			else
471d4c6f1e6SMasatake YAMATO 			{
472ce990805SThomas Braun 				file.exists = true;
473ce990805SThomas Braun 				file.isDirectory = (bool) S_ISDIR (status.st_mode);
474ce990805SThomas Braun 				file.isNormalFile = (bool) (S_ISREG (status.st_mode));
475ce990805SThomas Braun 				file.isExecutable = (bool) ((status.st_mode &
476d4c6f1e6SMasatake YAMATO 					(S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
477ce990805SThomas Braun 				file.isSetuid = (bool) ((status.st_mode & S_ISUID) != 0);
478ce990805SThomas Braun 				file.isSetgid = (bool) ((status.st_mode & S_ISGID) != 0);
479d4c6f1e6SMasatake YAMATO 				file.size = status.st_size;
480c314f261SMasatake YAMATO 				file.mtime = status.st_mtime;
481d4c6f1e6SMasatake YAMATO 			}
482d4c6f1e6SMasatake YAMATO 		}
483d4c6f1e6SMasatake YAMATO 	}
484d4c6f1e6SMasatake YAMATO 	return &file;
485d4c6f1e6SMasatake YAMATO }
486d4c6f1e6SMasatake YAMATO 
eStatFree(fileStatus * status)487d4c6f1e6SMasatake YAMATO extern void eStatFree (fileStatus *status)
488d4c6f1e6SMasatake YAMATO {
489d4c6f1e6SMasatake YAMATO 	if (status->name != NULL)
490d4c6f1e6SMasatake YAMATO 	{
491d4c6f1e6SMasatake YAMATO 		eFree (status->name);
492d4c6f1e6SMasatake YAMATO 		status->name = NULL;
493d4c6f1e6SMasatake YAMATO 	}
494d4c6f1e6SMasatake YAMATO }
495d4c6f1e6SMasatake YAMATO 
doesFileExist(const char * const fileName)496ce990805SThomas Braun extern bool doesFileExist (const char *const fileName)
497d4c6f1e6SMasatake YAMATO {
498d4c6f1e6SMasatake YAMATO 	fileStatus *status = eStat (fileName);
499d4c6f1e6SMasatake YAMATO 	return status->exists;
500d4c6f1e6SMasatake YAMATO }
501d4c6f1e6SMasatake YAMATO 
doesExecutableExist(const char * const fileName)502ce990805SThomas Braun extern bool doesExecutableExist (const char *const fileName)
503d4c6f1e6SMasatake YAMATO {
504d4c6f1e6SMasatake YAMATO 	fileStatus *status = eStat (fileName);
505d4c6f1e6SMasatake YAMATO 	return status->exists && status->isExecutable;
506d4c6f1e6SMasatake YAMATO }
507d4c6f1e6SMasatake YAMATO 
isRecursiveLink(const char * const dirName)508ce990805SThomas Braun extern bool isRecursiveLink (const char* const dirName)
509d4c6f1e6SMasatake YAMATO {
510ce990805SThomas Braun 	bool result = false;
511d4c6f1e6SMasatake YAMATO 	fileStatus *status = eStat (dirName);
512d4c6f1e6SMasatake YAMATO 	if (status->isSymbolicLink)
513d4c6f1e6SMasatake YAMATO 	{
514d4c6f1e6SMasatake YAMATO 		char* const path = absoluteFilename (dirName);
51517e0aa54SMasatake YAMATO 		while (isPathSeparator (path [strlen (path) - 1]))
516d4c6f1e6SMasatake YAMATO 			path [strlen (path) - 1] = '\0';
517d4c6f1e6SMasatake YAMATO 		while (! result  &&  strlen (path) > (size_t) 1)
518d4c6f1e6SMasatake YAMATO 		{
51917e0aa54SMasatake YAMATO 			char *const separator = strRSeparator (path);
520d4c6f1e6SMasatake YAMATO 			if (separator == NULL)
521d4c6f1e6SMasatake YAMATO 				break;
522d4c6f1e6SMasatake YAMATO 			else if (separator == path)  /* backed up to root directory */
523d4c6f1e6SMasatake YAMATO 				*(separator + 1) = '\0';
524d4c6f1e6SMasatake YAMATO 			else
525d4c6f1e6SMasatake YAMATO 				*separator = '\0';
526d4c6f1e6SMasatake YAMATO 			result = isSameFile (path, dirName);
527d4c6f1e6SMasatake YAMATO 		}
528d4c6f1e6SMasatake YAMATO 		eFree (path);
529d4c6f1e6SMasatake YAMATO 	}
530d4c6f1e6SMasatake YAMATO 	return result;
531d4c6f1e6SMasatake YAMATO }
532d4c6f1e6SMasatake YAMATO 
533d4c6f1e6SMasatake YAMATO /*
534d4c6f1e6SMasatake YAMATO  *  Pathname manipulation (O/S dependent!!!)
535d4c6f1e6SMasatake YAMATO  */
536d4c6f1e6SMasatake YAMATO 
isPathSeparator(const int c)537ce990805SThomas Braun static bool isPathSeparator (const int c)
538d4c6f1e6SMasatake YAMATO {
539ce990805SThomas Braun 	bool result;
540d4c6f1e6SMasatake YAMATO #if defined (MSDOS_STYLE_PATH)
541ce990805SThomas Braun 	result = (bool) (strchr (PathDelimiters, c) != NULL);
542d4c6f1e6SMasatake YAMATO #else
543ce990805SThomas Braun 	result = (bool) (c == PATH_SEPARATOR);
544d4c6f1e6SMasatake YAMATO #endif
545d4c6f1e6SMasatake YAMATO 	return result;
546d4c6f1e6SMasatake YAMATO }
547d4c6f1e6SMasatake YAMATO 
strSeparator(const char * s)54817e0aa54SMasatake YAMATO static char *strSeparator (const char *s)
54917e0aa54SMasatake YAMATO {
55017e0aa54SMasatake YAMATO #if defined (MSDOS_STYLE_PATH)
55117e0aa54SMasatake YAMATO 	return strpbrk (s, PathDelimiters);
55217e0aa54SMasatake YAMATO #else
55317e0aa54SMasatake YAMATO 	return strchr (s, PATH_SEPARATOR);
55417e0aa54SMasatake YAMATO #endif
55517e0aa54SMasatake YAMATO }
55617e0aa54SMasatake YAMATO 
strRSeparator(const char * s)55717e0aa54SMasatake YAMATO static char *strRSeparator (const char *s)
55817e0aa54SMasatake YAMATO {
55917e0aa54SMasatake YAMATO #if defined (MSDOS_STYLE_PATH)
56017e0aa54SMasatake YAMATO 	const char *last = NULL;
56117e0aa54SMasatake YAMATO 
56217e0aa54SMasatake YAMATO 	while (( s = strSeparator (s) ))
56317e0aa54SMasatake YAMATO 	{
56417e0aa54SMasatake YAMATO 		last = s;
56517e0aa54SMasatake YAMATO 		s++;
56617e0aa54SMasatake YAMATO 	}
56759f256efSK.Takata 	return (char*) last;
56817e0aa54SMasatake YAMATO #else
56917e0aa54SMasatake YAMATO 	return strrchr (s, PATH_SEPARATOR);
57017e0aa54SMasatake YAMATO #endif
57117e0aa54SMasatake YAMATO }
57217e0aa54SMasatake YAMATO 
canonicalizePath(char * const path CTAGS_ATTR_UNUSED)5738ccb7ee9SJiří Techet static void canonicalizePath (char *const path CTAGS_ATTR_UNUSED)
574d4c6f1e6SMasatake YAMATO {
575d4c6f1e6SMasatake YAMATO # if defined (MSDOS_STYLE_PATH)
576d4c6f1e6SMasatake YAMATO 	char *p;
577d4c6f1e6SMasatake YAMATO 	for (p = path  ;  *p != '\0'  ;  ++p)
578d4c6f1e6SMasatake YAMATO 		if (isPathSeparator (*p)  &&  *p != ':')
579468ef944SMasatake YAMATO 			*p = OUTPUT_PATH_SEPARATOR;
580d4c6f1e6SMasatake YAMATO # endif
581d4c6f1e6SMasatake YAMATO }
582d4c6f1e6SMasatake YAMATO 
isSameFile(const char * const name1,const char * const name2)583ce990805SThomas Braun extern bool isSameFile (const char *const name1, const char *const name2)
584d4c6f1e6SMasatake YAMATO {
585ce990805SThomas Braun 	bool result = false;
586d4c6f1e6SMasatake YAMATO #if defined (HAVE_STAT_ST_INO)
587d4c6f1e6SMasatake YAMATO 	struct stat stat1, stat2;
588d4c6f1e6SMasatake YAMATO 
589d4c6f1e6SMasatake YAMATO 	if (stat (name1, &stat1) == 0  &&  stat (name2, &stat2) == 0)
590ce990805SThomas Braun 		result = (bool) (stat1.st_ino == stat2.st_ino);
591d4c6f1e6SMasatake YAMATO #else
592d4c6f1e6SMasatake YAMATO 	{
593d4c6f1e6SMasatake YAMATO 		char *const n1 = absoluteFilename (name1);
594d4c6f1e6SMasatake YAMATO 		char *const n2 = absoluteFilename (name2);
595d4c6f1e6SMasatake YAMATO 		canonicalizePath (n1);
596d4c6f1e6SMasatake YAMATO 		canonicalizePath (n2);
597d4c6f1e6SMasatake YAMATO # if defined (CASE_INSENSITIVE_FILENAMES)
598ce990805SThomas Braun 		result = (bool) (strcasecmp (n1, n2) == 0);
599d4c6f1e6SMasatake YAMATO # else
600ce990805SThomas Braun 		result = (bool) (strcmp (n1, n2) == 0);
601d4c6f1e6SMasatake YAMATO # endif
602a32a50f1SMasatake YAMATO 		eFree (n1);
603a32a50f1SMasatake YAMATO 		eFree (n2);
604d4c6f1e6SMasatake YAMATO 	}
605d4c6f1e6SMasatake YAMATO #endif
606d4c6f1e6SMasatake YAMATO 	return result;
607d4c6f1e6SMasatake YAMATO }
608d4c6f1e6SMasatake YAMATO 
baseFilename(const char * const filePath)609d4c6f1e6SMasatake YAMATO extern const char *baseFilename (const char *const filePath)
610d4c6f1e6SMasatake YAMATO {
611d4c6f1e6SMasatake YAMATO #if defined (MSDOS_STYLE_PATH)
612d4c6f1e6SMasatake YAMATO 	const char *tail = NULL;
613d4c6f1e6SMasatake YAMATO 	unsigned int i;
614d4c6f1e6SMasatake YAMATO 
615d4c6f1e6SMasatake YAMATO 	/*  Find whichever of the path delimiters is last.
616d4c6f1e6SMasatake YAMATO 	 */
617d4c6f1e6SMasatake YAMATO 	for (i = 0  ;  i < strlen (PathDelimiters)  ;  ++i)
618d4c6f1e6SMasatake YAMATO 	{
6192acdcfa1SYasuhiro Matsumoto # ifdef HAVE_MBLEN
6202acdcfa1SYasuhiro Matsumoto 		const char *p;
6212acdcfa1SYasuhiro Matsumoto 		int ml;
6222acdcfa1SYasuhiro Matsumoto 
6232acdcfa1SYasuhiro Matsumoto 		/* Some DBCS has letter contains 0x5C in trailing byte.
6242acdcfa1SYasuhiro Matsumoto 		 * So skip to the trailing byte. */
6252acdcfa1SYasuhiro Matsumoto 		for (p = filePath  ;  *p != '\0'  ;  ++p)
6262acdcfa1SYasuhiro Matsumoto 		{
6272acdcfa1SYasuhiro Matsumoto 			ml = mblen(p, MB_LEN_MAX);
6282acdcfa1SYasuhiro Matsumoto 			if (ml > 1)
6292acdcfa1SYasuhiro Matsumoto 				p += ml - 1;
6302acdcfa1SYasuhiro Matsumoto 			else if (*p == PathDelimiters [i] && p > tail)
6312acdcfa1SYasuhiro Matsumoto 				tail = p;
6322acdcfa1SYasuhiro Matsumoto 		}
6332acdcfa1SYasuhiro Matsumoto # else
634d4c6f1e6SMasatake YAMATO 		const char *sep = strrchr (filePath, PathDelimiters [i]);
635d4c6f1e6SMasatake YAMATO 
636d4c6f1e6SMasatake YAMATO 		if (sep > tail)
637d4c6f1e6SMasatake YAMATO 			tail = sep;
6382acdcfa1SYasuhiro Matsumoto # endif
639d4c6f1e6SMasatake YAMATO 	}
640d4c6f1e6SMasatake YAMATO #else
64117e0aa54SMasatake YAMATO 	const char *tail = strRSeparator (filePath);
642d4c6f1e6SMasatake YAMATO #endif
643d4c6f1e6SMasatake YAMATO 	if (tail == NULL)
644d4c6f1e6SMasatake YAMATO 		tail = filePath;
645d4c6f1e6SMasatake YAMATO 	else
646d4c6f1e6SMasatake YAMATO 		++tail;  /* step past last delimiter */
647d4c6f1e6SMasatake YAMATO 
648d4c6f1e6SMasatake YAMATO 	return tail;
649d4c6f1e6SMasatake YAMATO }
650d4c6f1e6SMasatake YAMATO 
fileExtension(const char * const fileName)651d4c6f1e6SMasatake YAMATO extern const char *fileExtension (const char *const fileName)
652d4c6f1e6SMasatake YAMATO {
653d4c6f1e6SMasatake YAMATO 	const char *extension;
65462c9a9aaSMasatake YAMATO 	const char *pDelimiter;
655d4c6f1e6SMasatake YAMATO 	const char *const base = baseFilename (fileName);
656e96a4861SJiří Techet 
657d4c6f1e6SMasatake YAMATO 	pDelimiter = strrchr (base, '.');
658d4c6f1e6SMasatake YAMATO 
659d4c6f1e6SMasatake YAMATO 	if (pDelimiter == NULL)
660d4c6f1e6SMasatake YAMATO 		extension = "";
661d4c6f1e6SMasatake YAMATO 	else
662d4c6f1e6SMasatake YAMATO 		extension = pDelimiter + 1;  /* skip to first char of extension */
663d4c6f1e6SMasatake YAMATO 
664d4c6f1e6SMasatake YAMATO 	return extension;
665d4c6f1e6SMasatake YAMATO }
666d4c6f1e6SMasatake YAMATO 
baseFilenameSansExtensionNew(const char * const fileName,const char * const templateExt)667d4c6f1e6SMasatake YAMATO extern char* baseFilenameSansExtensionNew (const char *const fileName,
668d4c6f1e6SMasatake YAMATO 					   const char *const templateExt)
669d4c6f1e6SMasatake YAMATO {
67062c9a9aaSMasatake YAMATO 	const char *pDelimiter;
671d4c6f1e6SMasatake YAMATO 	const char *const base = baseFilename (fileName);
672d4c6f1e6SMasatake YAMATO 	char* shorten_base;
673d4c6f1e6SMasatake YAMATO 
674d4c6f1e6SMasatake YAMATO 	pDelimiter = strrchr (base, templateExt[0]);
675d4c6f1e6SMasatake YAMATO 
676d4c6f1e6SMasatake YAMATO 	if (pDelimiter && (strcmp (pDelimiter, templateExt) == 0))
677d4c6f1e6SMasatake YAMATO 	{
678d4c6f1e6SMasatake YAMATO 		shorten_base = eStrndup (base, pDelimiter - base);
679d4c6f1e6SMasatake YAMATO 		return shorten_base;
680d4c6f1e6SMasatake YAMATO 	}
681d4c6f1e6SMasatake YAMATO 	else
682d4c6f1e6SMasatake YAMATO 		return NULL;
683d4c6f1e6SMasatake YAMATO }
684d4c6f1e6SMasatake YAMATO 
isAbsolutePath(const char * const path)685ce990805SThomas Braun extern bool isAbsolutePath (const char *const path)
686d4c6f1e6SMasatake YAMATO {
68762c9a9aaSMasatake YAMATO 	bool result;
688d4c6f1e6SMasatake YAMATO #if defined (MSDOS_STYLE_PATH)
689d4c6f1e6SMasatake YAMATO 	if (isPathSeparator (path [0]))
690ce990805SThomas Braun 		result = true;
691d4c6f1e6SMasatake YAMATO 	else if (isalpha (path [0])  &&  path [1] == ':')
692d4c6f1e6SMasatake YAMATO 	{
693d4c6f1e6SMasatake YAMATO 		if (isPathSeparator (path [2]))
694ce990805SThomas Braun 			result = true;
695d4c6f1e6SMasatake YAMATO 		else
69662c9a9aaSMasatake YAMATO 		{
69762c9a9aaSMasatake YAMATO 			result = false;
698d4c6f1e6SMasatake YAMATO 			/*  We don't support non-absolute file names with a drive
699d4c6f1e6SMasatake YAMATO 			 *  letter, like `d:NAME' (it's too much hassle).
700d4c6f1e6SMasatake YAMATO 			 */
701d4c6f1e6SMasatake YAMATO 			error (FATAL,
702d4c6f1e6SMasatake YAMATO 				"%s: relative file names with drive letters not supported",
703d4c6f1e6SMasatake YAMATO 				path);
704d4c6f1e6SMasatake YAMATO 		}
70562c9a9aaSMasatake YAMATO 	}
70662c9a9aaSMasatake YAMATO 	else
70762c9a9aaSMasatake YAMATO 		result = false;
708d4c6f1e6SMasatake YAMATO #else
709d4c6f1e6SMasatake YAMATO 	result = isPathSeparator (path [0]);
710d4c6f1e6SMasatake YAMATO #endif
711d4c6f1e6SMasatake YAMATO 	return result;
712d4c6f1e6SMasatake YAMATO }
713d4c6f1e6SMasatake YAMATO 
combinePathAndFile(const char * const path,const char * const file)714d4c6f1e6SMasatake YAMATO extern char *combinePathAndFile (
715d4c6f1e6SMasatake YAMATO 	const char *const path, const char *const file)
716d4c6f1e6SMasatake YAMATO {
717d4c6f1e6SMasatake YAMATO 	vString *const filePath = vStringNew ();
7188f7065aaSMasatake YAMATO 	size_t len = strlen (path);
719d4c6f1e6SMasatake YAMATO 
7208f7065aaSMasatake YAMATO 	if (len)
7218f7065aaSMasatake YAMATO 	{
7228f7065aaSMasatake YAMATO 		const int lastChar = path [len - 1];
7238f7065aaSMasatake YAMATO 		bool terminated = isPathSeparator (lastChar);
724d4c6f1e6SMasatake YAMATO 		vStringCopyS (filePath, path);
725d4c6f1e6SMasatake YAMATO 		if (! terminated)
726d4c6f1e6SMasatake YAMATO 			vStringPut (filePath, OUTPUT_PATH_SEPARATOR);
7278f7065aaSMasatake YAMATO 	}
728d4c6f1e6SMasatake YAMATO 
7298f7065aaSMasatake YAMATO 	vStringCatS (filePath, file);
730d4c6f1e6SMasatake YAMATO 	return vStringDeleteUnwrap (filePath);
731d4c6f1e6SMasatake YAMATO }
732d4c6f1e6SMasatake YAMATO 
733d4c6f1e6SMasatake YAMATO /* Return a newly-allocated string whose contents concatenate those of
734d4c6f1e6SMasatake YAMATO  * s1, s2, s3.
735d4c6f1e6SMasatake YAMATO  * Routine adapted from Gnu etags.
736d4c6f1e6SMasatake YAMATO  */
concat(const char * s1,const char * s2,const char * s3)737d4c6f1e6SMasatake YAMATO static char* concat (const char *s1, const char *s2, const char *s3)
738d4c6f1e6SMasatake YAMATO {
739d4c6f1e6SMasatake YAMATO 	int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
740d4c6f1e6SMasatake YAMATO 	char *result = xMalloc (len1 + len2 + len3 + 1, char);
741d4c6f1e6SMasatake YAMATO 
742d4c6f1e6SMasatake YAMATO 	strcpy (result, s1);
743d4c6f1e6SMasatake YAMATO 	strcpy (result + len1, s2);
744d4c6f1e6SMasatake YAMATO 	strcpy (result + len1 + len2, s3);
745d4c6f1e6SMasatake YAMATO 	result [len1 + len2 + len3] = '\0';
746d4c6f1e6SMasatake YAMATO 
747d4c6f1e6SMasatake YAMATO 	return result;
748d4c6f1e6SMasatake YAMATO }
749d4c6f1e6SMasatake YAMATO 
750d4c6f1e6SMasatake YAMATO /* Return a newly allocated string containing the absolute file name of FILE
751d4c6f1e6SMasatake YAMATO  * given CWD (which should end with a slash).
752d4c6f1e6SMasatake YAMATO  * Routine adapted from Gnu etags.
753d4c6f1e6SMasatake YAMATO  */
absoluteFilename(const char * file)754d4c6f1e6SMasatake YAMATO extern char* absoluteFilename (const char *file)
755d4c6f1e6SMasatake YAMATO {
756d4c6f1e6SMasatake YAMATO 	char *slashp, *cp;
757d4c6f1e6SMasatake YAMATO 	char *res = NULL;
758d4c6f1e6SMasatake YAMATO 	if (isAbsolutePath (file))
759d4c6f1e6SMasatake YAMATO 	{
760d4c6f1e6SMasatake YAMATO #ifdef MSDOS_STYLE_PATH
761d4c6f1e6SMasatake YAMATO 		if (file [1] == ':')
762d4c6f1e6SMasatake YAMATO 			res = eStrdup (file);
763d4c6f1e6SMasatake YAMATO 		else
764d4c6f1e6SMasatake YAMATO 		{
765d4c6f1e6SMasatake YAMATO 			char drive [3];
766d4c6f1e6SMasatake YAMATO 			sprintf (drive, "%c:", currentdrive ());
767d4c6f1e6SMasatake YAMATO 			res = concat (drive, file, "");
768d4c6f1e6SMasatake YAMATO 		}
769d4c6f1e6SMasatake YAMATO #else
770d4c6f1e6SMasatake YAMATO 		res = eStrdup (file);
771d4c6f1e6SMasatake YAMATO #endif
772d4c6f1e6SMasatake YAMATO 	}
773d4c6f1e6SMasatake YAMATO 	else
774d4c6f1e6SMasatake YAMATO 		res = concat (CurrentDirectory, file, "");
775d4c6f1e6SMasatake YAMATO 
776d4c6f1e6SMasatake YAMATO 	/* Delete the "/dirname/.." and "/." substrings. */
77717e0aa54SMasatake YAMATO 	slashp = strSeparator (res);
778d4c6f1e6SMasatake YAMATO 	while (slashp != NULL  &&  slashp [0] != '\0')
779d4c6f1e6SMasatake YAMATO 	{
780d4c6f1e6SMasatake YAMATO 		if (slashp[1] == '.')
781d4c6f1e6SMasatake YAMATO 		{
782d4c6f1e6SMasatake YAMATO 			if (slashp [2] == '.' &&
78317e0aa54SMasatake YAMATO 				(isPathSeparator (slashp [3]) || slashp [3] == '\0'))
784d4c6f1e6SMasatake YAMATO 			{
785d4c6f1e6SMasatake YAMATO 				cp = slashp;
786d4c6f1e6SMasatake YAMATO 				do
787d4c6f1e6SMasatake YAMATO 					cp--;
788d4c6f1e6SMasatake YAMATO 				while (cp >= res  &&  ! isAbsolutePath (cp));
789d4c6f1e6SMasatake YAMATO 				if (cp < res)
790d4c6f1e6SMasatake YAMATO 					cp = slashp;/* the absolute name begins with "/.." */
791d4c6f1e6SMasatake YAMATO #ifdef MSDOS_STYLE_PATH
792d4c6f1e6SMasatake YAMATO 				/* Under MSDOS and NT we get `d:/NAME' as absolute file name,
7930d7b243eSK.Takata 				 * so the user could say `d:/../NAME'. We silently treat this
794d4c6f1e6SMasatake YAMATO 				 * as `d:/NAME'.
795d4c6f1e6SMasatake YAMATO 				 */
79617e0aa54SMasatake YAMATO 				else if (!isPathSeparator (cp [0]))
797d4c6f1e6SMasatake YAMATO 					cp = slashp;
798d4c6f1e6SMasatake YAMATO #endif
799d4c6f1e6SMasatake YAMATO 				memmove (cp, slashp + 3, strlen (slashp + 3) + 1);
800d4c6f1e6SMasatake YAMATO 				slashp = cp;
801d4c6f1e6SMasatake YAMATO 				continue;
802d4c6f1e6SMasatake YAMATO 			}
80317e0aa54SMasatake YAMATO 			else if (isPathSeparator (slashp [2])  ||  slashp [2] == '\0')
804d4c6f1e6SMasatake YAMATO 			{
805d4c6f1e6SMasatake YAMATO 				memmove (slashp, slashp + 2, strlen (slashp + 2) + 1);
806d4c6f1e6SMasatake YAMATO 				continue;
807d4c6f1e6SMasatake YAMATO 			}
808d4c6f1e6SMasatake YAMATO 		}
80917e0aa54SMasatake YAMATO 		slashp = strSeparator (slashp + 1);
810d4c6f1e6SMasatake YAMATO 	}
811d4c6f1e6SMasatake YAMATO 
812d4c6f1e6SMasatake YAMATO 	if (res [0] == '\0')
813e9ff00a0SMasatake YAMATO 	{
81465945ba5SMasatake YAMATO 		const char root [] = {OUTPUT_PATH_SEPARATOR, '\0'};
815e9ff00a0SMasatake YAMATO 		eFree (res);
81665945ba5SMasatake YAMATO 		res = eStrdup (root);
817e9ff00a0SMasatake YAMATO 	}
818d4c6f1e6SMasatake YAMATO 	else
819d4c6f1e6SMasatake YAMATO 	{
820d4c6f1e6SMasatake YAMATO #ifdef MSDOS_STYLE_PATH
821d4c6f1e6SMasatake YAMATO 		/* Canonicalize drive letter case. */
822d4c6f1e6SMasatake YAMATO 		if (res [1] == ':'  &&  islower (res [0]))
823d4c6f1e6SMasatake YAMATO 			res [0] = toupper (res [0]);
824d4c6f1e6SMasatake YAMATO #endif
825d4c6f1e6SMasatake YAMATO 	}
82628be57b1SMasatake YAMATO 	canonicalizePath (res);
827e9ff00a0SMasatake YAMATO 	return res;
828d4c6f1e6SMasatake YAMATO }
829d4c6f1e6SMasatake YAMATO 
830d4c6f1e6SMasatake YAMATO /* Return a newly allocated string containing the absolute file name of dir
831d4c6f1e6SMasatake YAMATO  * where `file' resides given `CurrentDirectory'.
832d4c6f1e6SMasatake YAMATO  * Routine adapted from Gnu etags.
833d4c6f1e6SMasatake YAMATO  */
absoluteDirname(char * file)834d4c6f1e6SMasatake YAMATO extern char* absoluteDirname (char *file)
835d4c6f1e6SMasatake YAMATO {
836d4c6f1e6SMasatake YAMATO 	char *slashp, *res;
837d4c6f1e6SMasatake YAMATO 	char save;
83817e0aa54SMasatake YAMATO 	slashp = strRSeparator (file);
839d4c6f1e6SMasatake YAMATO 	if (slashp == NULL)
840d4c6f1e6SMasatake YAMATO 		res = eStrdup (CurrentDirectory);
841d4c6f1e6SMasatake YAMATO 	else
842d4c6f1e6SMasatake YAMATO 	{
843d4c6f1e6SMasatake YAMATO 		save = slashp [1];
844d4c6f1e6SMasatake YAMATO 		slashp [1] = '\0';
845d4c6f1e6SMasatake YAMATO 		res = absoluteFilename (file);
846d4c6f1e6SMasatake YAMATO 		slashp [1] = save;
847d4c6f1e6SMasatake YAMATO 	}
848d4c6f1e6SMasatake YAMATO 	return res;
849d4c6f1e6SMasatake YAMATO }
850d4c6f1e6SMasatake YAMATO 
851d4c6f1e6SMasatake YAMATO /* Return a newly allocated string containing the file name of FILE relative
852d4c6f1e6SMasatake YAMATO  * to the absolute directory DIR (which should end with a slash).
853d4c6f1e6SMasatake YAMATO  * Routine adapted from Gnu etags.
854d4c6f1e6SMasatake YAMATO  */
relativeFilename(const char * file,const char * dir)855d4c6f1e6SMasatake YAMATO extern char* relativeFilename (const char *file, const char *dir)
856d4c6f1e6SMasatake YAMATO {
857d4c6f1e6SMasatake YAMATO 	const char *fp, *dp;
858d4c6f1e6SMasatake YAMATO 	char *absdir, *res;
859d4c6f1e6SMasatake YAMATO 	int i;
860d4c6f1e6SMasatake YAMATO 
861d4c6f1e6SMasatake YAMATO 	/* Find the common root of file and dir (with a trailing slash). */
862d4c6f1e6SMasatake YAMATO 	absdir = absoluteFilename (file);
863d4c6f1e6SMasatake YAMATO 	fp = absdir;
864d4c6f1e6SMasatake YAMATO 	dp = dir;
865004231d9SKevin Goodwin 	while (fnmChEq (*fp++, *dp++))
866d4c6f1e6SMasatake YAMATO 		continue;
867d4c6f1e6SMasatake YAMATO 	fp--;
868d4c6f1e6SMasatake YAMATO 	dp--;  /* back to the first differing char */
869d4c6f1e6SMasatake YAMATO 	do
870d4c6f1e6SMasatake YAMATO 	{  /* look at the equal chars until path sep */
871d4c6f1e6SMasatake YAMATO 		if (fp == absdir)
872d4c6f1e6SMasatake YAMATO 			return absdir;  /* first char differs, give up */
873d4c6f1e6SMasatake YAMATO 		fp--;
874d4c6f1e6SMasatake YAMATO 		dp--;
87517e0aa54SMasatake YAMATO 	} while (!isPathSeparator (*fp));
876d4c6f1e6SMasatake YAMATO 
877d4c6f1e6SMasatake YAMATO 	/* Build a sequence of "../" strings for the resulting relative file name.
878d4c6f1e6SMasatake YAMATO 	 */
879d4c6f1e6SMasatake YAMATO 	i = 0;
88017e0aa54SMasatake YAMATO 	while ((dp = strSeparator (dp + 1)) != NULL)
881d4c6f1e6SMasatake YAMATO 		i += 1;
882d4c6f1e6SMasatake YAMATO 	res = xMalloc (3 * i + strlen (fp + 1) + 1, char);
883d4c6f1e6SMasatake YAMATO 	res [0] = '\0';
884d4c6f1e6SMasatake YAMATO 	while (i-- > 0)
88565945ba5SMasatake YAMATO 	{
88665945ba5SMasatake YAMATO 		const char parent [] = {'.', '.', OUTPUT_PATH_SEPARATOR, '\0'};
88765945ba5SMasatake YAMATO 		strcat (res, parent);
88865945ba5SMasatake YAMATO 	}
889d4c6f1e6SMasatake YAMATO 
890d4c6f1e6SMasatake YAMATO 	/* Add the file name relative to the common root of file and dir. */
891d4c6f1e6SMasatake YAMATO 	strcat (res, fp + 1);
892a32a50f1SMasatake YAMATO 	eFree (absdir);
893d4c6f1e6SMasatake YAMATO 
894d4c6f1e6SMasatake YAMATO 	return res;
895d4c6f1e6SMasatake YAMATO }
896d4c6f1e6SMasatake YAMATO 
tempFileFP(const char * const mode,char ** const pName)897*d5355984SMasatake YAMATO extern FILE *tempFileFP (const char *const mode, char **const pName)
898d4c6f1e6SMasatake YAMATO {
899d4c6f1e6SMasatake YAMATO 	char *name;
900d4c6f1e6SMasatake YAMATO 	FILE *fp;
901d4c6f1e6SMasatake YAMATO 	int fd;
902d4c6f1e6SMasatake YAMATO #if defined(HAVE_MKSTEMP)
903d4c6f1e6SMasatake YAMATO 	const char *const pattern = "tags.XXXXXX";
904d4c6f1e6SMasatake YAMATO 	const char *tmpdir = NULL;
905d4c6f1e6SMasatake YAMATO 	fileStatus *file = eStat (ExecutableProgram);
906ea4db1e2SK.Takata # ifdef WIN32
907ea4db1e2SK.Takata 	tmpdir = getenv ("TMP");
908ea4db1e2SK.Takata # else
909d4c6f1e6SMasatake YAMATO 	if (! file->isSetuid)
910d4c6f1e6SMasatake YAMATO 		tmpdir = getenv ("TMPDIR");
911ea4db1e2SK.Takata # endif
912d4c6f1e6SMasatake YAMATO 	if (tmpdir == NULL)
913d4c6f1e6SMasatake YAMATO 		tmpdir = TMPDIR;
914d4c6f1e6SMasatake YAMATO 	name = xMalloc (strlen (tmpdir) + 1 + strlen (pattern) + 1, char);
915d4c6f1e6SMasatake YAMATO 	sprintf (name, "%s%c%s", tmpdir, OUTPUT_PATH_SEPARATOR, pattern);
916d4c6f1e6SMasatake YAMATO 	fd = mkstemp (name);
917d75f1db8SK.Takata # ifdef WIN32
918d75f1db8SK.Takata 	if (fd == -1)
919d75f1db8SK.Takata 	{
920d75f1db8SK.Takata 		/* mkstemp() sometimes fails with unknown reasons.
921d75f1db8SK.Takata 		 * Retry a few times. */
922d75f1db8SK.Takata 		int i;
923d75f1db8SK.Takata 		for (i = 0; i < 5 && fd == -1; i++)
924d75f1db8SK.Takata 		{
925d75f1db8SK.Takata 			sprintf (name, "%s%c%s", tmpdir, OUTPUT_PATH_SEPARATOR, pattern);
926d75f1db8SK.Takata 			fd = mkstemp (name);
927d75f1db8SK.Takata 		}
928d75f1db8SK.Takata 	}
929d75f1db8SK.Takata # endif
930d4c6f1e6SMasatake YAMATO 	eStatFree (file);
931d4c6f1e6SMasatake YAMATO #elif defined(HAVE_TEMPNAM)
932ea4db1e2SK.Takata 	const char *tmpdir = NULL;
933ea4db1e2SK.Takata # ifdef WIN32
934ea4db1e2SK.Takata 	tmpdir = getenv ("TMP");
935ea4db1e2SK.Takata # endif
936ea4db1e2SK.Takata 	if (tmpdir == NULL)
937ea4db1e2SK.Takata 		tmpdir = TMPDIR;
938ea4db1e2SK.Takata 	name = tempnam (tmpdir, "tags");
939d4c6f1e6SMasatake YAMATO 	if (name == NULL)
940d4c6f1e6SMasatake YAMATO 		error (FATAL | PERROR, "cannot allocate temporary file name");
941d4c6f1e6SMasatake YAMATO 	fd = open (name, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
942d4c6f1e6SMasatake YAMATO #else
943d4c6f1e6SMasatake YAMATO 	name = xMalloc (L_tmpnam, char);
944d4c6f1e6SMasatake YAMATO 	if (tmpnam (name) != name)
945d4c6f1e6SMasatake YAMATO 		error (FATAL | PERROR, "cannot assign temporary file name");
946d4c6f1e6SMasatake YAMATO 	fd = open (name, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
947d4c6f1e6SMasatake YAMATO #endif
948d4c6f1e6SMasatake YAMATO 	if (fd == -1)
94909142fccSMasatake YAMATO 		error (FATAL | PERROR, "cannot open temporary file: %s", name);
950d4c6f1e6SMasatake YAMATO 	fp = fdopen (fd, mode);
951d4c6f1e6SMasatake YAMATO 	if (fp == NULL)
952d4c6f1e6SMasatake YAMATO 		error (FATAL | PERROR, "cannot open temporary file");
953d4c6f1e6SMasatake YAMATO 	Assert (*pName == NULL);
954d4c6f1e6SMasatake YAMATO 	*pName = name;
955*d5355984SMasatake YAMATO 	return fp;
956*d5355984SMasatake YAMATO }
957*d5355984SMasatake YAMATO 
tempFile(const char * const mode,char ** const pName)958*d5355984SMasatake YAMATO extern MIO *tempFile (const char *const mode, char **const pName)
959*d5355984SMasatake YAMATO {
960*d5355984SMasatake YAMATO 	FILE *fp = tempFileFP (mode, pName);
961*d5355984SMasatake YAMATO 	return mio_new_fp (fp, fclose);
962d4c6f1e6SMasatake YAMATO }
963