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.
Files changed (138) hide show
  1. data/Gemfile +2 -0
  2. data/Rakefile +23 -0
  3. data/ctags.rb.gemspec +23 -0
  4. data/ext/.gitignore +3 -0
  5. data/ext/extconf.rb +15 -0
  6. data/ext/vendor/exuberant-ctags/.gitignore +6 -0
  7. data/ext/vendor/exuberant-ctags/.indent.pro +31 -0
  8. data/ext/vendor/exuberant-ctags/COPYING +340 -0
  9. data/ext/vendor/exuberant-ctags/EXTENDING.html +386 -0
  10. data/ext/vendor/exuberant-ctags/FAQ +371 -0
  11. data/ext/vendor/exuberant-ctags/INSTALL +215 -0
  12. data/ext/vendor/exuberant-ctags/INSTALL.oth +73 -0
  13. data/ext/vendor/exuberant-ctags/MAINTAINERS +88 -0
  14. data/ext/vendor/exuberant-ctags/Makefile.in +222 -0
  15. data/ext/vendor/exuberant-ctags/NEWS +871 -0
  16. data/ext/vendor/exuberant-ctags/README +73 -0
  17. data/ext/vendor/exuberant-ctags/ant.c +42 -0
  18. data/ext/vendor/exuberant-ctags/argproc.c +505 -0
  19. data/ext/vendor/exuberant-ctags/args.c +274 -0
  20. data/ext/vendor/exuberant-ctags/args.h +63 -0
  21. data/ext/vendor/exuberant-ctags/asm.c +387 -0
  22. data/ext/vendor/exuberant-ctags/asp.c +328 -0
  23. data/ext/vendor/exuberant-ctags/awk.c +81 -0
  24. data/ext/vendor/exuberant-ctags/basic.c +203 -0
  25. data/ext/vendor/exuberant-ctags/beta.c +321 -0
  26. data/ext/vendor/exuberant-ctags/c.c +2932 -0
  27. data/ext/vendor/exuberant-ctags/cobol.c +50 -0
  28. data/ext/vendor/exuberant-ctags/config.h.in +277 -0
  29. data/ext/vendor/exuberant-ctags/configure +7704 -0
  30. data/ext/vendor/exuberant-ctags/configure.ac +532 -0
  31. data/ext/vendor/exuberant-ctags/ctags.1 +1186 -0
  32. data/ext/vendor/exuberant-ctags/ctags.h +28 -0
  33. data/ext/vendor/exuberant-ctags/ctags.html +2087 -0
  34. data/ext/vendor/exuberant-ctags/ctags.spec +40 -0
  35. data/ext/vendor/exuberant-ctags/debug.c +113 -0
  36. data/ext/vendor/exuberant-ctags/debug.h +70 -0
  37. data/ext/vendor/exuberant-ctags/descrip.mms +68 -0
  38. data/ext/vendor/exuberant-ctags/dosbatch.c +42 -0
  39. data/ext/vendor/exuberant-ctags/e_amiga.h +24 -0
  40. data/ext/vendor/exuberant-ctags/e_djgpp.h +47 -0
  41. data/ext/vendor/exuberant-ctags/e_mac.h +143 -0
  42. data/ext/vendor/exuberant-ctags/e_msoft.h +76 -0
  43. data/ext/vendor/exuberant-ctags/e_os2.h +37 -0
  44. data/ext/vendor/exuberant-ctags/e_qdos.h +34 -0
  45. data/ext/vendor/exuberant-ctags/e_riscos.h +58 -0
  46. data/ext/vendor/exuberant-ctags/e_vms.h +31 -0
  47. data/ext/vendor/exuberant-ctags/eiffel.c +1352 -0
  48. data/ext/vendor/exuberant-ctags/entry.c +847 -0
  49. data/ext/vendor/exuberant-ctags/entry.h +103 -0
  50. data/ext/vendor/exuberant-ctags/erlang.c +189 -0
  51. data/ext/vendor/exuberant-ctags/flex.c +2243 -0
  52. data/ext/vendor/exuberant-ctags/fortran.c +2197 -0
  53. data/ext/vendor/exuberant-ctags/general.h +127 -0
  54. data/ext/vendor/exuberant-ctags/get.c +669 -0
  55. data/ext/vendor/exuberant-ctags/get.h +50 -0
  56. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/all-wcprops +47 -0
  57. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/entries +112 -0
  58. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/README.txt.svn-base +5 -0
  59. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regcomp.c.svn-base +3818 -0
  60. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex.c.svn-base +74 -0
  61. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex.h.svn-base +575 -0
  62. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex_internal.c.svn-base +1713 -0
  63. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex_internal.h.svn-base +773 -0
  64. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regexec.c.svn-base +4338 -0
  65. data/ext/vendor/exuberant-ctags/gnu_regex/README.txt +5 -0
  66. data/ext/vendor/exuberant-ctags/gnu_regex/regcomp.c +3818 -0
  67. data/ext/vendor/exuberant-ctags/gnu_regex/regex.c +74 -0
  68. data/ext/vendor/exuberant-ctags/gnu_regex/regex.h +575 -0
  69. data/ext/vendor/exuberant-ctags/gnu_regex/regex_internal.c +1713 -0
  70. data/ext/vendor/exuberant-ctags/gnu_regex/regex_internal.h +773 -0
  71. data/ext/vendor/exuberant-ctags/gnu_regex/regexec.c +4338 -0
  72. data/ext/vendor/exuberant-ctags/html.c +49 -0
  73. data/ext/vendor/exuberant-ctags/jscript.c +1572 -0
  74. data/ext/vendor/exuberant-ctags/keyword.c +258 -0
  75. data/ext/vendor/exuberant-ctags/keyword.h +34 -0
  76. data/ext/vendor/exuberant-ctags/lisp.c +139 -0
  77. data/ext/vendor/exuberant-ctags/lregex.c +704 -0
  78. data/ext/vendor/exuberant-ctags/lua.c +133 -0
  79. data/ext/vendor/exuberant-ctags/mac.c +273 -0
  80. data/ext/vendor/exuberant-ctags/magic.diff +21 -0
  81. data/ext/vendor/exuberant-ctags/main.c +584 -0
  82. data/ext/vendor/exuberant-ctags/main.h +32 -0
  83. data/ext/vendor/exuberant-ctags/maintainer.mak +476 -0
  84. data/ext/vendor/exuberant-ctags/make.c +217 -0
  85. data/ext/vendor/exuberant-ctags/matlab.c +44 -0
  86. data/ext/vendor/exuberant-ctags/mk_bc3.mak +46 -0
  87. data/ext/vendor/exuberant-ctags/mk_bc5.mak +49 -0
  88. data/ext/vendor/exuberant-ctags/mk_djg.mak +18 -0
  89. data/ext/vendor/exuberant-ctags/mk_manx.mak +65 -0
  90. data/ext/vendor/exuberant-ctags/mk_mingw.mak +31 -0
  91. data/ext/vendor/exuberant-ctags/mk_mpw.mak +130 -0
  92. data/ext/vendor/exuberant-ctags/mk_mvc.mak +40 -0
  93. data/ext/vendor/exuberant-ctags/mk_os2.mak +104 -0
  94. data/ext/vendor/exuberant-ctags/mk_qdos.mak +100 -0
  95. data/ext/vendor/exuberant-ctags/mk_sas.mak +63 -0
  96. data/ext/vendor/exuberant-ctags/mkinstalldirs +40 -0
  97. data/ext/vendor/exuberant-ctags/ocaml.c +1842 -0
  98. data/ext/vendor/exuberant-ctags/options.c +1842 -0
  99. data/ext/vendor/exuberant-ctags/options.h +155 -0
  100. data/ext/vendor/exuberant-ctags/parse.c +677 -0
  101. data/ext/vendor/exuberant-ctags/parse.h +129 -0
  102. data/ext/vendor/exuberant-ctags/parsers.h +63 -0
  103. data/ext/vendor/exuberant-ctags/pascal.c +267 -0
  104. data/ext/vendor/exuberant-ctags/perl.c +382 -0
  105. data/ext/vendor/exuberant-ctags/php.c +237 -0
  106. data/ext/vendor/exuberant-ctags/python.c +771 -0
  107. data/ext/vendor/exuberant-ctags/qdos.c +106 -0
  108. data/ext/vendor/exuberant-ctags/read.c +569 -0
  109. data/ext/vendor/exuberant-ctags/read.h +116 -0
  110. data/ext/vendor/exuberant-ctags/readtags.c +959 -0
  111. data/ext/vendor/exuberant-ctags/readtags.h +252 -0
  112. data/ext/vendor/exuberant-ctags/rexx.c +39 -0
  113. data/ext/vendor/exuberant-ctags/routines.c +891 -0
  114. data/ext/vendor/exuberant-ctags/routines.h +134 -0
  115. data/ext/vendor/exuberant-ctags/ruby.c +408 -0
  116. data/ext/vendor/exuberant-ctags/scheme.c +111 -0
  117. data/ext/vendor/exuberant-ctags/sh.c +115 -0
  118. data/ext/vendor/exuberant-ctags/slang.c +41 -0
  119. data/ext/vendor/exuberant-ctags/sml.c +212 -0
  120. data/ext/vendor/exuberant-ctags/sort.c +230 -0
  121. data/ext/vendor/exuberant-ctags/sort.h +32 -0
  122. data/ext/vendor/exuberant-ctags/source.mak +122 -0
  123. data/ext/vendor/exuberant-ctags/sql.c +2112 -0
  124. data/ext/vendor/exuberant-ctags/strlist.c +281 -0
  125. data/ext/vendor/exuberant-ctags/strlist.h +54 -0
  126. data/ext/vendor/exuberant-ctags/tcl.c +116 -0
  127. data/ext/vendor/exuberant-ctags/tex.c +524 -0
  128. data/ext/vendor/exuberant-ctags/verilog.c +340 -0
  129. data/ext/vendor/exuberant-ctags/vhdl.c +835 -0
  130. data/ext/vendor/exuberant-ctags/vim.c +636 -0
  131. data/ext/vendor/exuberant-ctags/vstring.c +232 -0
  132. data/ext/vendor/exuberant-ctags/vstring.h +85 -0
  133. data/ext/vendor/exuberant-ctags/yacc.c +40 -0
  134. data/lib/ctags/exuberant.rb +45 -0
  135. data/lib/ctags/version.rb +3 -0
  136. data/lib/ctags.rb +6 -0
  137. data/test/test_ctags.rb +24 -0
  138. 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: */