/***************************************************************************
 *                                                                         *
 *   RESERVE.C                                                             *
 *                                                                         *
 *   Copyright (c) 1994-1997 Galacticomm, Inc.    All Rights Reserved.     *
 *                                                                         *
 *   File Reservations Kernel, for avoiding read/write and write/write     *
 *   conflicts.                                                            *
 *                                                                         *
 *                                        - RNStein  7/6/94                *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "reserve.h"

#define FILREV "$Revision: 5 $"

static INT amstub(CHAR *grp,CHAR *fil);

struct reserve * FILEXP reserve;   /* current (or only) reservations domain*/

struct reserve *
inireserve(                        /* initialize a new reservations domain */
INT nusers,                        /* number of users (e.g. nterms)        */
INT *iuser,                        /* ptr to user-index var (e.g. &usrnum) */
INT lkpusr,                        /* write locks per user                 */
INT grpsiz,                        /* size of group strings (incl NUL)     */
INT filsiz,                        /* size of file strings (incl NUL)      */
INT (*amrhdl)(CHAR *grp,CHAR *fil))/* default "amreading()" resolver       */
                                   /* (or NULL=assume NOCONFLICT)          */
                                   /* returns ptr to reservations domain   */
{
     reserve=(struct reserve *)alczer(sizeof(struct reserve));
     reserve->nusers=nusers;
     reserve->iuser=iuser;
     reserve->lkpusr=lkpusr;
     reserve->grpsiz=grpsiz;
     reserve->filsiz=filsiz;
     reserve->writloks=alcblok(nusers,lkpusr*(grpsiz+filsiz));
     reserve->amreading=amrhdl == NULL ? amstub : amrhdl;
     return(reserve);
}

VOID
setrsv(                            /* set reservations domain              */
struct reserve *rsv)               /* return value from inireserve()       */
{
     reserve=rsv;
}

INT
w2writ(                            /* "I want to write (modify) this file" */
CHAR *grp,                         /* group name (e.g. Library name)       */
CHAR *fil,                         /* file name (or "*"=any file in group) */
INT lkn)                           /* lock number, 0 to lkpusr-1           */
                                   /* returns NOCONFLICT=reserved for you  */
{                                  /*         else=who writes or reads     */
     INT me,who;
     CHAR *lokptr;

     me=*reserve->iuser;
     if ((who=w2read(grp,fil)) != NOCONFLICT) {
          return(who);
     }
     if ((who=reserve->amreading(grp,fil)) != NOCONFLICT) {
          return(who);
     }
     lokptr=(CHAR *)ptrblok(reserve->writloks,me)
                   +lkn*(reserve->grpsiz+reserve->filsiz);
     stzcpy(lokptr,grp,reserve->grpsiz);
     stzcpy(lokptr+reserve->grpsiz,fil,reserve->filsiz);
     return(NOCONFLICT);
}

VOID
donewrit(                          /* "I'm done writing the file"          */
INT lkn)                           /* lock number, 0 to lkpusr-1, or -1=all*/
{                                  /* (un-write-reserve)                   */
     CHAR *lokptr;
     INT loksiz;

     loksiz=reserve->grpsiz+reserve->filsiz;
     if (lkn == -1) {
          setmem(ptrblok(reserve->writloks,*reserve->iuser),
                 reserve->lkpusr*loksiz,0);
     }
     else {
          lokptr=(CHAR *)ptrblok(reserve->writloks,*reserve->iuser)+lkn*loksiz;
          lokptr[0]='\0';
          lokptr[reserve->grpsiz]='\0';
     }
}

INT
w2read(                            /* "I want to read this file"           */
CHAR *grp,                         /* group name (e.g. Library name)       */
CHAR *fil)                         /* file name (or "*"=any file in group) */
{                                  /* returns NOCONFLICT=nobody, else=who  */
     INT who;
     INT loksiz;
     INT grpsiz;
     INT lkpusr;
     INT lok;
     CHAR *lokptr;

     lkpusr=reserve->lkpusr;
     grpsiz=reserve->grpsiz;
     loksiz=grpsiz+reserve->filsiz;
     for (who=0 ; who < reserve->nusers ; who++) {
          lokptr=(CHAR *)ptrblok(reserve->writloks,who);
          if (sameas(fil,"*")) {
               for (lok=0 ; lok < lkpusr ; lok++) {
                    if (sameas(grp,lokptr)) {
                         return(who);
                    }
                    lokptr+=loksiz;
               }
          }
          else {
               for (lok=0 ; lok < lkpusr ; lok++) {
                    if (sameas(grp,lokptr) && sameas(fil,lokptr+grpsiz)) {
                         return(who);
                    }
                    lokptr+=loksiz;
               }
          }
     }
     return(NOCONFLICT);
}

INT
whouse(                            /* Who is using this group?             */
CHAR *grp)                         /* group name (e.g. Library name)       */
{                                  /* return NOCONFLICT=nobody, else=who   */
     INT who;

     if ((who=w2read(grp,"*")) != NOCONFLICT) {
          return(who);
     }
     if ((who=reserve->amreading(grp,"*")) != NOCONFLICT) {
          return(who);
     }
     return(NOCONFLICT);
}

static INT
amstub(                            /* stub for reserve->amreading()        */
CHAR *grp,                         /* group name (e.g. Library name)       */
CHAR *fil)                         /* file name (or "*"=any file in group) */
{                                  /* returns NOCONFLICT=nobody, else=who  */
     (VOID)grp;
     (VOID)fil;
     return(NOCONFLICT);
}
