ctags.rb 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +2 -0
- data/Rakefile +23 -0
- data/ctags.rb.gemspec +23 -0
- data/ext/.gitignore +3 -0
- data/ext/extconf.rb +15 -0
- data/ext/vendor/exuberant-ctags/.gitignore +6 -0
- data/ext/vendor/exuberant-ctags/.indent.pro +31 -0
- data/ext/vendor/exuberant-ctags/COPYING +340 -0
- data/ext/vendor/exuberant-ctags/EXTENDING.html +386 -0
- data/ext/vendor/exuberant-ctags/FAQ +371 -0
- data/ext/vendor/exuberant-ctags/INSTALL +215 -0
- data/ext/vendor/exuberant-ctags/INSTALL.oth +73 -0
- data/ext/vendor/exuberant-ctags/MAINTAINERS +88 -0
- data/ext/vendor/exuberant-ctags/Makefile.in +222 -0
- data/ext/vendor/exuberant-ctags/NEWS +871 -0
- data/ext/vendor/exuberant-ctags/README +73 -0
- data/ext/vendor/exuberant-ctags/ant.c +42 -0
- data/ext/vendor/exuberant-ctags/argproc.c +505 -0
- data/ext/vendor/exuberant-ctags/args.c +274 -0
- data/ext/vendor/exuberant-ctags/args.h +63 -0
- data/ext/vendor/exuberant-ctags/asm.c +387 -0
- data/ext/vendor/exuberant-ctags/asp.c +328 -0
- data/ext/vendor/exuberant-ctags/awk.c +81 -0
- data/ext/vendor/exuberant-ctags/basic.c +203 -0
- data/ext/vendor/exuberant-ctags/beta.c +321 -0
- data/ext/vendor/exuberant-ctags/c.c +2932 -0
- data/ext/vendor/exuberant-ctags/cobol.c +50 -0
- data/ext/vendor/exuberant-ctags/config.h.in +277 -0
- data/ext/vendor/exuberant-ctags/configure +7704 -0
- data/ext/vendor/exuberant-ctags/configure.ac +532 -0
- data/ext/vendor/exuberant-ctags/ctags.1 +1186 -0
- data/ext/vendor/exuberant-ctags/ctags.h +28 -0
- data/ext/vendor/exuberant-ctags/ctags.html +2087 -0
- data/ext/vendor/exuberant-ctags/ctags.spec +40 -0
- data/ext/vendor/exuberant-ctags/debug.c +113 -0
- data/ext/vendor/exuberant-ctags/debug.h +70 -0
- data/ext/vendor/exuberant-ctags/descrip.mms +68 -0
- data/ext/vendor/exuberant-ctags/dosbatch.c +42 -0
- data/ext/vendor/exuberant-ctags/e_amiga.h +24 -0
- data/ext/vendor/exuberant-ctags/e_djgpp.h +47 -0
- data/ext/vendor/exuberant-ctags/e_mac.h +143 -0
- data/ext/vendor/exuberant-ctags/e_msoft.h +76 -0
- data/ext/vendor/exuberant-ctags/e_os2.h +37 -0
- data/ext/vendor/exuberant-ctags/e_qdos.h +34 -0
- data/ext/vendor/exuberant-ctags/e_riscos.h +58 -0
- data/ext/vendor/exuberant-ctags/e_vms.h +31 -0
- data/ext/vendor/exuberant-ctags/eiffel.c +1352 -0
- data/ext/vendor/exuberant-ctags/entry.c +847 -0
- data/ext/vendor/exuberant-ctags/entry.h +103 -0
- data/ext/vendor/exuberant-ctags/erlang.c +189 -0
- data/ext/vendor/exuberant-ctags/flex.c +2243 -0
- data/ext/vendor/exuberant-ctags/fortran.c +2197 -0
- data/ext/vendor/exuberant-ctags/general.h +127 -0
- data/ext/vendor/exuberant-ctags/get.c +669 -0
- data/ext/vendor/exuberant-ctags/get.h +50 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/all-wcprops +47 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/entries +112 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/README.txt.svn-base +5 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regcomp.c.svn-base +3818 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex.c.svn-base +74 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex.h.svn-base +575 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex_internal.c.svn-base +1713 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex_internal.h.svn-base +773 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regexec.c.svn-base +4338 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/README.txt +5 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regcomp.c +3818 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regex.c +74 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regex.h +575 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regex_internal.c +1713 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regex_internal.h +773 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regexec.c +4338 -0
- data/ext/vendor/exuberant-ctags/html.c +49 -0
- data/ext/vendor/exuberant-ctags/jscript.c +1572 -0
- data/ext/vendor/exuberant-ctags/keyword.c +258 -0
- data/ext/vendor/exuberant-ctags/keyword.h +34 -0
- data/ext/vendor/exuberant-ctags/lisp.c +139 -0
- data/ext/vendor/exuberant-ctags/lregex.c +704 -0
- data/ext/vendor/exuberant-ctags/lua.c +133 -0
- data/ext/vendor/exuberant-ctags/mac.c +273 -0
- data/ext/vendor/exuberant-ctags/magic.diff +21 -0
- data/ext/vendor/exuberant-ctags/main.c +584 -0
- data/ext/vendor/exuberant-ctags/main.h +32 -0
- data/ext/vendor/exuberant-ctags/maintainer.mak +476 -0
- data/ext/vendor/exuberant-ctags/make.c +217 -0
- data/ext/vendor/exuberant-ctags/matlab.c +44 -0
- data/ext/vendor/exuberant-ctags/mk_bc3.mak +46 -0
- data/ext/vendor/exuberant-ctags/mk_bc5.mak +49 -0
- data/ext/vendor/exuberant-ctags/mk_djg.mak +18 -0
- data/ext/vendor/exuberant-ctags/mk_manx.mak +65 -0
- data/ext/vendor/exuberant-ctags/mk_mingw.mak +31 -0
- data/ext/vendor/exuberant-ctags/mk_mpw.mak +130 -0
- data/ext/vendor/exuberant-ctags/mk_mvc.mak +40 -0
- data/ext/vendor/exuberant-ctags/mk_os2.mak +104 -0
- data/ext/vendor/exuberant-ctags/mk_qdos.mak +100 -0
- data/ext/vendor/exuberant-ctags/mk_sas.mak +63 -0
- data/ext/vendor/exuberant-ctags/mkinstalldirs +40 -0
- data/ext/vendor/exuberant-ctags/ocaml.c +1842 -0
- data/ext/vendor/exuberant-ctags/options.c +1842 -0
- data/ext/vendor/exuberant-ctags/options.h +155 -0
- data/ext/vendor/exuberant-ctags/parse.c +677 -0
- data/ext/vendor/exuberant-ctags/parse.h +129 -0
- data/ext/vendor/exuberant-ctags/parsers.h +63 -0
- data/ext/vendor/exuberant-ctags/pascal.c +267 -0
- data/ext/vendor/exuberant-ctags/perl.c +382 -0
- data/ext/vendor/exuberant-ctags/php.c +237 -0
- data/ext/vendor/exuberant-ctags/python.c +771 -0
- data/ext/vendor/exuberant-ctags/qdos.c +106 -0
- data/ext/vendor/exuberant-ctags/read.c +569 -0
- data/ext/vendor/exuberant-ctags/read.h +116 -0
- data/ext/vendor/exuberant-ctags/readtags.c +959 -0
- data/ext/vendor/exuberant-ctags/readtags.h +252 -0
- data/ext/vendor/exuberant-ctags/rexx.c +39 -0
- data/ext/vendor/exuberant-ctags/routines.c +891 -0
- data/ext/vendor/exuberant-ctags/routines.h +134 -0
- data/ext/vendor/exuberant-ctags/ruby.c +408 -0
- data/ext/vendor/exuberant-ctags/scheme.c +111 -0
- data/ext/vendor/exuberant-ctags/sh.c +115 -0
- data/ext/vendor/exuberant-ctags/slang.c +41 -0
- data/ext/vendor/exuberant-ctags/sml.c +212 -0
- data/ext/vendor/exuberant-ctags/sort.c +230 -0
- data/ext/vendor/exuberant-ctags/sort.h +32 -0
- data/ext/vendor/exuberant-ctags/source.mak +122 -0
- data/ext/vendor/exuberant-ctags/sql.c +2112 -0
- data/ext/vendor/exuberant-ctags/strlist.c +281 -0
- data/ext/vendor/exuberant-ctags/strlist.h +54 -0
- data/ext/vendor/exuberant-ctags/tcl.c +116 -0
- data/ext/vendor/exuberant-ctags/tex.c +524 -0
- data/ext/vendor/exuberant-ctags/verilog.c +340 -0
- data/ext/vendor/exuberant-ctags/vhdl.c +835 -0
- data/ext/vendor/exuberant-ctags/vim.c +636 -0
- data/ext/vendor/exuberant-ctags/vstring.c +232 -0
- data/ext/vendor/exuberant-ctags/vstring.h +85 -0
- data/ext/vendor/exuberant-ctags/yacc.c +40 -0
- data/lib/ctags/exuberant.rb +45 -0
- data/lib/ctags/version.rb +3 -0
- data/lib/ctags.rb +6 -0
- data/test/test_ctags.rb +24 -0
- metadata +233 -0
|
@@ -0,0 +1,891 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* $Id: routines.c 536 2007-06-02 06:09:00Z elliotth $
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2002-2003, Darren Hiebert
|
|
5
|
+
*
|
|
6
|
+
* This source code is released for free distribution under the terms of the
|
|
7
|
+
* GNU General Public License.
|
|
8
|
+
*
|
|
9
|
+
* This module contains a lose assortment of shared functions.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/*
|
|
13
|
+
* INCLUDE FILES
|
|
14
|
+
*/
|
|
15
|
+
#include "general.h" /* must always come first */
|
|
16
|
+
|
|
17
|
+
#ifdef HAVE_STDLIB_H
|
|
18
|
+
# include <stdlib.h> /* to declare malloc (), realloc () */
|
|
19
|
+
#endif
|
|
20
|
+
#include <ctype.h>
|
|
21
|
+
#include <string.h>
|
|
22
|
+
#include <stdarg.h>
|
|
23
|
+
#include <errno.h>
|
|
24
|
+
#include <stdio.h> /* to declare tempnam(), and SEEK_SET (hopefully) */
|
|
25
|
+
|
|
26
|
+
#ifdef HAVE_FCNTL_H
|
|
27
|
+
# include <fcntl.h> /* to declar O_RDWR, O_CREAT, O_EXCL */
|
|
28
|
+
#endif
|
|
29
|
+
#ifdef HAVE_UNISTD_H
|
|
30
|
+
# include <unistd.h> /* to declare mkstemp () */
|
|
31
|
+
#endif
|
|
32
|
+
|
|
33
|
+
/* To declare "struct stat" and stat ().
|
|
34
|
+
*/
|
|
35
|
+
#if defined (HAVE_SYS_TYPES_H)
|
|
36
|
+
# include <sys/types.h>
|
|
37
|
+
#else
|
|
38
|
+
# if defined (HAVE_TYPES_H)
|
|
39
|
+
# include <types.h>
|
|
40
|
+
# endif
|
|
41
|
+
#endif
|
|
42
|
+
#ifdef HAVE_SYS_STAT_H
|
|
43
|
+
# include <sys/stat.h>
|
|
44
|
+
#else
|
|
45
|
+
# ifdef HAVE_STAT_H
|
|
46
|
+
# include <stat.h>
|
|
47
|
+
# endif
|
|
48
|
+
#endif
|
|
49
|
+
|
|
50
|
+
#ifdef HAVE_DOS_H
|
|
51
|
+
# include <dos.h> /* to declare MAXPATH */
|
|
52
|
+
#endif
|
|
53
|
+
#ifdef HAVE_DIRECT_H
|
|
54
|
+
# include <direct.h> /* to _getcwd */
|
|
55
|
+
#endif
|
|
56
|
+
#ifdef HAVE_DIR_H
|
|
57
|
+
# include <dir.h> /* to declare findfirst() and findnext() */
|
|
58
|
+
#endif
|
|
59
|
+
#ifdef HAVE_IO_H
|
|
60
|
+
# include <io.h> /* to declare open() */
|
|
61
|
+
#endif
|
|
62
|
+
#include "debug.h"
|
|
63
|
+
#include "routines.h"
|
|
64
|
+
|
|
65
|
+
/*
|
|
66
|
+
* MACROS
|
|
67
|
+
*/
|
|
68
|
+
#ifndef TMPDIR
|
|
69
|
+
# define TMPDIR "/tmp"
|
|
70
|
+
#endif
|
|
71
|
+
|
|
72
|
+
/* File type tests.
|
|
73
|
+
*/
|
|
74
|
+
#ifndef S_ISREG
|
|
75
|
+
# if defined (S_IFREG) && ! defined (AMIGA)
|
|
76
|
+
# define S_ISREG(mode) ((mode) & S_IFREG)
|
|
77
|
+
# else
|
|
78
|
+
# define S_ISREG(mode) TRUE /* assume regular file */
|
|
79
|
+
# endif
|
|
80
|
+
#endif
|
|
81
|
+
|
|
82
|
+
#ifndef S_ISLNK
|
|
83
|
+
# ifdef S_IFLNK
|
|
84
|
+
# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
|
|
85
|
+
# else
|
|
86
|
+
# define S_ISLNK(mode) FALSE /* assume no soft links */
|
|
87
|
+
# endif
|
|
88
|
+
#endif
|
|
89
|
+
|
|
90
|
+
#ifndef S_ISDIR
|
|
91
|
+
# ifdef S_IFDIR
|
|
92
|
+
# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
|
|
93
|
+
# else
|
|
94
|
+
# define S_ISDIR(mode) FALSE /* assume no soft links */
|
|
95
|
+
# endif
|
|
96
|
+
#endif
|
|
97
|
+
|
|
98
|
+
#ifndef S_IFMT
|
|
99
|
+
# define S_IFMT 0
|
|
100
|
+
#endif
|
|
101
|
+
|
|
102
|
+
#ifndef S_IXUSR
|
|
103
|
+
# define S_IXUSR 0
|
|
104
|
+
#endif
|
|
105
|
+
#ifndef S_IXGRP
|
|
106
|
+
# define S_IXGRP 0
|
|
107
|
+
#endif
|
|
108
|
+
#ifndef S_IXOTH
|
|
109
|
+
# define S_IXOTH 0
|
|
110
|
+
#endif
|
|
111
|
+
|
|
112
|
+
#ifndef S_IRUSR
|
|
113
|
+
# define S_IRUSR 0400
|
|
114
|
+
#endif
|
|
115
|
+
#ifndef S_IWUSR
|
|
116
|
+
# define S_IWUSR 0200
|
|
117
|
+
#endif
|
|
118
|
+
|
|
119
|
+
#ifndef S_ISUID
|
|
120
|
+
# define S_ISUID 0
|
|
121
|
+
#endif
|
|
122
|
+
|
|
123
|
+
/* Hack for rediculous practice of Microsoft Visual C++.
|
|
124
|
+
*/
|
|
125
|
+
#if defined (WIN32)
|
|
126
|
+
# if defined (_MSC_VER)
|
|
127
|
+
# define stat _stat
|
|
128
|
+
# define getcwd _getcwd
|
|
129
|
+
# define currentdrive() (_getdrive() + 'A' - 1)
|
|
130
|
+
# define PATH_MAX _MAX_PATH
|
|
131
|
+
# elif defined (__BORLANDC__)
|
|
132
|
+
# define PATH_MAX MAXPATH
|
|
133
|
+
# define currentdrive() (getdisk() + 'A')
|
|
134
|
+
# elif defined (DJGPP)
|
|
135
|
+
# define currentdrive() (getdisk() + 'A')
|
|
136
|
+
# else
|
|
137
|
+
# define currentdrive() 'C'
|
|
138
|
+
# endif
|
|
139
|
+
#endif
|
|
140
|
+
|
|
141
|
+
#ifndef PATH_MAX
|
|
142
|
+
# define PATH_MAX 256
|
|
143
|
+
#endif
|
|
144
|
+
|
|
145
|
+
/*
|
|
146
|
+
* Miscellaneous macros
|
|
147
|
+
*/
|
|
148
|
+
#define selected(var,feature) (((int)(var) & (int)(feature)) == (int)feature)
|
|
149
|
+
|
|
150
|
+
/*
|
|
151
|
+
* DATA DEFINITIONS
|
|
152
|
+
*/
|
|
153
|
+
#if defined (MSDOS_STYLE_PATH)
|
|
154
|
+
const char *const PathDelimiters = ":/\\";
|
|
155
|
+
#elif defined (VMS)
|
|
156
|
+
const char *const PathDelimiters = ":]>";
|
|
157
|
+
#endif
|
|
158
|
+
|
|
159
|
+
char *CurrentDirectory;
|
|
160
|
+
|
|
161
|
+
static const char *ExecutableProgram;
|
|
162
|
+
static const char *ExecutableName;
|
|
163
|
+
|
|
164
|
+
/*
|
|
165
|
+
* FUNCTION PROTOTYPES
|
|
166
|
+
*/
|
|
167
|
+
#ifdef NEED_PROTO_STAT
|
|
168
|
+
extern int stat (const char *, struct stat *);
|
|
169
|
+
#endif
|
|
170
|
+
#ifdef NEED_PROTO_LSTAT
|
|
171
|
+
extern int lstat (const char *, struct stat *);
|
|
172
|
+
#endif
|
|
173
|
+
#if defined (MSDOS) || defined (WIN32) || defined (VMS) || defined (__EMX__) || defined (AMIGA)
|
|
174
|
+
# define lstat(fn,buf) stat(fn,buf)
|
|
175
|
+
#endif
|
|
176
|
+
|
|
177
|
+
/*
|
|
178
|
+
* FUNCTION DEFINITIONS
|
|
179
|
+
*/
|
|
180
|
+
|
|
181
|
+
extern void freeRoutineResources (void)
|
|
182
|
+
{
|
|
183
|
+
if (CurrentDirectory != NULL)
|
|
184
|
+
eFree (CurrentDirectory);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
extern void setExecutableName (const char *const path)
|
|
188
|
+
{
|
|
189
|
+
ExecutableProgram = path;
|
|
190
|
+
ExecutableName = baseFilename (path);
|
|
191
|
+
#ifdef VAXC
|
|
192
|
+
{
|
|
193
|
+
/* remove filetype from executable name */
|
|
194
|
+
char *p = strrchr (ExecutableName, '.');
|
|
195
|
+
if (p != NULL)
|
|
196
|
+
*p = '\0';
|
|
197
|
+
}
|
|
198
|
+
#endif
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
extern const char *getExecutableName (void)
|
|
202
|
+
{
|
|
203
|
+
return ExecutableName;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
extern const char *getExecutablePath (void)
|
|
207
|
+
{
|
|
208
|
+
return ExecutableProgram;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
extern void error (
|
|
212
|
+
const errorSelection selection, const char *const format, ...)
|
|
213
|
+
{
|
|
214
|
+
va_list ap;
|
|
215
|
+
|
|
216
|
+
va_start (ap, format);
|
|
217
|
+
fprintf (errout, "%s: %s", getExecutableName (),
|
|
218
|
+
selected (selection, WARNING) ? "Warning: " : "");
|
|
219
|
+
vfprintf (errout, format, ap);
|
|
220
|
+
if (selected (selection, PERROR))
|
|
221
|
+
#ifdef HAVE_STRERROR
|
|
222
|
+
fprintf (errout, " : %s", strerror (errno));
|
|
223
|
+
#else
|
|
224
|
+
perror (" ");
|
|
225
|
+
#endif
|
|
226
|
+
fputs ("\n", errout);
|
|
227
|
+
va_end (ap);
|
|
228
|
+
if (selected (selection, FATAL))
|
|
229
|
+
exit (1);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/*
|
|
233
|
+
* Memory allocation functions
|
|
234
|
+
*/
|
|
235
|
+
|
|
236
|
+
extern void *eMalloc (const size_t size)
|
|
237
|
+
{
|
|
238
|
+
void *buffer = malloc (size);
|
|
239
|
+
|
|
240
|
+
if (buffer == NULL)
|
|
241
|
+
error (FATAL, "out of memory");
|
|
242
|
+
|
|
243
|
+
return buffer;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
extern void *eCalloc (const size_t count, const size_t size)
|
|
247
|
+
{
|
|
248
|
+
void *buffer = calloc (count, size);
|
|
249
|
+
|
|
250
|
+
if (buffer == NULL)
|
|
251
|
+
error (FATAL, "out of memory");
|
|
252
|
+
|
|
253
|
+
return buffer;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
extern void *eRealloc (void *const ptr, const size_t size)
|
|
257
|
+
{
|
|
258
|
+
void *buffer;
|
|
259
|
+
if (ptr == NULL)
|
|
260
|
+
buffer = eMalloc (size);
|
|
261
|
+
else
|
|
262
|
+
{
|
|
263
|
+
buffer = realloc (ptr, size);
|
|
264
|
+
if (buffer == NULL)
|
|
265
|
+
error (FATAL, "out of memory");
|
|
266
|
+
}
|
|
267
|
+
return buffer;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
extern void eFree (void *const ptr)
|
|
271
|
+
{
|
|
272
|
+
Assert (ptr != NULL);
|
|
273
|
+
free (ptr);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/*
|
|
277
|
+
* String manipulation functions
|
|
278
|
+
*/
|
|
279
|
+
|
|
280
|
+
/*
|
|
281
|
+
* Compare two strings, ignoring case.
|
|
282
|
+
* Return 0 for match, < 0 for smaller, > 0 for bigger
|
|
283
|
+
* Make sure case is folded to uppercase in comparison (like for 'sort -f')
|
|
284
|
+
* This makes a difference when one of the chars lies between upper and lower
|
|
285
|
+
* ie. one of the chars [ \ ] ^ _ ` for ascii. (The '_' in particular !)
|
|
286
|
+
*/
|
|
287
|
+
extern int struppercmp (const char *s1, const char *s2)
|
|
288
|
+
{
|
|
289
|
+
int result;
|
|
290
|
+
do
|
|
291
|
+
{
|
|
292
|
+
result = toupper ((int) *s1) - toupper ((int) *s2);
|
|
293
|
+
} while (result == 0 && *s1++ != '\0' && *s2++ != '\0');
|
|
294
|
+
return result;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
extern int strnuppercmp (const char *s1, const char *s2, size_t n)
|
|
298
|
+
{
|
|
299
|
+
int result;
|
|
300
|
+
do
|
|
301
|
+
{
|
|
302
|
+
result = toupper ((int) *s1) - toupper ((int) *s2);
|
|
303
|
+
} while (result == 0 && --n > 0 && *s1++ != '\0' && *s2++ != '\0');
|
|
304
|
+
return result;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
#ifndef HAVE_STRSTR
|
|
308
|
+
extern char* strstr (const char *str, const char *substr)
|
|
309
|
+
{
|
|
310
|
+
const size_t length = strlen (substr);
|
|
311
|
+
const char *match = NULL;
|
|
312
|
+
const char *p;
|
|
313
|
+
|
|
314
|
+
for (p = str ; *p != '\0' && match == NULL ; ++p)
|
|
315
|
+
if (strncmp (p, substr, length) == 0)
|
|
316
|
+
match = p;
|
|
317
|
+
return (char*) match;
|
|
318
|
+
}
|
|
319
|
+
#endif
|
|
320
|
+
|
|
321
|
+
extern char* eStrdup (const char* str)
|
|
322
|
+
{
|
|
323
|
+
char* result = xMalloc (strlen (str) + 1, char);
|
|
324
|
+
strcpy (result, str);
|
|
325
|
+
return result;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
extern void toLowerString (char* str)
|
|
329
|
+
{
|
|
330
|
+
while (*str != '\0')
|
|
331
|
+
{
|
|
332
|
+
*str = tolower ((int) *str);
|
|
333
|
+
++str;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
extern void toUpperString (char* str)
|
|
338
|
+
{
|
|
339
|
+
while (*str != '\0')
|
|
340
|
+
{
|
|
341
|
+
*str = toupper ((int) *str);
|
|
342
|
+
++str;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/* Newly allocated string containing lower case conversion of a string.
|
|
347
|
+
*/
|
|
348
|
+
extern char* newLowerString (const char* str)
|
|
349
|
+
{
|
|
350
|
+
char* const result = xMalloc (strlen (str) + 1, char);
|
|
351
|
+
int i = 0;
|
|
352
|
+
do
|
|
353
|
+
result [i] = tolower ((int) str [i]);
|
|
354
|
+
while (str [i++] != '\0');
|
|
355
|
+
return result;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/* Newly allocated string containing upper case conversion of a string.
|
|
359
|
+
*/
|
|
360
|
+
extern char* newUpperString (const char* str)
|
|
361
|
+
{
|
|
362
|
+
char* const result = xMalloc (strlen (str) + 1, char);
|
|
363
|
+
int i = 0;
|
|
364
|
+
do
|
|
365
|
+
result [i] = toupper ((int) str [i]);
|
|
366
|
+
while (str [i++] != '\0');
|
|
367
|
+
return result;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/*
|
|
371
|
+
* File system functions
|
|
372
|
+
*/
|
|
373
|
+
|
|
374
|
+
extern void setCurrentDirectory (void)
|
|
375
|
+
{
|
|
376
|
+
#ifndef AMIGA
|
|
377
|
+
char* buf;
|
|
378
|
+
#endif
|
|
379
|
+
if (CurrentDirectory == NULL)
|
|
380
|
+
CurrentDirectory = xMalloc ((size_t) (PATH_MAX + 1), char);
|
|
381
|
+
#ifdef AMIGA
|
|
382
|
+
strcpy (CurrentDirectory, ".");
|
|
383
|
+
#else
|
|
384
|
+
buf = getcwd (CurrentDirectory, PATH_MAX);
|
|
385
|
+
if (buf == NULL)
|
|
386
|
+
perror ("");
|
|
387
|
+
#endif
|
|
388
|
+
if (CurrentDirectory [strlen (CurrentDirectory) - (size_t) 1] !=
|
|
389
|
+
PATH_SEPARATOR)
|
|
390
|
+
{
|
|
391
|
+
sprintf (CurrentDirectory + strlen (CurrentDirectory), "%c",
|
|
392
|
+
OUTPUT_PATH_SEPARATOR);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
#ifdef AMIGA
|
|
397
|
+
static boolean isAmigaDirectory (const char *const name)
|
|
398
|
+
{
|
|
399
|
+
boolean result = FALSE;
|
|
400
|
+
struct FileInfoBlock *const fib = xMalloc (1, struct FileInfoBlock);
|
|
401
|
+
if (fib != NULL)
|
|
402
|
+
{
|
|
403
|
+
const BPTR flock = Lock ((UBYTE *) name, (long) ACCESS_READ);
|
|
404
|
+
|
|
405
|
+
if (flock != (BPTR) NULL)
|
|
406
|
+
{
|
|
407
|
+
if (Examine (flock, fib))
|
|
408
|
+
result = ((fib->fib_DirEntryType >= 0) ? TRUE : FALSE);
|
|
409
|
+
UnLock (flock);
|
|
410
|
+
}
|
|
411
|
+
eFree (fib);
|
|
412
|
+
}
|
|
413
|
+
return result;
|
|
414
|
+
}
|
|
415
|
+
#endif
|
|
416
|
+
|
|
417
|
+
/* For caching of stat() calls */
|
|
418
|
+
extern fileStatus *eStat (const char *const fileName)
|
|
419
|
+
{
|
|
420
|
+
struct stat status;
|
|
421
|
+
static fileStatus file;
|
|
422
|
+
if (file.name == NULL || strcmp (fileName, file.name) != 0)
|
|
423
|
+
{
|
|
424
|
+
eStatFree (&file);
|
|
425
|
+
file.name = eStrdup (fileName);
|
|
426
|
+
if (lstat (file.name, &status) != 0)
|
|
427
|
+
file.exists = FALSE;
|
|
428
|
+
else
|
|
429
|
+
{
|
|
430
|
+
file.isSymbolicLink = (boolean) S_ISLNK (status.st_mode);
|
|
431
|
+
if (file.isSymbolicLink && stat (file.name, &status) != 0)
|
|
432
|
+
file.exists = FALSE;
|
|
433
|
+
else
|
|
434
|
+
{
|
|
435
|
+
file.exists = TRUE;
|
|
436
|
+
#ifdef AMIGA
|
|
437
|
+
file.isDirectory = isAmigaDirectory (file.name);
|
|
438
|
+
#else
|
|
439
|
+
file.isDirectory = (boolean) S_ISDIR (status.st_mode);
|
|
440
|
+
#endif
|
|
441
|
+
file.isNormalFile = (boolean) (S_ISREG (status.st_mode));
|
|
442
|
+
file.isExecutable = (boolean) ((status.st_mode &
|
|
443
|
+
(S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
|
|
444
|
+
file.isSetuid = (boolean) ((status.st_mode & S_ISUID) != 0);
|
|
445
|
+
file.size = status.st_size;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return &file;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
extern void eStatFree (fileStatus *status)
|
|
453
|
+
{
|
|
454
|
+
if (status->name != NULL)
|
|
455
|
+
{
|
|
456
|
+
eFree (status->name);
|
|
457
|
+
status->name = NULL;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
extern boolean doesFileExist (const char *const fileName)
|
|
462
|
+
{
|
|
463
|
+
fileStatus *status = eStat (fileName);
|
|
464
|
+
return status->exists;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
extern boolean isRecursiveLink (const char* const dirName)
|
|
468
|
+
{
|
|
469
|
+
boolean result = FALSE;
|
|
470
|
+
fileStatus *status = eStat (dirName);
|
|
471
|
+
if (status->isSymbolicLink)
|
|
472
|
+
{
|
|
473
|
+
char* const path = absoluteFilename (dirName);
|
|
474
|
+
while (path [strlen (path) - 1] == PATH_SEPARATOR)
|
|
475
|
+
path [strlen (path) - 1] = '\0';
|
|
476
|
+
while (! result && strlen (path) > (size_t) 1)
|
|
477
|
+
{
|
|
478
|
+
char *const separator = strrchr (path, PATH_SEPARATOR);
|
|
479
|
+
if (separator == NULL)
|
|
480
|
+
break;
|
|
481
|
+
else if (separator == path) /* backed up to root directory */
|
|
482
|
+
*(separator + 1) = '\0';
|
|
483
|
+
else
|
|
484
|
+
*separator = '\0';
|
|
485
|
+
result = isSameFile (path, dirName);
|
|
486
|
+
}
|
|
487
|
+
eFree (path);
|
|
488
|
+
}
|
|
489
|
+
return result;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
#ifndef HAVE_FGETPOS
|
|
493
|
+
|
|
494
|
+
extern int fgetpos (FILE *stream, fpos_t *pos)
|
|
495
|
+
{
|
|
496
|
+
int result = 0;
|
|
497
|
+
|
|
498
|
+
*pos = ftell (stream);
|
|
499
|
+
if (*pos == -1L)
|
|
500
|
+
result = -1;
|
|
501
|
+
|
|
502
|
+
return result;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
extern int fsetpos (FILE *stream, fpos_t const *pos)
|
|
506
|
+
{
|
|
507
|
+
return fseek (stream, *pos, SEEK_SET);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
#endif
|
|
511
|
+
|
|
512
|
+
/*
|
|
513
|
+
* Pathname manipulation (O/S dependent!!!)
|
|
514
|
+
*/
|
|
515
|
+
|
|
516
|
+
static boolean isPathSeparator (const int c)
|
|
517
|
+
{
|
|
518
|
+
boolean result;
|
|
519
|
+
#if defined (MSDOS_STYLE_PATH) || defined (VMS)
|
|
520
|
+
result = (boolean) (strchr (PathDelimiters, c) != NULL);
|
|
521
|
+
#else
|
|
522
|
+
result = (boolean) (c == PATH_SEPARATOR);
|
|
523
|
+
#endif
|
|
524
|
+
return result;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
#if ! defined (HAVE_STAT_ST_INO)
|
|
528
|
+
|
|
529
|
+
static void canonicalizePath (char *const path __unused__)
|
|
530
|
+
{
|
|
531
|
+
#if defined (MSDOS_STYLE_PATH)
|
|
532
|
+
char *p;
|
|
533
|
+
for (p = path ; *p != '\0' ; ++p)
|
|
534
|
+
if (isPathSeparator (*p) && *p != ':')
|
|
535
|
+
*p = PATH_SEPARATOR;
|
|
536
|
+
#endif
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
#endif
|
|
540
|
+
|
|
541
|
+
extern boolean isSameFile (const char *const name1, const char *const name2)
|
|
542
|
+
{
|
|
543
|
+
boolean result = FALSE;
|
|
544
|
+
#if defined (HAVE_STAT_ST_INO)
|
|
545
|
+
struct stat stat1, stat2;
|
|
546
|
+
|
|
547
|
+
if (stat (name1, &stat1) == 0 && stat (name2, &stat2) == 0)
|
|
548
|
+
result = (boolean) (stat1.st_ino == stat2.st_ino);
|
|
549
|
+
#else
|
|
550
|
+
{
|
|
551
|
+
char *const n1 = absoluteFilename (name1);
|
|
552
|
+
char *const n2 = absoluteFilename (name2);
|
|
553
|
+
canonicalizePath (n1);
|
|
554
|
+
canonicalizePath (n2);
|
|
555
|
+
# if defined (CASE_INSENSITIVE_FILENAMES)
|
|
556
|
+
result = (boolean) (strcasecmp (n1, n2) == 0);
|
|
557
|
+
#else
|
|
558
|
+
result = (boolean) (strcmp (n1, n2) == 0);
|
|
559
|
+
#endif
|
|
560
|
+
free (n1);
|
|
561
|
+
free (n2);
|
|
562
|
+
}
|
|
563
|
+
#endif
|
|
564
|
+
return result;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
extern const char *baseFilename (const char *const filePath)
|
|
568
|
+
{
|
|
569
|
+
#if defined (MSDOS_STYLE_PATH) || defined (VMS)
|
|
570
|
+
const char *tail = NULL;
|
|
571
|
+
unsigned int i;
|
|
572
|
+
|
|
573
|
+
/* Find whichever of the path delimiters is last.
|
|
574
|
+
*/
|
|
575
|
+
for (i = 0 ; i < strlen (PathDelimiters) ; ++i)
|
|
576
|
+
{
|
|
577
|
+
const char *sep = strrchr (filePath, PathDelimiters [i]);
|
|
578
|
+
|
|
579
|
+
if (sep > tail)
|
|
580
|
+
tail = sep;
|
|
581
|
+
}
|
|
582
|
+
#else
|
|
583
|
+
const char *tail = strrchr (filePath, PATH_SEPARATOR);
|
|
584
|
+
#endif
|
|
585
|
+
if (tail == NULL)
|
|
586
|
+
tail = filePath;
|
|
587
|
+
else
|
|
588
|
+
++tail; /* step past last delimiter */
|
|
589
|
+
#ifdef VAXC
|
|
590
|
+
{
|
|
591
|
+
/* remove version number from filename */
|
|
592
|
+
char *p = strrchr ((char *) tail, ';');
|
|
593
|
+
if (p != NULL)
|
|
594
|
+
*p = '\0';
|
|
595
|
+
}
|
|
596
|
+
#endif
|
|
597
|
+
|
|
598
|
+
return tail;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
extern const char *fileExtension (const char *const fileName)
|
|
602
|
+
{
|
|
603
|
+
const char *extension;
|
|
604
|
+
const char *pDelimiter = NULL;
|
|
605
|
+
const char *const base = baseFilename (fileName);
|
|
606
|
+
#ifdef QDOS
|
|
607
|
+
pDelimiter = strrchr (base, '_');
|
|
608
|
+
#endif
|
|
609
|
+
if (pDelimiter == NULL)
|
|
610
|
+
pDelimiter = strrchr (base, '.');
|
|
611
|
+
|
|
612
|
+
if (pDelimiter == NULL)
|
|
613
|
+
extension = "";
|
|
614
|
+
else
|
|
615
|
+
extension = pDelimiter + 1; /* skip to first char of extension */
|
|
616
|
+
|
|
617
|
+
return extension;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
extern boolean isAbsolutePath (const char *const path)
|
|
621
|
+
{
|
|
622
|
+
boolean result = FALSE;
|
|
623
|
+
#if defined (MSDOS_STYLE_PATH)
|
|
624
|
+
if (isPathSeparator (path [0]))
|
|
625
|
+
result = TRUE;
|
|
626
|
+
else if (isalpha (path [0]) && path [1] == ':')
|
|
627
|
+
{
|
|
628
|
+
if (isPathSeparator (path [2]))
|
|
629
|
+
result = TRUE;
|
|
630
|
+
else
|
|
631
|
+
/* We don't support non-absolute file names with a drive
|
|
632
|
+
* letter, like `d:NAME' (it's too much hassle).
|
|
633
|
+
*/
|
|
634
|
+
error (FATAL,
|
|
635
|
+
"%s: relative file names with drive letters not supported",
|
|
636
|
+
path);
|
|
637
|
+
}
|
|
638
|
+
#elif defined (VMS)
|
|
639
|
+
result = (boolean) (strchr (path, ':') != NULL);
|
|
640
|
+
#else
|
|
641
|
+
result = isPathSeparator (path [0]);
|
|
642
|
+
#endif
|
|
643
|
+
return result;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
extern vString *combinePathAndFile (
|
|
647
|
+
const char *const path, const char *const file)
|
|
648
|
+
{
|
|
649
|
+
vString *const filePath = vStringNew ();
|
|
650
|
+
#ifdef VMS
|
|
651
|
+
const char *const directoryId = strstr (file, ".DIR;1");
|
|
652
|
+
|
|
653
|
+
if (directoryId == NULL)
|
|
654
|
+
{
|
|
655
|
+
const char *const versionId = strchr (file, ';');
|
|
656
|
+
|
|
657
|
+
vStringCopyS (filePath, path);
|
|
658
|
+
if (versionId == NULL)
|
|
659
|
+
vStringCatS (filePath, file);
|
|
660
|
+
else
|
|
661
|
+
vStringNCatS (filePath, file, versionId - file);
|
|
662
|
+
vStringCopyToLower (filePath, filePath);
|
|
663
|
+
}
|
|
664
|
+
else
|
|
665
|
+
{
|
|
666
|
+
/* File really is a directory; append it to the path.
|
|
667
|
+
* Gotcha: doesn't work with logical names.
|
|
668
|
+
*/
|
|
669
|
+
vStringNCopyS (filePath, path, strlen (path) - 1);
|
|
670
|
+
vStringPut (filePath, '.');
|
|
671
|
+
vStringNCatS (filePath, file, directoryId - file);
|
|
672
|
+
if (strchr (path, '[') != NULL)
|
|
673
|
+
vStringPut (filePath, ']');
|
|
674
|
+
else
|
|
675
|
+
vStringPut (filePath, '>');
|
|
676
|
+
vStringTerminate (filePath);
|
|
677
|
+
}
|
|
678
|
+
#else
|
|
679
|
+
const int lastChar = path [strlen (path) - 1];
|
|
680
|
+
boolean terminated = isPathSeparator (lastChar);
|
|
681
|
+
|
|
682
|
+
vStringCopyS (filePath, path);
|
|
683
|
+
if (! terminated)
|
|
684
|
+
{
|
|
685
|
+
vStringPut (filePath, OUTPUT_PATH_SEPARATOR);
|
|
686
|
+
vStringTerminate (filePath);
|
|
687
|
+
}
|
|
688
|
+
vStringCatS (filePath, file);
|
|
689
|
+
#endif
|
|
690
|
+
|
|
691
|
+
return filePath;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/* Return a newly-allocated string whose contents concatenate those of
|
|
695
|
+
* s1, s2, s3.
|
|
696
|
+
* Routine adapted from Gnu etags.
|
|
697
|
+
*/
|
|
698
|
+
static char* concat (const char *s1, const char *s2, const char *s3)
|
|
699
|
+
{
|
|
700
|
+
int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
|
|
701
|
+
char *result = xMalloc (len1 + len2 + len3 + 1, char);
|
|
702
|
+
|
|
703
|
+
strcpy (result, s1);
|
|
704
|
+
strcpy (result + len1, s2);
|
|
705
|
+
strcpy (result + len1 + len2, s3);
|
|
706
|
+
result [len1 + len2 + len3] = '\0';
|
|
707
|
+
|
|
708
|
+
return result;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/* Return a newly allocated string containing the absolute file name of FILE
|
|
712
|
+
* given CWD (which should end with a slash).
|
|
713
|
+
* Routine adapted from Gnu etags.
|
|
714
|
+
*/
|
|
715
|
+
extern char* absoluteFilename (const char *file)
|
|
716
|
+
{
|
|
717
|
+
char *slashp, *cp;
|
|
718
|
+
char *res = NULL;
|
|
719
|
+
if (isAbsolutePath (file))
|
|
720
|
+
{
|
|
721
|
+
#ifdef MSDOS_STYLE_PATH
|
|
722
|
+
if (file [1] == ':')
|
|
723
|
+
res = eStrdup (file);
|
|
724
|
+
else
|
|
725
|
+
{
|
|
726
|
+
char drive [3];
|
|
727
|
+
sprintf (drive, "%c:", currentdrive ());
|
|
728
|
+
res = concat (drive, file, "");
|
|
729
|
+
}
|
|
730
|
+
#else
|
|
731
|
+
res = eStrdup (file);
|
|
732
|
+
#endif
|
|
733
|
+
}
|
|
734
|
+
else
|
|
735
|
+
res = concat (CurrentDirectory, file, "");
|
|
736
|
+
|
|
737
|
+
/* Delete the "/dirname/.." and "/." substrings. */
|
|
738
|
+
slashp = strchr (res, PATH_SEPARATOR);
|
|
739
|
+
while (slashp != NULL && slashp [0] != '\0')
|
|
740
|
+
{
|
|
741
|
+
if (slashp[1] == '.')
|
|
742
|
+
{
|
|
743
|
+
if (slashp [2] == '.' &&
|
|
744
|
+
(slashp [3] == PATH_SEPARATOR || slashp [3] == '\0'))
|
|
745
|
+
{
|
|
746
|
+
cp = slashp;
|
|
747
|
+
do
|
|
748
|
+
cp--;
|
|
749
|
+
while (cp >= res && ! isAbsolutePath (cp));
|
|
750
|
+
if (cp < res)
|
|
751
|
+
cp = slashp;/* the absolute name begins with "/.." */
|
|
752
|
+
#ifdef MSDOS_STYLE_PATH
|
|
753
|
+
/* Under MSDOS and NT we get `d:/NAME' as absolute file name,
|
|
754
|
+
* so the luser could say `d:/../NAME'. We silently treat this
|
|
755
|
+
* as `d:/NAME'.
|
|
756
|
+
*/
|
|
757
|
+
else if (cp [0] != PATH_SEPARATOR)
|
|
758
|
+
cp = slashp;
|
|
759
|
+
#endif
|
|
760
|
+
strcpy (cp, slashp + 3);
|
|
761
|
+
slashp = cp;
|
|
762
|
+
continue;
|
|
763
|
+
}
|
|
764
|
+
else if (slashp [2] == PATH_SEPARATOR || slashp [2] == '\0')
|
|
765
|
+
{
|
|
766
|
+
strcpy (slashp, slashp + 2);
|
|
767
|
+
continue;
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
slashp = strchr (slashp + 1, PATH_SEPARATOR);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
if (res [0] == '\0')
|
|
774
|
+
return eStrdup ("/");
|
|
775
|
+
else
|
|
776
|
+
{
|
|
777
|
+
#ifdef MSDOS_STYLE_PATH
|
|
778
|
+
/* Canonicalize drive letter case. */
|
|
779
|
+
if (res [1] == ':' && islower (res [0]))
|
|
780
|
+
res [0] = toupper (res [0]);
|
|
781
|
+
#endif
|
|
782
|
+
|
|
783
|
+
return res;
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
/* Return a newly allocated string containing the absolute file name of dir
|
|
788
|
+
* where `file' resides given `CurrentDirectory'.
|
|
789
|
+
* Routine adapted from Gnu etags.
|
|
790
|
+
*/
|
|
791
|
+
extern char* absoluteDirname (char *file)
|
|
792
|
+
{
|
|
793
|
+
char *slashp, *res;
|
|
794
|
+
char save;
|
|
795
|
+
slashp = strrchr (file, PATH_SEPARATOR);
|
|
796
|
+
if (slashp == NULL)
|
|
797
|
+
res = eStrdup (CurrentDirectory);
|
|
798
|
+
else
|
|
799
|
+
{
|
|
800
|
+
save = slashp [1];
|
|
801
|
+
slashp [1] = '\0';
|
|
802
|
+
res = absoluteFilename (file);
|
|
803
|
+
slashp [1] = save;
|
|
804
|
+
}
|
|
805
|
+
return res;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
/* Return a newly allocated string containing the file name of FILE relative
|
|
809
|
+
* to the absolute directory DIR (which should end with a slash).
|
|
810
|
+
* Routine adapted from Gnu etags.
|
|
811
|
+
*/
|
|
812
|
+
extern char* relativeFilename (const char *file, const char *dir)
|
|
813
|
+
{
|
|
814
|
+
const char *fp, *dp;
|
|
815
|
+
char *absdir, *res;
|
|
816
|
+
int i;
|
|
817
|
+
|
|
818
|
+
/* Find the common root of file and dir (with a trailing slash). */
|
|
819
|
+
absdir = absoluteFilename (file);
|
|
820
|
+
fp = absdir;
|
|
821
|
+
dp = dir;
|
|
822
|
+
while (*fp++ == *dp++)
|
|
823
|
+
continue;
|
|
824
|
+
fp--;
|
|
825
|
+
dp--; /* back to the first differing char */
|
|
826
|
+
do
|
|
827
|
+
{ /* look at the equal chars until path sep */
|
|
828
|
+
if (fp == absdir)
|
|
829
|
+
return absdir; /* first char differs, give up */
|
|
830
|
+
fp--;
|
|
831
|
+
dp--;
|
|
832
|
+
} while (*fp != PATH_SEPARATOR);
|
|
833
|
+
|
|
834
|
+
/* Build a sequence of "../" strings for the resulting relative file name.
|
|
835
|
+
*/
|
|
836
|
+
i = 0;
|
|
837
|
+
while ((dp = strchr (dp + 1, PATH_SEPARATOR)) != NULL)
|
|
838
|
+
i += 1;
|
|
839
|
+
res = xMalloc (3 * i + strlen (fp + 1) + 1, char);
|
|
840
|
+
res [0] = '\0';
|
|
841
|
+
while (i-- > 0)
|
|
842
|
+
strcat (res, "../");
|
|
843
|
+
|
|
844
|
+
/* Add the file name relative to the common root of file and dir. */
|
|
845
|
+
strcat (res, fp + 1);
|
|
846
|
+
free (absdir);
|
|
847
|
+
|
|
848
|
+
return res;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
extern FILE *tempFile (const char *const mode, char **const pName)
|
|
852
|
+
{
|
|
853
|
+
char *name;
|
|
854
|
+
FILE *fp;
|
|
855
|
+
int fd;
|
|
856
|
+
#if defined(HAVE_MKSTEMP)
|
|
857
|
+
const char *const pattern = "tags.XXXXXX";
|
|
858
|
+
const char *tmpdir = NULL;
|
|
859
|
+
fileStatus *file = eStat (ExecutableProgram);
|
|
860
|
+
if (! file->isSetuid)
|
|
861
|
+
tmpdir = getenv ("TMPDIR");
|
|
862
|
+
if (tmpdir == NULL)
|
|
863
|
+
tmpdir = TMPDIR;
|
|
864
|
+
name = xMalloc (strlen (tmpdir) + 1 + strlen (pattern) + 1, char);
|
|
865
|
+
sprintf (name, "%s%c%s", tmpdir, OUTPUT_PATH_SEPARATOR, pattern);
|
|
866
|
+
fd = mkstemp (name);
|
|
867
|
+
eStatFree (file);
|
|
868
|
+
#elif defined(HAVE_TEMPNAM)
|
|
869
|
+
name = tempnam (TMPDIR, "tags");
|
|
870
|
+
if (name == NULL)
|
|
871
|
+
error (FATAL | PERROR, "cannot allocate temporary file name");
|
|
872
|
+
fd = open (name, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
|
|
873
|
+
#else
|
|
874
|
+
name = xMalloc (L_tmpnam, char);
|
|
875
|
+
if (tmpnam (name) != name)
|
|
876
|
+
error (FATAL | PERROR, "cannot assign temporary file name");
|
|
877
|
+
fd = open (name, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
|
|
878
|
+
#endif
|
|
879
|
+
if (fd == -1)
|
|
880
|
+
error (FATAL | PERROR, "cannot open temporary file");
|
|
881
|
+
fp = fdopen (fd, mode);
|
|
882
|
+
if (fp == NULL)
|
|
883
|
+
error (FATAL | PERROR, "cannot open temporary file");
|
|
884
|
+
DebugStatement (
|
|
885
|
+
debugPrintf (DEBUG_STATUS, "opened temporary file %s\n", name); )
|
|
886
|
+
Assert (*pName == NULL);
|
|
887
|
+
*pName = name;
|
|
888
|
+
return fp;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
/* vi:set tabstop=4 shiftwidth=4: */
|