home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD v1.2 / amidev_cd_12.iso / reference / amiga_mail_vol2 / ii-87 / lockrecord.c < prev    next >
C/C++ Source or Header  |  1996-01-30  |  14KB  |  443 lines

  1. ; /* LockRecord.c - Execute me to compile me with SAS/C 6.56
  2. sc NMINC STRMERGE NOSTKCHK NODEBUG DATA=FAR IGNORE=73 LockRecord.c
  3. slink FROM LockRecord.o to LockRecord LIB lib:amiga.lib
  4. quit
  5. *
  6. * AmigaMail LockRecord()/UnLockRecord() example.
  7. */
  8.  
  9. /*
  10. (c)  Copyright 1992 Commodore-Amiga, Inc.   All rights reserved.
  11. The information contained herein is subject to change without notice,
  12. and is provided "as is" without warranty of any kind, either expressed
  13. or implied.  The entire risk as to the use of this information is
  14. assumed by the user.
  15. */
  16.  
  17. #include <exec/memory.h>
  18. #include <exec/lists.h>
  19. #include <dos/dosextens.h>
  20. #include <dos/rdargs.h>
  21. #include <dos/record.h>
  22. #include <utility/tagitem.h>
  23.  
  24. #include <clib/alib_protos.h>
  25. #include <clib/dos_protos.h>
  26. #include <clib/exec_protos.h>
  27. #include <clib/utility_protos.h>
  28.  
  29. void GetCommandLine(BPTR, struct RDArgs *rdargs, UBYTE *cmdbuffer);
  30. void DoLockRecord(BPTR, struct RDArgs *rdargs);
  31. void DoUnLockRecord(BPTR fh, struct RDArgs *rdargs);
  32. void ListRecordLocks(void);
  33. struct LockNode *FindRecordLock(ULONG offset, ULONG length);
  34.  
  35. /* List and node structures to keep track of record locks */
  36. struct LockNode {
  37.     struct LockNode *ln_Succ;
  38.     struct LockNode *ln_Pred;
  39.     ULONG ln_Counter;
  40.     ULONG ln_Offset;
  41.     ULONG ln_Length;
  42.     ULONG ln_Mode;
  43. };
  44.  
  45. struct LockList {
  46.     struct LockNode *lh_Head;
  47.     struct LockNode *lh_Tail;
  48.     struct LockNode *lh_TailPred;
  49.     ULONG lh_Counter;
  50. };
  51.  
  52. /* Pseudo data file */
  53. #define TESTFILE "t:locktest"
  54.  
  55. #define LOCK_TEMPLATE "OFFSET/K/N,LENGTH/K/N,EXCLUSIVE/S,IMMEDIATE/S,TIMEOUT/K/N"
  56. #define UNLOCK_TEMPLATE "OFFSET/K/N,LENGTH/K/N"
  57.  
  58. #define OFFSET_POS      0
  59. #define LENGTH_POS      1
  60. #define EXCLUSIVE_POS   2
  61. #define IMMEDIATE_POS   3
  62. #define TIMEOUT_POS     4
  63.  
  64. struct Library *SysBase;
  65. struct DosLibrary *DOSBase;
  66. struct Library *UtilityBase;
  67.  
  68. struct LockList *locklist;
  69.  
  70. LONG main(void)
  71. {
  72.     BPTR fh;
  73.     struct RDArgs *rdargs;
  74.     struct CSource *csource;
  75.     UBYTE *cmdbuffer;
  76.     struct LockNode *lnode, *nnode;
  77.     LONG error = RETURN_OK;
  78.  
  79.     SysBase = (*((struct Library **) 4));
  80.  
  81.     /* Fails silently if < 37 */
  82.     if (DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 37))
  83.     {
  84.         UtilityBase = DOSBase->dl_UtilityBase;
  85.  
  86.         if (locklist = AllocMem(sizeof(struct LockList), MEMF_CLEAR))
  87.         {
  88.             NewList((struct List *)locklist);
  89.  
  90.             /* Allocate RDArgs structure to parse command lines */
  91.             if (rdargs = AllocDosObject(DOS_RDARGS, TAG_END))
  92.             {
  93.                 csource = &rdargs->RDA_Source;
  94.  
  95.                 /* Get buffer to read command lines in */
  96.                 if (csource->CS_Buffer = AllocMem(512, MEMF_CLEAR))
  97.                 {
  98.                     csource->CS_Length = 512;
  99.                     csource->CS_CurChr = 0;
  100.  
  101.                     /* Buffer to isolate command keyword */
  102.                     if (cmdbuffer = AllocMem(80, MEMF_CLEAR))
  103.                     {
  104.  
  105.                         /* Open a testfile, create it if necessary */
  106.                         if (fh = Open(TESTFILE, MODE_READWRITE))
  107.                         {
  108.  
  109.                             /* Process command lines */
  110.                             GetCommandLine(fh, rdargs, cmdbuffer);
  111.  
  112.                             /* Try to get rid of outstanding record locks */
  113.                             lnode = locklist->lh_Head;
  114.                             while (nnode = lnode->ln_Succ)
  115.                             {
  116.  
  117.                                 /* Try to unlock pending locks */
  118.                                 if ((UnLockRecord(fh,
  119.                                                   lnode->ln_Offset,
  120.                                                   lnode->ln_Length)) == DOSFALSE)
  121.                                 {
  122.                    Printf("Error unlocking record %ld with offset %ld length %ld\n",
  123.                                         lnode->ln_Counter,
  124.                                         lnode->ln_Offset,
  125.                                         lnode->ln_Length);
  126.                                     if (IoErr())
  127.                                         PrintFault(IoErr(), NULL);
  128.                                 }
  129.                                 /* Remove node no matter what */
  130.                                 FreeMem(lnode, sizeof(struct LockNode));
  131.                                 lnode = nnode;
  132.                             };
  133.  
  134.                             Close(fh);
  135.                         }
  136.                         FreeMem(cmdbuffer, 80);
  137.                     } else
  138.                         SetIoErr(ERROR_NO_FREE_STORE);
  139.  
  140.                     FreeMem(csource->CS_Buffer, 512);
  141.                 } else
  142.                     SetIoErr(ERROR_NO_FREE_STORE);
  143.  
  144.                 FreeDosObject(DOS_RDARGS, rdargs);
  145.             } else
  146.                 SetIoErr(ERROR_NO_FREE_STORE);
  147.  
  148.             FreeMem(locklist, sizeof(struct LockList));
  149.         } else
  150.             SetIoErr(ERROR_NO_FREE_STORE);
  151.  
  152.  
  153.         error = IoErr();
  154.         if (error)
  155.         {
  156.             PrintFault(IoErr(), NULL);
  157.             error = RETURN_FAIL;
  158.         }
  159.  
  160.         CloseLibrary((struct Library *)DOSBase);
  161.     }
  162.     return(error);
  163. }
  164. void GetCommandLine(BPTR fh, struct RDArgs *rdargs, UBYTE *cmdbuffer)
  165. {
  166.     struct CSource *csource = &rdargs->RDA_Source;
  167.     UBYTE *cmdlinebuffer = csource->CS_Buffer;
  168.     LONG error;
  169.  
  170.     /* Prompt for command line */
  171.     Write(Output(), "Cmd> ", 5);
  172.  
  173.     /* Loop forever, waiting for commands */
  174.     for (;;)
  175.     {
  176.         /* Get command line */
  177.         if ((FGets(Input(), cmdlinebuffer, 512)) != NULL)
  178.         {
  179.  
  180.             /* Use ReadItem() to isolate actual command */
  181.             error = ReadItem(cmdbuffer, 80, csource);
  182.  
  183.             /* Break on error */
  184.             if (error == ITEM_ERROR)
  185.                 break;
  186.  
  187.             /* Make sure I've got something */
  188.             else if (error != ITEM_NOTHING)
  189.             {
  190.                 /* cmdbuffer now contains the command:
  191.                  *
  192.                  * KNOWN COMMANDS:
  193.                  * QUIT
  194.                  * LIST
  195.                  * LOCKRECORD
  196.                  * UNLOCKRECORD
  197.                  */
  198.  
  199.                 if ((Stricmp("QUIT", cmdbuffer)) == 0)
  200.                     break;
  201.                 else if ((Stricmp("HELP", cmdbuffer)) == 0)
  202.                 {
  203.                     Printf("Available commands:\n");
  204.                     Printf("LOCKRECORD %s\n", LOCK_TEMPLATE);
  205.                     Printf("UNLOCKRECORD %s\n", UNLOCK_TEMPLATE);
  206.                     Printf("LIST\n");
  207.                     Printf("QUIT\n");
  208.                 }
  209.                 else if ((Stricmp("LIST", cmdbuffer)) == 0)
  210.                     ListRecordLocks();  /* Show all current locks */
  211.                 else
  212.                 {
  213.  
  214.                     /* Note that I've already isolated the command
  215.                      * keyword, so I'm using Source->CS_CurChr to point
  216.                      * after it.
  217.                      */
  218.                     csource->CS_Buffer += csource->CS_CurChr;
  219.                     csource->CS_CurChr = 0;
  220.  
  221.                     if ((Stricmp("LOCKRECORD", cmdbuffer)) == 0)
  222.                         DoLockRecord(fh, rdargs);
  223.                     else if ((Stricmp("UNLOCKRECORD", cmdbuffer)) == 0)
  224.                         DoUnLockRecord(fh, rdargs);
  225.                     else
  226.                         PrintFault(ERROR_NOT_IMPLEMENTED, cmdbuffer);
  227.  
  228.                     /* Reset CSource */
  229.                     csource->CS_Buffer = cmdlinebuffer;
  230.                 }
  231.  
  232.                 /* Output new prompt. Make sure csource is OK. */
  233.                 Write(Output(), "Cmd> ", 5);
  234.                 csource->CS_CurChr = 0;
  235.             }
  236.         } else
  237.             break;
  238.     }
  239. }
  240.  
  241. void DoLockRecord(BPTR fh, struct RDArgs *rdargs)
  242. {
  243.     struct RDArgs *readargs;
  244.     LONG rargs[5];
  245.     ULONG offset, length, timeout, mode;
  246.     ULONG result;
  247.     struct LockNode *lnode;
  248.  
  249.     offset = length = timeout = mode = 0;
  250.     rargs[0] = rargs[1] = rargs[2] = rargs[3] = rargs[4] = 0;
  251.  
  252.     if (readargs = ReadArgs(LOCK_TEMPLATE, rargs, rdargs))
  253.     {
  254.  
  255.         if (rargs[OFFSET_POS])
  256.             offset = *((LONG *)rargs[OFFSET_POS]);
  257.         if (rargs[LENGTH_POS])
  258.             length = *((LONG *)rargs[LENGTH_POS]);
  259.         if (rargs[TIMEOUT_POS])
  260.             timeout = *((LONG *)rargs[TIMEOUT_POS]);
  261.  
  262.         /* Type of locking */
  263.         if (rargs[EXCLUSIVE_POS])
  264.         {
  265.             if (rargs[IMMEDIATE_POS])
  266.                 mode = REC_EXCLUSIVE_IMMED;
  267.             else
  268.                 mode = REC_EXCLUSIVE;
  269.         }
  270.         else
  271.         {
  272.             if (rargs[IMMEDIATE_POS])
  273.                 mode = REC_SHARED_IMMED;
  274.             else
  275.                 mode = REC_SHARED;
  276.         }
  277.  
  278.         rargs[0] = offset;
  279.         rargs[1] = length;
  280.         switch (mode)
  281.         {
  282.             case REC_EXCLUSIVE_IMMED:
  283.                 rargs[2] = (LONG)"REC_EXCLUSIVE_IMMED";
  284.                 break;
  285.             case REC_EXCLUSIVE:
  286.                 rargs[2] = (LONG)"REC_EXCLUSIVE";
  287.                 break;
  288.             case REC_SHARED_IMMED:
  289.                 rargs[2] = (LONG)"REC_SHARED_IMMED";
  290.                 break;
  291.             case REC_SHARED:
  292.                 rargs[2] = (LONG)"REC_SHARED";
  293.                 break;
  294.         }
  295.         rargs[3] = timeout;
  296.  
  297.  
  298.         /* Show what I'm going to do */
  299.         VFPrintf(Output(),
  300.             "LockRecord: Offset %ld, Length %ld, Mode %s, Timeout %ld...",
  301.             rargs);
  302.         Flush(Output());
  303.  
  304.         /* Lock the record. Parameters are not checked. It is f.e. possible to
  305.          * specify an offset larger than the size of the file. Possible since
  306.          * Record Locks are not related to the file itself, only the means for
  307.          * you to do arbitration.
  308.          *
  309.          * Note that the timeout value is in ticks...
  310.          */
  311.         result = LockRecord(fh, offset, length, mode, timeout);
  312.  
  313.         if (result == DOSTRUE)
  314.         {
  315.             Write(Output(), "OK\n", 3);
  316.  
  317.             /* Add a node to track this record lock */
  318.             if (lnode = AllocMem(sizeof(struct LockNode), MEMF_CLEAR))
  319.             {
  320.                 lnode->ln_Counter = locklist->lh_Counter++;
  321.                 lnode->ln_Offset = offset;
  322.                 lnode->ln_Length = length;
  323.                 lnode->ln_Mode = mode;
  324.  
  325.                 AddTail((struct List *)locklist, (struct Node *)lnode);
  326.             }
  327.             else
  328.             {
  329.                 /* Not enough memory for node. You're on your own... */
  330.                 Write(Output(), "Not enough memory to track record lock.\n", 40);
  331.             }
  332.         }
  333.         else
  334.         {
  335.             Write(Output(), "FAILED\n", 7);
  336.             if (IoErr())
  337.                 PrintFault(IoErr(), NULL);
  338.         }
  339.  
  340.         /* Release memory associated with readargs */
  341.         FreeArgs(readargs);
  342.     } else
  343.         PrintFault(IoErr(), NULL);
  344. }
  345.  
  346. void DoUnLockRecord(BPTR fh, struct RDArgs *rdargs)
  347. {
  348.     struct RDArgs *readargs;
  349.     LONG rargs[2];
  350.     ULONG offset, length;
  351.     ULONG result;
  352.     struct LockNode *lnode;
  353.  
  354.     offset = length = 0;
  355.     rargs[0] = rargs[1] = 0;
  356.  
  357.     if (readargs = ReadArgs(LOCK_TEMPLATE, rargs, rdargs))
  358.     {
  359.  
  360.         if (rargs[OFFSET_POS])
  361.             offset = *((LONG *)rargs[OFFSET_POS]);
  362.         if (rargs[LENGTH_POS])
  363.             length = *((LONG *)rargs[LENGTH_POS]);
  364.  
  365.         rargs[0] = offset;
  366.         rargs[1] = length;
  367.  
  368.         /* Show what I'm going to do */
  369.         VFPrintf(Output(), "UnLockRecord: Offset %ld, Length %ld...", rargs);
  370.         Flush(Output());
  371.  
  372.         /* Unlock indicated record with indicated offset and length.
  373.          * If the same record (same offset/length) is locked multiple times,
  374.          * only one, the first one in the list , will be unlocked.
  375.          */
  376.         result = UnLockRecord(fh, offset, length);
  377.  
  378.         if (result == DOSTRUE) {
  379.             Write(Output(), "OK\n", 3);
  380.  
  381.             /* Remove node associated with this lock */
  382.             if (lnode = FindRecordLock(offset, length))
  383.             {
  384.                 Remove((struct Node *)lnode);
  385.                 FreeMem(lnode, sizeof(struct LockNode));
  386.             }
  387.         }
  388.         else
  389.         {
  390.             Write(Output(), "FAILED\n", 7); /* Keep locknode */
  391.             if (IoErr())
  392.                 PrintFault(IoErr(), NULL);
  393.         }
  394.         /* Release memory associated with readargs */
  395.         FreeArgs(readargs);
  396.     } else
  397.         PrintFault(IoErr(), NULL);
  398. }
  399.  
  400. void ListRecordLocks(void)
  401. {
  402.     struct LockNode *lnode;
  403.     LONG rargs[4];
  404.  
  405.     for (lnode = locklist->lh_Head; lnode->ln_Succ; lnode = lnode->ln_Succ)
  406.     {
  407.         rargs[0] = lnode->ln_Counter;
  408.         rargs[1] = lnode->ln_Offset;
  409.         rargs[2] = lnode->ln_Length;
  410.  
  411.         switch (lnode->ln_Mode)
  412.         {
  413.             case REC_EXCLUSIVE_IMMED:
  414.                 rargs[3] = (LONG)"REC_EXCLUSIVE_IMMED";
  415.                 break;
  416.             case REC_EXCLUSIVE:
  417.                 rargs[3] = (LONG)"REC_EXCLUSIVE";
  418.                 break;
  419.             case REC_SHARED_IMMED:
  420.                 rargs[3] = (LONG)"REC_SHARED_IMMED";
  421.                 break;
  422.             case REC_SHARED:
  423.                 rargs[3] = (LONG)"REC_SHARED";
  424.                 break;
  425.         }
  426.  
  427.         VFPrintf(Output(), "RecordLock #%ld: Offset %ld Length %ld Mode %s\n", rargs);
  428.     }
  429.     Flush(Output());
  430. }
  431.  
  432. struct LockNode *FindRecordLock(ULONG offset, ULONG length)
  433. {
  434.     struct LockNode *lnode;
  435.  
  436.     for (lnode = locklist->lh_Head; lnode->ln_Succ; lnode = lnode->ln_Succ)
  437.     {
  438.         if ((lnode->ln_Offset == offset) && lnode->ln_Length == length)
  439.             return(lnode);
  440.     }
  441.     return(NULL);
  442. }
  443.