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