home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / os2 / remind / src / files.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-31  |  14.8 KB  |  557 lines

  1. /***************************************************************/
  2. /*                                                             */
  3. /*  FILES.C                                                    */
  4. /*                                                             */
  5. /*  Controls the opening and closing of files, etc.  Also      */
  6. /*  handles caching of lines and reading of lines from         */
  7. /*  files.                                                     */
  8. /*                                                             */
  9. /*  This file is part of REMIND.                               */
  10. /*  Copyright (C) 1992, 1993 by David F. Skoll.                */
  11. /*                                                             */
  12. /***************************************************************/
  13.  
  14. #include "config.h"
  15. #include <stdio.h>
  16. #ifdef HAVE_STDLIB_H
  17. #include <stdlib.h>
  18. #endif
  19. #ifdef HAVE_MALLOC_H
  20. #include <malloc.h>
  21. #endif
  22. #include <string.h>
  23. #include <ctype.h>
  24. #include <sys/types.h>
  25. #include <sys/stat.h>
  26. #include <time.h>
  27.  
  28. #if defined(__MSDOS__)
  29. #include <io.h>
  30. #endif
  31.  
  32. #ifdef __MSC__
  33. #include <dos.h>
  34. #endif
  35.  
  36. #include "types.h"
  37. #include "protos.h"
  38. #include "globals.h"
  39. #include "err.h"
  40.  
  41.  
  42. /* Convenient macro for closing files */
  43. #define FCLOSE(fp) (((fp)&&((fp)!=stdin)) ? (fclose(fp),(fp)=NULL) : ((fp)=NULL))
  44.  
  45. /* Define the structures needed by the file caching system */
  46. typedef struct cache {
  47.    struct cache *next;
  48.    char *text;
  49.    int LineNo;
  50. } CachedLine;
  51.  
  52. typedef struct cheader {
  53.    struct cheader *next;
  54.    char *filename;
  55.    CachedLine *cache;
  56. } CachedFile;
  57.  
  58. /* Define the structures needed by the INCLUDE file system */
  59. typedef struct {
  60.    char *filename;
  61.    int LineNo;
  62.    unsigned int IfFlags;
  63.    int NumIfs;
  64.    long offset;
  65.    CachedLine *CLine;
  66. } IncludeStruct;
  67.  
  68. static CachedFile *CachedFiles = (CachedFile *) NULL;
  69. static CachedLine *CLine = (CachedLine *) NULL;
  70.  
  71. static FILE *fp;
  72.  
  73. static IncludeStruct IStack[INCLUDE_NEST];
  74. static int IStackPtr = 0;
  75.  
  76. PRIVATE int ReadLineFromFile ARGS ((void));
  77. PRIVATE int CacheFile ARGS ((const char *fname));
  78. PRIVATE void DestroyCache ARGS ((CachedFile *cf));
  79.  
  80. /***************************************************************/
  81. /*                                                             */
  82. /*  ReadLine                                                   */
  83. /*                                                             */
  84. /*  Read a line from the file or cache.                        */
  85. /*                                                             */
  86. /***************************************************************/
  87. #ifdef HAVE_PROTOS
  88. PUBLIC int ReadLine(void)
  89. #else
  90. int ReadLine()
  91. #endif
  92. {
  93.    int r;
  94.  
  95. /* If we're at the end of a file, pop */
  96.    while (!CLine && !fp) {
  97.       r = PopFile();
  98.       if (r) return r;
  99.    }
  100.  
  101. /* If it's cached, read line from the cache */
  102.    if (CLine) {
  103.       CurLine = CLine->text;
  104.       LineNo = CLine->LineNo;
  105.       CLine = CLine->next;
  106.       FreshLine = 1;
  107.       if (DebugFlag & DB_ECHO_LINE) OutputLine(ErrFp);
  108.       return OK;
  109.    }
  110.  
  111. /* Not cached.  Read from the file. */
  112.    return ReadLineFromFile();
  113. }
  114.  
  115. /***************************************************************/
  116. /*                                                             */
  117. /*  ReadLineFromFile                                           */
  118. /*                                                             */
  119. /*  Read a line from the file pointed to by fp.                */
  120. /*                                                             */
  121. /***************************************************************/
  122. #ifdef HAVE_PROTOS
  123. PRIVATE int ReadLineFromFile(void)
  124. #else
  125. static ReadLineFromFile()
  126. #endif
  127. {
  128.    int l;
  129.    char *ptr;
  130.    char *tmp;
  131.  
  132.    CurLine = LineBuffer;
  133.    *LineBuffer = (char) 0;
  134.    l = 0;
  135.    ptr = LineBuffer;
  136.    while(fp) {
  137.       tmp=fgets(ptr, LINELEN-l, fp);
  138.       LineNo++;
  139.       if (ferror(fp)) return E_IO_ERR;
  140.       if (feof(fp) || !tmp) {
  141.          FCLOSE(fp);
  142.       }
  143.       l = strlen(LineBuffer);
  144.       if (l && (LineBuffer[l-1] == '\n')) LineBuffer[--l] = '\0';
  145.       if (l && (LineBuffer[l-1] == '\\')) {
  146.      l--;
  147.      ptr = LineBuffer+l;
  148.      if (l >= LINELEN-1) return E_LINE_2_LONG;
  149.      continue;
  150.       }
  151.       FreshLine = 1;
  152.       if (DebugFlag & DB_ECHO_LINE) OutputLine(ErrFp);
  153.       return OK;
  154.    }
  155.    return OK;
  156. }
  157.  
  158. /***************************************************************/
  159. /*                                                             */
  160. /*  OpenFile                                                   */
  161. /*                                                             */
  162. /*  Open a file for reading.  If it's in the cache, set        */
  163. /*  CLine.  Otherwise, open it on disk and set fp.  If         */
  164. /*  ShouldCache is 1, cache the file                           */
  165. /*                                                             */
  166. /***************************************************************/
  167. #ifdef HAVE_PROTOS
  168. PUBLIC int OpenFile(const char *fname)
  169. #else
  170. int OpenFile(fname)
  171. char *fname;
  172. #endif
  173. {
  174.    CachedFile *h = CachedFiles;
  175.    int r;
  176.  
  177. /* If it's in the cache, get it from there. */
  178.  
  179.    while (h) {
  180.       if (!strcmp(fname, h->filename)) {
  181.      CLine = h->cache;
  182.      STRSET(FileName, fname);
  183.      LineNo = 0;
  184.      if (FileName) return OK; else return E_NO_MEM;
  185.       }
  186.       h = h->next;
  187.    }
  188.  
  189. /* If it's a dash, then it's stdin */
  190.    if (!strcmp(fname, "-")) {
  191.       fp = stdin;
  192.    } else {
  193.       fp = fopen(fname, "r");
  194.    }
  195.    if (!fp) return E_CANT_OPEN;
  196.    CLine = NULL;
  197.    if (ShouldCache) {
  198.       LineNo = 0;
  199.       r = CacheFile(fname);
  200.       if (r == OK) {
  201.          fp = NULL;
  202.      CLine = CachedFiles->cache;
  203.       } else {
  204.          if (strcmp(fname, "-"))
  205.             fp = fopen(fname, "r");
  206.          else
  207.         fp = stdin;
  208.      if (!fp) return E_CANT_OPEN;
  209.       }
  210.    }
  211.    STRSET(FileName, fname);
  212.    LineNo = 0;
  213.    if (FileName) return OK; else return E_NO_MEM;
  214. }
  215.  
  216. /***************************************************************/
  217. /*                                                             */
  218. /*  CacheFile                                                  */
  219. /*                                                             */
  220. /*  Cache a file in memory.  If we fail, set ShouldCache to 0  */
  221. /*  Returns an indication of success or failure.               */
  222. /*                                                             */
  223. /***************************************************************/
  224. #ifdef HAVE_PROTOS
  225. PRIVATE int CacheFile(const char *fname)
  226. #else
  227. static int CacheFile(fname)
  228. char *fname;
  229. #endif
  230. {
  231.    int r;
  232.    CachedFile *cf;
  233.    CachedLine *cl;
  234.    char *s;
  235.  
  236.    cl = NULL;
  237. /* Create a file header */
  238.    cf = NEW(CachedFile);
  239.    cf->cache = NULL;
  240.    if (!cf) { ShouldCache = 0; FCLOSE(fp); return E_NO_MEM; }
  241.    cf->filename = StrDup(fname);
  242.    if (!cf->filename) {
  243.       ShouldCache = 0;
  244.       FCLOSE(fp);
  245.       free(cf);
  246.       return E_NO_MEM;
  247.    }
  248.  
  249. /* Read the file */
  250.    while(fp) {
  251.       r = ReadLineFromFile();
  252.       if (r) {
  253.          DestroyCache(cf);
  254.      ShouldCache = 0;
  255.      FCLOSE(fp);
  256.      return r;
  257.       }
  258. /* Skip blank chars */
  259.       s = LineBuffer;
  260.       while (isspace(*s)) s++;
  261.       if (*s && *s!=';' && *s!='#') {
  262. /* Add the line to the cache */
  263.          if (!cl) {
  264.         cf->cache = NEW(CachedLine);
  265.         if (!cf->cache) {
  266.            DestroyCache(cf);
  267.            ShouldCache = 0;
  268.            FCLOSE(fp);
  269.            return E_NO_MEM;
  270.             }
  271.         cl = cf->cache;
  272.          } else {
  273.         cl->next = NEW(CachedLine);
  274.         if (!cl->next) {
  275.            DestroyCache(cf);
  276.            ShouldCache = 0;
  277.            FCLOSE(fp);
  278.            return E_NO_MEM;
  279.             }
  280.         cl = cl->next;
  281.          }
  282.      cl->next = NULL;
  283.      cl->LineNo = LineNo;
  284.      cl->text = StrDup(s);
  285.      if (!cl->text) {
  286.         DestroyCache(cf);
  287.         ShouldCache = 0;
  288.         FCLOSE(fp);
  289.         return E_NO_MEM;
  290.          }
  291.       }
  292.    }
  293.  
  294. /* Put the cached file at the head of the queue */
  295.    cf->next = CachedFiles;
  296.    CachedFiles = cf;
  297.  
  298.    return OK;
  299. }
  300.  
  301. /***************************************************************/
  302. /*                                                             */
  303. /*  PopFile - we've reached the end.  Pop up to the previous   */
  304. /*  file, or return E_EOF                                      */
  305. /*                                                             */
  306. /***************************************************************/
  307. #ifdef HAVE_PROTOS
  308. PUBLIC int PopFile(void)
  309. #else
  310. int PopFile()
  311. #endif
  312. {
  313.    IncludeStruct *i;
  314.  
  315.    if (!Hush && NumIfs) Eprint("%s", ErrMsg[E_MISS_ENDIF]);
  316.    if (!IStackPtr) return E_EOF;
  317.    IStackPtr--;
  318.    i = &IStack[IStackPtr];
  319.  
  320.    LineNo = i->LineNo;
  321.    IfFlags = i->IfFlags;
  322.    NumIfs = i->NumIfs;
  323.    CLine = i->CLine;
  324.    fp = NULL;
  325.    STRSET(FileName, i->filename);
  326.    if (!CLine && (i->offset != -1L)) {
  327.    /* We must open the file, then seek to specified position */
  328.       if (strcmp(i->filename, "-"))
  329.          fp = fopen(i->filename, "r");
  330.       else
  331.          fp = stdin;
  332.       if (!fp) return E_CANT_OPEN;
  333.       if (fp != stdin)
  334.          (void) fseek(fp, i->offset, 0);  /* Trust that it works... */
  335.    }
  336.    free(i->filename);
  337.    return OK;
  338. }
  339.  
  340. /***************************************************************/
  341. /*                                                             */
  342. /*  DoInclude                                                  */
  343. /*                                                             */
  344. /*  The INCLUDE command.                                       */
  345. /*                                                             */
  346. /***************************************************************/
  347. #ifdef HAVE_PROTOS
  348. PUBLIC int DoInclude(ParsePtr p)
  349. #else
  350. int DoInclude(p)
  351. ParsePtr p;
  352. #endif
  353. {     
  354.     char tok[TOKSIZE];
  355.     int r, e;
  356.  
  357.     if ( (r=ParseToken(p, tok)) ) return r;
  358.     e = VerifyEoln(p); 
  359.     if (e) Eprint("%s", ErrMsg[e]);
  360.     if ( (r=IncludeFile(tok)) ) return r;
  361.     NumIfs = 0;
  362.     IfFlags = 0;
  363.     return OK;
  364. }
  365.  
  366. /***************************************************************/
  367. /*                                                             */
  368. /*  IncludeFile                                                */
  369. /*                                                             */
  370. /*  Process the INCLUDE command - actually do the file         */
  371. /*  inclusion.                                                 */
  372. /*                                                             */
  373. /***************************************************************/
  374. #ifdef HAVE_PROTOS
  375. PUBLIC int IncludeFile(const char *fname)
  376. #else
  377. int IncludeFile(fname)
  378. char *fname;
  379. #endif
  380. {
  381.    IncludeStruct *i;
  382.    int r;
  383.  
  384.    if (IStackPtr+1 >= INCLUDE_NEST) return E_NESTED_INCLUDE;
  385.    i = &IStack[IStackPtr];
  386.  
  387.    i->filename = StrDup(FileName);
  388.    if (!i->filename) return E_NO_MEM;
  389.    i->LineNo = LineNo;
  390.    i->NumIfs = NumIfs;
  391.    i->IfFlags = IfFlags;
  392.    i->CLine = CLine;
  393.    i->offset = -1L;
  394.    if (fp) {
  395.       i->offset = ftell(fp);
  396.       FCLOSE(fp);
  397.    }
  398.  
  399.    IStackPtr++;
  400.  
  401.    /* Try to open the new file */
  402.    if (!OpenFile(fname)) {
  403.       return OK;
  404.    }
  405.    /* Ugh!  We failed!  */
  406.    if ( (r=PopFile()) ) return r;
  407.    Eprint("%s: %s", ErrMsg[E_CANT_OPEN], fname);
  408.    return E_CANT_OPEN;
  409. }
  410.  
  411. /***************************************************************/
  412. /*                                                             */
  413. /* GetAccessDate - get the access date of a file.              */
  414. /*                                                             */
  415. /***************************************************************/
  416. #ifdef HAVE_PROTOS
  417. PUBLIC int GetAccessDate(char *file)
  418. #else
  419. int GetAccessDate(file)
  420. char *file;
  421. #endif
  422. {
  423.    struct stat statbuf;
  424.    struct tm *t1;
  425.  
  426.    if (stat(file, &statbuf)) return -1;
  427. #ifdef __TURBOC__
  428.    t1 = localtime( (time_t *) &(statbuf.st_atime) );
  429. #else
  430.    t1 = localtime(&(statbuf.st_atime));
  431. #endif
  432.  
  433.    if (t1->tm_year + 1900 < BASE)
  434.       return 0;
  435.    else
  436.       return Julian(t1->tm_year+1900, t1->tm_mon, t1->tm_mday);
  437. }
  438.  
  439. /***************************************************************/
  440. /*                                                             */
  441. /*  SetAccessDate                                              */
  442. /*                                                             */
  443. /*  Used only by DOS to set access date after we close the     */
  444. /*  file.  Not needed for UNIX.                                */
  445. /*                                                             */
  446. /***************************************************************/
  447. #if defined(__MSDOS__)
  448. /*
  449.  * WARNING WARNING WARNING WARNING
  450.  * In the version of Turbo C which I have, there is a bug in the
  451.  * stdio.h file.  The following lines correct the bug.  YOU MAY
  452.  * HAVE TO REMOVE THESE LINES FOR LATER VERSIONS OF TURBOC
  453.  */
  454. #ifdef __TURBOC__
  455. #ifndef fileno
  456. #define fileno(f) ((f)->fd)
  457. #endif
  458. #endif
  459.  
  460. #ifdef HAVE_PROTOS
  461. PUBLIC int SetAccessDate(char *fname, int jul)
  462. #else
  463. int SetAccessDate(fname, jul)
  464. char *fname;
  465. int jul;
  466. #endif
  467. {
  468.  
  469. #ifdef __TURBOC__   
  470.    int y, m, d;
  471.    struct ftime ft;
  472.    FILE *f;
  473.  
  474.    FromJulian(jul, &y, &m, &d);
  475.    ft.ft_tsec = 0;
  476.    ft.ft_min = 0;
  477.    ft.ft_hour = 12;  /* Arbitrarily set time to noon. */
  478.    ft.ft_day = (unsigned int) d;
  479.    ft.ft_month = (unsigned int) m+1;
  480.    ft.ft_year = (unsigned int) (y - 1980);
  481.  
  482.    f = fopen(fname, "r"); 
  483.    if (!f || setftime(fileno(f) , &ft)) {
  484.  
  485. #else /* Must be MSC */
  486.    if (utime(fname, (struct utimbuf *) NULL)) {
  487. #endif       
  488.       fprintf(ErrFp, ErrMsg[M_CANTSET_ACCESS], fname);
  489.  
  490. #ifdef __TURBOC__
  491.       if (f) FCLOSE(f);
  492. #endif
  493.       return -1;
  494.    }
  495.  
  496. #ifdef __TURBOC__
  497.    FCLOSE(f);
  498. #endif
  499.  
  500.    return 0;
  501. }
  502. #endif /* __MSDOS__ */
  503.  
  504. /***************************************************************/
  505. /*                                                             */
  506. /*  DestroyCache                                               */
  507. /*                                                             */
  508. /*  Free all the memory used by a cached file.                 */
  509. /*                                                             */
  510. /***************************************************************/
  511. #ifdef HAVE_PROTOS
  512. PRIVATE void DestroyCache(CachedFile *cf)
  513. #else
  514. static void DestroyCache(cf)
  515. CachedFile *cf;
  516. #endif
  517. {
  518.    CachedLine *cl, *cnext;
  519.    CachedFile *temp;
  520.    if (cf->filename) free(cf->filename);
  521.    cl = cf->cache;
  522.    while (cl) {
  523.       if (cl->text) free (cl->text);
  524.       cnext = cl->next;
  525.       free(cl);
  526.       cl = cnext;
  527.    }
  528.    if (CachedFiles == cf) CachedFiles = cf->next;
  529.    else {
  530.       temp = CachedFiles;
  531.       while(temp) {
  532.          if (temp->next == cf) {
  533.         temp->next = cf->next;
  534.         break;
  535.          }
  536.          temp = temp->next;
  537.       }
  538.    }
  539.    free(cf);
  540. }
  541.  
  542. /***************************************************************/
  543. /*                                                             */
  544. /*  TopLevel                                                   */
  545. /*                                                             */
  546. /*  Returns 1 if current file is top level, 0 otherwise.       */
  547. /*                                                             */
  548. /***************************************************************/
  549. #ifdef HAVE_PROTOS
  550. PUBLIC int TopLevel(void)
  551. #else
  552. int TopLevel()
  553. #endif
  554. {
  555.    return !IStackPtr;
  556. }
  557.