ctags.rb 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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: */