📄 read.c
字号:
/*****************************************************************************
* $Id: read.c,v 6.6 1998/08/01 05:16:20 darren Exp $
*
* Copyright (c) 1996-1998, Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains low level source and tag file read functions (line
* splicing and newline conversion for source files are performed at this
* level).
*****************************************************************************/
/*============================================================================
= Include files
============================================================================*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <limits.h> /* to define INT_MAX or MAXINT */
#include "ctags.h"
/*============================================================================
= Data declarations
============================================================================*/
typedef struct _langTab {
const char *extension;
langType language;
} langTab;
/*============================================================================
= Data definitions
============================================================================*/
sourceFile File = { NULL, NULL, 0L, -1L, '\0', FALSE, FALSE, LANG_IGNORE };
/*============================================================================
= Function prototypes
============================================================================*/
static void fileNewline __ARGS((void));
static boolean resizeLineBuffer __ARGS((lineBuf *const pLine));
/*============================================================================
= Function definitions
============================================================================*/
/*----------------------------------------------------------------------------
* Generic line reading with automatic buffer sizing
*--------------------------------------------------------------------------*/
extern void freeLineBuffer( pLine )
lineBuf *const pLine;
{
if (pLine->buffer != NULL)
free(pLine->buffer);
pLine->buffer = NULL;
pLine->size = 0;
}
static boolean resizeLineBuffer( pLine )
lineBuf *const pLine;
{
boolean ok = FALSE;
if (pLine->size <= INT_MAX / 2)
{
const int newSize = pLine->size * 2;
char *const newBuffer = (char *)realloc(pLine->buffer,(size_t)newSize);
if (newBuffer != NULL)
{
pLine->size = newSize;
pLine->buffer = newBuffer;
ok = TRUE;
}
}
return ok;
}
/* Read a newline terminated line from 'fp' and if it overflows the buffer
* specified by 'pLine', increase the buffer. The buffer never shrinks. The
* size of the buffer will always be the longest line encountered so far.
*/
extern char *readLine( pLine, fp )
lineBuf *const pLine;
FILE *const fp;
{
char *line = NULL;
if (fp != NULL) /* to free memory allocated to buffer */
{
boolean reReadLine;
if (pLine->buffer == NULL) /* if buffer not yet allocated... */
{
pLine->size = 32;
pLine->buffer = (char *)malloc((size_t)pLine->size);
}
/* If reading the line places any character other than a null or a
* newline at the last character position in the buffer (one less
* than the buffer size), then we must resize the buffer and
* reattempt to read the line.
*/
if (pLine->buffer != NULL) do
{
const long startOfLine = ftell(fp);
char *const pLastChar = pLine->buffer + pLine->size - 2;
reReadLine = FALSE;
*pLastChar = '\0';
line = fgets(pLine->buffer, pLine->size, fp);
if (*pLastChar != '\0' && *pLastChar != '\n') /* overflow */
{
if ((reReadLine = resizeLineBuffer(pLine)))
fseek(fp, startOfLine, SEEK_SET);
}
} while (reReadLine);
}
return line;
}
/*----------------------------------------------------------------------------
* Source file access functions
*--------------------------------------------------------------------------*/
/* This function opens a source file, and resets the line counter. If it
* fails, it will display an error message and leave the File.fp set to NULL.
*/
extern boolean fileOpen( fileName, language, isHeader )
const char *const fileName;
const langType language;
const boolean isHeader;
{
boolean opened = FALSE;
/* If another file was already open, then close it.
*/
if (File.fp != NULL)
{
fclose(File.fp); /* close any open source file */
File.fp = NULL;
}
File.fp = fopen(fileName, "rb"); /* must be binary mode for fseek() */
if (File.fp == NULL)
error(WARNING | PERROR, "cannot open \"%s\"", fileName);
else
{
opened = TRUE;
File.name = fileName;
File.lineNumber = 0L;
File.seek = 0L;
File.afterNL = TRUE;
if (strlen(fileName) > TagFile.max.file)
TagFile.max.file = strlen(fileName);
/* Determine whether this is a header File.
*/
File.isHeader = isHeader;
File.language = language;
DebugStatement( debugOpen(fileName, File.isHeader, File.language); )
}
return opened;
}
extern void fileClose()
{
if (File.fp != NULL)
{
/* The line count of the file is 1 too big, since it is one-based
* and is incremented upon each newline.
*/
if (Option.printTotals)
addTotals(0, File.lineNumber - 1L, getFileSize(File.name));
fclose(File.fp);
File.fp = NULL;
}
}
/* Action to take for each encountered source newline.
*/
static void fileNewline()
{
File.afterNL = FALSE;
File.seek = ftell(File.fp);
++File.lineNumber;
DebugStatement( if (Option.breakLine == File.lineNumber) lineBreak(); )
}
/* This function reads a single character from the stream.
*/
extern int fileGetc()
{
boolean escaped = FALSE;
int c;
/* If there is an ungotten character, then return it. Don't do any
* other processing on it, though, because we already did that the
* first time it was read.
*/
if (File.ungetch != '\0')
{
c = File.ungetch;
File.ungetch = '\0';
return c; /* return here to avoid re-calling debugPutc() */
}
nextChar: /* not structured, but faster for this critical path */
/* If previous character was a newline, then we're starting a line.
*/
if (File.afterNL)
fileNewline();
c = getc(File.fp);
switch (c)
{
default:
if (escaped)
{
ungetc(c, File.fp); /* return character after BACKSLASH */
c = BACKSLASH;
}
break;
case BACKSLASH: /* test for line splicing */
if (escaped)
ungetc(c, File.fp); /* push back one just read */
else
{
escaped = TRUE; /* defer test until next character */
goto nextChar;
}
break;
/* The following cases turn line breaks into a canonical form. The three
* commonly used forms if line breaks: LF (UNIX), CR (MacIntosh), and
* CR-LF (MS-DOS) are converted into a generic newline.
*/
case CRETURN:
{
const int next = getc(File.fp); /* is CR followed by LF? */
/* If this is a carriage-return/line-feed pair, treat it as one
* newline, throwing away the line-feed.
*/
if (next != NEWLINE)
ungetc(next, File.fp);
}
c = NEWLINE; /* convert CR into newline */
case NEWLINE:
File.afterNL = TRUE;
if (escaped) /* check for line splicing */
{
DebugStatement(
debugPutc(BACKSLASH, DEBUG_RAW); /* print the characters */
debugPutc(c, DEBUG_RAW); /* we're throwing away */
)
escaped = FALSE; /* BACKSLASH now fully processed */
goto nextChar; /* through away "\NEWLINE" */
}
break;
}
DebugStatement( debugPutc(c, DEBUG_RAW); )
return c;
}
extern void fileUngetc( c )
int c;
{
File.ungetch = c;
}
/* Places into the line buffer the contents of the line referenced by
* "location".
*/
extern char *getSourceLine( pLine, location )
lineBuf *const pLine;
const long location;
{
const long orignalPosition = ftell(File.fp);
char *line;
fseek(File.fp, location, SEEK_SET);
line = readLine(pLine, File.fp);
fseek(File.fp, orignalPosition, SEEK_SET);
return line;
}
/* vi:set tabstop=8 shiftwidth=4: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -