home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / LANGUAGS / C / MFILE.LBR / MFILE.CZ / MFILE.C
Text File  |  2000-06-30  |  8KB  |  384 lines

  1. /* mfile.c - a program to permit arbitrary numbers of concurrently
  2.  *        open files
  3.  */
  4. #include <stdio.h>
  5.  
  6. #include "dequeue.h"        /* dequeue package */
  7.  
  8. #define lruMFS lastNode        /* dequeue macros */
  9. #define mruMFS firstNode
  10. #define ERROR -1
  11.  
  12. /* a test for valid internal fd
  13.    - used to try to catch user errors
  14. */
  15. #define validMFS(x,y) ((y->mfdNum) == x)
  16.  
  17. extern    long    lseek();
  18.  
  19. #define MAXFILES 60    /* this value can be arbitrarily large */
  20. #define MAXOPEN  12    /* this is the number of files the host handles */
  21. #define OK    1
  22.  
  23. typedef int EFD;    /* host system file descriptor */
  24. typedef int MFD;    /* internal file descriptor */
  25. typedef    struct mfS
  26.         {
  27.         /* dequeue structure */
  28.         struct    mfS
  29.             *pMFS, *nMFS;
  30.         int    mfdNum;
  31.  
  32.         /* internal file descriptor data */
  33.         int    status;
  34.         int    efd;
  35.  
  36.         /* currency data */
  37.         char    fname[65];
  38.         long    lpos;
  39.         }
  40.     MFS;
  41.  
  42. /* various file statuses - used in mfS.status to determine validity
  43.    of element and operations */
  44. #define OPEN        1
  45. #define CLOSED        2
  46. #define UNASSIGNED    0
  47.  
  48. #define EMPTY    -1    /* signals out of internal fd */
  49. #define UNINIT    -2    /* signals intialization needed */
  50.  
  51. /* hide some internal details unless debugging */
  52. #if defined DEBUG
  53. #define Static
  54. #else
  55. #define Static static
  56. #endif
  57.  
  58. Static    MFS    *mFiles[MAXFILES];    /* list of all internal fd */
  59. Static    MFD    mfdFree = UNINIT;    /* empty free list */
  60. Static unsigned    numOpen = 0;        /* number of currently open files */
  61.  
  62. /*
  63.  *    (semi) standard low level file primitives
  64.  */
  65.  
  66. MFD    mOpen(fname, mode)
  67. char    *fname;
  68. int    mode;
  69. {
  70.     int    temp;
  71.  
  72.     obtainEFD();    /* ensure 1 host fd is free */
  73.     temp = mfdCreate( open(fname, mode) );
  74.  
  75. #if defined(DEBUG)
  76. printf("open:%s to mfd %d\n",fname,temp);
  77. dump(mFiles[temp]);
  78. #endif
  79.     if (temp < 0)
  80.         return ERROR;
  81.     numOpen++;
  82.     strcpy(mFiles[temp]->fname, fname);    /* establish currency */
  83.     return(temp);
  84. }
  85.  
  86. MFD    mCreate(fname, mode)
  87. char    *fname;
  88. int    mode;
  89. {
  90.     int    temp;
  91.  
  92.     obtainEFD();
  93.     temp = mfdCreate( create(fname, mode, 0) );
  94. #if defined(DEBUG)
  95. printf("create: %s to mfd %d\n",fname,temp);
  96. dump(mFiles[temp]);
  97. #endif
  98.     if (temp < 0)
  99.         return ERROR;
  100.     numOpen++;
  101.     strcpy(mFiles[temp]->fname, fname);
  102.     return(temp);
  103. }
  104.  
  105. int    mClose(mfd)
  106. MFD    mfd;
  107. {
  108.     MFS    *mfs;
  109.  
  110. #if defined(DEBUG)
  111.     printf("mClose:");
  112.     dump(mFiles[mfd]);
  113. #endif
  114.  
  115.     mfs = mFiles[mfd];
  116.     if (validMFS(mfd, mfs))
  117.         {
  118.         if (mfs->status == OPEN)
  119.             {
  120.             if (close(mfs->efd) < 0)
  121.                 return ERROR;
  122.             numOpen--;
  123.             }
  124.         mfdDestroy(mfd);
  125.         return 0;
  126.         }
  127.     else return ERROR;
  128. }
  129.  
  130. int mRead(mfd,buf,cnt)
  131. MFD    mfd;
  132. char    *buf;
  133. int    cnt;
  134. {
  135. #if defined(DEBUG)
  136.     int tmp;
  137.     printf("mRead(%d,%04x,%d) - %d\n",
  138.         mfd,
  139.         buf,
  140.         cnt,
  141.         tmp = read(mReopen(mfd), buf, cnt)
  142.     );
  143.     return tmp;
  144. #else
  145.     return read(mReopen(mfd), buf, cnt);
  146. #endif
  147. }
  148.  
  149. int mWrite(mfd,buf,cnt)
  150. MFD    mfd;
  151. char    *buf;
  152. int    cnt;
  153. {
  154. #if defined(DEBUG)
  155.     int tmp;
  156.     printf("mWrite(%d,%04x,%d) - %d\n",
  157.         mfd,
  158.         buf,
  159.         cnt,
  160.         tmp = write(mReopen(mfd), buf, cnt)
  161.     );
  162.     return tmp;
  163. #else
  164.     return write(mReopen(mfd), buf, cnt);
  165. #endif
  166. }
  167.  
  168. long mlseek(mfd, offs, mode)
  169. MFD    mfd;
  170. long    offs;
  171. int    mode;
  172. {
  173. #if defined(DEBUG)
  174.     long tmp;
  175.     printf("mlseek(%d,%ld,%d) - %d\n",
  176.         mfd,
  177.         offs,
  178.         mode,
  179.         tmp = lseek(mReopen(mfd), offs, mode)
  180.     );
  181.     return tmp;
  182. #else
  183.     return lseek(mReopen(mfd), offs, mode);
  184. #endif
  185. }
  186.  
  187. /* Low level internal functions
  188.  */
  189.  
  190. /* get host file descriptor for file, closing other files if need to. */
  191. EFD    mReopen(mfd)
  192. MFD    mfd;
  193. {
  194. register MFS    *mfs;
  195.  
  196.     mfs = mFiles[mfd];
  197.     if (validMFS(mfd,mfs))    /* check fd is valid */
  198.         {
  199. #if defined(DEBUG)
  200. printf("mReopen:");
  201. dump(mfs);
  202. #endif
  203.  
  204.         switch(mfs->status)    /* what is current real file status */
  205.             {
  206.             case OPEN: /* file is currently open */
  207.                 mSplice(mfs);    /* make this most recently used */
  208. #if defined(DEBUG)
  209. printf("mReopen:");
  210. dump(mfs);
  211. #endif
  212.                 return mfs->efd;
  213.  
  214.             case CLOSED:    /* file needs to be reOpened */
  215.                 if (obtainEFD())
  216.                     {
  217.                     mEnQue(mfs);    /* put on open list */
  218.                     mRestore(mfs);    /* restore currency */
  219. #if defined(DEBUG)
  220. printf("mReopen:");
  221. dump(mfs);
  222. #endif
  223.                     return mfs->efd;
  224.                     }
  225.                 else return ERROR;
  226.             default:
  227.                 return ERROR;
  228.             }
  229.         }
  230.     else return ERROR;
  231. }
  232.  
  233. /* routine to ensure at least one host file descriptor is available
  234.     ie: after x = obtainEFD(), numOpen < MAXOPEN or x == 0; */
  235. Static int obtainEFD()
  236. {
  237.     MFS    *oMfs;
  238.  
  239.     if (numOpen < MAXOPEN)    /* still unused space */
  240.         return OK;
  241.  
  242.     oMfs = lruMFS;        /* get least recently used file */
  243.  
  244. #if defined(DEBUG)
  245. printf("obtainEFD: lruMFD %d\n",oMfs->mfdNum);
  246. #endif
  247.  
  248.     /* save currency info and close file */
  249.     if (mSave(oMfs))
  250.         {
  251.         /* successfully freed up one host fd */
  252.         oMfs->status = CLOSED;
  253.         close(oMfs->efd);
  254.         mDeQue(oMfs);        /* remove lru file from active queue */
  255.         return OK;
  256.         }
  257.  
  258.     return 0;    /* failed to close file */
  259. }
  260.  
  261. /* mSave() - store currency information prior to temporary file closure
  262. ** you will no doubt have a better way to do this on
  263. ** your system, but it would make the package non portable.
  264. ** changing this to grab lpos and name from low level fd
  265. ** would speed it up.
  266. */
  267. Static int mSave(mfs)
  268. MFS    *mfs;
  269. {
  270.     /* save currency information */
  271.     sync();    /* flush buffers to disk - optional */
  272.  
  273.     /* >>>NOTE<<< this will not work for non-seekable devices
  274.        (e.g. keyboards, printers, crts &tc */
  275.     mfs->lpos = lseek(mfs->efd, 0L, 1);
  276.     if (close(mfs->efd) < 0)
  277.         return 0;
  278.     numOpen--;
  279.     return OK;
  280. }
  281.  
  282. /* restore currency information */
  283. Static EFD mRestore(mfs)
  284. MFS    *mfs;
  285. {
  286.     int    temp;
  287.  
  288.     mfs->efd = open(mfs->fname,0);
  289.     if (mfs->efd >= 0)
  290.         {
  291.         if (mfs->lpos != -1L)    /* may be at start of file anyway */
  292.             mfs->lpos = lseek(mfs->efd, mfs->lpos, 0);
  293.         mfs->status = OPEN;
  294.         numOpen++;
  295.         }
  296.     else mfs->status = ERROR;
  297.     return mfs->efd;
  298. }
  299.  
  300. Static MFD mfdCreate(efd)
  301. EFD    efd;
  302. {
  303.     MFD    mfd;
  304. register MFS    *mfs;
  305.     char *malloc();
  306.  
  307.     if (efd < 0)
  308.         return ERROR;
  309.  
  310.     if (mfdFree < 0)
  311.         if (mfdFree == EMPTY)    /* out of file slots */
  312.             return ERROR;
  313.         else mInit();        /* initialise fd array */
  314.  
  315.     mfd = mfdFree;
  316.     mfs = (MFS *) malloc(sizeof(MFS));
  317.     if (mfs == NULL)    /* out of space for file details */
  318.         return ERROR;
  319.  
  320.     mfdFree = mFiles[mfdFree];    /* pop free slot stack */
  321.     mFiles[mfd] = mfs;        /* assoc mfs with mfd */
  322.     mfs->mfdNum = mfd;        /* assoc mfd with mfs */
  323.     mfs->efd = efd;            /* assoc eon fd with mfs */
  324.     mfs->status = OPEN;        /* flag status as open */
  325.     (mfs->nMFS) = (mfs->pMFS) = UNINIT;    /* not on any queue yet */
  326.     mfs->fname[0] = '\0';        /* no file name yet */
  327.     mfs->lpos = -1L;        /* no position yet */
  328.  
  329.     mEnQue(mfs);            /* put mfs as most recently used */
  330.  
  331.     return mfd;            /* return file slot number */
  332. }
  333.  
  334. Static int mfdDestroy(mfd)
  335. MFD    mfd;
  336. {
  337.     MFS    *mfs;
  338.  
  339.     mfs = mFiles[mfd];
  340.     if (validMFS(mfd,mfs))
  341.         {
  342.         if ( (mfs->status) == OPEN )
  343.             mDeQue(mfs);
  344.         free(mfs);
  345.         mFiles[mfd] = mfdFree;
  346.         mfdFree = mfd;
  347.         }
  348.     else return ERROR;
  349. }
  350.  
  351. mInit()
  352. {
  353.     int    i;
  354.  
  355.     for (i = 0; i<MAXFILES; i++) mFiles[i]=i+1;
  356.     mFiles[i-1] = -1;
  357.     mfdFree = 1;
  358. }
  359.  
  360. #if defined(DEBUG)
  361. dump(f)
  362. MFS    *f;
  363. {
  364.  
  365. printf(" Element %04x:%d,%s,%d[%04x|%04x]%s,%ld\n",
  366.     f,
  367.     f->mfdNum,
  368.     (
  369.         (f->status == 1) ? "OPEN" :
  370.         (f->status == 2) ? "CLOSED" :
  371.         (f->status == 0) ? "UNASSIGNED" :
  372.         (f->status ==-1) ? "ERROR" :
  373.         "???"
  374.     ),
  375.     f->efd,
  376.     f->pMFS,
  377.     f->nMFS,
  378.     f->fname,
  379.     f->lpos);
  380. }
  381. #endif
  382.  
  383. /* end of mfile.c */
  384.