This is read.c in view mode; [Download] [Up]
/***************************************************************************** * $Id: read.c,v 1.9 1997/04/26 05:41:50 darren Exp $ * * Copyright (c) 1996-1997, Darren Hiebert * * Conains low level source file read functions (line splicing and newline * conversion are performed at this level). *****************************************************************************/ /*============================================================================ = Include files ============================================================================*/ #ifdef HAVE_CONFIG_H # include <config.h> #endif /* To declare "struct stat" and stat(). */ #if __MWERKS__ # include <stat.h> /* there is no sys directory on the Mac */ #else # include <sys/types.h> # include <sys/stat.h> #endif #include "ctags.h" /*============================================================================ = Defines ============================================================================*/ /*---------------------------------------------------------------------------- *- Portability ----------------------------------------------------------------------------*/ /* These might not be defined. */ #ifndef S_ISREG # if defined(S_IFREG) && !defined(AMIGA) # define S_ISREG(mode) ((mode) & S_IFREG) # else # define S_ISREG(mode) TRUE /* assume regular file */ # endif #endif #ifndef S_ISLNK # ifdef S_IFLNK # define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) # else # define S_ISLNK(mode) FALSE /* assume no soft links */ # endif #endif /*---------------------------------------------------------------------------- *- Miscellaneous ----------------------------------------------------------------------------*/ #define is_file(st) (S_ISLNK((st)->st_mode) || S_ISREG((st)->st_mode)) /*============================================================================ = Data definitions ============================================================================*/ sourceFile File = { NULL, NULL, 0, -1, FALSE, 0, FALSE, FALSE }; /*============================================================================ = Function prototypes ============================================================================*/ static boolean isFileHeader __ARGS((const char *const name)); static void fileNewline __ARGS((void)); /*============================================================================ = Function definitions ============================================================================*/ /* Determines whether the specified file name is considered to be a header * file for the purposes of determining whether enclosed tags are global or * static. */ static boolean isFileHeader( name ) const char *const name; { boolean header = FALSE; /* default unless match found */ const char *extension; extension = strrchr(name, '.'); /* find last '.' */ if (extension != NULL) { int i; ++extension; /* skip to character after '.' */ for (i = 0 ; Option.headerExt[i] != NULL ; ++i) { if (strcmp(Option.headerExt[i], extension) == 0) { header = TRUE; /* found in list */ break; } } } return header; } /* This function opens a 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( name ) const char *const name; { boolean opened = FALSE; struct stat file_status; /* If another file was already open, then close it. */ if (File.fp != NULL) { fclose(File.fp); /* close any open source file */ File.fp = NULL; } if (stat(name, &file_status) != 0) perror(name); else if (is_file(&file_status)) { File.fp = fopen(name, "rb"); /* must be binary mode for fseek() */ if (File.fp == NULL) perror(name); else { opened = TRUE; File.name = name; File.lineNumber = 0L; File.seek = 0L; File.afterNL = TRUE; File.warned = FALSE; if (strlen(name) > TagFile.max.file) TagFile.max.file = strlen(name); /* Determine whether this is a header File. */ File.header = isFileHeader(name); #ifdef DEBUG debugOpen(name); #endif } } return opened; } extern void fileClose() { if (File.fp != NULL) { 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++; #ifdef DEBUG if (Option.breakLine == File.lineNumber) lineBreak(); #endif } /* 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 */ { #ifdef DEBUG debugPutc(BACKSLASH, DEBUG_VISUAL); /* print the characters */ debugPutc(c, DEBUG_VISUAL); /* we are throwing away */ #endif escaped = FALSE; /* BACKSLASH now fully processed */ goto nextChar; /* through away "\NEWLINE" */ } break; } #ifdef DEBUG debugPutc(c, DEBUG_VISUAL); #endif return c; } extern void fileUngetc( c ) int c; { File.ungetch = c; } /* Places into "line_buffer" the contents of the line referenced by "seek". */ extern void getFileLine( seek, line_buffer, maxLength ) const long seek; char *const line_buffer; const unsigned int maxLength; { const long oldseek = ftell(File.fp); /* remember original position */ fseek(File.fp, seek, SEEK_SET); fgets(line_buffer, (int)maxLength, File.fp); fseek(File.fp, oldseek, SEEK_SET); /* return to original position */ } /* vi:set tabstop=8 shiftwidth=4: */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.