function gag_hasins(mdim,pf,pn,dict,name,in)
  use gsys_interfaces, except_this=>gag_hasins
  !---------------------------------------------------------------------
  ! @ public
  !  *** This version for dictionaries as character string arrays ***
  !       Insert a new name or replace an existing name
  !       in a dictionnary using a hashing structure
  !       and a list of pointers.
  !
  !       GAG_HASINS      0       E  Invalid name
  !                       1       S  Successfully inserted
  !                       2       E  Too many names
  !                       3       S  Successfully replaced
  !
  !       PF      I(0:27) PF(J) Address of first name beginning
  !                       with CHAR(J-ICHAR('A')) in dictionnary.
  !                       PF(26) is the address of the first
  !                       available place.                        Input/Output
  !                       PF(27) is the number of symbols
  !       PN      I(MDIM) Address of next name with same first
  !                       letter. If PN(J)=0, no more such name.  Input/Output
  !---------------------------------------------------------------------
  integer(kind=4) :: gag_hasins  ! Function value on return
  integer(kind=4),  intent(in)    :: mdim        ! Size of dictionnary
  integer(kind=4),  intent(inout) :: pf(0:27)    !
  integer(kind=4),  intent(inout) :: pn(mdim)    !
  character(len=*), intent(inout) :: dict(mdim)  ! Dictionnary array of size MDIM
  character(len=*), intent(inout) :: name        ! Name to be inserted
  integer(kind=4),  intent(out)   :: in          ! Address of this name
  ! Local
  integer(kind=4) :: j,k
  !
  in = 0
  gag_hasins = 0
  !
  ! Find the place in PF
  call sic_upper(name)
  j = ichar(name(1:1))-ichar('A')
  if (j.lt.0 .or. j.gt.25) return
  !
  ! Find if it exits already
  k = pf(j)
  do while(k.gt.0)
    if (name.eq.dict(k)) then
      in = k
      gag_hasins = 3
      return
    endif
    k = pn(k)
  enddo
  !
  ! Find if place left
  if (pf(26).eq.0) then
    gag_hasins = 2
  else
    !
    ! Insert NAME in place and set pointers
    k = pf(26)
    pf(26) = pn(k)
    pn(k) = pf(j)
    pf(j) = k
    dict(k) = name
    in = k
    pf(27) = pf(27)+1
    gag_hasins = 1
  endif
end function gag_hasins
!
subroutine gag_hasini(mdim,pf,pn)
  !---------------------------------------------------------------------
  ! @ public
  ! SIC   Internal routine
  !  *** This version for all kind of dictionaries ***
  !       Initialise a hashing structure for a possible dictionnary.
  ! Arguments :
  !       MDIM    I       Size of dictionnary
  !       PF      I(0:27) PF(J) Address of first name beginning
  !                       with CHAR(J-ICHAR('A')) in dictionnary.
  !                       PF(26) is the address of the first
  !                       available place.
  !                       PF(27) the number of symbol
  !       PN      I(MDIM) Address of next name with same first
  !                       letter. If PN(J)=0, no more such name.
  !---------------------------------------------------------------------
  integer(kind=4), intent(in)  :: mdim      !
  integer(kind=4), intent(out) :: pf(0:27)  !
  integer(kind=4), intent(out) :: pn(mdim)  !
  ! Local
  integer(kind=4) :: i
  !
  do i=0,25
    pf(i) = 0
  enddo
  pf(26) = 1
  pf(27) = 0
  do i=1,mdim-1
    pn(i) = i+1
  enddo
  pn(mdim) = 0
end subroutine gag_hasini
!
function gag_hasdel(mdim,pf,pn,dict,name)
  use gsys_interfaces, except_this=>gag_hasdel
  !---------------------------------------------------------------------
  ! @ public
  !  *** This version for dictionaries as character string arrays ***
  !       Delete a name in a dictionnary using a hashing structure
  !       and a list of pointers.
  !
  !       GAG_HASDEL      1       Name deleted
  !                       3       Name does not exist
  !
  !       PF      I(0:27) PF(J) Address of first name beginning
  !                       with CHAR(J-ICHAR('A')) in dictionnary.
  !                       PF(26) is the address of the first
  !                       available place.                        Input/Output
  !                       PF(27) is the number of symbols
  !       PN      I(MDIM) Address of next name with same first
  !                       letter. If PN(J)=0, no more such name.  Input/Output
  !---------------------------------------------------------------------
  integer(kind=4) :: gag_hasdel  ! Function value on return
  integer(kind=4),  intent(in)    :: mdim        ! Size of dictionnary
  integer(kind=4),  intent(inout) :: pf(0:27)    !
  integer(kind=4),  intent(inout) :: pn(mdim)    !
  character(len=*), intent(in)    :: dict(mdim)  ! Dictionnary array of size MDIM
  character(len=*), intent(inout) :: name        ! Name to be deleted
  ! Local
  integer(kind=4) :: j,kl,k
  !
  gag_hasdel = 3
  ! Find the place in PF
  call sic_upper(name)
  j = ichar(name(1:1))-ichar('A')
  if (j.lt.0 .or. j.gt.25) return
  !
  ! Now examine if it is a known symbol
  kl = 0
  k = pf(j)
10 if (k.eq.0) return
  if (name.ne.dict(k)) then
    kl = k
    k = pn(k)
    goto 10
  endif
  !
  ! Now delete it
  gag_hasdel = 1
  if (kl.ne.0) then
    pn(kl) = pn(k)
  else
    pf(j) = pn(k)
  endif
  pn(k) = pf(26)
  pf(26) = k
  pf(27) = pf(27)-1
end function gag_hasdel
!
function gag_hasfin(mdim,pf,pn,dict,name,in)
  use gsys_interfaces, except_this=>gag_hasfin
  !---------------------------------------------------------------------
  ! @ public
  !  *** This version for dictionaries as character string arrays ***
  !       Find a name in a dictionnary using a hashing structure
  !       and a list of pointers.
  !
  !       GAG_HASFIN      0       No such name
  !                       1       Name found
  !       PF      I(0:27) PF(J) Address of first name beginning
  !                       with CHAR(J-ICHAR('A')) in dictionnary.
  !                       PF(26) is the address of the first
  !                       available place.                        Input
  !       PN      I(MDIM) Address of next name with same first
  !                       letter. If PN(J)=0, no more such name.  Input
  !---------------------------------------------------------------------
  integer(kind=4) :: gag_hasfin  ! Function value on return
  integer(kind=4),  intent(in)    :: mdim        ! Size of dictionnary
  integer(kind=4),  intent(in)    :: pf(0:27)    !
  integer(kind=4),  intent(in)    :: pn(mdim)    !
  character(len=*), intent(in)    :: dict(mdim)  ! Dictionnary array of size MDIM
  character(len=*), intent(inout) :: name        ! Name to be found
  integer(kind=4),  intent(out)   :: in          ! Address of this name
  ! Local
  integer(kind=4) :: j
  !
  ! If no symbol return
  in = 0
  gag_hasfin = 0
  if (pf(27).eq.0) return
  !
  ! Find the place in PF
  call sic_upper(name)
  j = ichar(name(1:1))-ichar('A')
  if (j.lt.0 .or. j.gt.25) return
  !
  ! Now examine the chained structure from this point
  j = pf(j)
10 if (j.eq.0) return
  if (name.eq.dict(j)) then
    in = j
    gag_hasfin = 1
    return
  endif
  j = pn(j)
  goto 10
end function gag_hasfin
!
subroutine gag_haslis(mdim,pf,pn,list,leng)
  !---------------------------------------------------------------------
  ! @ public
  !  *** This version for all kind of dictionaries ***
  !
  !  List a dictionnary using a hashing structure and a list of pointers.
  ! This routine just builds the list of pointers to current entries.
  !
  ! THERE IS NO WARRANTY THE OUTPUT LIST IS SORTED ALPHABETICALLY.
  ! Actually with the current hashing method, the output list is sorted
  ! by first letter only. Use subroutine gag_hassort for a fully sorted
  ! list.
  !
  !   PF(0:27)   PF(0:25) Address of first name beginning with
  !                       CHAR(J-ICHAR('A')) in dictionnary.
  !              PF(26)   is the address of the first available place.
  !              PF(27)   the number of symbols
  !   PN(MDIM)            Address of next name with same first letter.
  !                       If PN(J)=0, no more such name.
  !---------------------------------------------------------------------
  integer(kind=4), intent(in)  :: mdim        ! Size of dictionnary
  integer(kind=4), intent(in)  :: pf(0:27)    !
  integer(kind=4), intent(in)  :: pn(mdim)    !
  integer(kind=4), intent(out) :: list(mdim)  ! List of entries in dictionnary
  integer(kind=4), intent(out) :: leng        ! Current number of entries
  ! Local
  integer(kind=4) :: i,j
  !
  leng = 0
  if (pf(27).eq.0) return
  do i=0,25
    if (pf(i).le.0)  cycle
    j = pf(i)
    leng = leng+1
    list(leng) = j
    do while (pn(j).gt.0)
      j = pn(j)
      leng = leng+1
      list(leng) = j
    enddo
  enddo
end subroutine gag_haslis
