home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / MISC / SQDEV200.ZIP / SRC / SQ_HELP.C < prev    next >
C/C++ Source or Header  |  1994-05-23  |  13KB  |  500 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_HELP.C 1.4 1994/01/17 02:31:17 sjd Exp sjd $";
  26. #pragma on(unreferenced)
  27.  
  28. #define MSGAPI_HANDLERS
  29. #define MSGAPI_NO_OLD_TYPES
  30.  
  31. #include <io.h>
  32. #include <fcntl.h>
  33. #include <string.h>
  34. #include <assert.h>
  35. #include <errno.h>
  36. #include "prog.h"
  37. #include "msgapi.h"
  38. #include "api_sq.h"
  39. #include "apidebug.h"
  40.  
  41. /* Read the base header from the beginning of the .sqd file */
  42.  
  43. unsigned _SquishReadBaseHeader(HAREA ha, SQBASE *psqb)
  44. {
  45.   if (lseek(Sqd->sfd, 0L, SEEK_SET) != 0 ||
  46.       read(Sqd->sfd, (char *)psqb, sizeof *psqb) != (int)sizeof *psqb)
  47.   {
  48.     if (errno==EACCES || errno==-1)
  49.       msgapierr=MERR_SHARE;
  50.     else
  51.       msgapierr=MERR_BADF;
  52.  
  53.     return FALSE;
  54.   }
  55.  
  56.   return TRUE;
  57. }
  58.  
  59.  
  60.  
  61.  
  62. /* Write the base header back to the beginning of the .sqd file */
  63.  
  64. unsigned _SquishWriteBaseHeader(HAREA ha, SQBASE *psqb)
  65. {
  66.   if (lseek(Sqd->sfd, 0L, SEEK_SET) != 0 ||
  67.       write(Sqd->sfd, (char *)psqb, sizeof *psqb) != (int)sizeof *psqb)
  68.   {
  69.     msgapierr=MERR_NODS;
  70.     return FALSE;
  71.   }
  72.  
  73.   return TRUE;
  74. }
  75.  
  76.  
  77.  
  78. /* Release the specified frame to the free chain.  The frame is             *
  79.  * located at offset 'fo', and the header at that offset has                *
  80.  * already been loaded into *psqh.  This function does **not**              *
  81.  * change the links of other messages that may point to this                *
  82.  * message; it simply threads the current message into the free chain.      *
  83.  *                                                                          *
  84.  * This function assumes that we have exclusive access to the Squish base.  */
  85.  
  86. unsigned _SquishInsertFreeChain(HAREA ha, FOFS fo, SQHDR *psqh)
  87. {
  88.   SQHDR sqh=*psqh;
  89.  
  90.   assert(Sqd->fHaveExclusive);
  91.  
  92.   sqh.id=SQHDRID;
  93.   sqh.frame_type=FRAME_FREE;
  94.   sqh.msg_length=sqh.clen=0L;
  95.  
  96.   /* If we have no existing free frames, then this is easy */
  97.  
  98.   if (Sqd->foLastFree==NULL_FRAME)
  99.   {
  100.     sqh.prev_frame=NULL_FRAME;
  101.     sqh.next_frame=NULL_FRAME;
  102.  
  103.     /* Try to write this frame back to the file */
  104.  
  105.     if (! _SquishWriteHdr(ha, fo, &sqh))
  106.       return FALSE;
  107.  
  108.     Sqd->foFree=Sqd->foLastFree=fo;
  109.     return TRUE;
  110.   }
  111.  
  112.  
  113.   /* There is an existing frame, so we must append to the end of the        *
  114.    * chain.                                                                 */
  115.  
  116.   sqh.prev_frame=Sqd->foLastFree;
  117.   sqh.next_frame=NULL_FRAME;
  118.  
  119.  
  120.   /* Update the last chain in the free list, pointing it to us */
  121.  
  122.   if (!_SquishSetFrameNext(ha, sqh.prev_frame, fo))
  123.     return FALSE;
  124.  
  125.  
  126.   /* Try to write the current frame to disk */
  127.  
  128.   if (_SquishWriteHdr(ha, fo, &sqh))
  129.   {
  130.     Sqd->foLastFree=fo;
  131.     return TRUE;
  132.   }
  133.   else
  134.   {
  135.     /* The write failed, so just hope that we can undo what we did        *
  136.      * earlier.                                                           */
  137.  
  138.     (void)_SquishSetFrameNext(ha, sqh.prev_frame, NULL_FRAME);
  139.     return FALSE;
  140.   }
  141. }
  142.  
  143.  
  144.  
  145. /* Change the 'next' link of the foModify frame to the value foValue */
  146.  
  147. unsigned _SquishSetFrameNext(HAREA ha, FOFS foModify, FOFS foValue)
  148. {
  149.   SQHDR sqh;
  150.  
  151.   if (!_SquishReadHdr(ha, foModify, &sqh))
  152.     return FALSE;
  153.  
  154.   sqh.next_frame=foValue;
  155.  
  156.   return _SquishWriteHdr(ha, foModify, &sqh);
  157. }
  158.  
  159.  
  160.  
  161. /* Change the 'prior' link of the foModify frame to the value foValue */
  162.  
  163. unsigned _SquishSetFramePrev(HAREA ha, FOFS foModify, FOFS foValue)
  164. {
  165.   SQHDR sqh;
  166.  
  167.   if (!_SquishReadHdr(ha, foModify, &sqh))
  168.     return FALSE;
  169.  
  170.   sqh.prev_frame=foValue;
  171.  
  172.   return _SquishWriteHdr(ha, foModify, &sqh);
  173. }
  174.  
  175.  
  176.  
  177. /* This function ensures that the message handle is readable */
  178.  
  179. unsigned _SquishReadMode(HMSG hmsg)
  180. {
  181.   if (hmsg->wMode != MOPEN_READ && hmsg->wMode != MOPEN_RW)
  182.   {
  183.     msgapierr=MERR_EACCES;
  184.     return FALSE;
  185.   }
  186.  
  187.   return TRUE;
  188. }
  189.  
  190.  
  191.  
  192. /* This function ensures that the message handle is writable */
  193.  
  194. unsigned _SquishWriteMode(HMSG hmsg)
  195. {
  196.   if (hmsg->wMode != MOPEN_CREATE && hmsg->wMode != MOPEN_WRITE &&
  197.       hmsg->wMode != MOPEN_RW)
  198.   {
  199.     msgapierr=MERR_EACCES;
  200.     return FALSE;
  201.   }
  202.  
  203.   return TRUE;
  204. }
  205.  
  206.  
  207.  
  208. /* Translate a message number into a frame offset for area 'ha' */
  209.  
  210. FOFS _SquishGetFrameOfs(HAREA ha, dword dwMsg)
  211. {
  212.   SQIDX sqi;
  213.  
  214.  
  215.   msgapierr=MERR_NOENT;
  216.  
  217.   /* Check for simple stuff that we can handle by following our own         *
  218.    * linked list.                                                           */
  219.  
  220.   if (dwMsg==ha->cur_msg)
  221.     return Sqd->foCur;
  222.   else if (dwMsg==ha->cur_msg-1)
  223.     return Sqd->foPrev;
  224.   else if (dwMsg==ha->cur_msg+1)
  225.     return Sqd->foNext;
  226.  
  227.   /* We couldn't just follow the linked list, so we will have to consult    *
  228.    * the Squish index file to find it.                                      */
  229.  
  230.   if (! SidxGet(Sqd->hix, dwMsg, &sqi))
  231.     return NULL_FRAME;
  232.  
  233.   return sqi.ofs;
  234. }
  235.  
  236.  
  237. /* Read the Squish header 'psqh' from the specified frame offset */
  238.  
  239. unsigned _SquishReadHdr(HAREA ha, FOFS fo, SQHDR *psqh)
  240. {
  241.   /* Ensure that we are reading a valid frame header */
  242.  
  243.   if (fo < sizeof(SQBASE))
  244.   {
  245.     msgapierr=MERR_BADA;
  246.     return FALSE;
  247.   }
  248.  
  249.   /* Seek and read the header */
  250.  
  251.   if (fo >= Sqd->foEnd ||
  252.       lseek(Sqd->sfd, fo, SEEK_SET) != fo ||
  253.       read(Sqd->sfd, (char *)psqh, sizeof *psqh) != (int)sizeof *psqh ||
  254.       psqh->id != SQHDRID)
  255.   {
  256.     msgapierr=MERR_BADF;
  257.     return FALSE;
  258.   }
  259.  
  260.   return TRUE;
  261. }
  262.  
  263.  
  264.  
  265. /* Write the Squish header 'psqh' to the specified frame offset */
  266.  
  267. unsigned _SquishWriteHdr(HAREA ha, FOFS fo, SQHDR *psqh)
  268. {
  269.   /* Make sure that we don't write over the file header */
  270.  
  271.   if (fo < sizeof(SQBASE))
  272.   {
  273.     msgapierr=MERR_BADA;
  274.     return FALSE;
  275.   }
  276.  
  277.   if (lseek(Sqd->sfd, fo, SEEK_SET) != fo ||
  278.       write(Sqd->sfd, (char *)psqh, sizeof *psqh) != (int)sizeof *psqh)
  279.   {
  280.     msgapierr=MERR_NODS;
  281.     return FALSE;
  282.   }
  283.  
  284.   return TRUE;
  285. }
  286.  
  287.  
  288. /* This function fixes the in-memory pointers after message dwMsg was       *
  289.  * removed from the index file.                                             *
  290.  *                                                                          *
  291.  * This function assumes that we have exclusive access to the Squish base.  */
  292.  
  293. unsigned _SquishFixMemoryPointers(HAREA ha, dword dwMsg, SQHDR *psqh)
  294. {
  295.   assert(Sqd->fHaveExclusive);
  296.  
  297.   /* Adjust the first/last message pointers */
  298.  
  299.   if (dwMsg==1)
  300.     Sqd->foFirst=psqh->next_frame;
  301.  
  302.   if (dwMsg==ha->num_msg)
  303.     Sqd->foLast=psqh->prev_frame;
  304.  
  305.  
  306.   /* Now fix up the in-memory version of the prior/next links */
  307.  
  308.   if (dwMsg==ha->cur_msg+1)
  309.     Sqd->foNext=psqh->next_frame;
  310.  
  311.   if (dwMsg==ha->cur_msg-1)
  312.     Sqd->foPrev=psqh->prev_frame;
  313.  
  314.  
  315.   /* If we killed the message that we are on, it's a special case */
  316.  
  317.   if (dwMsg==ha->cur_msg)
  318.   {
  319.     SQHDR sqh;
  320.  
  321.     /* Go to the header of the prior msg */
  322.  
  323.     if (!_SquishReadHdr(ha, psqh->prev_frame, &sqh))
  324.     {
  325.       /* That does not exist, so go to msg 0 */
  326.  
  327.       Sqd->foCur=Sqd->foPrev=NULL_FRAME;
  328.       Sqd->foNext=Sqd->foFirst;
  329.       ha->cur_msg=0;
  330.     }
  331.     else
  332.     {
  333.       /* Otherwise, adjust pointers appropriately */
  334.  
  335.       Sqd->foCur=psqh->prev_frame;
  336.       Sqd->foPrev=sqh.prev_frame;
  337.       Sqd->foNext=sqh.next_frame;
  338.       ha->cur_msg--;
  339.     }
  340.   }
  341.   else
  342.   {
  343.     /* We didn't kill the current msg, so just decrement cur_msg if         *
  344.      * we were higher than the deleted message.                             */
  345.  
  346.     if (ha->cur_msg >= dwMsg)
  347.       ha->cur_msg--;
  348.   }
  349.  
  350.  
  351.   /* Adjust the message numbers appropriately */
  352.  
  353.   ha->num_msg--;
  354.   ha->high_msg--;
  355.  
  356.   if (ha->high_water >= dwMsg)
  357.     ha->high_water--;
  358.  
  359.   return TRUE;
  360. }
  361.  
  362.  
  363.  
  364.  
  365.  
  366. /* Write the index back to disk and free the associated memory */
  367.  
  368. unsigned _SquishFreeIndex(HAREA ha, dword dwMsg, SQIDX *psqi,
  369.                           dword dwIdxSize, unsigned fWrite)
  370. {
  371.   unsigned rc=TRUE;
  372.   long ofs;
  373.  
  374.   if (fWrite)
  375.   {
  376.     /* Seek to the offset of the message that we want to delete */
  377.  
  378.     ofs=((long)dwMsg-1L) * (long)sizeof(SQIDX);
  379.  
  380.     /* Write it back out to disk at the same position */
  381.  
  382.     rc=(lseek(Sqd->ifd, ofs, SEEK_SET)==ofs &&
  383.         write(Sqd->ifd, (char *)psqi, (unsigned)dwIdxSize)==(int)dwIdxSize);
  384.   }
  385.  
  386.   pfree(psqi);
  387.  
  388.   return rc;
  389. }
  390.  
  391.  
  392.  
  393. #if 0
  394. /* Read from the index file, starting at the dwMsg'th record */
  395.  
  396. SQIDX * _SquishAllocIndex(HAREA ha, dword dwMsg, dword *pdwIdxSize)
  397. {
  398.   SQIDX *psqi;
  399.   dword dwIdxSize;
  400.   long ofs;
  401.  
  402.   /* We only need enough memory to read in the index file from the point    *
  403.    * that we are deleting a message.                                        */
  404.  
  405.   dwIdxSize = ((long)ha->num_msg - (long)dwMsg + 1L) * (long)sizeof(SQIDX);
  406.  
  407.  
  408.   /* Handle problems that we may have when working on a 16-bit platform */
  409.  
  410.   if (dwIdxSize > 65000L)
  411.   {
  412.   }
  413.  
  414.   /* Allocate memory for handling the index */
  415.  
  416.   if ((psqi=palloc((size_t)dwIdxSize))==NULL)
  417.   {
  418.     msgapierr=MERR_NOMEM;
  419.     return NULL;
  420.   }
  421.  
  422.  
  423.   /* Seek to the offset of the message that we want to delete */
  424.  
  425.   ofs=((long)dwMsg-1L) * (long)sizeof(SQIDX);
  426.  
  427.  
  428.   /* Now read it from disk */
  429.  
  430.   if (lseek(Sqd->ifd, ofs, SEEK_SET) != ofs ||
  431.       read(Sqd->ifd, (char *)psqi, (unsigned)dwIdxSize) != (signed)dwIdxSize)
  432.   {
  433.     msgapierr=MERR_BADF;
  434.     pfree(psqi);
  435.     return NULL;
  436.   }
  437.  
  438.   *pdwIdxSize=dwIdxSize;
  439.   return psqi;
  440. }
  441.  
  442. /* This function removes the specified message number from the Squish index *
  443.  * file, moving the rest of the index file back over the message number to  *
  444.  * fill in the gaps.                                                        *
  445.  *                                                                          *
  446.  * This function also adjusts the message number pointers everywhere to     *
  447.  * accomodate for the deletion of this message.                             *
  448.  *                                                                          *
  449.  * This function assumes that we have exclusive access to the Squish base.  */
  450.  
  451. unsigned _SquishRemoveIndex(HAREA ha, dword dwMsg, SQIDX *psqiOut, SQHDR *psqh)
  452. {
  453.   dword dwIdxSize;
  454.   SQIDX *psqiLast;
  455.   SQIDX *psqi;
  456.   unsigned rc;
  457.  
  458.   assert(Sqd->fHaveExclusive);
  459.  
  460.   /* Read the index from disk */
  461.  
  462.   if ((psqi=_SquishAllocIndex(ha, dwMsg, &dwIdxSize))==NULL)
  463.     return FALSE;
  464.  
  465.  
  466.   /* If the caller wants a copy of the record that we are deleting... */
  467.  
  468.   if (psqiOut)
  469.     memmove(psqiOut, psqi, sizeof(SQIDX));
  470.  
  471.  
  472.   /* Shift everything over by one to accomodate for the deleted msg */
  473.  
  474.   memmove(psqi, psqi+1, (size_t)dwIdxSize-sizeof(SQIDX));
  475.  
  476.  
  477.   /* Blank out the last index pointer in the file so that it is invalid */
  478.  
  479.   psqiLast=psqi + (ha->num_msg - (long)dwMsg);
  480.  
  481.   psqiLast->ofs=NULL_FRAME;
  482.   psqiLast->umsgid=(UMSGID)-1L;
  483.   psqiLast->hash=(dword)-1L;
  484.  
  485.  
  486.   /* Write it back to disk and free memory */
  487.  
  488.   rc=_SquishFreeIndex(ha, dwMsg, psqi, dwIdxSize, TRUE);
  489.  
  490.  
  491.   /* If the delete succeeded, adjust the memory pointers */
  492.  
  493.   if (rc)
  494.     rc=_SquishFixMemoryPointers(ha, dwMsg, psqh);
  495.  
  496.   return rc;
  497. }
  498. #endif
  499.  
  500.