/*******************************************/
/*                                         */
/*  File: chtmlidfs.c                      */
/*  Purpose: c2html identifier unit        */
/*                                         */
/*  Author: Sfiligoi Igor                  */
/*                                         */
/*  Created      : 25.03.1997              */
/*  Last modified: 15.04.1997              */
/*                                         */
/*******************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "chtmldefs.h"
#include "chtmlidfs.h"

typedef struct _hash_el
         {
	   struct _hash_el *next;
	   char *elstr;
	   char *htmlname;
	   char *elurl;
         } HASH_EL;

#define HASH_EL_NR     211

typedef HASH_EL HASH_TABLE[HASH_EL_NR];

/* hash function */

int hash_func(char *elstr)
{
 char *p;
 unsigned int h=0, g;

 for (p=elstr; *p != 0; p++)
        {
         h = (h<<4) + (*p);
         if ((g=h&0xf0000000))  /* assign to g */
                {
                 h = h ^ (g>>24);
                 h = h ^ g;
                }
        }
 return h % HASH_EL_NR;
}



/* Init Routines */

void *hash_new()
{
 HASH_TABLE *table;
 int i;

 table = (HASH_TABLE *) malloc(sizeof(HASH_TABLE));
 for (i=0; i<HASH_EL_NR; i++)
   { /* the first ellement is dummy to preserve uniformity */
     (*table)[i].next = NULL;
     (*table)[i].elstr = NULL;
     (*table)[i].htmlname = NULL;
     (*table)[i].elurl = NULL;
   }

 return table;
}

void hash_dispose(void *hash)
{
 HASH_TABLE *table;
 int i;

 table = (HASH_TABLE *) hash;

 for (i=0; i<HASH_EL_NR; i++)
   {
     HASH_EL *hashel;

     for (hashel = (*table)[i].next;
	  hashel!=NULL;
	  hashel = (*table)[i].next)
       {
	 (*table)[i].next=hashel->next;
	 free(hashel->next);
	 free(hashel->elstr);
	 free(hashel->htmlname);
	 free(hashel->elurl);
       }
   }
}

/* Delete an  Idf */

void hash_del(void *hash,
	      char *idfname)
{
 HASH_TABLE *table;
 HASH_EL *hashel;
 unsigned int hash_nr;

 table = (HASH_TABLE *) hash;
 hash_nr = hash_func(idfname);

 for (hashel = &((*table)[hash_nr]);
      hashel->next!=NULL;
      hashel = hashel->next)
   if (strcmp(hashel->next->elstr,idfname)==0)
     { /* found, delete it */
       HASH_EL *tmp_hashel;
       
       tmp_hashel = hashel->next;
       hashel->next = hashel->next->next;

       free(tmp_hashel->elstr);
       free(tmp_hashel->htmlname);
       free(tmp_hashel->elurl);

       return;
     }
}

/* Add Idf */

void hash_add(void *hash,
	      char *idfname,
	      char *htmlname)
{
 HASH_TABLE *table;
 HASH_EL *hashel;
 unsigned int hash_nr;

 table = (HASH_TABLE *) hash;

 hash_nr = hash_func(idfname);

 hashel = (HASH_EL *) malloc(sizeof(HASH_EL));
 hashel->elstr = (char *) malloc(strlen(idfname)+1);
 strcpy(hashel->elstr,idfname);
 if (htmlname==NULL)
   {
     hashel->htmlname = NULL;
     hashel->elurl = (char *) malloc(strlen(idfname)+2);
     sprintf(hashel->elurl,"#%s",idfname);
   }
 else
   {
     hashel->htmlname = normalize_dir(htmlname,chidir);

     if ((strchr(htmlname,'#')==NULL)&&(strchr(htmlname,'?')==NULL))
       { /* a filename, needs the internal link */
	 char *tmpname;

	 tmpname = normalize_dir(htmlname,outdir);
	 hashel->elurl = (char *) malloc(strlen(tmpname)+strlen(idfname)+2);
	 sprintf(hashel->elurl,"%s#%s",tmpname,idfname);
	 free(tmpname);
       }
     else
       { /* already has all it needs */
	 hashel->elurl = normalize_dir(htmlname,outdir);
       }
   }

 hashel->next = (*table)[hash_nr].next;
 (*table)[hash_nr].next = hashel;
}

/* Search */

char *hash_find(void *hash,
		char *idfname)
{
 HASH_TABLE *table;
 HASH_EL *hashel;
 unsigned int hash_nr;

 table = (HASH_TABLE *) hash;
 hash_nr = hash_func(idfname);

 for (hashel = (*table)[hash_nr].next;
      hashel!=NULL;
      hashel = hashel->next)
   if (strcmp(hashel->elstr,idfname)==0)
     return hashel->elurl; /* true, found */

 return NULL; /* false, not found */
}

/* hash IO */

char *hash_load(void *hash,
		char *filename)
{
 FILE *hashfile;
 char *htmlname,*mainhtmlname,*tmpname;
 char idfname[1024];
 int res,i;

 hashfile = fopen(filename,"r");

 /* test if it is a real chi file */
 fscanf(hashfile,"%s\n",idfname);
 if (strcmp(idfname,"CHI")!=0)
   {
     fprintf(stderr,"WARNING: %s not a CHI file, skipped!\n",filename);
     fclose(hashfile);
     return NULL;
   }



 mainhtmlname = (char *) malloc(4096);
 fscanf(hashfile,"%s\n",mainhtmlname);

 if (mainhtmlname[0]!='*')
   { /* there is a filename */
     if (!((mainhtmlname[0]=='/')||
	   (((mainhtmlname[0]=='h')||(mainhtmlname[0]=='H'))&&
	    ((mainhtmlname[1]=='t')||(mainhtmlname[1]=='T'))&&
	    ((mainhtmlname[2]=='t')||(mainhtmlname[2]=='T'))&&
	    ((mainhtmlname[3]=='p')||(mainhtmlname[3]=='P'))&&
	    (mainhtmlname[4]==':'))))
       { /* must be trasformed in a path relative to the current dir */
	 char *dirname;
	 int i;
	 
	 dirname = (char *) malloc(strlen(filename)+strlen(mainhtmlname)+1); /* worst case */
	 
	 strcpy(dirname,filename);
	 for(i=strlen(dirname)-1; dirname[i]!='/'; i--)
	   dirname[i] = 0;
	 strcat(dirname,mainhtmlname);
	 
	 free(mainhtmlname);
	 mainhtmlname=dirname;
       }
     
     tmpname = mainhtmlname;
     mainhtmlname = normalize_dir(tmpname,outdir);
     free(tmpname);
   }
 else
   { /* no filename */
     free(mainhtmlname);
     mainhtmlname=NULL;
   }

 htmlname = (char *) malloc(4096);

 for (res=fscanf(hashfile,"%s %s\n",idfname,htmlname);
      res!=EOF;
      res=fscanf(hashfile,"%s %s\n",idfname,htmlname))
   {
     if (!((htmlname[0]=='/')||
	   (((htmlname[0]=='h')||(htmlname[0]=='H'))&&
	    ((htmlname[1]=='t')||(htmlname[1]=='T'))&&
	    ((htmlname[2]=='t')||(htmlname[2]=='T'))&&
	    ((htmlname[3]=='p')||(htmlname[3]=='P'))&&
	    (htmlname[4]==':'))))
       { /* must be trasformed in a path relative to the current dir */
	 char *dirname;
	 int i;
	 
	 dirname = (char *) malloc(strlen(filename)+strlen(htmlname)+1); /* worst case */
	 
	 strcpy(dirname,filename);
	 for(i=strlen(dirname)-1; dirname[i]!='/'; i--)
	   dirname[i] = 0;
	 strcat(dirname,htmlname);
	 
	 free(htmlname);
	 htmlname=dirname;
       }

     /* do not allow multiple copies */
     hash_del(hash,idfname);
     hash_add(hash,idfname,htmlname);

     free(htmlname);
     htmlname = (char *) malloc(4096);
   }

 fclose(hashfile);
 return mainhtmlname;
}

void hash_save(void *hash,
	       char *filename,
	       char *htmlname)
{
 FILE *hashfile;
 HASH_TABLE *table;
 char * norm_htmlname;
 int i;

 table = (HASH_TABLE *) hash;

 norm_htmlname = normalize_dir(htmlname,chidir);

 hashfile = fopen(filename,"w");

 /* write idf */
 fprintf(hashfile,"CHI\n");

 fprintf(hashfile,"%s\n",norm_htmlname);

 for (i=0; i<HASH_EL_NR; i++)
   {
     HASH_EL *hashel;

    
     for (hashel=(*table)[i].next;
	  hashel!=NULL;
	  hashel=hashel->next)
       {
	 if (hashel->htmlname!=NULL)
	   fprintf(hashfile,"%s %s\n",hashel->elstr,hashel->htmlname);
	 else
	   fprintf(hashfile,"%s %s\n",hashel->elstr,norm_htmlname);
       }
   }

 free(norm_htmlname);
 fclose(hashfile);
}