~ubuntu-branches/ubuntu/utopic/exuberant-ctags/utopic

« back to all changes in this revision

Viewing changes to read.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson
  • Date: 2006-07-31 09:09:12 UTC
  • mfrom: (1.1.1 upstream) (2.1.1 edgy)
  • Revision ID: james.westby@ubuntu.com-20060731090912-rxe2jt8nz6g2k2zx
Tags: 1:5.6-1
* New upstream release (closes: #374097).
* Fix accidentally-unrendered line in ctags(1) (closes: #271323).
* Policy version 3.7.2: no changes required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
*   $Id: read.c,v 1.6 2002/06/19 05:27:17 darren Exp $
 
2
*   $Id: read.c,v 1.7 2006/05/30 04:37:12 darren Exp $
3
3
*
4
4
*   Copyright (c) 1996-2002, Darren Hiebert
5
5
*
13
13
/*
14
14
*   INCLUDE FILES
15
15
*/
16
 
#include "general.h"    /* must always come first */
 
16
#include "general.h"  /* must always come first */
17
17
 
18
18
#include <string.h>
19
19
#include <ctype.h>
29
29
/*
30
30
*   DATA DEFINITIONS
31
31
*/
32
 
inputFile File;                 /* globally read through macros */
33
 
static fpos_t StartOfLine;      /* holds deferred position of start of line */
 
32
inputFile File;  /* globally read through macros */
 
33
static fpos_t StartOfLine;  /* holds deferred position of start of line */
34
34
 
35
35
/*
36
36
*   FUNCTION DEFINITIONS
38
38
 
39
39
extern void freeSourceFileResources (void)
40
40
{
41
 
    vStringDelete (File.name);
42
 
    vStringDelete (File.path);
43
 
    vStringDelete (File.source.name);
44
 
    vStringDelete (File.line);
 
41
        vStringDelete (File.name);
 
42
        vStringDelete (File.path);
 
43
        vStringDelete (File.source.name);
 
44
        vStringDelete (File.line);
45
45
}
46
46
 
47
47
/*
50
50
 
51
51
static void setInputFileName (const char *const fileName)
52
52
{
53
 
    const char *const head = fileName;
54
 
    const char *const tail = baseFilename (head);
55
 
 
56
 
    if (File.name != NULL)
57
 
        vStringDelete (File.name);
58
 
    File.name = vStringNewInit (fileName);
59
 
 
60
 
    if (File.path != NULL)
61
 
        vStringDelete (File.path);
62
 
    if (tail == head)
63
 
        File.path = NULL;
64
 
    else
65
 
    {
66
 
        const size_t length = tail - head - 1;
67
 
        File.path = vStringNew ();
68
 
        vStringNCopyS (File.path, fileName, length);
69
 
    }
 
53
        const char *const head = fileName;
 
54
        const char *const tail = baseFilename (head);
 
55
 
 
56
        if (File.name != NULL)
 
57
                vStringDelete (File.name);
 
58
        File.name = vStringNewInit (fileName);
 
59
 
 
60
        if (File.path != NULL)
 
61
                vStringDelete (File.path);
 
62
        if (tail == head)
 
63
                File.path = NULL;
 
64
        else
 
65
        {
 
66
                const size_t length = tail - head - 1;
 
67
                File.path = vStringNew ();
 
68
                vStringNCopyS (File.path, fileName, length);
 
69
        }
70
70
}
71
71
 
72
72
static void setSourceFileParameters (vString *const fileName)
73
73
{
74
 
    if (File.source.name != NULL)
75
 
        vStringDelete (File.source.name);
76
 
    File.source.name = fileName;
77
 
 
78
 
    if (File.source.tagPath != NULL)
79
 
        eFree (File.source.tagPath);
80
 
    if (! Option.tagRelative || isAbsolutePath (vStringValue (fileName)))
81
 
        File.source.tagPath = eStrdup (vStringValue (fileName));
82
 
    else
83
 
        File.source.tagPath =
84
 
                relativeFilename (vStringValue (fileName), TagFile.directory);
85
 
 
86
 
    if (vStringLength (fileName) > TagFile.max.file)
87
 
        TagFile.max.file = vStringLength (fileName);
88
 
 
89
 
    File.source.isHeader = isIncludeFile (vStringValue (fileName));
90
 
    File.source.language = getFileLanguage (vStringValue (fileName));
 
74
        if (File.source.name != NULL)
 
75
                vStringDelete (File.source.name);
 
76
        File.source.name = fileName;
 
77
 
 
78
        if (File.source.tagPath != NULL)
 
79
                eFree (File.source.tagPath);
 
80
        if (! Option.tagRelative || isAbsolutePath (vStringValue (fileName)))
 
81
                File.source.tagPath = eStrdup (vStringValue (fileName));
 
82
        else
 
83
                File.source.tagPath =
 
84
                                relativeFilename (vStringValue (fileName), TagFile.directory);
 
85
 
 
86
        if (vStringLength (fileName) > TagFile.max.file)
 
87
                TagFile.max.file = vStringLength (fileName);
 
88
 
 
89
        File.source.isHeader = isIncludeFile (vStringValue (fileName));
 
90
        File.source.language = getFileLanguage (vStringValue (fileName));
91
91
}
92
92
 
93
93
static boolean setSourceFileName (vString *const fileName)
94
94
{
95
 
    boolean result = FALSE;
96
 
    if (getFileLanguage (vStringValue (fileName)) != LANG_IGNORE)
97
 
    {
98
 
        vString *pathName;
99
 
        if (isAbsolutePath (vStringValue (fileName)) || File.path == NULL)
100
 
            pathName = vStringNewCopy (fileName);
101
 
        else
102
 
            pathName = combinePathAndFile (vStringValue (File.path),
103
 
                                        vStringValue (fileName));
104
 
        setSourceFileParameters (pathName);
105
 
        result = TRUE;
106
 
    }
107
 
    return result;
 
95
        boolean result = FALSE;
 
96
        if (getFileLanguage (vStringValue (fileName)) != LANG_IGNORE)
 
97
        {
 
98
                vString *pathName;
 
99
                if (isAbsolutePath (vStringValue (fileName)) || File.path == NULL)
 
100
                        pathName = vStringNewCopy (fileName);
 
101
                else
 
102
                        pathName = combinePathAndFile (
 
103
                                        vStringValue (File.path), vStringValue (fileName));
 
104
                setSourceFileParameters (pathName);
 
105
                result = TRUE;
 
106
        }
 
107
        return result;
108
108
}
109
109
 
110
110
/*
113
113
 
114
114
static int skipWhite (void)
115
115
{
116
 
    int c;
117
 
    do
118
 
        c = getc (File.fp);
119
 
    while (c == ' '  ||  c == '\t');
120
 
    return c;
 
116
        int c;
 
117
        do
 
118
                c = getc (File.fp);
 
119
        while (c == ' '  ||  c == '\t');
 
120
        return c;
121
121
}
122
122
 
123
123
static unsigned long readLineNumber (void)
124
124
{
125
 
    unsigned long lNum = 0;
126
 
    int c = skipWhite ();
127
 
    while (c != EOF  &&  isdigit (c))
128
 
    {
129
 
        lNum = (lNum * 10) + (c - '0');
130
 
        c = getc (File.fp);
131
 
    }
132
 
    ungetc (c, File.fp);
133
 
    if (c != ' '  &&  c != '\t')
134
 
        lNum = 0;
 
125
        unsigned long lNum = 0;
 
126
        int c = skipWhite ();
 
127
        while (c != EOF  &&  isdigit (c))
 
128
        {
 
129
                lNum = (lNum * 10) + (c - '0');
 
130
                c = getc (File.fp);
 
131
        }
 
132
        ungetc (c, File.fp);
 
133
        if (c != ' '  &&  c != '\t')
 
134
                lNum = 0;
135
135
 
136
 
    return lNum;
 
136
        return lNum;
137
137
}
138
138
 
139
139
/* While ANSI only permits lines of the form:
146
146
 */
147
147
static vString *readFileName (void)
148
148
{
149
 
    vString *const fileName = vStringNew ();
150
 
    boolean quoteDelimited = FALSE;
151
 
    int c = skipWhite ();
152
 
 
153
 
    if (c == '"')
154
 
    {
155
 
        c = getc (File.fp);             /* skip double-quote */
156
 
        quoteDelimited = TRUE;
157
 
    }
158
 
    while (c != EOF  &&  c != '\n'  &&
159
 
            (quoteDelimited ? (c != '"') : (c != ' '  &&  c != '\t')))
160
 
    {
161
 
        vStringPut (fileName, c);
162
 
        c = getc (File.fp);
163
 
    }
164
 
    if (c == '\n')
165
 
        ungetc (c, File.fp);
166
 
    vStringPut (fileName, '\0');
167
 
 
168
 
    return fileName;
 
149
        vString *const fileName = vStringNew ();
 
150
        boolean quoteDelimited = FALSE;
 
151
        int c = skipWhite ();
 
152
 
 
153
        if (c == '"')
 
154
        {
 
155
                c = getc (File.fp);  /* skip double-quote */
 
156
                quoteDelimited = TRUE;
 
157
        }
 
158
        while (c != EOF  &&  c != '\n'  &&
 
159
                        (quoteDelimited ? (c != '"') : (c != ' '  &&  c != '\t')))
 
160
        {
 
161
                vStringPut (fileName, c);
 
162
                c = getc (File.fp);
 
163
        }
 
164
        if (c == '\n')
 
165
                ungetc (c, File.fp);
 
166
        vStringPut (fileName, '\0');
 
167
 
 
168
        return fileName;
169
169
}
170
170
 
171
171
static boolean parseLineDirective (void)
172
172
{
173
 
    boolean result = FALSE;
174
 
    int c = skipWhite ();
175
 
    DebugStatement ( const char* lineStr = ""; )
176
 
 
177
 
    if (isdigit (c))
178
 
    {
179
 
        ungetc (c, File.fp);
180
 
        result = TRUE;
181
 
    }
182
 
    else if (c == 'l'  &&  getc (File.fp) == 'i'  &&
183
 
             getc (File.fp) == 'n'  &&  getc (File.fp) == 'e')
184
 
    {
185
 
        c = getc (File.fp);
186
 
        if (c == ' '  ||  c == '\t')
187
 
        {
188
 
            DebugStatement ( lineStr = "line"; )
189
 
            result = TRUE;
190
 
        }
191
 
    }
192
 
    if (result)
193
 
    {
194
 
        const unsigned long lNum = readLineNumber ();
195
 
        if (lNum == 0)
196
 
            result = FALSE;
197
 
        else
198
 
        {
199
 
            vString *const fileName = readFileName ();
200
 
            if (vStringLength (fileName) == 0)
201
 
            {
202
 
                File.source.lineNumber = lNum - 1;  /* applies to NEXT line */
203
 
                DebugStatement ( debugPrintf (DEBUG_RAW, "#%s %ld", lineStr, lNum); )
204
 
            }
205
 
            else if (setSourceFileName (fileName))
206
 
            {
207
 
                File.source.lineNumber = lNum - 1;  /* applies to NEXT line */
208
 
                DebugStatement ( debugPrintf (DEBUG_RAW, "#%s %ld \"%s\"",
209
 
                                lineStr, lNum, vStringValue (fileName)); )
210
 
            }
211
 
 
212
 
            if (Option.include.fileNames && vStringLength (fileName) > 0 &&
213
 
                lNum == 1)
214
 
            {
215
 
                tagEntryInfo tag;
216
 
                initTagEntry (&tag, baseFilename (vStringValue (fileName)));
217
 
 
218
 
                tag.isFileEntry     = TRUE;
219
 
                tag.lineNumberEntry = TRUE;
220
 
                tag.lineNumber      = 1;
221
 
                tag.kindName        = "file";
222
 
                tag.kind            = 'F';
223
 
 
224
 
                makeTagEntry (&tag);
225
 
            }
226
 
            vStringDelete (fileName);
227
 
            result = TRUE;
228
 
        }
229
 
    }
230
 
    return result;
 
173
        boolean result = FALSE;
 
174
        int c = skipWhite ();
 
175
        DebugStatement ( const char* lineStr = ""; )
 
176
 
 
177
        if (isdigit (c))
 
178
        {
 
179
                ungetc (c, File.fp);
 
180
                result = TRUE;
 
181
        }
 
182
        else if (c == 'l'  &&  getc (File.fp) == 'i'  &&
 
183
                         getc (File.fp) == 'n'  &&  getc (File.fp) == 'e')
 
184
        {
 
185
                c = getc (File.fp);
 
186
                if (c == ' '  ||  c == '\t')
 
187
                {
 
188
                        DebugStatement ( lineStr = "line"; )
 
189
                        result = TRUE;
 
190
                }
 
191
        }
 
192
        if (result)
 
193
        {
 
194
                const unsigned long lNum = readLineNumber ();
 
195
                if (lNum == 0)
 
196
                        result = FALSE;
 
197
                else
 
198
                {
 
199
                        vString *const fileName = readFileName ();
 
200
                        if (vStringLength (fileName) == 0)
 
201
                        {
 
202
                                File.source.lineNumber = lNum - 1;  /* applies to NEXT line */
 
203
                                DebugStatement ( debugPrintf (DEBUG_RAW, "#%s %ld", lineStr, lNum); )
 
204
                        }
 
205
                        else if (setSourceFileName (fileName))
 
206
                        {
 
207
                                File.source.lineNumber = lNum - 1;  /* applies to NEXT line */
 
208
                                DebugStatement ( debugPrintf (DEBUG_RAW, "#%s %ld \"%s\"",
 
209
                                                                lineStr, lNum, vStringValue (fileName)); )
 
210
                        }
 
211
 
 
212
                        if (Option.include.fileNames && vStringLength (fileName) > 0 &&
 
213
                                lNum == 1)
 
214
                        {
 
215
                                tagEntryInfo tag;
 
216
                                initTagEntry (&tag, baseFilename (vStringValue (fileName)));
 
217
 
 
218
                                tag.isFileEntry     = TRUE;
 
219
                                tag.lineNumberEntry = TRUE;
 
220
                                tag.lineNumber      = 1;
 
221
                                tag.kindName        = "file";
 
222
                                tag.kind            = 'F';
 
223
 
 
224
                                makeTagEntry (&tag);
 
225
                        }
 
226
                        vStringDelete (fileName);
 
227
                        result = TRUE;
 
228
                }
 
229
        }
 
230
        return result;
231
231
}
232
232
 
233
233
/*
240
240
extern boolean fileOpen (const char *const fileName, const langType language)
241
241
{
242
242
#ifdef VMS
243
 
    const char *const openMode = "r";
 
243
        const char *const openMode = "r";
244
244
#else
245
 
    const char *const openMode = "rb";
 
245
        const char *const openMode = "rb";
246
246
#endif
247
 
    boolean opened = FALSE;
248
 
 
249
 
    /*  If another file was already open, then close it.
250
 
     */
251
 
    if (File.fp != NULL)
252
 
    {
253
 
        fclose (File.fp);               /* close any open source file */
254
 
        File.fp = NULL;
255
 
    }
256
 
 
257
 
    File.fp = fopen (fileName, openMode);
258
 
    if (File.fp == NULL)
259
 
        error (WARNING | PERROR, "cannot open \"%s\"", fileName);
260
 
    else
261
 
    {
262
 
        opened = TRUE;
263
 
 
264
 
        setInputFileName (fileName);
265
 
        fgetpos (File.fp, &StartOfLine);
266
 
        fgetpos (File.fp, &File.filePosition);
267
 
        File.currentLine  = NULL;
268
 
        File.language     = language;
269
 
        File.lineNumber   = 0L;
270
 
        File.eof          = FALSE;
271
 
        File.newLine      = TRUE;
272
 
 
273
 
        if (File.line != NULL)
274
 
            vStringClear (File.line);
275
 
 
276
 
        setSourceFileParameters (vStringNewInit (fileName));
277
 
        File.source.lineNumber = 0L;
278
 
 
279
 
        verbose ("OPENING %s as %s language %sfile\n", fileName,
280
 
                getLanguageName (language),
281
 
                File.source.isHeader ? "include " : "");
282
 
    }
283
 
    return opened;
 
247
        boolean opened = FALSE;
 
248
 
 
249
        /*      If another file was already open, then close it.
 
250
         */
 
251
        if (File.fp != NULL)
 
252
        {
 
253
                fclose (File.fp);  /* close any open source file */
 
254
                File.fp = NULL;
 
255
        }
 
256
 
 
257
        File.fp = fopen (fileName, openMode);
 
258
        if (File.fp == NULL)
 
259
                error (WARNING | PERROR, "cannot open \"%s\"", fileName);
 
260
        else
 
261
        {
 
262
                opened = TRUE;
 
263
 
 
264
                setInputFileName (fileName);
 
265
                fgetpos (File.fp, &StartOfLine);
 
266
                fgetpos (File.fp, &File.filePosition);
 
267
                File.currentLine  = NULL;
 
268
                File.language     = language;
 
269
                File.lineNumber   = 0L;
 
270
                File.eof          = FALSE;
 
271
                File.newLine      = TRUE;
 
272
 
 
273
                if (File.line != NULL)
 
274
                        vStringClear (File.line);
 
275
 
 
276
                setSourceFileParameters (vStringNewInit (fileName));
 
277
                File.source.lineNumber = 0L;
 
278
 
 
279
                verbose ("OPENING %s as %s language %sfile\n", fileName,
 
280
                                getLanguageName (language),
 
281
                                File.source.isHeader ? "include " : "");
 
282
        }
 
283
        return opened;
284
284
}
285
285
 
286
286
extern void fileClose (void)
287
287
{
288
 
    if (File.fp != NULL)
289
 
    {
290
 
        /*  The line count of the file is 1 too big, since it is one-based
291
 
         *  and is incremented upon each newline.
292
 
         */
293
 
        if (Option.printTotals)
 
288
        if (File.fp != NULL)
294
289
        {
295
 
            fileStatus *status = eStat (vStringValue (File.name));
296
 
            addTotals (0, File.lineNumber - 1L, status->size);
 
290
                /*  The line count of the file is 1 too big, since it is one-based
 
291
                 *  and is incremented upon each newline.
 
292
                 */
 
293
                if (Option.printTotals)
 
294
                {
 
295
                        fileStatus *status = eStat (vStringValue (File.name));
 
296
                        addTotals (0, File.lineNumber - 1L, status->size);
 
297
                }
 
298
                fclose (File.fp);
 
299
                File.fp = NULL;
297
300
        }
298
 
        fclose (File.fp);
299
 
        File.fp = NULL;
300
 
    }
301
301
}
302
302
 
303
303
extern boolean fileEOF (void)
304
304
{
305
 
    return File.eof;
 
305
        return File.eof;
306
306
}
307
307
 
308
308
/*  Action to take for each encountered source newline.
309
309
 */
310
310
static void fileNewline (void)
311
311
{
312
 
    File.filePosition = StartOfLine;
313
 
    File.newLine = FALSE;
314
 
    File.lineNumber++;
315
 
    File.source.lineNumber++;
316
 
    DebugStatement ( if (Option.breakLine == File.lineNumber) lineBreak (); )
317
 
    DebugStatement ( debugPrintf (DEBUG_RAW, "%6ld: ", File.lineNumber); )
 
312
        File.filePosition = StartOfLine;
 
313
        File.newLine = FALSE;
 
314
        File.lineNumber++;
 
315
        File.source.lineNumber++;
 
316
        DebugStatement ( if (Option.breakLine == File.lineNumber) lineBreak (); )
 
317
        DebugStatement ( debugPrintf (DEBUG_RAW, "%6ld: ", File.lineNumber); )
318
318
}
319
319
 
320
320
/*  This function reads a single character from the stream, performing newline
322
322
 */
323
323
static int iFileGetc (void)
324
324
{
325
 
    int c;
 
325
        int     c;
326
326
readnext:
327
 
    c = getc (File.fp);
328
 
 
329
 
    /*  If previous character was a newline, then we're starting a line.
330
 
     */
331
 
    if (File.newLine  &&  c != EOF)
332
 
    {
333
 
        fileNewline ();
334
 
        if (c == '#'  &&  Option.lineDirectives)
335
 
        {
336
 
            if (parseLineDirective ())
337
 
                goto readnext;
338
 
            else
339
 
            {
340
 
                fsetpos (File.fp, &StartOfLine);
341
 
                c = getc (File.fp);
342
 
            }
343
 
        }
344
 
    }
345
 
 
346
 
    if (c == EOF)
347
 
        File.eof = TRUE;
348
 
    else if (c == NEWLINE)
349
 
    {
350
 
        File.newLine = TRUE;
351
 
        fgetpos (File.fp, &StartOfLine);
352
 
    }
353
 
    else if (c == CRETURN)
354
 
    {
355
 
        /*  Turn line breaks into a canonical form. The three commonly
356
 
         *  used forms if line breaks: LF (UNIX), CR (MacIntosh), and
357
 
         *  CR-LF (MS-DOS) are converted into a generic newline.
 
327
        c = getc (File.fp);
 
328
 
 
329
        /*      If previous character was a newline, then we're starting a line.
358
330
         */
359
 
        const int next = getc (File.fp);        /* is CR followed by LF? */
360
 
 
361
 
        if (next != NEWLINE)
362
 
            ungetc (next, File.fp);
363
 
 
364
 
        c = NEWLINE;                            /* convert CR into newline */
365
 
        File.newLine = TRUE;
366
 
        fgetpos (File.fp, &StartOfLine);
367
 
    }
368
 
    DebugStatement ( debugPutc (DEBUG_RAW, c); )
369
 
    return c;
 
331
        if (File.newLine  &&  c != EOF)
 
332
        {
 
333
                fileNewline ();
 
334
                if (c == '#'  &&  Option.lineDirectives)
 
335
                {
 
336
                        if (parseLineDirective ())
 
337
                                goto readnext;
 
338
                        else
 
339
                        {
 
340
                                fsetpos (File.fp, &StartOfLine);
 
341
                                c = getc (File.fp);
 
342
                        }
 
343
                }
 
344
        }
 
345
 
 
346
        if (c == EOF)
 
347
                File.eof = TRUE;
 
348
        else if (c == NEWLINE)
 
349
        {
 
350
                File.newLine = TRUE;
 
351
                fgetpos (File.fp, &StartOfLine);
 
352
        }
 
353
        else if (c == CRETURN)
 
354
        {
 
355
                /*  Turn line breaks into a canonical form. The three commonly
 
356
                 *  used forms if line breaks: LF (UNIX), CR (MacIntosh), and
 
357
                 *  CR-LF (MS-DOS) are converted into a generic newline.
 
358
                 */
 
359
                const int next = getc (File.fp);  /* is CR followed by LF? */
 
360
 
 
361
                if (next != NEWLINE)
 
362
                        ungetc (next, File.fp);
 
363
 
 
364
                c = NEWLINE;  /* convert CR into newline */
 
365
                File.newLine = TRUE;
 
366
                fgetpos (File.fp, &StartOfLine);
 
367
        }
 
368
        DebugStatement ( debugPutc (DEBUG_RAW, c); )
 
369
        return c;
370
370
}
371
371
 
372
372
extern void fileUngetc (int c)
373
373
{
374
 
    File.ungetch = c;
 
374
        File.ungetch = c;
375
375
}
376
376
 
377
377
static vString *iFileGetLine (void)
378
378
{
379
 
    vString *result = NULL;
380
 
    int c;
381
 
    if (File.line == NULL)
382
 
        File.line = vStringNew ();
383
 
    vStringClear (File.line);
384
 
    do
385
 
    {
386
 
        c = iFileGetc ();
387
 
        if (c != EOF)
388
 
            vStringPut (File.line, c);
389
 
        if (c == '\n'  ||  (c == EOF  &&  vStringLength (File.line) > 0))
 
379
        vString *result = NULL;
 
380
        int c;
 
381
        if (File.line == NULL)
 
382
                File.line = vStringNew ();
 
383
        vStringClear (File.line);
 
384
        do
390
385
        {
391
 
            vStringTerminate (File.line);
 
386
                c = iFileGetc ();
 
387
                if (c != EOF)
 
388
                        vStringPut (File.line, c);
 
389
                if (c == '\n'  ||  (c == EOF  &&  vStringLength (File.line) > 0))
 
390
                {
 
391
                        vStringTerminate (File.line);
392
392
#ifdef HAVE_REGEX
393
 
            if (vStringLength (File.line) > 0)
394
 
                matchRegex (File.line, File.source.language);
 
393
                        if (vStringLength (File.line) > 0)
 
394
                                matchRegex (File.line, File.source.language);
395
395
#endif
396
 
            result = File.line;
397
 
            break;
398
 
        }
399
 
    } while (c != EOF);
400
 
    Assert (result != NULL  ||  File.eof);
401
 
    return result;
 
396
                        result = File.line;
 
397
                        break;
 
398
                }
 
399
        } while (c != EOF);
 
400
        Assert (result != NULL  ||  File.eof);
 
401
        return result;
402
402
}
403
403
 
404
404
/*  Do not mix use of fileReadLine () and fileGetc () for the same file.
405
405
 */
406
406
extern int fileGetc (void)
407
407
{
408
 
    int c;
 
408
        int c;
409
409
 
410
 
    /*  If there is an ungotten character, then return it.  Don't do any
411
 
     *  other processing on it, though, because we already did that the
412
 
     *  first time it was read through fileGetc ().
413
 
     */
414
 
    if (File.ungetch != '\0')
415
 
    {
416
 
        c = File.ungetch;
417
 
        File.ungetch = '\0';
418
 
        return c;           /* return here to avoid re-calling debugPutc () */
419
 
    }
420
 
    do
421
 
    {
422
 
        if (File.currentLine != NULL)
423
 
        {
424
 
            c = *File.currentLine++;
425
 
            if (c == '\0')
426
 
                File.currentLine = NULL;
427
 
        }
428
 
        else
429
 
        {
430
 
            vString* const line = iFileGetLine ();
431
 
            if (line != NULL)
432
 
                File.currentLine = (unsigned char*) vStringValue (line);
433
 
            if (File.currentLine == NULL)
434
 
                c = EOF;
435
 
            else
436
 
                c = '\0';
437
 
        }
438
 
    } while (c == '\0');
439
 
    DebugStatement ( debugPutc (DEBUG_READ, c); )
440
 
    return c;
 
410
        /*  If there is an ungotten character, then return it.  Don't do any
 
411
         *  other processing on it, though, because we already did that the
 
412
         *  first time it was read through fileGetc ().
 
413
         */
 
414
        if (File.ungetch != '\0')
 
415
        {
 
416
                c = File.ungetch;
 
417
                File.ungetch = '\0';
 
418
                return c;  /* return here to avoid re-calling debugPutc () */
 
419
        }
 
420
        do
 
421
        {
 
422
                if (File.currentLine != NULL)
 
423
                {
 
424
                        c = *File.currentLine++;
 
425
                        if (c == '\0')
 
426
                                File.currentLine = NULL;
 
427
                }
 
428
                else
 
429
                {
 
430
                        vString* const line = iFileGetLine ();
 
431
                        if (line != NULL)
 
432
                                File.currentLine = (unsigned char*) vStringValue (line);
 
433
                        if (File.currentLine == NULL)
 
434
                                c = EOF;
 
435
                        else
 
436
                                c = '\0';
 
437
                }
 
438
        } while (c == '\0');
 
439
        DebugStatement ( debugPutc (DEBUG_READ, c); )
 
440
        return c;
441
441
}
442
442
 
443
443
/*  An alternative interface to fileGetc (). Do not mix use of fileReadLine()
447
447
 */
448
448
extern const unsigned char *fileReadLine (void)
449
449
{
450
 
    vString* const line = iFileGetLine ();
451
 
    const unsigned char* result = NULL;
452
 
    if (line != NULL)
453
 
    {
454
 
        result = (const unsigned char*) vStringValue (line);
455
 
        vStringStripNewline (line);
456
 
        DebugStatement ( debugPrintf (DEBUG_READ, "%s\n", result); )
457
 
    }
458
 
    return result;
 
450
        vString* const line = iFileGetLine ();
 
451
        const unsigned char* result = NULL;
 
452
        if (line != NULL)
 
453
        {
 
454
                result = (const unsigned char*) vStringValue (line);
 
455
                vStringStripNewline (line);
 
456
                DebugStatement ( debugPrintf (DEBUG_READ, "%s\n", result); )
 
457
        }
 
458
        return result;
459
459
}
460
460
 
461
461
/*
463
463
 */
464
464
extern char *readLine (vString *const vLine, FILE *const fp)
465
465
{
466
 
    char *result = NULL;
467
 
 
468
 
    vStringClear (vLine);
469
 
    if (fp == NULL)             /* to free memory allocated to buffer */
470
 
        error (FATAL, "NULL file pointer");
471
 
    else
472
 
    {
473
 
        boolean reReadLine;
474
 
 
475
 
        /*  If reading the line places any character other than a null or a
476
 
         *  newline at the last character position in the buffer (one less
477
 
         *  than the buffer size), then we must resize the buffer and
478
 
         *  reattempt to read the line.
479
 
         */
480
 
        do
 
466
        char *result = NULL;
 
467
 
 
468
        vStringClear (vLine);
 
469
        if (fp == NULL)  /* to free memory allocated to buffer */
 
470
                error (FATAL, "NULL file pointer");
 
471
        else
481
472
        {
482
 
            char *const pLastChar = vStringValue (vLine) + vStringSize (vLine) -2;
483
 
            fpos_t startOfLine;
 
473
                boolean reReadLine;
484
474
 
485
 
            fgetpos (fp, &startOfLine);
486
 
            reReadLine = FALSE;
487
 
            *pLastChar = '\0';
488
 
            result = fgets (vStringValue (vLine), (int) vStringSize (vLine), fp);
489
 
            if (result == NULL)
490
 
            {
491
 
                if (! feof (fp))
492
 
                    error (FATAL | PERROR, "Failure on attempt to read file");
493
 
            }
494
 
            else if (*pLastChar != '\0'  &&
495
 
                     *pLastChar != '\n'  &&  *pLastChar != '\r')
496
 
            {
497
 
                /*  buffer overflow */
498
 
                reReadLine = vStringAutoResize (vLine);
499
 
                if (reReadLine)
500
 
                    fsetpos (fp, &startOfLine);
501
 
                else
502
 
                    error (FATAL | PERROR, "input line too big; out of memory");
503
 
            }
504
 
            else
505
 
            {
506
 
                char* eol;
507
 
                vStringSetLength (vLine);
508
 
                /* canonicalize new line */
509
 
                eol = vStringValue (vLine) + vStringLength (vLine) - 1;
510
 
                if (*eol == '\r')
511
 
                    *eol = '\n';
512
 
                else if (*(eol - 1) == '\r'  &&  *eol == '\n')
 
475
                /*  If reading the line places any character other than a null or a
 
476
                 *  newline at the last character position in the buffer (one less
 
477
                 *  than the buffer size), then we must resize the buffer and
 
478
                 *  reattempt to read the line.
 
479
                 */
 
480
                do
513
481
                {
514
 
                    *(eol - 1) = '\n';
515
 
                    *eol = '\0';
516
 
                    --vLine->length;
517
 
                }
518
 
            }
519
 
        } while (reReadLine);
520
 
    }
521
 
    return result;
 
482
                        char *const pLastChar = vStringValue (vLine) + vStringSize (vLine) -2;
 
483
                        fpos_t startOfLine;
 
484
 
 
485
                        fgetpos (fp, &startOfLine);
 
486
                        reReadLine = FALSE;
 
487
                        *pLastChar = '\0';
 
488
                        result = fgets (vStringValue (vLine), (int) vStringSize (vLine), fp);
 
489
                        if (result == NULL)
 
490
                        {
 
491
                                if (! feof (fp))
 
492
                                        error (FATAL | PERROR, "Failure on attempt to read file");
 
493
                        }
 
494
                        else if (*pLastChar != '\0'  &&
 
495
                                         *pLastChar != '\n'  &&  *pLastChar != '\r')
 
496
                        {
 
497
                                /*  buffer overflow */
 
498
                                reReadLine = vStringAutoResize (vLine);
 
499
                                if (reReadLine)
 
500
                                        fsetpos (fp, &startOfLine);
 
501
                                else
 
502
                                        error (FATAL | PERROR, "input line too big; out of memory");
 
503
                        }
 
504
                        else
 
505
                        {
 
506
                                char* eol;
 
507
                                vStringSetLength (vLine);
 
508
                                /* canonicalize new line */
 
509
                                eol = vStringValue (vLine) + vStringLength (vLine) - 1;
 
510
                                if (*eol == '\r')
 
511
                                        *eol = '\n';
 
512
                                else if (*(eol - 1) == '\r'  &&  *eol == '\n')
 
513
                                {
 
514
                                        *(eol - 1) = '\n';
 
515
                                        *eol = '\0';
 
516
                                        --vLine->length;
 
517
                                }
 
518
                        }
 
519
                } while (reReadLine);
 
520
        }
 
521
        return result;
522
522
}
523
523
 
524
524
/*  Places into the line buffer the contents of the line referenced by
525
525
 *  "location".
526
526
 */
527
 
extern char *readSourceLine (vString *const vLine, fpos_t location,
528
 
                             long *const pSeekValue)
 
527
extern char *readSourceLine (
 
528
                vString *const vLine, fpos_t location, long *const pSeekValue)
529
529
{
530
 
    fpos_t orignalPosition;
531
 
    char *result;
532
 
 
533
 
    fgetpos (File.fp, &orignalPosition);
534
 
    fsetpos (File.fp, &location);
535
 
    if (pSeekValue != NULL)
536
 
        *pSeekValue = ftell (File.fp);
537
 
    result = readLine (vLine, File.fp);
538
 
    if (result == NULL)
539
 
        error (FATAL, "Unexpected end of file: %s", vStringValue (File.name));
540
 
    fsetpos (File.fp, &orignalPosition);
541
 
 
542
 
    return result;
 
530
        fpos_t orignalPosition;
 
531
        char *result;
 
532
 
 
533
        fgetpos (File.fp, &orignalPosition);
 
534
        fsetpos (File.fp, &location);
 
535
        if (pSeekValue != NULL)
 
536
                *pSeekValue = ftell (File.fp);
 
537
        result = readLine (vLine, File.fp);
 
538
        if (result == NULL)
 
539
                error (FATAL, "Unexpected end of file: %s", vStringValue (File.name));
 
540
        fsetpos (File.fp, &orignalPosition);
 
541
 
 
542
        return result;
543
543
}
544
544
 
545
 
/* vi:set tabstop=8 shiftwidth=4: */
 
545
/* vi:set tabstop=4 shiftwidth=4: */