read.c
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:8k
源码类别:

编辑器/阅读器

开发平台:

DOS

  1. /*****************************************************************************
  2. *   $Id: read.c,v 6.6 1998/08/01 05:16:20 darren Exp $
  3. *
  4. *   Copyright (c) 1996-1998, 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 (line
  10. *   splicing and newline conversion for source files are performed at this
  11. *   level).
  12. *****************************************************************************/
  13. /*============================================================================
  14. =   Include files
  15. ============================================================================*/
  16. #ifdef HAVE_CONFIG_H
  17. # include <config.h>
  18. #endif
  19. #include <limits.h> /* to define INT_MAX or MAXINT */
  20. #include "ctags.h"
  21. /*============================================================================
  22. =   Data declarations
  23. ============================================================================*/
  24. typedef struct _langTab {
  25.     const char *extension;
  26.     langType language;
  27. } langTab;
  28. /*============================================================================
  29. =   Data definitions
  30. ============================================================================*/
  31. sourceFile File = { NULL, NULL, 0L, -1L, '', FALSE, FALSE, LANG_IGNORE };
  32. /*============================================================================
  33. =   Function prototypes
  34. ============================================================================*/
  35. static void fileNewline __ARGS((void));
  36. static boolean resizeLineBuffer __ARGS((lineBuf *const pLine));
  37. /*============================================================================
  38. =   Function definitions
  39. ============================================================================*/
  40. /*----------------------------------------------------------------------------
  41.  * Generic line reading with automatic buffer sizing
  42.  *--------------------------------------------------------------------------*/
  43. extern void freeLineBuffer( pLine )
  44.     lineBuf *const pLine;
  45. {
  46.     if (pLine->buffer != NULL)
  47. free(pLine->buffer);
  48.     pLine->buffer = NULL;
  49.     pLine->size = 0;
  50. }
  51. static boolean resizeLineBuffer( pLine )
  52.     lineBuf *const pLine;
  53. {
  54.     boolean ok = FALSE;
  55.     if (pLine->size <= INT_MAX / 2)
  56.     {
  57. const int newSize = pLine->size * 2;
  58. char *const newBuffer = (char *)realloc(pLine->buffer,(size_t)newSize);
  59. if (newBuffer != NULL)
  60. {
  61.     pLine->size = newSize;
  62.     pLine->buffer = newBuffer;
  63.     ok = TRUE;
  64. }
  65.     }
  66.     return ok;
  67. }
  68. /*  Read a newline terminated line from 'fp' and if it overflows the buffer
  69.  *  specified by 'pLine', increase the buffer. The buffer never shrinks. The
  70.  *  size of the buffer will always be the longest line encountered so far.
  71.  */
  72. extern char *readLine( pLine, fp )
  73.     lineBuf *const pLine;
  74.     FILE *const fp;
  75. {
  76.     char *line = NULL;
  77.     if (fp != NULL) /* to free memory allocated to buffer */
  78.     {
  79. boolean reReadLine;
  80. if (pLine->buffer == NULL) /* if buffer not yet allocated... */
  81. {
  82.     pLine->size = 32;
  83.     pLine->buffer = (char *)malloc((size_t)pLine->size);
  84. }
  85. /*  If reading the line places any character other than a null or a
  86.  *  newline at the last character position in the buffer (one less
  87.  *  than the buffer size), then we must resize the buffer and
  88.  *  reattempt to read the line.
  89.  */
  90. if (pLine->buffer != NULL) do 
  91. {
  92.     const long startOfLine = ftell(fp);
  93.     char *const pLastChar = pLine->buffer + pLine->size - 2;
  94.     reReadLine = FALSE;
  95.     *pLastChar = '';
  96.     line = fgets(pLine->buffer, pLine->size, fp);
  97.     if (*pLastChar != ''  &&  *pLastChar != 'n') /* overflow */
  98.     {
  99. if ((reReadLine = resizeLineBuffer(pLine)))
  100.     fseek(fp, startOfLine, SEEK_SET);
  101.     }
  102. } while (reReadLine);
  103.     }
  104.     return line;
  105. }
  106. /*----------------------------------------------------------------------------
  107.  * Source file access functions
  108.  *--------------------------------------------------------------------------*/
  109. /*  This function opens a source file, and resets the line counter.  If it
  110.  *  fails, it will display an error message and leave the File.fp set to NULL.
  111.  */
  112. extern boolean fileOpen( fileName, language, isHeader )
  113.     const char *const fileName;
  114.     const langType language;
  115.     const boolean isHeader;
  116. {
  117.     boolean opened = FALSE;
  118.     /* If another file was already open, then close it.
  119.      */
  120.     if (File.fp != NULL)
  121.     {
  122. fclose(File.fp); /* close any open source file */
  123. File.fp = NULL;
  124.     }
  125.     File.fp = fopen(fileName, "rb");  /* must be binary mode for fseek() */
  126.     if (File.fp == NULL)
  127. error(WARNING | PERROR, "cannot open "%s"", fileName);
  128.     else
  129.     {
  130. opened = TRUE;
  131. File.name = fileName;
  132. File.lineNumber = 0L;
  133. File.seek = 0L;
  134. File.afterNL    = TRUE;
  135. if (strlen(fileName) > TagFile.max.file)
  136.     TagFile.max.file = strlen(fileName);
  137. /* Determine whether this is a header File.
  138.     */
  139. File.isHeader = isHeader;
  140. File.language = language;
  141. DebugStatement( debugOpen(fileName, File.isHeader, File.language); )
  142.     }
  143.     return opened;
  144. }
  145. extern void fileClose()
  146. {
  147.     if (File.fp != NULL)
  148.     {
  149. /*  The line count of the file is 1 too big, since it is one-based
  150.  *  and is incremented upon each newline.
  151.  */
  152. if (Option.printTotals)
  153.     addTotals(0, File.lineNumber - 1L, getFileSize(File.name));
  154. fclose(File.fp);
  155. File.fp = NULL;
  156.     }
  157. }
  158. /*  Action to take for each encountered source newline.
  159.  */
  160. static void fileNewline()
  161. {
  162.     File.afterNL = FALSE;
  163.     File.seek  = ftell(File.fp);
  164.     ++File.lineNumber;
  165.     DebugStatement( if (Option.breakLine == File.lineNumber) lineBreak(); )
  166. }
  167. /*  This function reads a single character from the stream. 
  168.  */
  169. extern int fileGetc()
  170. {
  171.     boolean escaped = FALSE;
  172.     int c;
  173.     /* If there is an ungotten character, then return it.  Don't do any
  174.      * other processing on it, though, because we already did that the
  175.      * first time it was read.
  176.      */
  177.     if (File.ungetch != '')
  178.     {
  179. c = File.ungetch;
  180. File.ungetch = '';
  181. return c;     /* return here to avoid re-calling debugPutc() */
  182.     }
  183. nextChar: /* not structured, but faster for this critical path */
  184.     /* If previous character was a newline, then we're starting a line.
  185.      */
  186.     if (File.afterNL)
  187. fileNewline();
  188.     c = getc(File.fp);
  189.     switch (c)
  190.     {
  191.     default:
  192. if (escaped)
  193. {
  194.     ungetc(c, File.fp); /* return character after BACKSLASH */
  195.     c = BACKSLASH;
  196. }
  197. break;
  198.     case BACKSLASH: /* test for line splicing */
  199. if (escaped)
  200.     ungetc(c, File.fp); /* push back one just read */
  201. else
  202. {
  203.     escaped = TRUE; /* defer test until next character */
  204.     goto nextChar;
  205. }
  206. break;
  207.     /* The following cases turn line breaks into a canonical form. The three
  208.      * commonly used forms if line breaks: LF (UNIX), CR (MacIntosh), and
  209.      * CR-LF (MS-DOS) are converted into a generic newline.
  210.      */
  211.     case CRETURN:
  212. {
  213.     const int next = getc(File.fp); /* is CR followed by LF? */
  214.     /* If this is a carriage-return/line-feed pair, treat it as one
  215.      * newline, throwing away the line-feed.
  216.      */
  217.     if (next != NEWLINE)
  218. ungetc(next, File.fp);
  219. }
  220. c = NEWLINE; /* convert CR into newline */
  221.     case NEWLINE:
  222. File.afterNL = TRUE;
  223. if (escaped) /* check for line splicing */
  224. {
  225.     DebugStatement(
  226. debugPutc(BACKSLASH, DEBUG_RAW);     /* print the characters */
  227. debugPutc(c, DEBUG_RAW);      /*  we're throwing away */
  228.     )
  229.     escaped = FALSE;     /* BACKSLASH now fully processed */
  230.     goto nextChar;     /* through away "NEWLINE" */
  231. }
  232. break;
  233.     }
  234.     DebugStatement( debugPutc(c, DEBUG_RAW); )
  235.     return c;
  236. }
  237. extern void fileUngetc( c )
  238.     int c;
  239. {
  240.     File.ungetch = c;
  241. }
  242. /*  Places into the line buffer the contents of the line referenced by
  243.  *  "location".
  244.  */
  245. extern char *getSourceLine( pLine, location )
  246.     lineBuf *const pLine;
  247.     const long location;
  248. {
  249.     const long orignalPosition = ftell(File.fp);
  250.     char *line;
  251.     fseek(File.fp, location, SEEK_SET);
  252.     line = readLine(pLine, File.fp);
  253.     fseek(File.fp, orignalPosition, SEEK_SET);
  254.     return line;
  255. }
  256. /* vi:set tabstop=8 shiftwidth=4: */