~ubuntu-branches/ubuntu/utopic/geany/utopic

« back to all changes in this revision

Viewing changes to .pc/git_build_with_latest_glib.patch/tagmanager/ctags.c

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha
  • Date: 2013-04-19 21:00:25 UTC
  • Revision ID: package-import@ubuntu.com-20130419210025-tsuvhqufntxj5rsy
Tags: 1.22+dfsg-2ubuntu1
* debian/patches/git_build_with_latest_glib.patch:
  - Backport patch from 1.23 to fix build failure with glib 2.36

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
*
 
3
*   Copyright (c) 1996-2001, Darren Hiebert
 
4
*
 
5
*   Author: Darren Hiebert <darren@hiebert.com>, <darren@hiwaay.net>
 
6
*           http://darren.hiebert.com
 
7
*
 
8
*   This source code is released for free distribution under the terms of the
 
9
*   GNU General Public License. It is provided on an as-is basis and no
 
10
*   responsibility is accepted for its failure to perform as expected.
 
11
*
 
12
*   This is a reimplementation of the ctags (1) program. It is an attempt to
 
13
*   provide a fully featured ctags program which is free of the limitations
 
14
*   which most (all?) others are subject to.
 
15
*
 
16
*   This module contains top level start-up and portability functions.
 
17
*/
 
18
 
 
19
/*
 
20
*   INCLUDE FILES
 
21
*/
 
22
#include "general.h"    /* must always come first */
 
23
#include <glib.h>
 
24
#include <glib/gstdio.h>
 
25
 
 
26
#ifdef HAVE_STDLIB_H
 
27
# include <stdlib.h>            /* to declare malloc (), realloc () */
 
28
#endif
 
29
#include <string.h>
 
30
#include <errno.h>
 
31
#include <ctype.h>
 
32
 
 
33
#include <stdio.h>              /* to declare SEEK_SET (hopefully) */
 
34
# include <fcntl.h>             /* to declar O_RDWR, O_CREAT, O_EXCL */
 
35
# include <unistd.h>            /* to declare mkstemp () */
 
36
 
 
37
#ifdef AMIGA
 
38
# include <dos/dosasl.h>        /* for struct AnchorPath */
 
39
# include <clib/dos_protos.h>   /* function prototypes */
 
40
# define ANCHOR_BUF_SIZE 512
 
41
# define ANCHOR_SIZE (sizeof (struct AnchorPath) + ANCHOR_BUF_SIZE)
 
42
# ifdef __SASC
 
43
   extern struct DosLibrary *DOSBase;
 
44
#  include <pragmas/dos_pragmas.h>
 
45
# endif
 
46
#endif
 
47
 
 
48
#include <stdarg.h>
 
49
 
 
50
 
 
51
 
 
52
/*  To declare "struct stat" and stat ().
 
53
 */
 
54
#if defined (HAVE_SYS_TYPES_H)
 
55
# include <sys/types.h>
 
56
#else
 
57
# if defined (HAVE_TYPES_H)
 
58
#  include <types.h>
 
59
# endif
 
60
#endif
 
61
#ifdef HAVE_SYS_STAT_H
 
62
# include <sys/stat.h>
 
63
#else
 
64
# ifdef HAVE_STAT_H
 
65
#  include <stat.h>
 
66
# endif
 
67
#endif
 
68
 
 
69
/*  To provide directory searching for recursion feature.
 
70
 */
 
71
#ifdef HAVE_DIRENT_H
 
72
# ifdef __BORLANDC__
 
73
#  define boolean BORLAND_boolean
 
74
# endif
 
75
# include <dirent.h>
 
76
# undef boolean
 
77
#endif
 
78
#ifdef HAVE_DIRECT_H
 
79
# include <direct.h>    /* to _getcwd */
 
80
#endif
 
81
#ifdef HAVE_DOS_H
 
82
# include <dos.h>       /* to declare FA_DIREC */
 
83
#endif
 
84
#ifdef HAVE_DIR_H
 
85
# include <dir.h>       /* to declare findfirst () and findnext () */
 
86
#endif
 
87
#ifdef HAVE_IO_H
 
88
# include <io.h>        /* to declare _finddata_t in MSVC++ 4.x */
 
89
#endif
 
90
 
 
91
/*  To provide timings features if available.
 
92
 */
 
93
#ifdef HAVE_CLOCK
 
94
# ifdef HAVE_TIME_H
 
95
#  include <time.h>
 
96
# endif
 
97
#else
 
98
# ifdef HAVE_TIMES
 
99
#  ifdef HAVE_SYS_TIMES_H
 
100
#   include <sys/times.h>
 
101
#  endif
 
102
# endif
 
103
#endif
 
104
 
 
105
#include "entry.h"
 
106
#include "keyword.h"
 
107
#include "main.h"
 
108
#include "options.h"
 
109
#include "parse.h"
 
110
#include "read.h"
 
111
#include "vstring.h"
 
112
 
 
113
#ifdef TRAP_MEMORY_CALLS
 
114
# include "safe_malloc.h"
 
115
#endif
 
116
 
 
117
/*
 
118
*   MACROS
 
119
*/
 
120
 
 
121
/*
 
122
 *  Miscellaneous macros
 
123
 */
 
124
#define selected(var,feature)   (((int)(var) & (int)(feature)) == (int)feature)
 
125
#define plural(value)           (((unsigned long)(value) == 1L) ? "" : "s")
 
126
 
 
127
/*
 
128
 *  Portability macros
 
129
 */
 
130
#ifndef PATH_SEPARATOR
 
131
# if defined (MSDOS_STYLE_PATH)
 
132
#  define PATH_SEPARATOR '\\'
 
133
# elif defined (QDOS)
 
134
#  define PATH_SEPARATOR '_'
 
135
# else
 
136
#  define PATH_SEPARATOR '/'
 
137
# endif
 
138
#endif
 
139
 
 
140
#if defined (MSDOS_STYLE_PATH) && defined (UNIX_PATH_SEPARATOR)
 
141
# define OUTPUT_PATH_SEPARATOR  '/'
 
142
#else
 
143
# define OUTPUT_PATH_SEPARATOR  PATH_SEPARATOR
 
144
#endif
 
145
 
 
146
/*  File type tests.
 
147
 */
 
148
#ifndef S_ISREG
 
149
# if defined (S_IFREG) && ! defined (AMIGA)
 
150
#  define S_ISREG(mode)     ((mode) & S_IFREG)
 
151
# else
 
152
#  define S_ISREG(mode)     TRUE        /* assume regular file */
 
153
# endif
 
154
#endif
 
155
 
 
156
#ifndef S_ISLNK
 
157
# ifdef S_IFLNK
 
158
#  define S_ISLNK(mode)     (((mode) & S_IFMT) == S_IFLNK)
 
159
# else
 
160
#  define S_ISLNK(mode)     FALSE       /* assume no soft links */
 
161
# endif
 
162
#endif
 
163
 
 
164
#ifndef S_ISDIR
 
165
# ifdef S_IFDIR
 
166
#  define S_ISDIR(mode)     (((mode) & S_IFMT) == S_IFDIR)
 
167
# else
 
168
#  define S_ISDIR(mode)     FALSE       /* assume no soft links */
 
169
# endif
 
170
#endif
 
171
 
 
172
#ifndef S_IXUSR
 
173
# define S_IXUSR 0
 
174
#endif
 
175
#ifndef S_IXGRP
 
176
# define S_IXGRP 0
 
177
#endif
 
178
#ifndef S_IXOTH
 
179
# define S_IXOTH 0
 
180
#endif
 
181
 
 
182
#ifndef S_IRUSR
 
183
# define S_IRUSR 0400
 
184
#endif
 
185
#ifndef S_IWUSR
 
186
# define S_IWUSR 0200
 
187
#endif
 
188
 
 
189
/*  Hack for rediculous practice of Microsoft Visual C++.
 
190
 */
 
191
#if defined (WIN32)
 
192
# if defined (_MSC_VER)
 
193
#  define stat    _stat
 
194
#  define getcwd  _getcwd
 
195
#  define PATH_MAX  _MAX_PATH
 
196
# elif defined (__BORLANDC__)
 
197
#  define PATH_MAX  MAXPATH
 
198
# endif
 
199
#endif
 
200
 
 
201
#ifndef PATH_MAX
 
202
# define PATH_MAX 256
 
203
#endif
 
204
 
 
205
/*
 
206
*   DATA DEFINITIONS
 
207
*/
 
208
#if defined (MSDOS_STYLE_PATH)
 
209
static const char PathDelimiters [] = ":/\\";
 
210
#elif defined (VMS)
 
211
static const char PathDelimiters [] = ":]>";
 
212
#endif
 
213
 
 
214
#ifndef TMPDIR
 
215
# define TMPDIR "/tmp"
 
216
#endif
 
217
 
 
218
char *CurrentDirectory = NULL;
 
219
#ifdef HAVE_MKSTEMP
 
220
static const char *ExecutableProgram = NULL;
 
221
#endif
 
222
static const char *ExecutableName = "geany";
 
223
static stringList* Excluded = NULL;
 
224
 
 
225
static struct { long files, lines, bytes; } Totals = { 0, 0, 0 };
 
226
 
 
227
#ifdef AMIGA
 
228
# include "ctags.h"
 
229
  static const char *VERsion = "$VER: "PROGRAM_NAME" "PROGRAM_VERSION" "
 
230
# ifdef __SASC
 
231
  __AMIGADATE__
 
232
# else
 
233
  __DATE__
 
234
# endif
 
235
  " "AUTHOR_NAME" $";
 
236
#endif
 
237
 
 
238
/*
 
239
*   FUNCTION PROTOTYPES
 
240
*/
 
241
#ifdef NEED_PROTO_STAT
 
242
extern int stat (const char *, struct stat *);
 
243
#endif
 
244
#ifdef NEED_PROTO_LSTAT
 
245
extern int lstat (const char *, struct stat *);
 
246
#endif
 
247
 
 
248
#if 0
 
249
static boolean createTagsForEntry (const char *const entryName);
 
250
#endif
 
251
 
 
252
/*
 
253
*   FUNCTION DEFINITIONS
 
254
*/
 
255
 
 
256
extern const char *getExecutableName (void)
 
257
{
 
258
    return ExecutableName;
 
259
}
 
260
 
 
261
#if 0
 
262
static void setCurrentDirectory (void)
 
263
{
 
264
#ifdef AMIGA
 
265
    char* const cwd = eStrdup (".");
 
266
#else
 
267
    char* const cwd = getcwd (NULL, PATH_MAX);
 
268
#endif
 
269
    CurrentDirectory = xMalloc (strlen (cwd) + 2, char);
 
270
    if (cwd [strlen (cwd) - (size_t) 1] == PATH_SEPARATOR)
 
271
        strcpy (CurrentDirectory, cwd);
 
272
    else
 
273
        sprintf (CurrentDirectory, "%s%c", cwd, OUTPUT_PATH_SEPARATOR);
 
274
    free (cwd);
 
275
}
 
276
#endif
 
277
 
 
278
extern void error (const errorSelection selection,
 
279
                   const char *const format, ...)
 
280
{
 
281
    va_list ap;
 
282
 
 
283
    va_start (ap, format);
 
284
    fprintf (errout, "%s: %s", getExecutableName (),
 
285
            selected (selection, WARNING) ? "Warning: " : "");
 
286
    vfprintf (errout, format, ap);
 
287
    if (selected (selection, PERROR))
 
288
        fprintf (errout, " : %s", g_strerror (errno));
 
289
    fputs ("\n", errout);
 
290
    va_end (ap);
 
291
    if (selected (selection, FATAL))
 
292
        exit (1);
 
293
}
 
294
 
 
295
#ifndef HAVE_STRICMP
 
296
extern int stricmp (const char *s1, const char *s2)
 
297
{
 
298
    int result;
 
299
    do
 
300
    {
 
301
        result = toupper ((int) *s1) - toupper ((int) *s2);
 
302
    } while (result == 0  &&  *s1++ != '\0'  &&  *s2++ != '\0');
 
303
    return result;
 
304
}
 
305
#endif
 
306
 
 
307
#ifndef HAVE_STRNICMP
 
308
extern int strnicmp (const char *s1, const char *s2, size_t n)
 
309
{
 
310
    int result;
 
311
    do
 
312
    {
 
313
        result = toupper ((int) *s1) - toupper ((int) *s2);
 
314
    } while (result == 0  &&  --n > 0  &&  *s1++ != '\0'  &&  *s2++ != '\0');
 
315
    return result;
 
316
}
 
317
#endif
 
318
 
 
319
#ifndef HAVE_STRSTR
 
320
extern char* strstr (const char *str, const char *substr)
 
321
{
 
322
    const size_t length = strlen (substr);
 
323
    const char *match = NULL;
 
324
    const char *p;
 
325
 
 
326
    for (p = str  ;  *p != '\0'  &&  match == NULL  ;  ++p)
 
327
        if (strncmp (p, substr, length) == 0)
 
328
            match = p;
 
329
    return (char*) match;
 
330
}
 
331
#endif
 
332
 
 
333
extern char* eStrdup (const char* str)
 
334
{
 
335
    char* result = xMalloc (strlen (str) + 1, char);
 
336
    strcpy (result, str);
 
337
    return result;
 
338
}
 
339
 
 
340
extern void *eMalloc (const size_t size)
 
341
{
 
342
    void *buffer = g_malloc (size);
 
343
 
 
344
    if (buffer == NULL)
 
345
        error (FATAL, "out of memory");
 
346
 
 
347
    return buffer;
 
348
}
 
349
 
 
350
extern void *eCalloc (const size_t count, const size_t size)
 
351
{
 
352
    void *buffer = calloc (count, size);
 
353
 
 
354
    if (buffer == NULL)
 
355
        error (FATAL, "out of memory");
 
356
 
 
357
    return buffer;
 
358
}
 
359
 
 
360
extern void *eRealloc (void *const ptr, const size_t size)
 
361
{
 
362
    void *buffer;
 
363
    if (ptr == NULL)
 
364
        buffer = eMalloc (size);
 
365
    else
 
366
    {
 
367
        buffer = g_realloc (ptr, size);
 
368
        if (buffer == NULL)
 
369
            error (FATAL, "out of memory");
 
370
    }
 
371
    return buffer;
 
372
}
 
373
 
 
374
extern void eFree (void *const ptr)
 
375
{
 
376
    if (ptr != NULL)
 
377
        free (ptr);
 
378
}
 
379
 
 
380
extern void toLowerString (char* str)
 
381
{
 
382
    while (*str != '\0')
 
383
    {
 
384
        *str = tolower ((int) *str);
 
385
        ++str;
 
386
    }
 
387
}
 
388
 
 
389
extern void toUpperString (char* str)
 
390
{
 
391
    while (*str != '\0')
 
392
    {
 
393
        *str = toupper ((int) *str);
 
394
        ++str;
 
395
    }
 
396
}
 
397
 
 
398
/*  Newly allocated string containing lower case conversion of a string.
 
399
 */
 
400
extern char* newLowerString (const char* str)
 
401
{
 
402
    char* const result = xMalloc (strlen (str) + 1, char);
 
403
    int i = 0;
 
404
    do
 
405
        result [i] = tolower ((int) str [i]);
 
406
    while (str [i++] != '\0');
 
407
    return result;
 
408
}
 
409
 
 
410
/*  Newly allocated string containing upper case conversion of a string.
 
411
 */
 
412
extern char* newUpperString (const char* str)
 
413
{
 
414
    char* const result = xMalloc (strlen (str) + 1, char);
 
415
    int i = 0;
 
416
    do
 
417
        result [i] = toupper ((int) str [i]);
 
418
    while (str [i++] != '\0');
 
419
    return result;
 
420
}
 
421
 
 
422
extern long unsigned int getFileSize (const char *const name)
 
423
{
 
424
    struct stat fileStatus;
 
425
    unsigned long size = 0;
 
426
 
 
427
    if (g_stat (name, &fileStatus) == 0)
 
428
        size = fileStatus.st_size;
 
429
 
 
430
    return size;
 
431
}
 
432
 
 
433
#if 0
 
434
static boolean isSymbolicLink (const char *const name)
 
435
{
 
436
#if defined (MSDOS) || defined (WIN32) || defined (VMS) || defined (__EMX__) || defined (AMIGA)
 
437
    return FALSE;
 
438
#else
 
439
    struct stat fileStatus;
 
440
    boolean result = FALSE;
 
441
 
 
442
    if (g_lstat (name, &fileStatus) == 0)
 
443
        result = (boolean) (S_ISLNK (fileStatus.st_mode));
 
444
 
 
445
    return result;
 
446
#endif
 
447
}
 
448
 
 
449
static boolean isNormalFile (const char *const name)
 
450
{
 
451
    struct stat fileStatus;
 
452
    boolean result = FALSE;
 
453
 
 
454
    if (g_stat (name, &fileStatus) == 0)
 
455
        result = (boolean) (S_ISREG (fileStatus.st_mode));
 
456
 
 
457
    return result;
 
458
}
 
459
#endif
 
460
 
 
461
extern boolean isExecutable (const char *const name)
 
462
{
 
463
    struct stat fileStatus;
 
464
    boolean result = FALSE;
 
465
 
 
466
    if (g_stat (name, &fileStatus) == 0)
 
467
        result = (boolean) ((fileStatus.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) != 0);
 
468
 
 
469
    return result;
 
470
}
 
471
 
 
472
extern boolean isSameFile (const char *const name1, const char *const name2)
 
473
{
 
474
    boolean result = FALSE;
 
475
#ifdef HAVE_STAT_ST_INO
 
476
    struct stat stat1, stat2;
 
477
 
 
478
    if (g_stat (name1, &stat1) == 0  &&  g_stat (name2, &stat2) == 0)
 
479
        result = (boolean) (stat1.st_ino == stat2.st_ino);
 
480
#endif
 
481
    return result;
 
482
}
 
483
 
 
484
#ifdef HAVE_MKSTEMP
 
485
 
 
486
static boolean isSetUID (const char *const name)
 
487
{
 
488
#if defined (VMS) || defined (MSDOS) || defined (WIN32) || defined (__EMX__) || defined (AMIGA)
 
489
    return FALSE;
 
490
#else
 
491
    struct stat fileStatus;
 
492
    boolean result = FALSE;
 
493
 
 
494
    if (g_stat (name, &fileStatus) == 0)
 
495
        result = (boolean) ((fileStatus.st_mode & S_ISUID) != 0);
 
496
 
 
497
    return result;
 
498
#endif
 
499
}
 
500
 
 
501
#endif
 
502
 
 
503
#if 0
 
504
static boolean isDirectory (const char *const name)
 
505
{
 
506
    boolean result = FALSE;
 
507
#ifdef AMIGA
 
508
    struct FileInfoBlock *const fib = xMalloc (1, struct FileInfoBlock);
 
509
 
 
510
    if (fib != NULL)
 
511
    {
 
512
        const BPTR flock = Lock ((UBYTE *) name, (long) ACCESS_READ);
 
513
 
 
514
        if (flock != (BPTR) NULL)
 
515
        {
 
516
            if (Examine (flock, fib))
 
517
                result = ((fib->fib_DirEntryType >= 0) ? TRUE : FALSE);
 
518
            UnLock (flock);
 
519
        }
 
520
        eFree (fib);
 
521
    }
 
522
#else
 
523
    struct stat fileStatus;
 
524
 
 
525
    if (g_stat (name, &fileStatus) == 0)
 
526
        result = (boolean) S_ISDIR (fileStatus.st_mode);
 
527
#endif
 
528
    return result;
 
529
}
 
530
#endif
 
531
 
 
532
extern boolean doesFileExist (const char *const fileName)
 
533
{
 
534
    struct stat fileStatus;
 
535
 
 
536
    return (boolean) (g_stat (fileName, &fileStatus) == 0);
 
537
}
 
538
 
 
539
/*#ifndef HAVE_FGETPOS*/
 
540
/*
 
541
extern int fgetpos ( stream, pos )
 
542
    FILE *const stream;
 
543
    fpos_t *const pos;
 
544
{
 
545
    int result = 0;
 
546
 
 
547
    *pos = ftell (stream);
 
548
    if (*pos == -1L)
 
549
        result = -1;
 
550
 
 
551
    return result;
 
552
}
 
553
 
 
554
extern int fsetpos ( stream, pos )
 
555
    FILE *const stream;
 
556
    fpos_t *const pos;
 
557
{
 
558
    return fseek (stream, *pos, SEEK_SET);
 
559
}
 
560
*/
 
561
/*#endif*/
 
562
 
 
563
extern void addTotals (const unsigned int files,
 
564
                       const long unsigned int lines,
 
565
                       const long unsigned int bytes)
 
566
{
 
567
    Totals.files += files;
 
568
    Totals.lines += lines;
 
569
    Totals.bytes += bytes;
 
570
}
 
571
 
 
572
extern boolean isDestinationStdout (void)
 
573
{
 
574
    boolean toStdout = FALSE;
 
575
 
 
576
    if (Option.xref  ||  Option.filter  ||
 
577
        (Option.tagFileName != NULL  &&  (strcmp (Option.tagFileName, "-") == 0
 
578
#if defined (VMS)
 
579
    || strcmp (Option.tagFileName, "sys$output") == 0
 
580
#else
 
581
    || strcmp (Option.tagFileName, "/dev/stdout") == 0
 
582
#endif
 
583
        )))
 
584
        toStdout = TRUE;
 
585
    return toStdout;
 
586
}
 
587
 
 
588
extern FILE *tempFile (const char *const mode, char **const pName)
 
589
{
 
590
    char *name;
 
591
    FILE *fp;
 
592
    int fd;
 
593
#ifdef HAVE_MKSTEMP
 
594
    const char *const template = "tags.XXXXXX";
 
595
    const char *tmpdir = NULL;
 
596
    if (! isSetUID (ExecutableProgram))
 
597
        tmpdir = getenv ("TMPDIR");
 
598
    if (tmpdir == NULL)
 
599
        tmpdir = TMPDIR;
 
600
    name = xMalloc (strlen (tmpdir) + 1 + strlen (template) + 1, char);
 
601
    sprintf (name, "%s%c%s", tmpdir, OUTPUT_PATH_SEPARATOR, template);
 
602
#ifdef G_OS_WIN32
 
603
    fd = mkstemps(name, 0);
 
604
#else
 
605
    fd = mkstemp(name);
 
606
#endif
 
607
#else
 
608
    name = xMalloc (L_tmpnam, char);
 
609
    if (tmpnam (name) != name)
 
610
        error (FATAL | PERROR, "cannot assign temporary file name");
 
611
    fd = open (name, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
 
612
#endif
 
613
    if (fd == -1)
 
614
        error (FATAL | PERROR, "cannot open temporary file");
 
615
    fp = fdopen (fd, mode);
 
616
    if (fp == NULL)
 
617
        error (FATAL | PERROR, "cannot open temporary file");
 
618
    DebugStatement (
 
619
        debugPrintf (DEBUG_STATUS, "opened temporary file %s\n", name); )
 
620
    Assert (*pName == NULL);
 
621
    *pName = name;
 
622
    return fp;
 
623
}
 
624
 
 
625
/*
 
626
 *  Pathname manipulation (O/S dependent!!!)
 
627
 */
 
628
 
 
629
extern const char *baseFilename (const char *const filePath)
 
630
{
 
631
#if defined (MSDOS_STYLE_PATH) || defined (VMS)
 
632
    const char *tail = NULL;
 
633
    unsigned int i;
 
634
 
 
635
    /*  Find whichever of the path delimiters is last.
 
636
     */
 
637
    for (i = 0  ;  i < strlen (PathDelimiters)  ;  ++i)
 
638
    {
 
639
        const char *sep = strrchr (filePath, PathDelimiters [i]);
 
640
 
 
641
        if (sep > tail)
 
642
            tail = sep;
 
643
    }
 
644
#else
 
645
    const char *tail = strrchr (filePath, PATH_SEPARATOR);
 
646
#endif
 
647
    if (tail == NULL)
 
648
        tail = filePath;
 
649
    else
 
650
        ++tail;                 /* step past last delimiter */
 
651
#ifdef VAXC
 
652
    {
 
653
        /* remove version number from filename */
 
654
        char *p = strrchr ((char *) tail, ';');
 
655
        if (p != NULL)
 
656
            *p = '\0';
 
657
    }
 
658
#endif
 
659
 
 
660
    return tail;
 
661
}
 
662
 
 
663
extern boolean isAbsolutePath (const char *const path)
 
664
{
 
665
    boolean result = FALSE;
 
666
#if defined (MSDOS_STYLE_PATH)
 
667
    if (strchr (PathDelimiters, path [0]) != NULL)
 
668
        result = TRUE;
 
669
    else if (isalpha (path [0])  &&  path [1] == ':')
 
670
    {
 
671
        if (strchr (PathDelimiters, path [2]) != NULL)
 
672
            result = TRUE;
 
673
        else
 
674
            /*  We don't support non-absolute file names with a drive
 
675
             *  letter, like `d:NAME' (it's too much hassle).
 
676
             */
 
677
            error (FATAL,
 
678
                "%s: relative file names with drive letters not supported",
 
679
                path);
 
680
    }
 
681
#elif defined (VMS)
 
682
    result = (boolean) (strchr (path, ':') != NULL);
 
683
#else
 
684
    result = (boolean) (path [0] == PATH_SEPARATOR);
 
685
#endif
 
686
    return result;
 
687
}
 
688
 
 
689
/* Return a newly-allocated string whose contents concatenate those of
 
690
 * s1, s2, s3.
 
691
 * Routine adapted from Gnu etags.
 
692
 */
 
693
static char* concat (const char *s1, const char *s2, const char *s3)
 
694
{
 
695
  int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
 
696
  char *result = xMalloc (len1 + len2 + len3 + 1, char);
 
697
 
 
698
  strcpy (result, s1);
 
699
  strcpy (result + len1, s2);
 
700
  strcpy (result + len1 + len2, s3);
 
701
  result [len1 + len2 + len3] = '\0';
 
702
 
 
703
  return result;
 
704
}
 
705
 
 
706
/* Return a newly allocated string containing the absolute file name of FILE
 
707
 * given CWD (which should end with a slash).
 
708
 * Routine adapted from Gnu etags.
 
709
 */
 
710
static char* absoluteFilename (const char *file)
 
711
{
 
712
    char *slashp, *cp;
 
713
    char *res = NULL;
 
714
 
 
715
    if (isAbsolutePath (file))
 
716
        res = eStrdup (file);
 
717
    else
 
718
        res = concat (CurrentDirectory, file, "");
 
719
 
 
720
    /* Delete the "/dirname/.." and "/." substrings. */
 
721
    slashp = strchr (res, '/');
 
722
    while (slashp != NULL  &&  slashp [0] != '\0')
 
723
    {
 
724
        if (slashp[1] == '.')
 
725
        {
 
726
            if (slashp [2] == '.' && (slashp [3] == '/' || slashp [3] == '\0'))
 
727
            {
 
728
                cp = slashp;
 
729
                do
 
730
                    cp--;
 
731
                while (cp >= res  &&  ! isAbsolutePath (cp));
 
732
                if (cp < res)
 
733
                    cp = slashp;/* the absolute name begins with "/.." */
 
734
#ifdef MSDOS_STYLE_PATH
 
735
                /* Under MSDOS and NT we get `d:/NAME' as absolute file name,
 
736
                 * so the luser could say `d:/../NAME'. We silently treat this
 
737
                 * as `d:/NAME'.
 
738
                 */
 
739
                else if (cp [0] != '/')
 
740
                    cp = slashp;
 
741
#endif
 
742
                strcpy (cp, slashp + 3);
 
743
                slashp = cp;
 
744
                continue;
 
745
            }
 
746
            else if (slashp [2] == '/'  ||  slashp [2] == '\0')
 
747
            {
 
748
                strcpy (slashp, slashp + 2);
 
749
                continue;
 
750
            }
 
751
        }
 
752
        slashp = strchr (slashp + 1, '/');
 
753
    }
 
754
 
 
755
    if (res [0] == '\0')
 
756
        return eStrdup ("/");
 
757
    else
 
758
    {
 
759
#ifdef MSDOS_STYLE_PATH
 
760
        /* Canonicalize drive letter case.  */
 
761
        if (res [1] == ':'  &&  islower (res [0]))
 
762
            res [0] = toupper (res [0]);
 
763
#endif
 
764
 
 
765
        return res;
 
766
    }
 
767
}
 
768
 
 
769
/* Return a newly allocated string containing the absolute file name of dir
 
770
 * where FILE resides given CWD (which should end with a slash).
 
771
 * Routine adapted from Gnu etags.
 
772
 */
 
773
extern char* absoluteDirname (char *file)
 
774
{
 
775
    char *slashp, *res;
 
776
    char save;
 
777
#ifdef MSDOS_STYLE_PATH
 
778
    char *p;
 
779
    for (p = file  ;  *p != '\0'  ;  p++)
 
780
        if (*p == '\\')
 
781
            *p = '/';
 
782
#endif
 
783
    slashp = strrchr (file, '/');
 
784
    if (slashp == NULL)
 
785
        res = eStrdup (CurrentDirectory);
 
786
    else
 
787
    {
 
788
        save = slashp [1];
 
789
        slashp [1] = '\0';
 
790
        res = absoluteFilename (file);
 
791
        slashp [1] = save;
 
792
    }
 
793
    return res;
 
794
}
 
795
 
 
796
/* Return a newly allocated string containing the file name of FILE relative
 
797
 * to the absolute directory DIR (which should end with a slash).
 
798
 * Routine adapted from Gnu etags.
 
799
 */
 
800
extern char* relativeFilename (const char *file, const char *dir)
 
801
{
 
802
    const char *fp, *dp;
 
803
    char *absdir, *res;
 
804
    int i;
 
805
 
 
806
    /* Find the common root of file and dir (with a trailing slash). */
 
807
    absdir = absoluteFilename (file);
 
808
    fp = absdir;
 
809
    dp = dir;
 
810
    while (*fp++ == *dp++)
 
811
        continue;
 
812
    fp--;
 
813
    dp--;                       /* back to the first differing char */
 
814
    do
 
815
    {                           /* look at the equal chars until '/' */
 
816
        if (fp == absdir)
 
817
            return absdir;      /* first char differs, give up */
 
818
        fp--;
 
819
        dp--;
 
820
    } while (*fp != '/');
 
821
 
 
822
    /* Build a sequence of "../" strings for the resulting relative file name.
 
823
     */
 
824
    i = 0;
 
825
    while ((dp = strchr (dp + 1, '/')) != NULL)
 
826
        i += 1;
 
827
    res = xMalloc (3 * i + strlen (fp + 1) + 1, char);
 
828
    res [0] = '\0';
 
829
    while (i-- > 0)
 
830
        strcat (res, "../");
 
831
 
 
832
    /* Add the file name relative to the common root of file and dir. */
 
833
    strcat (res, fp + 1);
 
834
    free (absdir);
 
835
 
 
836
    return res;
 
837
}
 
838
 
 
839
extern vString *combinePathAndFile (const char *const path,
 
840
                                    const char *const file)
 
841
{
 
842
    vString *const filePath = vStringNew ();
 
843
#ifdef VMS
 
844
    const char *const directoryId = strstr (file, ".DIR;1");
 
845
 
 
846
    if (directoryId == NULL)
 
847
    {
 
848
        const char *const versionId = strchr (file, ';');
 
849
 
 
850
        vStringCopyS (filePath, path);
 
851
        if (versionId == NULL)
 
852
            vStringCatS (filePath, file);
 
853
        else
 
854
            vStringNCatS (filePath, file, versionId - file);
 
855
        vStringCopyToLower (filePath, filePath);
 
856
    }
 
857
    else
 
858
    {
 
859
        /*  File really is a directory; append it to the path.
 
860
         *  Gotcha: doesn't work with logical names.
 
861
         */
 
862
        vStringNCopyS (filePath, path, strlen (path) - 1);
 
863
        vStringPut (filePath, '.');
 
864
        vStringNCatS (filePath, file, directoryId - file);
 
865
        if (strchr (path, '[') != NULL)
 
866
            vStringPut (filePath, ']');
 
867
        else
 
868
            vStringPut (filePath, '>');
 
869
        vStringTerminate (filePath);
 
870
    }
 
871
#else
 
872
    const int lastChar = path [strlen (path) - 1];
 
873
# ifdef MSDOS_STYLE_PATH
 
874
    boolean terminated = (boolean) (strchr (PathDelimiters, lastChar) != NULL);
 
875
# else
 
876
    boolean terminated = (boolean) (lastChar == PATH_SEPARATOR);
 
877
# endif
 
878
 
 
879
    vStringCopyS (filePath, path);
 
880
    if (! terminated)
 
881
    {
 
882
        vStringPut (filePath, OUTPUT_PATH_SEPARATOR);
 
883
        vStringTerminate (filePath);
 
884
    }
 
885
    vStringCatS (filePath, file);
 
886
#endif
 
887
 
 
888
    return filePath;
 
889
}
 
890
 
 
891
/*
 
892
 *      Create tags
 
893
 */
 
894
 
 
895
extern void processExcludeOption (const char *const __unused__ option,
 
896
                                  const char *const parameter)
 
897
{
 
898
    if (parameter [0] == '\0')
 
899
        freeList (&Excluded);
 
900
    else if (parameter [0] == '@')
 
901
    {
 
902
        stringList* const new = stringListNewFromFile (parameter + 1);
 
903
        if (Excluded == NULL)
 
904
            Excluded = new;
 
905
        else
 
906
            stringListCombine (Excluded, new);
 
907
    }
 
908
    else
 
909
    {
 
910
        vString *const item = vStringNewInit (parameter);
 
911
        if (Excluded == NULL)
 
912
            Excluded = stringListNew ();
 
913
        stringListAdd (Excluded, item);
 
914
    }
 
915
}
 
916
 
 
917
#if 0
 
918
static boolean excludedFile (const char* const name)
 
919
{
 
920
    const char* base = baseFilename (name);
 
921
    boolean result = FALSE;
 
922
    if (Excluded != NULL)
 
923
    {
 
924
        result = stringListFileMatched (Excluded, base);
 
925
        if (! result  &&  name != base)
 
926
            result = stringListFileMatched (Excluded, name);
 
927
    }
 
928
#ifdef AMIGA
 
929
    /* not a good solution, but the only one which works often */
 
930
    if (! result)
 
931
        result = (boolean) (strcmp (name, TagFile.name) == 0);
 
932
#endif
 
933
    return result;
 
934
}
 
935
 
 
936
# if defined (MSDOS) || defined (WIN32)
 
937
 
 
938
static boolean createTagsForMatchingEntries (char *const pattern)
 
939
{
 
940
    boolean resize = FALSE;
 
941
    const size_t dirLength = baseFilename (pattern) - (char *) pattern;
 
942
    vString *const filePath = vStringNew ();
 
943
#if defined (HAVE_FINDFIRST)
 
944
    struct ffblk fileInfo;
 
945
    int result = findfirst (pattern, &fileInfo, FA_DIREC);
 
946
 
 
947
    while (result == 0)
 
948
    {
 
949
        const char *const entryName = fileInfo.ff_name;
 
950
 
 
951
        /*  We must not recurse into the directories "." or "..".
 
952
         */
 
953
        if (strcmp (entryName, ".") != 0  &&  strcmp (entryName, "..") != 0)
 
954
        {
 
955
            vStringNCopyS (filePath, pattern, dirLength);
 
956
            vStringCatS (filePath, entryName);
 
957
            resize |= createTagsForEntry (vStringValue (filePath));
 
958
        }
 
959
        result = findnext (&fileInfo);
 
960
    }
 
961
#elif defined (HAVE__FINDFIRST)
 
962
    struct _finddata_t fileInfo;
 
963
    long hFile = _findfirst (pattern, &fileInfo);
 
964
 
 
965
    if (hFile != -1L)
 
966
    {
 
967
        do
 
968
        {
 
969
            const char *const entryName = fileInfo.name;
 
970
 
 
971
            /*  We must not recurse into the directories "." or "..".
 
972
             */
 
973
            if (strcmp (entryName, ".") != 0  &&  strcmp (entryName, "..") != 0)
 
974
            {
 
975
                vStringNCopyS (filePath, pattern, dirLength);
 
976
                vStringCatS (filePath, entryName);
 
977
                resize |= createTagsForEntry (vStringValue (filePath));
 
978
            }
 
979
        } while (_findnext (hFile, &fileInfo) == 0);
 
980
        _findclose (hFile);
 
981
    }
 
982
#endif
 
983
 
 
984
    vStringDelete (filePath);
 
985
    return resize;
 
986
}
 
987
 
 
988
#elif defined (AMIGA)
 
989
 
 
990
static boolean createTagsForMatchingEntries (char *const pattern)
 
991
{
 
992
    boolean resize = FALSE;
 
993
    struct AnchorPath *const anchor =
 
994
                        (struct AnchorPath *) eMalloc ((size_t) ANCHOR_SIZE);
 
995
 
 
996
    if (anchor != NULL)
 
997
    {
 
998
        LONG result;
 
999
 
 
1000
        memset (anchor, 0, (size_t) ANCHOR_SIZE);
 
1001
        anchor->ap_Strlen = ANCHOR_BUF_SIZE; /* ap_Length no longer supported */
 
1002
 
 
1003
        /*  Allow '.' for current directory.
 
1004
         */
 
1005
#ifdef APF_DODOT
 
1006
        anchor->ap_Flags = APF_DODOT | APF_DOWILD;
 
1007
#else
 
1008
        anchor->ap_Flags = APF_DoDot | APF_DoWild;
 
1009
#endif
 
1010
 
 
1011
        result = MatchFirst ((UBYTE *) pattern, anchor);
 
1012
        while (result == 0)
 
1013
        {
 
1014
            resize |= createTagsForEntry ((char *) anchor->ap_Buf);
 
1015
            result = MatchNext (anchor);
 
1016
        }
 
1017
        MatchEnd (anchor);
 
1018
        eFree (anchor);
 
1019
    }
 
1020
    return resize;
 
1021
}
 
1022
 
 
1023
#endif
 
1024
 
 
1025
static boolean isRecursiveLink (const char* const dirName)
 
1026
{
 
1027
    boolean result = FALSE;
 
1028
    char* const path = absoluteFilename (dirName);
 
1029
    while (path [strlen (path) - 1] == PATH_SEPARATOR)
 
1030
        path [strlen (path) - 1] = '\0';
 
1031
    while (! result  &&  strlen (path) > (size_t) 1)
 
1032
    {
 
1033
        char *const separator = strrchr (path, PATH_SEPARATOR);
 
1034
        if (separator == NULL)
 
1035
            break;
 
1036
        else if (separator == path)     /* backed up to root directory */
 
1037
            *(separator + 1) = '\0';
 
1038
        else
 
1039
            *separator = '\0';
 
1040
        result = isSameFile (path, dirName);
 
1041
    }
 
1042
    eFree (path);
 
1043
    return result;
 
1044
}
 
1045
 
 
1046
static boolean recurseIntoDirectory (const char *const dirName)
 
1047
{
 
1048
    boolean resize = FALSE;
 
1049
    if (isRecursiveLink (dirName))
 
1050
        verbose ("ignoring \"%s\" (recursive link)\n", dirName);
 
1051
    else if (! Option.recurse)
 
1052
        verbose ("ignoring \"%s\" (directory)\n", dirName);
 
1053
    else
 
1054
    {
 
1055
#if defined (HAVE_OPENDIR)
 
1056
        DIR *const dir = opendir (dirName);
 
1057
        if (dir == NULL)
 
1058
            error (WARNING | PERROR, "cannot recurse into directory \"%s\"",
 
1059
                   dirName);
 
1060
        else
 
1061
        {
 
1062
            struct dirent *entry;
 
1063
            verbose ("RECURSING into directory \"%s\"\n", dirName);
 
1064
            while ((entry = readdir (dir)) != NULL)
 
1065
            {
 
1066
                if (strcmp (entry->d_name, ".") != 0  &&
 
1067
                    strcmp (entry->d_name, "..") != 0)
 
1068
                {
 
1069
                    vString *filePath;
 
1070
                    if (strcmp (dirName, ".") == 0)
 
1071
                        filePath = vStringNewInit (entry->d_name);
 
1072
                    else
 
1073
                        filePath = combinePathAndFile (dirName, entry->d_name);
 
1074
                    resize |= createTagsForEntry (vStringValue (filePath));
 
1075
                    vStringDelete (filePath);
 
1076
                }
 
1077
            }
 
1078
            closedir (dir);
 
1079
        }
 
1080
#elif defined (AMIGA) || defined (MSDOS) || defined (WIN32)
 
1081
        vString *const pattern = vStringNew ();
 
1082
        verbose ("RECURSING into directory \"%s\"\n", dirName);
 
1083
# ifdef AMIGA
 
1084
        if (*dirName != '\0'  &&  strcmp (dirName, ".") != 0)
 
1085
        {
 
1086
            vStringCopyS (pattern, dirName);
 
1087
            if (dirName [strlen (dirName) - 1] != '/')
 
1088
                vStringPut (pattern, '/');
 
1089
        }
 
1090
        vStringCatS (pattern, "#?");
 
1091
# else
 
1092
        vStringCopyS (pattern, dirName);
 
1093
        vStringPut (pattern, OUTPUT_PATH_SEPARATOR);
 
1094
        vStringCatS (pattern, "*.*");
 
1095
# endif
 
1096
        resize = createTagsForMatchingEntries (vStringValue (pattern));
 
1097
        vStringDelete (pattern);
 
1098
#endif  /* HAVE_OPENDIR */
 
1099
    }
 
1100
    return resize;
 
1101
}
 
1102
 
 
1103
static boolean createTagsForEntry (const char *const entryName)
 
1104
{
 
1105
    boolean resize = FALSE;
 
1106
 
 
1107
    Assert (entryName != NULL);
 
1108
    if (excludedFile (entryName))
 
1109
        verbose ("excluding \"%s\"\n", entryName);
 
1110
    else if (isSymbolicLink (entryName)  &&  ! Option.followLinks)
 
1111
        verbose ("ignoring \"%s\" (symbolic link)\n", entryName);
 
1112
    else if (! doesFileExist (entryName))
 
1113
        error (WARNING | PERROR, "cannot open source file \"%s\"", entryName);
 
1114
    else if (isDirectory (entryName))
 
1115
        resize = recurseIntoDirectory (entryName);
 
1116
    else if (! isNormalFile (entryName))
 
1117
        verbose ("ignoring \"%s\" (special file)\n", entryName);
 
1118
    else
 
1119
        resize = parseFile (entryName);
 
1120
 
 
1121
    return resize;
 
1122
}
 
1123
 
 
1124
static boolean createTagsForArgs (cookedArgs* const args)
 
1125
{
 
1126
    boolean resize = FALSE;
 
1127
 
 
1128
    /*  Generate tags for each argument on the command line.
 
1129
     */
 
1130
    while (! cArgOff (args))
 
1131
    {
 
1132
        const char *arg = cArgItem (args);
 
1133
 
 
1134
#if defined (MSDOS) || defined (WIN32)
 
1135
        vString *const pattern = vStringNewInit (arg);
 
1136
        char *patternS = vStringValue (pattern);
 
1137
 
 
1138
        /*  We must transform the "." and ".." forms into something that can
 
1139
         *  be expanded by the MSDOS/Windows functions.
 
1140
         */
 
1141
        if (Option.recurse  &&
 
1142
            (strcmp (patternS, ".") == 0  ||  strcmp (patternS, "..") == 0))
 
1143
        {
 
1144
            vStringPut (pattern, OUTPUT_PATH_SEPARATOR);
 
1145
            vStringCatS (pattern, "*.*");
 
1146
        }
 
1147
        resize |= createTagsForMatchingEntries (patternS);
 
1148
        vStringDelete (pattern);
 
1149
#else
 
1150
        resize |= createTagsForEntry (arg);
 
1151
#endif
 
1152
        cArgForth (args);
 
1153
        parseOptions (args);
 
1154
    }
 
1155
    return resize;
 
1156
}
 
1157
 
 
1158
/*  Read from an opened file a list of file names for which to generate tags.
 
1159
 */
 
1160
static boolean createTagsFromFileInput (FILE* const fp, const boolean filter)
 
1161
{
 
1162
    boolean resize = FALSE;
 
1163
    if (fp != NULL)
 
1164
    {
 
1165
        cookedArgs* args = cArgNewFromLineFile (fp);
 
1166
        parseOptions (args);
 
1167
        while (! cArgOff (args))
 
1168
        {
 
1169
            resize |= createTagsForEntry (cArgItem (args));
 
1170
            if (filter)
 
1171
            {
 
1172
                if (Option.filterTerminator != NULL)
 
1173
                    fputs (Option.filterTerminator, stdout);
 
1174
                fflush (stdout);
 
1175
            }
 
1176
            cArgForth (args);
 
1177
            parseOptions (args);
 
1178
        }
 
1179
        cArgDelete (args);
 
1180
    }
 
1181
    return resize;
 
1182
}
 
1183
 
 
1184
/*  Read from a named file a list of file names for which to generate tags.
 
1185
 */
 
1186
static boolean createTagsFromListFile (const char* const fileName)
 
1187
{
 
1188
    boolean resize;
 
1189
    Assert (fileName != NULL);
 
1190
    if (strcmp (fileName, "-") == 0)
 
1191
        resize = createTagsFromFileInput (stdin, FALSE);
 
1192
    else
 
1193
    {
 
1194
        FILE* const fp = g_fopen (fileName, "r");
 
1195
        if (fp == NULL)
 
1196
            error (FATAL | PERROR, "cannot open list file \"%s\"", fileName);
 
1197
        resize = createTagsFromFileInput (fp, FALSE);
 
1198
        fclose (fp);
 
1199
    }
 
1200
    return resize;
 
1201
}
 
1202
 
 
1203
#if defined (HAVE_CLOCK)
 
1204
# define CLOCK_AVAILABLE
 
1205
# ifndef CLOCKS_PER_SEC
 
1206
#  define CLOCKS_PER_SEC        1000000
 
1207
# endif
 
1208
#elif defined (HAVE_TIMES)
 
1209
# define CLOCK_AVAILABLE
 
1210
# define CLOCKS_PER_SEC 60
 
1211
static clock_t clock (void)
 
1212
{
 
1213
    struct tms buf;
 
1214
 
 
1215
    times (&buf);
 
1216
    return (buf.tms_utime + buf.tms_stime);
 
1217
}
 
1218
#else
 
1219
# define clock()  (clock_t)0
 
1220
#endif
 
1221
 
 
1222
static void printTotals (const clock_t *const timeStamps)
 
1223
{
 
1224
    const unsigned long totalTags = TagFile.numTags.added +
 
1225
                                    TagFile.numTags.prev;
 
1226
 
 
1227
    fprintf (errout, "%ld file%s, %ld line%s (%ld kB) scanned",
 
1228
            Totals.files, plural (Totals.files),
 
1229
            Totals.lines, plural (Totals.lines),
 
1230
            Totals.bytes/1024L);
 
1231
#ifdef CLOCK_AVAILABLE
 
1232
    {
 
1233
        const double interval = ((double) (timeStamps [1] - timeStamps [0])) /
 
1234
                                CLOCKS_PER_SEC;
 
1235
 
 
1236
        fprintf (errout, " in %.01f seconds", interval);
 
1237
        if (interval != (double) 0.0)
 
1238
            fprintf (errout, " (%lu kB/s)",
 
1239
                    (unsigned long) (Totals.bytes / interval) / 1024L);
 
1240
    }
 
1241
#endif
 
1242
    fputc ('\n', errout);
 
1243
 
 
1244
    fprintf (errout, "%lu tag%s added to tag file",
 
1245
            TagFile.numTags.added, plural (TagFile.numTags.added));
 
1246
    if (Option.append)
 
1247
        fprintf (errout, " (now %lu tags)", totalTags);
 
1248
    fputc ('\n', errout);
 
1249
 
 
1250
    if (totalTags > 0  &&  Option.sorted)
 
1251
    {
 
1252
        fprintf (errout, "%lu tag%s sorted", totalTags, plural (totalTags));
 
1253
#ifdef CLOCK_AVAILABLE
 
1254
        fprintf (errout, " in %.02f seconds",
 
1255
                ((double) (timeStamps [2] - timeStamps [1])) / CLOCKS_PER_SEC);
 
1256
#endif
 
1257
        fputc ('\n', errout);
 
1258
    }
 
1259
 
 
1260
#ifdef TM_DEBUG
 
1261
    fprintf (errout, "longest tag line = %lu\n",
 
1262
            (unsigned long) TagFile.max.line);
 
1263
#endif
 
1264
}
 
1265
 
 
1266
static void makeTags (cookedArgs* args)
 
1267
{
 
1268
    clock_t timeStamps [3];
 
1269
    boolean resize = FALSE;
 
1270
    boolean files = (boolean)(! cArgOff (args) || Option.fileList != NULL
 
1271
                              || Option.filter);
 
1272
 
 
1273
    if (! files  &&  ! Option.recurse)
 
1274
        error (FATAL, "No files specified. Try \"%s --help\".",
 
1275
               getExecutableName ());
 
1276
 
 
1277
#define timeStamp(n) timeStamps[(n)]=(Option.printTotals ? clock():(clock_t)0)
 
1278
    if (! Option.filter)
 
1279
        openTagFile ();
 
1280
 
 
1281
    timeStamp (0);
 
1282
 
 
1283
    if (! cArgOff (args))
 
1284
    {
 
1285
        verbose ("Reading command line arguments\n");
 
1286
        resize = createTagsForArgs (args);
 
1287
    }
 
1288
    if (Option.fileList != NULL)
 
1289
    {
 
1290
        verbose ("Reading list file\n");
 
1291
        resize = (boolean) (createTagsFromListFile (Option.fileList) || resize);
 
1292
    }
 
1293
    if (Option.filter)
 
1294
    {
 
1295
        verbose ("Reading filter input\n");
 
1296
        resize = (boolean) (createTagsFromFileInput (stdin, TRUE) || resize);
 
1297
    }
 
1298
    if (! files  &&  Option.recurse)
 
1299
        resize = recurseIntoDirectory (".");
 
1300
 
 
1301
    timeStamp (1);
 
1302
 
 
1303
    if (! Option.filter)
 
1304
        closeTagFile (resize);
 
1305
 
 
1306
    timeStamp (2);
 
1307
 
 
1308
    if (Option.printTotals)
 
1309
        printTotals (timeStamps);
 
1310
#undef timeStamp
 
1311
}
 
1312
 
 
1313
/*
 
1314
 *      Start up code
 
1315
 */
 
1316
 
 
1317
static void setExecutableName (const char *const path)
 
1318
{
 
1319
    ExecutableProgram = path;
 
1320
    ExecutableName = baseFilename (path);
 
1321
#ifdef VAXC
 
1322
{
 
1323
    /* remove filetype from executable name */
 
1324
    char *p = strrchr (ExecutableName, '.');
 
1325
    if (p != NULL)
 
1326
        *p = '\0';
 
1327
}
 
1328
#endif
 
1329
}
 
1330
 
 
1331
extern int ctags_main (int __unused__ argc, char **argv)
 
1332
{
 
1333
    cookedArgs *args;
 
1334
#ifdef VMS
 
1335
    extern int getredirection (int *ac, char ***av);
 
1336
 
 
1337
    /* do wildcard expansion and I/O redirection */
 
1338
    getredirection (&argc, &argv);
 
1339
#endif
 
1340
 
 
1341
#ifdef AMIGA
 
1342
    /* This program doesn't work when started from the Workbench */
 
1343
    if (argc == 0)
 
1344
        exit (1);
 
1345
#endif
 
1346
 
 
1347
#ifdef __EMX__
 
1348
    _wildcard (&argc, &argv);   /* expand wildcards in argument list */
 
1349
#endif
 
1350
 
 
1351
#if defined (macintosh) && BUILD_MPW_TOOL == 0
 
1352
    argc = ccommand (&argv);
 
1353
#endif
 
1354
 
 
1355
    setCurrentDirectory ();
 
1356
    setExecutableName (*argv++);
 
1357
#ifdef HAVE_REGEX
 
1358
    checkRegex ();
 
1359
#endif
 
1360
 
 
1361
    /* always excluded by default */
 
1362
    processExcludeOption (NULL, "EIFGEN");
 
1363
    processExcludeOption (NULL, "SCCS");
 
1364
 
 
1365
    args = cArgNewFromArgv (argv);
 
1366
    previewFirstOption (args);
 
1367
    testEtagsInvocation ();
 
1368
    initializeParsing ();
 
1369
    initOptions ();
 
1370
    readOptionConfiguration ();
 
1371
    verbose ("Reading initial options from command line\n");
 
1372
    parseOptions (args);
 
1373
    checkOptions ();
 
1374
    makeTags (args);
 
1375
 
 
1376
    /*  Clean up.
 
1377
     */
 
1378
    eFree (CurrentDirectory);
 
1379
    freeList (&Excluded);
 
1380
    cArgDelete (args);
 
1381
    freeKeywordTable ();
 
1382
    freeSourceFileResources ();
 
1383
    freeTagFileResources ();
 
1384
    freeOptionResources ();
 
1385
    freeParserResources ();
 
1386
#ifdef HAVE_REGEX
 
1387
    freeRegexResources ();
 
1388
#endif
 
1389
 
 
1390
    exit (0);
 
1391
    return 0;
 
1392
}
 
1393
#endif
 
1394
 
 
1395
/* wrap g_warning so we don't include glib.h for all parsers, to keep compat with CTags */
 
1396
void utils_warn(const char *msg)
 
1397
{
 
1398
    g_warning("%s", msg);
 
1399
}
 
1400
 
 
1401
/* vi:set tabstop=8 shiftwidth=4: */