~ubuntu-branches/ubuntu/lucid/codelite/lucid

« back to all changes in this revision

Viewing changes to sdk/ctags/read.c

  • Committer: Bazaar Package Importer
  • Author(s): Chow Loong Jin
  • Date: 2009-01-12 15:46:55 UTC
  • Revision ID: james.westby@ubuntu.com-20090112154655-sdynrljcb6u167yw
Tags: upstream-1.0.2674+dfsg
ImportĀ upstreamĀ versionĀ 1.0.2674+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
*   $Id: read.c,v 1.7 2006/05/30 04:37:12 darren Exp $
 
3
*
 
4
*   Copyright (c) 1996-2002, 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 low level source and tag file read functions (newline
 
10
*   conversion for source files are performed at this level).
 
11
*/
 
12
 
 
13
/*
 
14
*   INCLUDE FILES
 
15
*/
 
16
#include "general.h"  /* must always come first */
 
17
 
 
18
#include <string.h>
 
19
#include <ctype.h>
 
20
#include "clist.h"
 
21
#include "string_util.h"
 
22
 
 
23
#define FILE_WRITE
 
24
#include "read.h"
 
25
#include "debug.h"
 
26
#include "entry.h"
 
27
#include "main.h"
 
28
#include "routines.h"
 
29
#include "options.h"
 
30
 
 
31
/*
 
32
*   DATA DEFINITIONS
 
33
*/
 
34
inputFile File;  /* globally read through macros */
 
35
static fpos_t StartOfLine;  /* holds deferred position of start of line */
 
36
 
 
37
/*
 
38
*   FUNCTION DEFINITIONS
 
39
*/
 
40
 
 
41
extern void freeSourceFileResources (void)
 
42
{
 
43
        vStringDelete (File.name);
 
44
        vStringDelete (File.path);
 
45
        vStringDelete (File.source.name);
 
46
        vStringDelete (File.line);
 
47
}
 
48
 
 
49
static char *load_file(const char *fileName) {
 
50
        FILE *fp;
 
51
        long len;
 
52
        char *buf = NULL;
 
53
 
 
54
        fp = fopen(fileName, "rb");
 
55
        if (!fp) {
 
56
                return 0;
 
57
        }
 
58
 
 
59
 
 
60
        fseek(fp, 0, SEEK_END);                 
 
61
        len = ftell(fp);                                
 
62
        fseek(fp, 0, SEEK_SET);                 
 
63
        buf = (char *)malloc(len+1);    
 
64
 
 
65
 
 
66
        long bytes = fread(buf, sizeof(char), len, fp);
 
67
        if (bytes != len) {
 
68
                fclose(fp);
 
69
                return 0;
 
70
        }
 
71
 
 
72
        buf[len] = 0;   // make it null terminated string
 
73
        fclose(fp);
 
74
        return buf;
 
75
}
 
76
 
 
77
/*
 
78
 *   Source file access functions
 
79
 */
 
80
 
 
81
static void setInputFileName (const char *const fileName)
 
82
{
 
83
        const char *const head = fileName;
 
84
        const char *const tail = baseFilename (head);
 
85
 
 
86
        if (File.name != NULL)
 
87
                vStringDelete (File.name);
 
88
        File.name = vStringNewInit (fileName);
 
89
 
 
90
        if (File.path != NULL)
 
91
                vStringDelete (File.path);
 
92
        if (tail == head)
 
93
                File.path = NULL;
 
94
        else
 
95
        {
 
96
                const size_t length = tail - head - 1;
 
97
                File.path = vStringNew ();
 
98
                vStringNCopyS (File.path, fileName, length);
 
99
        }
 
100
}
 
101
 
 
102
static void setSourceFileParameters (vString *const fileName)
 
103
{
 
104
        if (File.source.name != NULL)
 
105
                vStringDelete (File.source.name);
 
106
        File.source.name = fileName;
 
107
 
 
108
        if (File.source.tagPath != NULL)
 
109
                eFree (File.source.tagPath);
 
110
        if (! Option.tagRelative || isAbsolutePath (vStringValue (fileName)))
 
111
                File.source.tagPath = eStrdup (vStringValue (fileName));
 
112
        else
 
113
                File.source.tagPath =
 
114
                                relativeFilename (vStringValue (fileName), TagFile.directory);
 
115
 
 
116
        if (vStringLength (fileName) > TagFile.max.file)
 
117
                TagFile.max.file = vStringLength (fileName);
 
118
 
 
119
        File.source.isHeader = isIncludeFile (vStringValue (fileName));
 
120
        File.source.language = getFileLanguage (vStringValue (fileName));
 
121
}
 
122
 
 
123
static boolean setSourceFileName (vString *const fileName)
 
124
{
 
125
        boolean result = FALSE;
 
126
        if (getFileLanguage (vStringValue (fileName)) != LANG_IGNORE)
 
127
        {
 
128
                vString *pathName;
 
129
                if (isAbsolutePath (vStringValue (fileName)) || File.path == NULL)
 
130
                        pathName = vStringNewCopy (fileName);
 
131
                else
 
132
                        pathName = combinePathAndFile (
 
133
                                        vStringValue (File.path), vStringValue (fileName));
 
134
                setSourceFileParameters (pathName);
 
135
                result = TRUE;
 
136
        }
 
137
        return result;
 
138
}
 
139
 
 
140
/*
 
141
 *   Line directive parsing
 
142
 */
 
143
 
 
144
static int skipWhite (void)
 
145
{
 
146
        int c;
 
147
        do
 
148
                c = getc (File.fp);
 
149
        while (c == ' '  ||  c == '\t');
 
150
        return c;
 
151
}
 
152
 
 
153
static unsigned long readLineNumber (void)
 
154
{
 
155
        unsigned long lNum = 0;
 
156
        int c = skipWhite ();
 
157
        while (c != EOF  &&  isdigit (c))
 
158
        {
 
159
                lNum = (lNum * 10) + (c - '0');
 
160
                c = getc (File.fp);
 
161
        }
 
162
        ungetc (c, File.fp);
 
163
        if (c != ' '  &&  c != '\t')
 
164
                lNum = 0;
 
165
 
 
166
        return lNum;
 
167
}
 
168
 
 
169
/* While ANSI only permits lines of the form:
 
170
 *   # line n "filename"
 
171
 * Earlier compilers generated lines of the form
 
172
 *   # n filename
 
173
 * GNU C will output lines of the form:
 
174
 *   # n "filename"
 
175
 * So we need to be fairly flexible in what we accept.
 
176
 */
 
177
static vString *readFileName (void)
 
178
{
 
179
        vString *const fileName = vStringNew ();
 
180
        boolean quoteDelimited = FALSE;
 
181
        int c = skipWhite ();
 
182
 
 
183
        if (c == '"')
 
184
        {
 
185
                c = getc (File.fp);  /* skip double-quote */
 
186
                quoteDelimited = TRUE;
 
187
        }
 
188
        while (c != EOF  &&  c != '\n'  &&
 
189
                        (quoteDelimited ? (c != '"') : (c != ' '  &&  c != '\t')))
 
190
        {
 
191
                vStringPut (fileName, c);
 
192
                c = getc (File.fp);
 
193
        }
 
194
        if (c == '\n')
 
195
                ungetc (c, File.fp);
 
196
        vStringPut (fileName, '\0');
 
197
 
 
198
        return fileName;
 
199
}
 
200
 
 
201
static boolean parseLineDirective (void)
 
202
{
 
203
        boolean result = FALSE;
 
204
        int c = skipWhite ();
 
205
        DebugStatement ( const char* lineStr = ""; )
 
206
 
 
207
        if (isdigit (c))
 
208
        {
 
209
                ungetc (c, File.fp);
 
210
                result = TRUE;
 
211
        }
 
212
        else if (c == 'l'  &&  getc (File.fp) == 'i'  &&
 
213
                         getc (File.fp) == 'n'  &&  getc (File.fp) == 'e')
 
214
        {
 
215
                c = getc (File.fp);
 
216
                if (c == ' '  ||  c == '\t')
 
217
                {
 
218
                        DebugStatement ( lineStr = "line"; )
 
219
                        result = TRUE;
 
220
                }
 
221
        }
 
222
        if (result)
 
223
        {
 
224
                const unsigned long lNum = readLineNumber ();
 
225
                if (lNum == 0)
 
226
                        result = FALSE;
 
227
                else
 
228
                {
 
229
                        vString *const fileName = readFileName ();
 
230
                        if (vStringLength (fileName) == 0)
 
231
                        {
 
232
                                File.source.lineNumber = lNum - 1;  /* applies to NEXT line */
 
233
                                DebugStatement ( debugPrintf (DEBUG_RAW, "#%s %ld", lineStr, lNum); )
 
234
                        }
 
235
                        else if (setSourceFileName (fileName))
 
236
                        {
 
237
                                File.source.lineNumber = lNum - 1;  /* applies to NEXT line */
 
238
                                DebugStatement ( debugPrintf (DEBUG_RAW, "#%s %ld \"%s\"",
 
239
                                                                lineStr, lNum, vStringValue (fileName)); )
 
240
                        }
 
241
 
 
242
                        if (Option.include.fileNames && vStringLength (fileName) > 0 &&
 
243
                                lNum == 1)
 
244
                        {
 
245
                                tagEntryInfo tag;
 
246
                                initTagEntry (&tag, baseFilename (vStringValue (fileName)));
 
247
 
 
248
                                tag.isFileEntry     = TRUE;
 
249
                                tag.lineNumberEntry = TRUE;
 
250
                                tag.lineNumber      = 1;
 
251
                                tag.kindName        = "file";
 
252
                                tag.kind            = 'F';
 
253
 
 
254
                                makeTagEntry (&tag);
 
255
                        }
 
256
                        vStringDelete (fileName);
 
257
                        result = TRUE;
 
258
                }
 
259
        }
 
260
        return result;
 
261
}
 
262
 
 
263
/*
 
264
 *   Source file I/O operations
 
265
 */
 
266
 
 
267
/*  This function opens a source file, and resets the line counter.  If it
 
268
 *  fails, it will display an error message and leave the File.fp set to NULL.
 
269
 */
 
270
extern boolean fileOpen (const char *const fileName, const langType language)
 
271
{
 
272
#ifdef VMS
 
273
        const char *const openMode = "r";
 
274
#else
 
275
        const char *const openMode = "rb";
 
276
#endif
 
277
        boolean opened = FALSE;
 
278
 
 
279
        /*      If another file was already open, then close it.
 
280
         */
 
281
        if (File.fp != NULL)
 
282
        {
 
283
                fclose (File.fp);  /* close any open source file */
 
284
                File.fp = NULL;
 
285
        }
 
286
 
 
287
        File.fp = fopen (fileName, openMode);
 
288
        if (File.fp == NULL)
 
289
                error (WARNING | PERROR, "cannot open \"%s\"", fileName);
 
290
        else
 
291
        {
 
292
                opened = TRUE;
 
293
 
 
294
                setInputFileName (fileName);
 
295
                fgetpos (File.fp, &StartOfLine);
 
296
                fgetpos (File.fp, &File.filePosition);
 
297
                File.currentLine  = NULL;
 
298
                File.language     = language;
 
299
                File.lineNumber   = 0L;
 
300
                File.eof          = FALSE;
 
301
                File.newLine      = TRUE;
 
302
 
 
303
                if (File.line != NULL)
 
304
                        vStringClear (File.line);
 
305
 
 
306
                setSourceFileParameters (vStringNewInit (fileName));
 
307
                File.source.lineNumber = 0L;
 
308
 
 
309
                verbose ("OPENING %s as %s language %sfile\n", fileName,
 
310
                                getLanguageName (language),
 
311
                                File.source.isHeader ? "include " : "");
 
312
        }
 
313
        return opened;
 
314
}
 
315
 
 
316
extern void fileClose (void)
 
317
{
 
318
        if (File.fp != NULL)
 
319
        {
 
320
                /*  The line count of the file is 1 too big, since it is one-based
 
321
                 *  and is incremented upon each newline.
 
322
                 */
 
323
                if (Option.printTotals)
 
324
                {
 
325
                        fileStatus *status = eStat (vStringValue (File.name));
 
326
                        addTotals (0, File.lineNumber - 1L, status->size);
 
327
                }
 
328
                fclose (File.fp);
 
329
                File.fp = NULL;
 
330
        }
 
331
}
 
332
 
 
333
extern boolean fileEOF (void)
 
334
{
 
335
        return File.eof;
 
336
}
 
337
 
 
338
/*  Action to take for each encountered source newline.
 
339
 */
 
340
static void fileNewline (void)
 
341
{
 
342
        File.filePosition = StartOfLine;
 
343
        File.newLine = FALSE;
 
344
        File.lineNumber++;
 
345
        File.source.lineNumber++;
 
346
        DebugStatement ( if (Option.breakLine == File.lineNumber) lineBreak (); )
 
347
        DebugStatement ( debugPrintf (DEBUG_RAW, "%6ld: ", File.lineNumber); )
 
348
}
 
349
 
 
350
/*  This function reads a single character from the stream, performing newline
 
351
 *  canonicalization.
 
352
 */
 
353
static int iFileGetc (void)
 
354
{
 
355
        int     c;
 
356
readnext:
 
357
        c = getc (File.fp);
 
358
 
 
359
        /*      If previous character was a newline, then we're starting a line.
 
360
         */
 
361
        if (File.newLine  &&  c != EOF)
 
362
        {
 
363
                fileNewline ();
 
364
                if (c == '#'  &&  Option.lineDirectives)
 
365
                {
 
366
                        if (parseLineDirective ())
 
367
                                goto readnext;
 
368
                        else
 
369
                        {
 
370
                                fsetpos (File.fp, &StartOfLine);
 
371
                                c = getc (File.fp);
 
372
                        }
 
373
                }
 
374
        }
 
375
 
 
376
        if (c == EOF)
 
377
                File.eof = TRUE;
 
378
        else if (c == NEWLINE)
 
379
        {
 
380
                File.newLine = TRUE;
 
381
                fgetpos (File.fp, &StartOfLine);
 
382
        }
 
383
        else if (c == CRETURN)
 
384
        {
 
385
                /*  Turn line breaks into a canonical form. The three commonly
 
386
                 *  used forms if line breaks: LF (UNIX), CR (MacIntosh), and
 
387
                 *  CR-LF (MS-DOS) are converted into a generic newline.
 
388
                 */
 
389
                const int next = getc (File.fp);  /* is CR followed by LF? */
 
390
 
 
391
                if (next != NEWLINE)
 
392
                        ungetc (next, File.fp);
 
393
 
 
394
                c = NEWLINE;  /* convert CR into newline */
 
395
                File.newLine = TRUE;
 
396
                fgetpos (File.fp, &StartOfLine);
 
397
        }
 
398
        DebugStatement ( debugPutc (DEBUG_RAW, c); )
 
399
        return c;
 
400
}
 
401
 
 
402
extern void fileUngetc (int c)
 
403
{
 
404
        File.ungetch = c;
 
405
}
 
406
 
 
407
static vString *iFileGetLine (void)
 
408
{
 
409
        static list_t *replacements = (list_t *)0;
 
410
        static int first = 1;
 
411
        
 
412
        vString *result = NULL;
 
413
        int c;
 
414
        if (File.line == NULL)
 
415
                File.line = vStringNew ();
 
416
        vStringClear (File.line);
 
417
        do
 
418
        {
 
419
                c = iFileGetc ();
 
420
                if (c != EOF)
 
421
                        vStringPut (File.line, c);
 
422
                if (c == '\n'  ||  (c == EOF  &&  vStringLength (File.line) > 0))
 
423
                {
 
424
                        vStringTerminate (File.line);
 
425
#ifdef HAVE_REGEX
 
426
                        if (vStringLength (File.line) > 0)
 
427
                                matchRegex (File.line, File.source.language);
 
428
#endif
 
429
                        result = File.line;
 
430
                        break;
 
431
                }
 
432
        } while (c != EOF);
 
433
        Assert (result != NULL  ||  File.eof);
 
434
        
 
435
        /* try to load the file once */
 
436
        if( first ) {
 
437
                char *content = (char*)0;
 
438
                char *file_name = getenv("CTAGS_REPLACEMENTS");
 
439
                
 
440
                first = 0;
 
441
                if(file_name) {
 
442
                        /* open the file */
 
443
                        content = load_file(file_name);
 
444
                        if(content) {
 
445
                                replacements = string_split(content, "=");
 
446
                                free(content);
 
447
                        }
 
448
                }
 
449
        }
 
450
        
 
451
        if( result && replacements && replacements->size ) {
 
452
                
 
453
                int first_loop = 1;
 
454
                char *src = result->buffer;
 
455
                char *new_str = src;
 
456
                char *tmp = 0;
 
457
                list_node_t *node = replacements->head;
 
458
                
 
459
                while( node ) {
 
460
                        tmp = string_replace(new_str, ((string_pair_t*)node->data)->key, ((string_pair_t*)node->data)->data);
 
461
                        if(!first_loop) {
 
462
                                free(new_str);
 
463
                        }
 
464
                        
 
465
                        new_str = tmp;
 
466
                        first_loop = 0;
 
467
                        
 
468
                        /* advance to next item in the list */
 
469
                        node = node->next;
 
470
                }
 
471
                
 
472
                if(new_str != result->buffer) {
 
473
                        vStringClear(File.line);
 
474
                        vStringCatS(File.line, new_str);
 
475
                        free(new_str);
 
476
                }
 
477
        }
 
478
        
 
479
        return result;
 
480
}
 
481
 
 
482
/*  Do not mix use of fileReadLine () and fileGetc () for the same file.
 
483
 */
 
484
extern int fileGetc (void)
 
485
{
 
486
        int c;
 
487
 
 
488
        /*  If there is an ungotten character, then return it.  Don't do any
 
489
         *  other processing on it, though, because we already did that the
 
490
         *  first time it was read through fileGetc ().
 
491
         */
 
492
        if (File.ungetch != '\0')
 
493
        {
 
494
                c = File.ungetch;
 
495
                File.ungetch = '\0';
 
496
                return c;  /* return here to avoid re-calling debugPutc () */
 
497
        }
 
498
        do
 
499
        {
 
500
                if (File.currentLine != NULL)
 
501
                {
 
502
                        c = *File.currentLine++;
 
503
                        if (c == '\0')
 
504
                                File.currentLine = NULL;
 
505
                }
 
506
                else
 
507
                {
 
508
                        vString* const line = iFileGetLine ();
 
509
                        if (line != NULL)
 
510
                                File.currentLine = (unsigned char*) vStringValue (line);
 
511
                        if (File.currentLine == NULL)
 
512
                                c = EOF;
 
513
                        else
 
514
                                c = '\0';
 
515
                }
 
516
        } while (c == '\0');
 
517
        DebugStatement ( debugPutc (DEBUG_READ, c); )
 
518
        return c;
 
519
}
 
520
 
 
521
/*  An alternative interface to fileGetc (). Do not mix use of fileReadLine()
 
522
 *  and fileGetc() for the same file. The returned string does not contain
 
523
 *  the terminating newline. A NULL return value means that all lines in the
 
524
 *  file have been read and we are at the end of file.
 
525
 */
 
526
extern const unsigned char *fileReadLine (void)
 
527
{
 
528
        vString* const line = iFileGetLine ();
 
529
        const unsigned char* result = NULL;
 
530
        if (line != NULL)
 
531
        {
 
532
                result = (const unsigned char*) vStringValue (line);
 
533
                vStringStripNewline (line);
 
534
                DebugStatement ( debugPrintf (DEBUG_READ, "%s\n", result); )
 
535
        }
 
536
        return result;
 
537
}
 
538
 
 
539
/*
 
540
 *   Source file line reading with automatic buffer sizing
 
541
 */
 
542
extern char *readLine (vString *const vLine, FILE *const fp)
 
543
{
 
544
        char *result = NULL;
 
545
 
 
546
        vStringClear (vLine);
 
547
        if (fp == NULL)  /* to free memory allocated to buffer */
 
548
                error (FATAL, "NULL file pointer");
 
549
        else
 
550
        {
 
551
                boolean reReadLine;
 
552
 
 
553
                /*  If reading the line places any character other than a null or a
 
554
                 *  newline at the last character position in the buffer (one less
 
555
                 *  than the buffer size), then we must resize the buffer and
 
556
                 *  reattempt to read the line.
 
557
                 */
 
558
                do
 
559
                {
 
560
                        char *const pLastChar = vStringValue (vLine) + vStringSize (vLine) -2;
 
561
                        fpos_t startOfLine;
 
562
 
 
563
                        fgetpos (fp, &startOfLine);
 
564
                        reReadLine = FALSE;
 
565
                        *pLastChar = '\0';
 
566
                        result = fgets (vStringValue (vLine), (int) vStringSize (vLine), fp);
 
567
                        if (result == NULL)
 
568
                        {
 
569
                                if (! feof (fp))
 
570
                                        error (FATAL | PERROR, "Failure on attempt to read file");
 
571
                        }
 
572
                        else if (*pLastChar != '\0'  &&
 
573
                                         *pLastChar != '\n'  &&  *pLastChar != '\r')
 
574
                        {
 
575
                                /*  buffer overflow */
 
576
                                reReadLine = vStringAutoResize (vLine);
 
577
                                if (reReadLine)
 
578
                                        fsetpos (fp, &startOfLine);
 
579
                                else
 
580
                                        error (FATAL | PERROR, "input line too big; out of memory");
 
581
                        }
 
582
                        else
 
583
                        {
 
584
                                char* eol;
 
585
                                vStringSetLength (vLine);
 
586
                                /* canonicalize new line */
 
587
                                eol = vStringValue (vLine) + vStringLength (vLine) - 1;
 
588
                                if (*eol == '\r')
 
589
                                        *eol = '\n';
 
590
                                else if (*(eol - 1) == '\r'  &&  *eol == '\n')
 
591
                                {
 
592
                                        *(eol - 1) = '\n';
 
593
                                        *eol = '\0';
 
594
                                        --vLine->length;
 
595
                                }
 
596
                        }
 
597
                } while (reReadLine);
 
598
        }
 
599
        return result;
 
600
}
 
601
 
 
602
/*  Places into the line buffer the contents of the line referenced by
 
603
 *  "location".
 
604
 */
 
605
extern char *readSourceLine (
 
606
                vString *const vLine, fpos_t location, long *const pSeekValue)
 
607
{
 
608
        fpos_t orignalPosition;
 
609
        char *result;
 
610
 
 
611
        fgetpos (File.fp, &orignalPosition);
 
612
        fsetpos (File.fp, &location);
 
613
        if (pSeekValue != NULL)
 
614
                *pSeekValue = ftell (File.fp);
 
615
        result = readLine (vLine, File.fp);
 
616
        if (result == NULL)
 
617
                error (FATAL, "Unexpected end of file: %s", vStringValue (File.name));
 
618
        fsetpos (File.fp, &orignalPosition);
 
619
 
 
620
        return result;
 
621
}
 
622
 
 
623
extern char *readSourceLines (vString* const vLine, fpos_t location, fpos_t endPos)
 
624
{
 
625
        fpos_t orignalPosition;
 
626
        char *result;
 
627
        long startpos, endpos, currpos;
 
628
        vString* const tmpstr = vStringNew();
 
629
 
 
630
        fgetpos (File.fp, &orignalPosition);
 
631
        fsetpos (File.fp, &location);
 
632
 
 
633
        startpos = ftell(File.fp);
 
634
        /* set the cursor at the end position */
 
635
        fsetpos (File.fp, &endPos);
 
636
        endpos   = ftell(File.fp);
 
637
 
 
638
        /* set pointer to start point */
 
639
        fsetpos (File.fp, &location);
 
640
 
 
641
        vStringClear(vLine);
 
642
        
 
643
        while( 1 ){
 
644
                result = readLine (tmpstr, File.fp);
 
645
                if (result == NULL){
 
646
                        error (FATAL, "Unexpected end of file: %s", vStringValue (File.name));
 
647
                }
 
648
                vStringCat(vLine, tmpstr);
 
649
                currpos = ftell(File.fp);
 
650
                if(currpos > endpos){
 
651
                        break;
 
652
                }
 
653
        }
 
654
 
 
655
        fsetpos (File.fp, &orignalPosition);
 
656
        vStringDelete(tmpstr);
 
657
        return vLine->buffer;
 
658
}
 
659
 
 
660
/* vi:set tabstop=4 shiftwidth=4: */