home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / MISC / SQDEV200.ZIP / SRC / SQ_IDX.C < prev    next >
C/C++ Source or Header  |  1994-05-23  |  16KB  |  660 lines

  1. /***************************************************************************
  2.  *                                                                         *
  3.  *  Squish Developers Kit Source, Version 2.00                             *
  4.  *  Copyright 1989-1994 by SCI Communications.  All rights reserved.       *
  5.  *                                                                         *
  6.  *  USE OF THIS FILE IS SUBJECT TO THE RESTRICTIONS CONTAINED IN THE       *
  7.  *  SQUISH DEVELOPERS KIT LICENSING AGREEMENT IN SQDEV.PRN.  IF YOU DO NOT *
  8.  *  FIND THE TEXT OF THIS AGREEMENT IN THE AFOREMENTIONED FILE, OR IF YOU  *
  9.  *  DO NOT HAVE THIS FILE, YOU SHOULD IMMEDIATELY CONTACT THE AUTHOR AT    *
  10.  *  ONE OF THE ADDRESSES LISTED BELOW.  IN NO EVENT SHOULD YOU PROCEED TO  *
  11.  *  USE THIS FILE WITHOUT HAVING ACCEPTED THE TERMS OF THE SQUISH          *
  12.  *  DEVELOPERS KIT LICENSING AGREEMENT, OR SUCH OTHER AGREEMENT AS YOU ARE *
  13.  *  ABLE TO REACH WITH THE AUTHOR.                                         *
  14.  *                                                                         *
  15.  *  You can contact the author at one of the address listed below:         *
  16.  *                                                                         *
  17.  *  Scott Dudley       FidoNet     1:249/106                               *
  18.  *  777 Downing St.    Internet    sjd@f106.n249.z1.fidonet.org            *
  19.  *  Kingston, Ont.     CompuServe  >INTERNET:sjd@f106.n249.z1.fidonet.org  *
  20.  *  Canada  K7M 5N3    BBS         1-613-634-3058, V.32bis                 *
  21.  *                                                                         *
  22.  ***************************************************************************/
  23.  
  24. #pragma off(unreferenced)
  25. static char rcs_id[]="$Id: sq_idx.c 1.13 1994/03/27 13:27:45 sjd Exp sjd $";
  26. #pragma on(unreferenced)
  27.  
  28. #define MSGAPI_HANDLERS
  29. #define MSGAPI_NO_OLD_TYPES
  30.  
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <io.h>
  34. #include <fcntl.h>
  35. #include <assert.h>
  36. #include <limits.h>
  37. #include "prog.h"
  38. #include "msgapi.h"
  39. #include "api_sq.h"
  40. #include "apidebug.h"
  41.  
  42. #define HixSqd            ((struct _sqdata *)(hix)->ha->apidata)
  43.  
  44.  
  45. #ifdef __FLAT__
  46.   #define MORE_SPACE       256      /* Allow for up to 256 additions */
  47.   #define SEGMENT_SIZE    (LONG_MAX/(long)sizeof(SQIDX))
  48.   #define SHIFT_SIZE      32768
  49. #else
  50.   #define MORE_SPACE        16      /* Allow for up to 16 additions */
  51.   #define SEGMENT_SIZE    (32767L/(long)sizeof(SQIDX))
  52.   #define SHIFT_SIZE      8192
  53. #endif
  54.  
  55.  
  56. #if defined(__FARDATA__) || defined(__FLAT__)
  57.   #define fmemmove memmove
  58. #else
  59.   #define fmemmove f_memmove
  60. #endif
  61.  
  62.  
  63. /* Open the index file and read the index for this area */
  64.  
  65. HIDX _SquishOpenIndex(HAREA ha)
  66. {
  67.   HIDX hix;
  68.  
  69.   if ((hix=palloc(sizeof(*hix)))==NULL)
  70.   {
  71.     msgapierr=MERR_NOMEM;
  72.     return NULL;
  73.   }
  74.  
  75.   /* Store the current area handle */
  76.  
  77.   hix->id=ID_HIDX;
  78.   hix->ha=ha;
  79.   hix->lDeltaLo=-1;
  80.   hix->lDeltaHi=-1;
  81.   hix->cSeg=0;
  82.   hix->fBuffer=0;
  83.  
  84.   return hix;
  85. }
  86.  
  87.  
  88. /* This function returns the size of the virtual index */
  89.  
  90. dword _SquishIndexSize(HIDX hix)
  91. {
  92.   dword lSize;
  93.   int i;
  94.  
  95.   assert(hix->id==ID_HIDX);
  96.  
  97.   if (!hix->fBuffer)
  98.     lSize=(dword)lseek(HixSqd->ifd, 0L, SEEK_END);
  99.   else
  100.   {
  101.     for (i=0, lSize=0; i < hix->cSeg; i++)
  102.       lSize += hix->pss[i].dwUsed * (dword)sizeof(SQIDX);
  103.   }
  104.  
  105.   return lSize;
  106. }
  107.  
  108.  
  109.  
  110. /* Start buffering reads/writes to the index file */
  111.  
  112. int _SquishBeginBuffer(HIDX hix)
  113. {
  114.   dword dwMsgs;
  115.   int i;
  116.  
  117.   assert(hix->id==ID_HIDX);
  118.  
  119.   /* Multiple buffers are ok, but we only need to do it once */
  120.  
  121.   if (hix->fBuffer++ != 0)
  122.     return TRUE;
  123.  
  124.   hix->cSeg=(int)(hix->ha->num_msg / SEGMENT_SIZE) + 1;
  125.  
  126.   /* Allocate memory for the array of segments */
  127.  
  128.   if ((hix->pss=palloc(sizeof(SQIDXSEG) * (unsigned)hix->cSeg))==NULL)
  129.   {
  130.     msgapierr=MERR_NOMEM;
  131.     hix->fBuffer=0;
  132.     return FALSE;
  133.   }
  134.  
  135.   dwMsgs=hix->ha->num_msg;                /* Read all messages into memory */
  136.  
  137.   /* Find out how many records are in the file */
  138.  
  139.   if ((hix->lAllocatedRecords=lseek(HixSqd->ifd, 0L, SEEK_END)) < 0)
  140.   {
  141.     msgapierr=MERR_BADF;
  142.     hix->fBuffer=0;
  143.     return FALSE;
  144.   }
  145.  
  146.   /* Find out the number of records, not the number of bytes */
  147.  
  148.   hix->lAllocatedRecords /= sizeof(SQIDX);
  149.  
  150.  
  151.   /* Read from head of index file */
  152.  
  153.   (void)lseek(HixSqd->ifd, 0L, SEEK_SET); 
  154.  
  155.   /* Repeat for each segment in the index file */
  156.  
  157.   for (i=0; i < hix->cSeg; i++)
  158.   {
  159.     dword dwSize=min(dwMsgs+MORE_SPACE, (long)SEGMENT_SIZE);
  160.     unsigned uiSize;
  161.  
  162.     /* Try to allocate memory for this segment */
  163.  
  164.     if ((hix->pss[i].psqi=farpalloc((size_t)dwSize * (size_t)sizeof(SQIDX)))==NULL)
  165.     {
  166.       while (i--)
  167.         farpfree(hix->pss[i].psqi);
  168.  
  169.       pfree(hix->pss);
  170.  
  171.       msgapierr=MERR_NOMEM;
  172.       hix->fBuffer=0;
  173.       return FALSE;
  174.     }
  175.  
  176.     hix->pss[i].dwMax=dwSize;
  177.  
  178.     /* Now read in the messages for this segment */
  179.  
  180.     dwSize=min(dwMsgs, SEGMENT_SIZE);
  181.  
  182.     uiSize=(unsigned)dwSize * (unsigned)sizeof(SQIDX);
  183.  
  184.     if (farread(HixSqd->ifd, (char far *)hix->pss[i].psqi, uiSize) != (int)uiSize)
  185.     {
  186.       do
  187.         farpfree(hix->pss[i].psqi);
  188.       while (i--);
  189.  
  190.       pfree(hix->pss);
  191.  
  192.       msgapierr=MERR_BADF;
  193.       hix->fBuffer=0;
  194.       return FALSE;
  195.     }
  196.  
  197.     /* Decrement the count for msgs in the next segment, if necessary */
  198.  
  199.     if (dwSize != SEGMENT_SIZE)
  200.       dwMsgs=0;
  201.     else
  202.       dwMsgs -= SEGMENT_SIZE;
  203.  
  204.  
  205.     hix->pss[i].dwUsed=dwSize;
  206.   }
  207.  
  208.   /* Now we have the whole file in memory */
  209.  
  210.   return TRUE;
  211. }
  212.  
  213.  
  214. /* Return a pointer to the 'dwMsg'th message in the buffered index */
  215.  
  216. static SQIDX far *sidx(HIDX hix, dword dwMsg)
  217. {
  218.   dword dwStart=1L;
  219.   int i;
  220.  
  221.   for (i=0; i < hix->cSeg; i++)
  222.   {
  223.     if (dwMsg >= dwStart && dwMsg < dwStart + hix->pss[i].dwUsed)
  224.       return hix->pss[i].psqi + (size_t)(dwMsg - dwStart);
  225.  
  226.     dwStart += hix->pss[i].dwUsed;
  227.   }
  228.  
  229.   return NULL;
  230. }
  231.  
  232.  
  233. /* Get an index from the virtual index file */
  234.  
  235. int SidxGet(HIDX hix, dword dwMsg, SQIDX *psqi)
  236. {
  237.   SQIDX far *psqiFound;
  238.  
  239.   assert(hix->id==ID_HIDX);
  240.  
  241.   if (!hix->fBuffer)
  242.   {
  243.     (void)lseek(HixSqd->ifd, (long)(dwMsg-1) * (long)sizeof(SQIDX), SEEK_SET);
  244.  
  245.     if (farread(HixSqd->ifd, (char far *)psqi, sizeof(SQIDX)) != (int)sizeof(SQIDX))
  246.     {
  247.       msgapierr=MERR_BADF;
  248.       return FALSE;
  249.     }
  250.  
  251.     return TRUE;
  252.   }
  253.  
  254.   psqiFound=sidx(hix, dwMsg);
  255.  
  256.   if (!psqiFound)
  257.     return FALSE;
  258.  
  259.   *psqi=*psqiFound;
  260.   return TRUE;
  261. }
  262.  
  263.  
  264.  
  265.  
  266. /* Add a new index record to the end of the array */
  267.  
  268. static int near _SquishAppendIndexRecord(HIDX hix, SQIDX *psqi)
  269. {
  270.   SQIDXSEG *pss;
  271.  
  272.  
  273.   /* If we need to expand the index file on disk, do so now */
  274.  
  275.   if ((long)hix->ha->num_msg > hix->lAllocatedRecords)
  276.   {
  277.     long lSize;
  278.     SQIDX sqi;
  279.  
  280.     /* Make room for up to 64 new records */
  281.  
  282.     hix->lAllocatedRecords=hix->ha->num_msg+64;
  283.     lSize=(hix->lAllocatedRecords-1) * (long)sizeof(SQIDX);
  284.  
  285.     sqi.ofs=0L;
  286.     sqi.umsgid=(UMSGID)-1L;
  287.     sqi.hash=(UMSGID)-1L;
  288.  
  289.     /* Write a blank index entry at the appropriate location to fill        *
  290.      * up the file.                                                         */
  291.  
  292.     if (lseek(HixSqd->ifd, lSize, SEEK_SET) != lSize ||
  293.         write(HixSqd->ifd, (char *)&sqi, sizeof sqi) != sizeof(sqi))
  294.     {
  295.       msgapierr=MERR_NODS;
  296.       return FALSE;
  297.     }
  298.   }
  299.  
  300.   /* If we already have some segments... */
  301.  
  302.   if (hix->cSeg)
  303.   {
  304.     /* Add to an existing segment */
  305.  
  306.     pss=hix->pss + hix->cSeg-1;
  307.  
  308.     /* If the record fits within this segment, just append it. */
  309.  
  310.     if (pss->dwUsed < pss->dwMax)
  311.     {
  312.       pss->psqi[(size_t)pss->dwUsed]=*psqi;
  313.       pss->dwUsed++;
  314.       return TRUE;
  315.     }
  316.  
  317.     /* If we can expand this segment by reallocating memory... */
  318.  
  319.     if (pss->dwMax < SEGMENT_SIZE)
  320.     {
  321.       SQIDX far *psqiNew;
  322.  
  323.       assert(pss->dwMax >= pss->dwUsed);
  324.  
  325.       /* Don't use realloc because we cannot afford to lose the info that we  *
  326.        * already have!                                                        */
  327.  
  328.       if ((psqiNew=farpalloc(((size_t)pss->dwMax + MORE_SPACE) * sizeof(SQIDX)))==NULL)
  329.       {
  330.         msgapierr=MERR_NOMEM;
  331.         return FALSE;
  332.       }
  333.  
  334.       (void) fmemmove(psqiNew,
  335.                       pss->psqi,
  336.                       (size_t)pss->dwUsed * (size_t)sizeof(SQIDX));
  337.  
  338.       psqiNew[(size_t)pss->dwUsed]=*psqi;
  339.  
  340.       pss->dwUsed++;
  341.       pss->dwMax += MORE_SPACE;
  342.  
  343.       farpfree(pss->psqi);
  344.       pss->psqi=psqiNew;
  345.       return TRUE;
  346.     }
  347.   }
  348.  
  349.  
  350.   /* If we arrived here, we either have no segments, or all of our          *
  351.    * existing segments are full.  To handle this, we need to reallocate     *
  352.    * the array of pointers to segments and add a new one.                   */
  353.  
  354.   if ((pss=palloc(sizeof(SQIDXSEG) * (size_t)(hix->cSeg+1)))==NULL)
  355.   {
  356.     msgapierr=MERR_NOMEM;
  357.     return FALSE;
  358.   }
  359.  
  360.   (void)memmove(pss, hix->pss, (size_t)hix->cSeg * sizeof(SQIDXSEG));
  361.   hix->pss=pss;
  362.  
  363.   /* Allocate memory for the new segment */
  364.  
  365.   if ((hix->pss[hix->cSeg].psqi=farpalloc(MORE_SPACE * sizeof(SQIDX)))==NULL)
  366.   {
  367.     msgapierr=MERR_NOMEM;
  368.     return FALSE;
  369.   }
  370.  
  371.   pss=hix->pss + hix->cSeg;
  372.  
  373.   /* Add the specified record to our indices */
  374.  
  375.   pss->dwUsed=1;
  376.   pss->dwMax=MORE_SPACE;
  377.   *pss->psqi=*psqi;
  378.  
  379.   /* Increment the segment count */
  380.  
  381.   hix->cSeg++;
  382.   return TRUE;
  383. }
  384.  
  385.  
  386. /* Store an index entry in the virtual index file */
  387.  
  388. int SidxPut(HIDX hix, dword dwMsg, SQIDX *psqi)
  389. {
  390.   SQIDX far *psqiFound;
  391.   int rc;
  392.  
  393.   assert(hix->id==ID_HIDX);
  394.  
  395.   if (!hix->fBuffer)
  396.   {
  397.     (void)lseek(HixSqd->ifd, (long)(dwMsg-1) * (long)sizeof(SQIDX), SEEK_SET);
  398.  
  399.     if (farwrite(HixSqd->ifd, (char far *)psqi, sizeof(SQIDX)) != (int)sizeof(SQIDX))
  400.     {
  401.       msgapierr=MERR_NODS;
  402.       return FALSE;
  403.     }
  404.  
  405.     return TRUE;
  406.   }
  407.  
  408.   /* If we can't find the appropriate index record */
  409.  
  410.   if ((psqiFound=sidx(hix, dwMsg))==NULL)
  411.   {
  412.     rc=FALSE;
  413.  
  414.     /* If the index is out of range, only create a new record if it's       *
  415.      * to be placed at EOF.                                                 */
  416.  
  417.     if (dwMsg==hix->ha->num_msg+1)
  418.       rc=_SquishAppendIndexRecord(hix, psqi);
  419.   }
  420.   else
  421.   {
  422.     *psqiFound=*psqi;
  423.     rc=TRUE;
  424.   }
  425.  
  426.   if (rc)
  427.   {
  428.     if (hix->lDeltaLo==-1 || hix->lDeltaLo > (long)dwMsg)
  429.       hix->lDeltaLo=(long)dwMsg;
  430.  
  431.     if (hix->lDeltaHi==-1 || hix->lDeltaHi < (long)dwMsg)
  432.       hix->lDeltaHi=(long)dwMsg;
  433.   }
  434.  
  435.   return rc;
  436. }
  437.  
  438.  
  439. /* Delete an entry from the index */
  440.  
  441. unsigned _SquishRemoveIndexEntry(HIDX hix, dword dwMsg, SQIDX *psqiOut,
  442.                                  SQHDR *psqh, int fFixPointers)
  443. {
  444.   SQIDX sqi;
  445.   char *pcBuf;
  446.   int got, i;
  447.  
  448.   assert(hix->id==ID_HIDX);
  449.  
  450.   /* Create a blank record for writing at the end */
  451.  
  452.   sqi.ofs=NULL_FRAME;
  453.   sqi.umsgid=(UMSGID)-1L;
  454.   sqi.hash=(dword)-1L;
  455.  
  456.   if (hix->fBuffer)
  457.   {
  458.     dword dwStart=1L;
  459.  
  460.     /* Find the segment containing the deleted message */
  461.  
  462.     for (i=0; i < hix->cSeg; i++)
  463.     {
  464.       /* If it's in this segment */
  465.  
  466.       if (dwMsg >= dwStart && dwMsg < dwStart + hix->pss[i].dwUsed)
  467.       {
  468.         int j=(int)(dwMsg-dwStart);
  469.         unsigned rc=TRUE;
  470.  
  471.         /* If caller wants copy of deleted record */
  472.  
  473.         if (psqiOut)
  474.           *psqiOut=hix->pss[i].psqi[j];
  475.  
  476.         /* Shift the rest of the text over this segment */
  477.  
  478.         (void)fmemmove(hix->pss[i].psqi+j, hix->pss[i].psqi+j+1,
  479.                        (size_t)(hix->pss[i].dwUsed - (dword)j - (dword)1)
  480.                           * (size_t)sizeof(SQIDX));
  481.  
  482.         hix->pss[i].dwUsed--;
  483.  
  484.         if (!_SquishAppendIndexRecord(hix, &sqi))
  485.           rc=FALSE;
  486.  
  487.         if (hix->lDeltaLo==-1 || hix->lDeltaLo > (long)dwMsg)
  488.           hix->lDeltaLo=(long)dwMsg;
  489.  
  490.         hix->lDeltaHi=(long)_SquishIndexSize(hix) / (long)sizeof(SQIDX);
  491.  
  492.         if (fFixPointers && rc)
  493.           return _SquishFixMemoryPointers(hix->ha, dwMsg, psqh);
  494.         else
  495.           return rc;
  496.       }
  497.  
  498.       dwStart += hix->pss[i].dwUsed;
  499.     }
  500.  
  501.     /* Huh?  Message not in index! */
  502.  
  503.     return FALSE;
  504.   }
  505.  
  506.  
  507.   /* Else if it's not buffered: */
  508.  
  509.  
  510.   (void)lseek(HixSqd->ifd, (long)dwMsg * (long)sizeof(SQIDX), SEEK_SET);
  511.  
  512.  
  513.   if ((pcBuf=palloc(SHIFT_SIZE))==NULL)
  514.   {
  515.     msgapierr=MERR_NOMEM;
  516.     return FALSE;
  517.   }
  518.  
  519.   while ((got=read(HixSqd->ifd, pcBuf, SHIFT_SIZE)) > 0)
  520.   {
  521.     /* Skip back to one position before this index entry */
  522.  
  523.     (void)lseek(HixSqd->ifd, -(long)got - sizeof(SQIDX), SEEK_CUR);
  524.  
  525.     if (write(HixSqd->ifd, pcBuf, (unsigned)got) != got)
  526.     {
  527.       msgapierr=MERR_BADF;
  528.       return FALSE;
  529.     }
  530.  
  531.     (void)lseek(HixSqd->ifd, (long)sizeof(SQIDX), SEEK_CUR);
  532.   }
  533.  
  534.   pfree(pcBuf);
  535.  
  536.   /* Now write the last entry to stomp over the index element that is at    *
  537.    * the end of the file.                                                   */
  538.  
  539.   (void)lseek(HixSqd->ifd, -(long)sizeof(SQIDX), SEEK_CUR);
  540.  
  541.   if (write(HixSqd->ifd, (char *)&sqi, sizeof(SQIDX)) != (int)sizeof(SQIDX))
  542.   {
  543.     msgapierr=MERR_BADF;
  544.     return FALSE;
  545.   }
  546.  
  547.   if (fFixPointers)
  548.     return _SquishFixMemoryPointers(hix->ha, dwMsg, psqh);
  549.   else
  550.     return TRUE;
  551. }
  552.  
  553.  
  554.  
  555. /* Close an index file handle */
  556.  
  557. unsigned _SquishCloseIndex(HIDX hix)
  558. {
  559.   assert(hix->id==ID_HIDX);
  560.  
  561.   while (hix->fBuffer)
  562.     if (!_SquishEndBuffer(hix))
  563.       return FALSE;
  564.  
  565.   hix->id=0;
  566.  
  567.   pfree(hix);
  568.  
  569.   return TRUE;
  570. }
  571.  
  572.  
  573.  
  574. /* Dump the index file buffer */
  575.  
  576. int _SquishEndBuffer(HIDX hix)
  577. {
  578.   int i;
  579.   int rc=TRUE;
  580.   long lSize;
  581.  
  582.   assert(hix->id==ID_HIDX);
  583.  
  584.   if (hix->fBuffer==0)
  585.     return FALSE;
  586.  
  587.   if (--hix->fBuffer != 0)
  588.     return TRUE;
  589.  
  590.  
  591.   /* Reduce the index file to the size that it really should be */
  592.  
  593.   lSize=(long)hix->ha->num_msg * (long)sizeof(SQIDX);
  594.   setfsize(HixSqd->ifd, lSize);
  595.  
  596.  
  597.   /* If we need to rewrite the index */
  598.  
  599.   if (hix->lDeltaLo != -1 && hix->lDeltaHi != -1)
  600.   {
  601.     dword dwStart=1;
  602.  
  603.     (void) lseek(HixSqd->ifd,
  604.                  (hix->lDeltaLo - 1L) * (long)sizeof(SQIDX),
  605.                  SEEK_SET);
  606.  
  607.     for (i=0; i < hix->cSeg; i++)
  608.     {
  609.       unsigned uiWriteSize;
  610.  
  611.       /* If this buffer is within the "delta" range */
  612.  
  613.       if ((long)dwStart + (long)hix->pss[i].dwUsed > hix->lDeltaLo &&
  614.           (long)dwStart <= hix->lDeltaHi)
  615.       {
  616.         size_t j, size;
  617.  
  618.         if ((long)dwStart > hix->lDeltaLo)
  619.           j=0;
  620.         else
  621.           j=(size_t)(hix->lDeltaLo-(long)dwStart);
  622.  
  623.         if ((long)dwStart + (long)hix->pss[i].dwUsed > hix->lDeltaHi)
  624.           size = (size_t)(hix->lDeltaHi - (long)dwStart + 1L);
  625.         else
  626.           size = (size_t)(hix->pss[i].dwUsed);
  627.  
  628.         size -= j;
  629.  
  630.         uiWriteSize=(size_t)size * (size_t)sizeof(SQIDX);
  631.  
  632.         if (rc)
  633.         {
  634.           if (farwrite(HixSqd->ifd, (char far *)(hix->pss[i].psqi+j), uiWriteSize)
  635.                  != (int)uiWriteSize)
  636.  
  637.           {
  638.             msgapierr=MERR_NODS;
  639.             rc=FALSE;
  640.           }
  641.         }
  642.       }
  643.  
  644.       dwStart += hix->pss[i].dwUsed;
  645.     }
  646.   }
  647.  
  648.  
  649.   /* Free the memory used by these segments */
  650.  
  651.   for (i=0; i < hix->cSeg; i++)
  652.     farpfree(hix->pss[i].psqi);
  653.  
  654.   pfree(hix->pss);
  655.   hix->cSeg=0;
  656.  
  657.   return rc;
  658. }
  659.  
  660.