This is files.c in view mode; [Download] [Up]
/***************************************************************/ /* */ /* FILES.C */ /* */ /* Controls the opening and closing of files, etc. Also */ /* handles caching of lines and reading of lines from */ /* files. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992, 1993, 1994 by David F. Skoll. */ /* */ /***************************************************************/ #include "config.h" #include <stdio.h> #ifdef HAVE_STDLIB_H #include <stdlib.h> #endif #ifdef HAVE_MALLOC_H #include <malloc.h> #endif #include <string.h> #include <ctype.h> #include <sys/types.h> #include <sys/stat.h> #include <time.h> #if defined(__MSDOS__) #include <io.h> #endif #ifdef __MSC__ #include <dos.h> #endif #include "types.h" #include "protos.h" #include "globals.h" #include "err.h" /* Convenient macro for closing files */ #define FCLOSE(fp) (((fp)&&((fp)!=stdin)) ? (fclose(fp),(fp)=NULL) : ((fp)=NULL)) /* Define the structures needed by the file caching system */ typedef struct cache { struct cache *next; char *text; int LineNo; } CachedLine; typedef struct cheader { struct cheader *next; char *filename; CachedLine *cache; } CachedFile; /* Define the structures needed by the INCLUDE file system */ typedef struct { char *filename; int LineNo; unsigned int IfFlags; int NumIfs; long offset; CachedLine *CLine; } IncludeStruct; static CachedFile *CachedFiles = (CachedFile *) NULL; static CachedLine *CLine = (CachedLine *) NULL; static FILE *fp; static IncludeStruct IStack[INCLUDE_NEST]; static int IStackPtr = 0; PRIVATE int ReadLineFromFile ARGS ((void)); PRIVATE int CacheFile ARGS ((const char *fname)); PRIVATE void DestroyCache ARGS ((CachedFile *cf)); /***************************************************************/ /* */ /* ReadLine */ /* */ /* Read a line from the file or cache. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int ReadLine(void) #else int ReadLine() #endif { int r; /* If we're at the end of a file, pop */ while (!CLine && !fp) { r = PopFile(); if (r) return r; } /* If it's cached, read line from the cache */ if (CLine) { CurLine = CLine->text; LineNo = CLine->LineNo; CLine = CLine->next; FreshLine = 1; if (DebugFlag & DB_ECHO_LINE) OutputLine(ErrFp); return OK; } /* Not cached. Read from the file. */ return ReadLineFromFile(); } /***************************************************************/ /* */ /* ReadLineFromFile */ /* */ /* Read a line from the file pointed to by fp. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PRIVATE int ReadLineFromFile(void) #else static ReadLineFromFile() #endif { int l; char *ptr; char *tmp; CurLine = LineBuffer; *LineBuffer = (char) 0; l = 0; ptr = LineBuffer; while(fp) { tmp=fgets(ptr, LINELEN-l, fp); LineNo++; if (ferror(fp)) return E_IO_ERR; if (feof(fp) || !tmp) { FCLOSE(fp); } l = strlen(LineBuffer); if (l && (LineBuffer[l-1] == '\n')) LineBuffer[--l] = '\0'; if (l && (LineBuffer[l-1] == '\\')) { l--; ptr = LineBuffer+l; if (l >= LINELEN-1) return E_LINE_2_LONG; continue; } FreshLine = 1; if (DebugFlag & DB_ECHO_LINE) OutputLine(ErrFp); return OK; } return OK; } /***************************************************************/ /* */ /* OpenFile */ /* */ /* Open a file for reading. If it's in the cache, set */ /* CLine. Otherwise, open it on disk and set fp. If */ /* ShouldCache is 1, cache the file */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int OpenFile(const char *fname) #else int OpenFile(fname) char *fname; #endif { CachedFile *h = CachedFiles; int r; /* If it's in the cache, get it from there. */ while (h) { if (!strcmp(fname, h->filename)) { CLine = h->cache; STRSET(FileName, fname); LineNo = 0; if (FileName) return OK; else return E_NO_MEM; } h = h->next; } /* If it's a dash, then it's stdin */ if (!strcmp(fname, "-")) { fp = stdin; } else { fp = fopen(fname, "r"); } if (!fp) return E_CANT_OPEN; CLine = NULL; if (ShouldCache) { LineNo = 0; r = CacheFile(fname); if (r == OK) { fp = NULL; CLine = CachedFiles->cache; } else { if (strcmp(fname, "-")) fp = fopen(fname, "r"); else fp = stdin; if (!fp) return E_CANT_OPEN; } } STRSET(FileName, fname); LineNo = 0; if (FileName) return OK; else return E_NO_MEM; } /***************************************************************/ /* */ /* CacheFile */ /* */ /* Cache a file in memory. If we fail, set ShouldCache to 0 */ /* Returns an indication of success or failure. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PRIVATE int CacheFile(const char *fname) #else static int CacheFile(fname) char *fname; #endif { int r; CachedFile *cf; CachedLine *cl; char *s; cl = NULL; /* Create a file header */ cf = NEW(CachedFile); cf->cache = NULL; if (!cf) { ShouldCache = 0; FCLOSE(fp); return E_NO_MEM; } cf->filename = StrDup(fname); if (!cf->filename) { ShouldCache = 0; FCLOSE(fp); free(cf); return E_NO_MEM; } /* Read the file */ while(fp) { r = ReadLineFromFile(); if (r) { DestroyCache(cf); ShouldCache = 0; FCLOSE(fp); return r; } /* Skip blank chars */ s = LineBuffer; while (isspace(*s)) s++; if (*s && *s!=';' && *s!='#') { /* Add the line to the cache */ if (!cl) { cf->cache = NEW(CachedLine); if (!cf->cache) { DestroyCache(cf); ShouldCache = 0; FCLOSE(fp); return E_NO_MEM; } cl = cf->cache; } else { cl->next = NEW(CachedLine); if (!cl->next) { DestroyCache(cf); ShouldCache = 0; FCLOSE(fp); return E_NO_MEM; } cl = cl->next; } cl->next = NULL; cl->LineNo = LineNo; cl->text = StrDup(s); if (!cl->text) { DestroyCache(cf); ShouldCache = 0; FCLOSE(fp); return E_NO_MEM; } } } /* Put the cached file at the head of the queue */ cf->next = CachedFiles; CachedFiles = cf; return OK; } /***************************************************************/ /* */ /* PopFile - we've reached the end. Pop up to the previous */ /* file, or return E_EOF */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int PopFile(void) #else int PopFile() #endif { IncludeStruct *i; if (!Hush && NumIfs) Eprint("%s", ErrMsg[E_MISS_ENDIF]); if (!IStackPtr) return E_EOF; IStackPtr--; i = &IStack[IStackPtr]; LineNo = i->LineNo; IfFlags = i->IfFlags; NumIfs = i->NumIfs; CLine = i->CLine; fp = NULL; STRSET(FileName, i->filename); if (!CLine && (i->offset != -1L)) { /* We must open the file, then seek to specified position */ if (strcmp(i->filename, "-")) fp = fopen(i->filename, "r"); else fp = stdin; if (!fp) return E_CANT_OPEN; if (fp != stdin) (void) fseek(fp, i->offset, 0); /* Trust that it works... */ } free(i->filename); return OK; } /***************************************************************/ /* */ /* DoInclude */ /* */ /* The INCLUDE command. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int DoInclude(ParsePtr p) #else int DoInclude(p) ParsePtr p; #endif { char tok[TOKSIZE]; int r, e; if ( (r=ParseToken(p, tok)) ) return r; e = VerifyEoln(p); if (e) Eprint("%s", ErrMsg[e]); if ( (r=IncludeFile(tok)) ) return r; NumIfs = 0; IfFlags = 0; return OK; } /***************************************************************/ /* */ /* IncludeFile */ /* */ /* Process the INCLUDE command - actually do the file */ /* inclusion. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int IncludeFile(const char *fname) #else int IncludeFile(fname) char *fname; #endif { IncludeStruct *i; int r; if (IStackPtr+1 >= INCLUDE_NEST) return E_NESTED_INCLUDE; i = &IStack[IStackPtr]; i->filename = StrDup(FileName); if (!i->filename) return E_NO_MEM; i->LineNo = LineNo; i->NumIfs = NumIfs; i->IfFlags = IfFlags; i->CLine = CLine; i->offset = -1L; if (fp) { i->offset = ftell(fp); FCLOSE(fp); } IStackPtr++; /* Try to open the new file */ if (!OpenFile(fname)) { return OK; } /* Ugh! We failed! */ if ( (r=PopFile()) ) return r; Eprint("%s: %s", ErrMsg[E_CANT_OPEN], fname); return E_CANT_OPEN; } /***************************************************************/ /* */ /* GetAccessDate - get the access date of a file. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int GetAccessDate(char *file) #else int GetAccessDate(file) char *file; #endif { struct stat statbuf; struct tm *t1; if (stat(file, &statbuf)) return -1; #ifdef __TURBOC__ t1 = localtime( (time_t *) &(statbuf.st_atime) ); #else t1 = localtime(&(statbuf.st_atime)); #endif if (t1->tm_year + 1900 < BASE) return 0; else return Julian(t1->tm_year+1900, t1->tm_mon, t1->tm_mday); } /***************************************************************/ /* */ /* SetAccessDate */ /* */ /* Used only by DOS to set access date after we close the */ /* file. Not needed for UNIX. */ /* */ /***************************************************************/ #if defined(__MSDOS__) /* * WARNING WARNING WARNING WARNING * In the version of Turbo C which I have, there is a bug in the * stdio.h file. The following lines correct the bug. YOU MAY * HAVE TO REMOVE THESE LINES FOR LATER VERSIONS OF TURBOC */ #ifdef __TURBOC__ #ifndef fileno #define fileno(f) ((f)->fd) #endif #endif #ifdef HAVE_PROTOS PUBLIC int SetAccessDate(char *fname, int jul) #else int SetAccessDate(fname, jul) char *fname; int jul; #endif { #ifdef __TURBOC__ int y, m, d; struct ftime ft; FILE *f; FromJulian(jul, &y, &m, &d); ft.ft_tsec = 0; ft.ft_min = 0; ft.ft_hour = 12; /* Arbitrarily set time to noon. */ ft.ft_day = (unsigned int) d; ft.ft_month = (unsigned int) m+1; ft.ft_year = (unsigned int) (y - 1980); f = fopen(fname, "r"); if (!f || setftime(fileno(f) , &ft)) { #else /* Must be MSC */ if (utime(fname, (struct utimbuf *) NULL)) { #endif fprintf(ErrFp, ErrMsg[M_CANTSET_ACCESS], fname); #ifdef __TURBOC__ if (f) FCLOSE(f); #endif return -1; } #ifdef __TURBOC__ FCLOSE(f); #endif return 0; } #endif /* __MSDOS__ */ /***************************************************************/ /* */ /* DestroyCache */ /* */ /* Free all the memory used by a cached file. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PRIVATE void DestroyCache(CachedFile *cf) #else static void DestroyCache(cf) CachedFile *cf; #endif { CachedLine *cl, *cnext; CachedFile *temp; if (cf->filename) free(cf->filename); cl = cf->cache; while (cl) { if (cl->text) free (cl->text); cnext = cl->next; free(cl); cl = cnext; } if (CachedFiles == cf) CachedFiles = cf->next; else { temp = CachedFiles; while(temp) { if (temp->next == cf) { temp->next = cf->next; break; } temp = temp->next; } } free(cf); } /***************************************************************/ /* */ /* TopLevel */ /* */ /* Returns 1 if current file is top level, 0 otherwise. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int TopLevel(void) #else int TopLevel() #endif { return !IStackPtr; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.